diff --git a/package.json b/package.json index b1d1ff40..58b48f15 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "js-cookie": "^3.0.1", "lz-string": "^1.4.4", "message-port-api": "^0.0.5", + "minisearch": "^6.0.1", "pinia": "^2.0.29", "pinia-plugin-persistedstate": "^3.0.2", "pinia-plugin-persistedstate-2": "^2.0.10", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f2dee8c6..5111f0da 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -70,6 +70,9 @@ dependencies: message-port-api: specifier: ^0.0.5 version: 0.0.5 + minisearch: + specifier: ^6.0.1 + version: 6.0.1 pinia: specifier: ^2.0.29 version: 2.0.29(typescript@4.9.4)(vue@3.2.45) @@ -6744,6 +6747,10 @@ packages: resolution: {integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==} dev: true + /minisearch@6.0.1: + resolution: {integrity: sha512-Ly1w0nHKnlhAAh6/BF/+9NgzXfoJxaJ8nhopFhQ3NcvFJrFIL+iCg9gw9e9UMBD+XIsp/RyznJ/o5UIe5Kw+kg==} + dev: false + /mkdirp-classic@0.5.3: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} dev: true diff --git a/setup.vitest.ts b/setup.vitest.ts new file mode 100644 index 00000000..dc69b2bd --- /dev/null +++ b/setup.vitest.ts @@ -0,0 +1,24 @@ +window.Http = { + version: "0.0.21", + get(options) { + return fetch(options.url) + .then((res) => res.text()) + .then((text) => { + return { + data: text, + } + }) + }, + post(options) { + return fetch(options.url, { + method: "POST", + body: JSON.stringify(options.data), + }) + .then((res) => res.text()) + .then((text) => { + return { + data: text, + } + }) + }, +} diff --git a/src/apis/parser/myanimelist/episodes.ts b/src/apis/parser/myanimelist/episodes.ts index a6b1ee63..f6404b8f 100644 --- a/src/apis/parser/myanimelist/episodes.ts +++ b/src/apis/parser/myanimelist/episodes.ts @@ -1 +1,18 @@ -export function AnimeEpisodes(html) {} +import { parserDom } from "../__helpers__/parserDom" + +export default function AnimeEpisodes(html: string) { + const $ = parserDom(html) + + return $(".episode-list-data") + .toArray() + .map((ep) => { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const number = $(ep).find(".episode-number").attr("data-raw")! + const name = $(ep).find(".episode-title > a").text().trim() + const japanese = $(ep).find(".di-ib").text().trim() + const time = $(ep).find(".episode-aired").text().trim() + const average = $(ep).find(".episode-aired").text() + + return { number, name, japanese, time, average } + }) +} diff --git a/src/apis/runs/myanimelist/episodes.spec.ts b/src/apis/runs/myanimelist/episodes.spec.ts new file mode 100644 index 00000000..546ed479 --- /dev/null +++ b/src/apis/runs/myanimelist/episodes.spec.ts @@ -0,0 +1,106 @@ +import { getEpisodesMyAnimeList } from "./episodes" + +describe("episodes", () => { + describe("getEpisodesMyAnimeList", () => { + test("should work in all of one page", async () => { + expect( + await getEpisodesMyAnimeList( + "https://myanimelist.net/anime/41389/Tonikaku_Kawaii" + ).then((items) => + items.map((item) => { + delete item.japanese + return item + }) + ) + ).toEqual([ + { + number: "1", + name: "Marriage", + time: "Oct 3, 2020", + average: "Oct 3, 2020", + }, + { + number: "2", + name: "The First Night", + time: "Oct 10, 2020", + average: "Oct 10, 2020", + }, + { + number: "3", + name: "Sisters", + time: "Oct 17, 2020", + average: "Oct 17, 2020", + }, + { + number: "4", + name: "Promise", + time: "Oct 24, 2020", + average: "Oct 24, 2020", + }, + { + number: "5", + name: "Rings", + time: "Oct 31, 2020", + average: "Oct 31, 2020", + }, + { + number: "6", + name: "News", + time: "Nov 7, 2020", + average: "Nov 7, 2020", + }, + { + number: "7", + name: "Trip", + time: "Nov 14, 2020", + average: "Nov 14, 2020", + }, + { + number: "8", + name: "Parents", + time: "Nov 21, 2020", + average: "Nov 21, 2020", + }, + { + number: "9", + name: "Daily Life", + time: "Nov 28, 2020", + average: "Nov 28, 2020", + }, + { + number: "10", + name: "The Way Home", + time: "Dec 5, 2020", + average: "Dec 5, 2020", + }, + { + number: "11", + name: "Friends", + time: "Dec 12, 2020", + average: "Dec 12, 2020", + }, + { + number: "12", + name: "Husband and Wife", + time: "Dec 19, 2020", + average: "Dec 19, 2020", + }, + { + number: "13", + name: "SNS", + time: "N/A", + average: "N/A", + }, + ]) + }) + + test("should search by offset", async () => { + const diff = await getEpisodesMyAnimeList( + "https://myanimelist.net/anime/235/Detective_Conan", + 100 + ) + + expect(diff.length).toBe(100) + }) + }) +}) diff --git a/src/apis/runs/myanimelist/episodes.ts b/src/apis/runs/myanimelist/episodes.ts new file mode 100644 index 00000000..bf6f2b40 --- /dev/null +++ b/src/apis/runs/myanimelist/episodes.ts @@ -0,0 +1,27 @@ +// first in query id anime + +import type MyAnimeListEpisodesParser from "src/apis/parser/myanimelist/episodes" +import { get } from "src/logic/http" + +import { useCache } from "../../useCache" +import Worker from "../../workers/myanimelist/episodes" +import { PostWorker } from "../../wrap-worker" + +export async function getEpisodesMyAnimeList(url: string, offset: number = 0) { + return await useCache(`${url}/episode`, async () => { + const html = + import.meta.env.MODE === "test" + ? await fetch(`${url}/episode?offset=${offset}`).then((res) => res.text()) + : await ( + await get(`${url}/episode?offset=${offset}`) + ).data + + if (import.meta.env.MODE === "test") { + return import("../../parser/myanimelist/episodes").then((res) => + res.default(html) + ) + } + + return PostWorker(Worker, html) + }) +} diff --git a/src/apis/runs/myanimelist/search.ts b/src/apis/runs/myanimelist/search.ts index 4c2d840b..a7775302 100644 --- a/src/apis/runs/myanimelist/search.ts +++ b/src/apis/runs/myanimelist/search.ts @@ -2,6 +2,7 @@ import MiniSearch from "minisearch" import type MyAnimeListSearchParser from "src/apis/parser/myanimelist/search" +import { get } from "src/logic/http" import { useCache } from "../../useCache" import Worker from "../../workers/myanimelist/search?worker" @@ -12,11 +13,11 @@ const BEFORE_SEASON = "ss|\\wd" async function runRawSearch(query: string) { return await useCache(`myanimelist/search/${query}`, async () => { - const html = await fetch( + const { data: html } = await get( `https://myanimelist.net/anime.php?cat=anime&q=${encodeURIComponent( query )}&type=0&score=0&status=0&p=0&r=0&sm=0&sd=0&sy=0&em=0&ed=0&ey=0&c%5B%5D=a&c%5B%5D=b&c%5B%5D=c&c%5B%5D=f` - ).then((res) => res.text()) + ) if (import.meta.env.MODE === "test") { return import("../../parser/myanimelist/search").then((res) => @@ -168,7 +169,9 @@ export async function getAmimeMyAnimeList( // Index all documents miniSearch.addAll(anime) - const result = miniSearch.search(otherRmd)[0] as unknown as Awaited>[0] + const result = miniSearch.search(otherRmd)[0] as unknown as Awaited< + ReturnType + >[0] console.log(otherRmd, result) // console.log(otherRmd, result.slice(0, 10)) // .filter((item) => { @@ -192,7 +195,3 @@ export async function getAmimeMyAnimeList( throw err } } - -export function getEpisodesAnimeMyAnimeList(url: string) { - return fetch(`${url}/episode`).then((res) => res.text()) -} diff --git a/src/apis/workers/myanimelist/episodes.ts b/src/apis/workers/myanimelist/episodes.ts new file mode 100644 index 00000000..672d3861 --- /dev/null +++ b/src/apis/workers/myanimelist/episodes.ts @@ -0,0 +1,4 @@ +import { WrapWorker } from "../..//wrap-worker" +import Episodes from "../../parser/myanimelist/episodes" + +WrapWorker(Episodes) diff --git a/src/boot/installed-extension.ts b/src/boot/installed-extension.ts index cc6ee22d..49f5cc1c 100644 --- a/src/boot/installed-extension.ts +++ b/src/boot/installed-extension.ts @@ -1,13 +1,13 @@ import { i18n } from "src/boot/i18n" import { ref, watch } from "vue" -const installed = ref() +const installed = ref(typeof window.Http === 'object') setTimeout(() => { if (!installed.value) installed.value = false }, 5_0000) // eslint-disable-next-line functional/no-let -let Http: Http +let Http: Http = window.Http Object.defineProperty(window, "Http", { get() { // console.log("================= set Http ==================") diff --git a/vitest.config.ts b/vitest.config.ts index cb3cf28b..f7761781 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,8 +1,16 @@ +import path from "path" import { defineConfig } from "vitest/config" export default defineConfig({ + resolve: { + alias: { + boot: path.resolve(__dirname, "src/boot"), + stores: path.resolve(__dirname, "src/stores"), + }, + }, test: { environment: "jsdom", globals: true, + setupFiles: ["./setup.vitest.ts"], }, })