UNPKG

@animespace/bangumi

Version:

Create your own Anime Space

272 lines (264 loc) 9.41 kB
'use strict'; const prompts = require('prompts'); const path = require('path'); const fs = require('fs-extra'); const core = require('@animespace/core'); const client$1 = require('@animegarden/client'); const color = require('@breadc/color'); const dateFns = require('date-fns'); const bgmc = require('bgmc'); function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; } const prompts__default = /*#__PURE__*/_interopDefaultCompat(prompts); const path__default = /*#__PURE__*/_interopDefaultCompat(path); const fs__default = /*#__PURE__*/_interopDefaultCompat(fs); const version = "0.1.0-beta.24"; const client = new bgmc.BgmClient(core.ufetch, { maxRetry: 1, userAgent: `animespace/${version} (https://github.com/yjl9903/AnimeSpace)` }); async function generatePlan(system, collections, options) { const output = []; const writeln = (text) => { if (options.create) { output.push(text); } else { console.log(text); } }; const now = /* @__PURE__ */ new Date(); const date = inferDate(options.date); writeln(`title: \u521B\u5EFA\u4E8E ${dateFns.format(now, "yyyy-MM-dd hh:mm")}`); writeln(``); writeln(`date: ${dateFns.format(date, "yyyy-MM-dd hh:mm")}`); writeln(``); writeln(`status: onair`); writeln(``); writeln(`onair:`); for (const anime of collections) { if (typeof anime === "object") { const begin = anime.subject?.date ? new Date(anime.subject.date) : void 0; if (begin && begin.getTime() < date.getTime()) { continue; } if (options.create) { system.logger.log( `${color.lightBlue("Searching")} ${color.bold( anime.subject?.name_cn || anime.subject?.name || `Bangumi ${anime.subject_id}` )}` ); } } try { const item = await client.subject(typeof anime === "object" ? anime.subject_id : anime); const title = item.name_cn || item.name; const aliasBox = item.infobox?.find((box) => box.key === "\u522B\u540D"); const translations = Array.isArray(aliasBox?.value) ? aliasBox?.value.map((v) => v?.v).filter(Boolean) ?? [] : typeof aliasBox?.value === "string" ? [aliasBox.value] : []; if (item.name && item.name !== title) { translations.unshift(item.name); } const plan = { title, bgm: "" + item.id, season: inferSeason(title, ...translations), type: inferType(item), translations }; const escapeString = (t) => t.replace(`'`, `''`); writeln(` - title: ${escapeString(plan.title)}`); writeln(` alias:`); for (const t of plan.translations ?? []) { writeln(` - '${escapeString(t)}'`); } if (plan.season !== 1) { writeln(` season: ${plan.season}`); } writeln(` bgm: '${plan.bgm}'`); if (plan.type) { writeln(` type: '${plan.type}'`); } if (options.fansub) { const fansub = await getFansub([plan.title, ...plan.translations]); writeln(` fansub:`); if (fansub.length === 0) { writeln(` # No fansub found, please check the translations or search keywords`); } for (const f of fansub) { writeln(` - ${f}`); } if (fansub.length === 0 && options.create) { system.logger.warn(`No fansub found for ${title}`); } } const includeURL = [title, ...translations].map( (t) => t.replace(/\[/g, "%5B").replace(/\]/g, "%5D").replace(/,/g, "%2C").replace(/"/g, "%22").replace(/ /g, "%20") ).map((v) => "include=" + v); writeln( ` # https://animes.garden/resources/1?${includeURL.join("&")}&after=${encodeURIComponent( date.toISOString() )}` ); writeln(``); } catch (error) { if (typeof anime === "object") { system.logger.error( `${color.lightRed("Failed to search")} ${color.bold( anime.subject?.name_cn || anime.subject?.name || `Bangumi ${anime.subject_id}` )}` ); } else { system.logger.error(error); } } } if (options.create) { const p = path__default.join(system.space.root.resolve(options.create).path); await fs__default.writeFile(p, output.join("\n"), "utf-8"); } } async function searchBgm(input) { return (await client.search(input, { type: 2 })).list ?? []; } async function getCollections(username) { const list = []; while (true) { const { data } = await client.getCollections(username, { subject_type: 2, type: 3, limit: 50, offset: list.length }); if (data && data.length > 0) { list.push(...data); } else { break; } } return core.uniqBy(list, (c) => "" + c.subject_id); } async function getFansub(titles) { const { resources } = await client$1.fetchResources({ fetch: core.ufetch, include: titles, count: -1, retry: 5 }); return core.uniqBy( resources.filter((r) => !!r.fansub), (r) => r.fansub.name ).map((r) => r.fansub.name); } function inferType(subject) { const FILM = ["\u7535\u5F71", "\u5267\u573A\u7248"]; const titles = [subject.name, subject.name_cn]; { for (const title of titles) { for (const f of FILM) { if (title && title.includes(f)) { return "\u7535\u5F71"; } } } } { for (const tag of subject.tags) { if (FILM.includes(tag.name)) { return "\u7535\u5F71"; } } } return void 0; } function inferSeason(...titles) { for (const title of titles) { { const match = /Season\s*(\d+)/.exec(title); if (match) { return +match[1]; } } { const match = /第\s*(\d+)\s*(季|期)/.exec(title); if (match) { return +match[1]; } } if (title.includes("\u7B2C\u4E8C\u5B63")) return 2; if (title.includes("\u7B2C\u4E09\u5B63")) return 3; if (title.includes("\u7B2C\u56DB\u5B63")) return 4; if (title.includes("\u7B2C\u4E94\u5B63")) return 5; if (title.includes("\u7B2C\u516D\u5B63")) return 6; if (title.includes("\u7B2C\u4E03\u5B63")) return 7; if (title.includes("\u7B2C\u516B\u5B63")) return 8; if (title.includes("\u7B2C\u4E5D\u5B63")) return 9; if (title.includes("\u7B2C\u5341\u5B63")) return 10; } return 1; } function inferDate(now) { const date = !!now ? new Date(now) : /* @__PURE__ */ new Date(); const d1 = new Date(dateFns.getYear(date), 1, 1, 0, 0, 0); const d2 = new Date(dateFns.getYear(date), 4, 1, 0, 0, 0); const d3 = new Date(dateFns.getYear(date), 7, 1, 0, 0, 0); const d4 = new Date(dateFns.getYear(date), 10, 1, 0, 0, 0); const d5 = new Date(dateFns.getYear(date) + 1, 1, 1, 0, 0, 0); if (d1.getTime() > date.getTime()) { return dateFns.subMonths(d1, 1); } else if (d2.getTime() > date.getTime()) { return dateFns.subMonths(d2, 1); } else if (d3.getTime() > date.getTime()) { return dateFns.subMonths(d3, 1); } else if (d4.getTime() > date.getTime()) { return dateFns.subMonths(d4, 1); } else { return dateFns.subMonths(d5, 1); } } function Bangumi(options) { const defaultUsername = options.username; return { name: "bangumi", options, command(system, cli) { const logger = system.logger.withTag("bangumi"); cli.command("bangumi search <input>", "Search anime from bangumi and generate plan").alias("bgm search").option("--date <date>", "Specify the onair begin date").option("--fansub", "Generate fansub list").action(async (input, options2) => { const bgms = await searchBgm(input); if (bgms.length === 0) { logger.warn("\u672A\u627E\u5230\u4EFB\u4F55\u52A8\u753B"); return; } const selected = bgms.length === 1 ? { bangumi: bgms } : await prompts__default({ type: "multiselect", name: "bangumi", message: "\u9009\u62E9\u5C06\u8981\u751F\u6210\u8BA1\u5212\u7684\u52A8\u753B", choices: bgms.map((bgm) => ({ title: (bgm.name_cn || bgm.name) ?? String(bgm.id), value: bgm })), hint: "- \u4E0A\u4E0B\u79FB\u52A8, \u7A7A\u683C\u9009\u62E9, \u56DE\u8F66\u786E\u8BA4", // @ts-ignore instructions: false }); if (!selected.bangumi) { return; } if (bgms.length > 1) { logger.log(""); } await generatePlan( system, selected.bangumi.map((bgm) => bgm.id), { create: void 0, fansub: options2.fansub, date: options2.date } ); }); cli.command("bangumi generate", "Generate Plan from your bangumi collections").alias("bgm gen").alias("bgm generate").option("--username <username>", "Bangumi username").option("--create <filename>", "Create plan file in the space directory").option("--fansub", "Generate fansub list").option("--date <date>", "Specify the onair begin date").action(async (options2) => { const username = options2.username ?? defaultUsername ?? ""; if (!username) { logger.error("You should provide your bangumi username with --username <username>"); } const collections = await getCollections(username); return await generatePlan(system, collections, options2); }); } }; } exports.Bangumi = Bangumi;