116 lines
5.6 KiB
JavaScript
116 lines
5.6 KiB
JavaScript
#!/usr/bin/env node
|
|
'use strict';
|
|
|
|
const fs = require('fs').promises;
|
|
const path = require('path');
|
|
const { publishManifest } = require('./lib/publisher');
|
|
const { discoverWeebCentral } = require('./adapters/weebcentral');
|
|
const { lookupAniList } = require('./metadata/anilist');
|
|
const { runArchive } = require('./jobs/weebcentral-archive');
|
|
const { runQueue } = require('./jobs/weebcentral-queue');
|
|
|
|
function flag(args, name, fallback) {
|
|
const index = args.indexOf(name);
|
|
return index < 0 ? fallback : args[index + 1];
|
|
}
|
|
|
|
async function main() {
|
|
const args = process.argv.slice(2);
|
|
const command = args.shift();
|
|
if (command === 'publish') {
|
|
const file = args[0];
|
|
if (!file) throw new Error('Usage: publish <manifest.json> [--library path] [--metadata-search title] [--replace]');
|
|
const manifest = JSON.parse(await fs.readFile(path.resolve(file), 'utf8'));
|
|
const metadataSearch = flag(args, '--metadata-search');
|
|
if (metadataSearch) {
|
|
const metadata = await lookupAniList(metadataSearch);
|
|
manifest.series.metadata = { ...metadata, title: manifest.series.title };
|
|
manifest.series.scraper = { ...(manifest.series.scraper || {}), ids: { ...(manifest.series.scraper?.ids || {}), anilist: metadata['x-anilist']?.id } };
|
|
}
|
|
const result = await publishManifest(manifest, { libraryRoot: flag(args, '--library'), replace: args.includes('--replace') });
|
|
console.log(JSON.stringify(result, null, 2));
|
|
return;
|
|
}
|
|
if (command === 'discover-weebcentral') {
|
|
const url = args[0];
|
|
if (!url) throw new Error('Usage: discover-weebcentral <series-url> --out manifest.json [--limit 3]');
|
|
const manifest = await discoverWeebCentral(url, { limit: Number(flag(args, '--limit', 3)) });
|
|
const out = flag(args, '--out');
|
|
if (out) await fs.writeFile(path.resolve(out), JSON.stringify(manifest, null, 2) + '\n');
|
|
else console.log(JSON.stringify(manifest, null, 2));
|
|
return;
|
|
}
|
|
if (command === 'metadata-anilist') {
|
|
const search = args.join(' ');
|
|
if (!search) throw new Error('Usage: metadata-anilist <title>');
|
|
console.log(JSON.stringify(await lookupAniList(search), null, 2));
|
|
return;
|
|
}
|
|
if (command === 'archive-weebcentral') {
|
|
const url = args[0];
|
|
if (!url) throw new Error('Usage: archive-weebcentral <series-url> [--library path] [--metadata-search title]');
|
|
await runArchive({
|
|
seriesUrl: url,
|
|
libraryRoot: flag(args, '--library', 'library'),
|
|
metadataSearch: flag(args, '--metadata-search'),
|
|
minMs: Number(flag(args, '--min-ms', 8000)),
|
|
maxMs: Number(flag(args, '--max-ms', 15000)),
|
|
chapterMinMs: Number(flag(args, '--chapter-min-ms', 30000)),
|
|
chapterMaxMs: Number(flag(args, '--chapter-max-ms', 60000)),
|
|
});
|
|
return;
|
|
}
|
|
if (command === 'status-weebcentral') {
|
|
const url = args[0];
|
|
if (!url) throw new Error('Usage: status-weebcentral <series-url> [--library path]');
|
|
const sourceId = url.split('/series/')[1]?.split('/')[0];
|
|
if (!sourceId) throw new Error('Could not read WeebCentral series id');
|
|
const workRoot = path.resolve(flag(args, '--library', 'library'), `.mcscraper-work-${sourceId}`);
|
|
const state = JSON.parse(await fs.readFile(path.join(workRoot, 'job.json'), 'utf8'));
|
|
console.log(JSON.stringify({
|
|
status: state.status || 'unknown',
|
|
completed: state.completed?.length || 0,
|
|
total: state.total || null,
|
|
percent: state.total ? Math.round((state.completed?.length || 0) * 1000 / state.total) / 10 : null,
|
|
lastChapter: state.lastChapter || null,
|
|
current: state.current || null,
|
|
lastProblem: state.lastProblem || null,
|
|
lastError: state.lastError || null,
|
|
problemCount: state.problemCount || 0,
|
|
rate: state.rate || null,
|
|
updated: state.updated || null,
|
|
log: path.join(workRoot, 'job.log'),
|
|
}, null, 2));
|
|
return;
|
|
}
|
|
if (command === 'run-wishlist') {
|
|
const entries = [
|
|
['The Gamer', '01J76XY9DYH4MH2HZG2PPF74A6', 'The-Gamer'],
|
|
['Kanojo Okarishimasu', '01J76XYC7KP5M48JAY8S4ZNDX5', 'Kanojo-Okarishimasu'],
|
|
['Toradora', '01J76XY7J4Z4G6E42GED6QEQXZ', 'Toradora'],
|
|
['Solo Leveling', '01J76XYCPSY3C4BNPBRY8JMCBE', 'Solo-Leveling'],
|
|
['Gantz', '01J76XY7EREQ4B1Q5Z5RJ749V6', 'Gantz'],
|
|
['One Piece', '01J76XY7E9FNDZ1DBBM6PBJPFK', 'One-Piece'],
|
|
].map(([title, id, slug]) => ({ id, title, url: `https://weebcentral.com/series/${id}/${slug}` }));
|
|
await runQueue({
|
|
entries,
|
|
waitForFolder: flag(args, '--wait-for', 'Berserk'),
|
|
libraryRoot: flag(args, '--library', 'library'),
|
|
minMs: Number(flag(args, '--min-ms', 3000)),
|
|
maxMs: Number(flag(args, '--max-ms', 7000)),
|
|
chapterMinMs: Number(flag(args, '--chapter-min-ms', 12000)),
|
|
chapterMaxMs: Number(flag(args, '--chapter-max-ms', 25000)),
|
|
});
|
|
return;
|
|
}
|
|
if (command === 'status-queue') {
|
|
const queueRoot = path.resolve(flag(args, '--library', 'library'), '.mcscraper-queue');
|
|
const state = JSON.parse(await fs.readFile(path.join(queueRoot, 'queue.json'), 'utf8'));
|
|
console.log(JSON.stringify({ ...state, log: path.join(queueRoot, 'queue.log') }, null, 2));
|
|
return;
|
|
}
|
|
console.log('Commands:\n publish <manifest.json> [--library path] [--metadata-search title] [--replace]\n discover-weebcentral <url> [--limit 3] [--out file]\n archive-weebcentral <url> [--library path] [--metadata-search title]\n status-weebcentral <url> [--library path]\n run-wishlist [--library path] [--wait-for Berserk]\n status-queue [--library path]\n metadata-anilist <title>');
|
|
}
|
|
|
|
main().catch(error => { console.error(`[scraper] ${error.message}`); process.exitCode = 1; });
|