UNPKG

animepaste

Version:

Paste your favourite anime online

280 lines (274 loc) 8.81 kB
'use strict'; const node_module = require('node:module'); const prompts = require('prompts'); const createDebug = require('debug'); const fastestLevenshtein = require('fastest-levenshtein'); const color = require('@breadc/color'); const dateFns = require('date-fns'); const index = require('./animepaste.7298200f.cjs'); const utils = require('./animepaste.5967bc8e.cjs'); function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; } const prompts__default = /*#__PURE__*/_interopDefaultCompat(prompts); const createDebug__default = /*#__PURE__*/_interopDefaultCompat(createDebug); const debug = createDebug__default("anime:search"); function getDefaultKeywords(bgm) { return index.filterDef([ bgm.title, ...Object.values(bgm.titleTranslate).flat(), bgm.dmhy ]); } async function userSearch(anime, option) { const bgms = await promptSearch(anime, option); for (const bgm of bgms) { const keywords = getDefaultKeywords(bgm); option.beginDate = dateFns.subMonths(new Date(bgm.begin), 1); await search(bgm, keywords, option); } if (option.plan && bgms.length > 0) { await outputPlan(bgms); } } async function daemonSearch(bgmId, optionKeywords, option = { type: "tv" }) { const items = await importBgmdata(); let found = false; for (const bgm of items) { if (bgmId === bgm.bgmId) { found = true; const keywords = optionKeywords ?? getDefaultKeywords(bgm); option.beginDate = dateFns.subMonths(new Date(bgm.begin), 1); await search(bgm, keywords, option); if (option.plan) { await outputPlan([bgm]); } break; } } if (!found) { const keywords = [...optionKeywords ?? []]; if (option.title && !option.plan) { await search({ bgmId, titleCN: option.title }, keywords, option); } else if (!option.title) { debug(`Fallback to search ${bgmId} on bgm.tv`); const { BgmClient } = await import('@animepaste/bangumi/bgm'); const client = new BgmClient(); client.setupUserAgent(); const bgm = await client.fetchSubject(bgmId); keywords.push(bgm.title, bgm.titleCN); await search(bgm, keywords, option); if (option.plan) { await outputPlan([bgm]); } } } } async function search(bgm, keywords, option = { type: "tv" }) { if (option.title) { keywords = [...keywords]; keywords.push(option.title); } const log = option.log ?? true; if (log) { index.logger.empty(); index.logger.info( index.okColor("Refresh ") + index.titleColor(bgm.titleCN) + ` (${utils.bangumiLink(bgm.bgmId)})` ); } debug(`Search "${bgm.titleCN}"`); for (const keyword of keywords) { debug("- " + keyword); } const result = await index.context.magnetStore.search(keywords, { limit: option.beginDate, listener: index.IndexListener, Episode: true }); for (const resource of result) { if (resource.title.indexOf("MKV") !== -1) continue; if (resource.title.indexOf("HEVC") !== -1) continue; if (!resource.Episode) { await index.context.episodeStore.createEpisode(bgm.bgmId, resource); } } if (option.raw) { index.printMagnets(result); } else if (log) { const episodes = await index.context.episodeStore.listEpisodes(bgm.bgmId); const map = index.groupBy(episodes, (ep) => ep.fansub); for (const [key, eps] of map) { index.logger.tab.info(color.bold(key)); eps.sort((a, b) => a.ep - b.ep); for (const ep of eps) { index.logger.tab.tab.info( `${color.dim(index.formatEP(ep.ep))} ${color.link( ep.magnet.title, index.context.magnetStore.idToLink(ep.magnet.id) )}` ); } } } } async function outputPlan(animes) { const date = new Date( Math.min(...animes.map((a) => new Date(a.begin).getTime())) ); index.logger.empty(); index.logger.println(`--- ${dateFns.format( new Date(), "yyyy-MM-dd \u65B0\u756A\u653E\u9001\u8BA1\u5212")} ---`); index.logger.empty(); index.logger.println(`name: ${dateFns.format( new Date(), "yyyy-MM-dd \u65B0\u756A\u653E\u9001\u8BA1\u5212")}`); index.logger.empty(); index.logger.println(`date: ${dateFns.format(date, "yyyy-MM-dd HH:mm")}`); index.logger.empty(); index.logger.println(`state: onair`); index.logger.empty(); index.logger.println(`sync: true`); index.logger.empty(); index.logger.println(`onair:`); for (const anime of animes) { const episodes = await index.context.episodeStore.listEpisodes(anime.bgmId); index.logger.tab.println(`- title: ${anime.titleCN}`); index.logger.tab.println(` bgmId: '${anime.bgmId}'`); index.logger.tab.println(` fansub:`); const map = index.groupBy(episodes, (ep) => ep.fansub); for (const [key] of map) { index.logger.tab.tab.println(` - ${key}`); } index.logger.empty(); } } async function promptSearch(anime, option) { if (anime) { const bgms = await searchInBgmdata(anime, option); return await promptBgm(bgms); } else { const year = (/* @__PURE__ */ new Date()).getFullYear(); await prompts__default( [ { type: option.year ? null : "select", name: "year", message: "\u5E74\u4EFD?", choices: new Array(5).fill(void 0).map((_v, i) => ({ title: String(year - i) + " \u5E74", value: String(year - i) })), initial: 0, onState({ value }) { option.year = value; } }, { type: option.month ? null : "select", name: "month", message: "\u5B63\u5EA6?", choices: [ { title: "1 \u6708", value: "1" }, { title: "4 \u6708", value: "4" }, { title: "7 \u6708", value: "7" }, { title: "10 \u6708", value: "10" } ], initial: 0, onState({ value }) { option.month = value; } } ], { onCancel: () => { throw new Error("Operation cancelled"); } } ); const items = await importBgmdata(option); return await promptBgm(items, false); } } async function promptBgm(bgms, enableDate = true) { const { value: bgm } = await prompts__default({ type: "multiselect", name: "value", message: "\u52A8\u753B?", choices: bgms.map((bgm2) => { const d = getBgmDate(bgm2); return { title: bgm2.titleCN + (enableDate ? ` (${d.year}-${d.month})` : ""), value: bgm2 }; }), hint: "- Space to select, Return to submit", // @ts-ignore instructions: false }); return bgm ?? []; } async function searchInBgmdata(name, option, length = 5) { const items = await importBgmdata(option); const include = []; const similar = []; for (const item of items) { const titles = getDefaultKeywords(item); let included = false; let dis = Number.MAX_SAFE_INTEGER; for (const title of titles) { const d = fastestLevenshtein.distance(name, title); if (d === Math.abs(title.length - name.length)) { included = true; } dis = Math.min(dis, d); } if (included) { include.push(item); if (include.length >= length) { return include; } } if (similar.length < length) { similar.push({ item, dis }); } else { let mxId = 0; for (let i = 1; i < similar.length; i++) { if (similar[i].dis > similar[mxId].dis) { mxId = i; } } if (similar[mxId].dis > dis) { similar.splice(mxId); similar.push({ item, dis }); } } } if (include.length > 0) { return include; } else { return similar.map(({ item }) => item); } } async function importBgmdata(option = { type: "tv" }) { const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (document.currentScript && document.currentScript.src || new URL('shared/animepaste.21394988.cjs', document.baseURI).href))); const { load } = require$1("@animepaste/bangumi"); const bangumis = load("cli-data.json").bangumis; debug("Load Bangumi data OK"); return bangumis.filter((bgm) => { const d = getBgmDate(bgm); if (option.year && +option.year !== d.year) return false; if (option.month && +option.month !== d.month) return false; return bgm.type === option.type; }); } function getBgmDate(bgm) { const d = new Date(bgm.begin); return { year: d.getFullYear(), month: d.getMonth() + 1, date: d.getDate(), weekday: d.getDay() }; } exports.daemonSearch = daemonSearch; exports.search = search; exports.userSearch = userSearch;