Official release dates from MangaUpdates; peers lower ecosystem dates (BL-0048, BL-0049)
- scraper/metadata/release-dates.js fills x-dates.release from MangaUpdates publisher releases. MangaUpdates also lists English back-catalog re-releases, so a date is kept only inside the AniList original run, when no scanlation or source upload is more than 4 days earlier, and when it fits the release order (no lower chapter dated after a higher one). Seasons that restart chapter numbers are skipped; dates this job wrote and no longer accepts are withdrawn. - The scraper refreshes ongoing series nightly before its update checks, only while no download runs, and bumps the publish revision so the reader reconciles. - tools/release-dates.js for a whole library (dry run default). Production dry run: 728 chapters dated (Kagurabachi, JJK, Chainsaw Man, One Piece from 928). - Peer sync: chapters this library already has adopt a peer's earlier ecosystem date (job result ecosystemLowered); the peer listing now carries dates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e0dacd81c6
commit
7b52da2f9c
8 files changed
+402
-7
No files matched your search
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
// Official chapter release dates from MangaUpdates (BL-0048) for a whole library or one manga.
|
||||
// Dry run by default. Apply only with the scraper stopped (--apply --writers-stopped), then let a
|
||||
// full reconciliation (or admin Rescan) pick up the edited chapter.json files.
|
||||
const fs = require('node:fs').promises;
|
||||
const path = require('node:path');
|
||||
const { ReleaseDateSources, refreshMangaReleaseDates } = require('../scraper/metadata/release-dates');
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const apply = args.includes('--apply');
|
||||
const only = args.find(arg => arg.startsWith('--manga='))?.slice('--manga='.length);
|
||||
const cacheDir = args.find(arg => arg.startsWith('--cache='))?.slice('--cache='.length) || path.join(require('node:os').tmpdir(), 'mangacircus-release-dates');
|
||||
const root = args.find(arg => !arg.startsWith('--'));
|
||||
if (!root || args.some(arg => arg.startsWith('--') && !['--apply', '--writers-stopped'].includes(arg) && !/^--(manga|cache)=/.test(arg))
|
||||
|| (apply && !args.includes('--writers-stopped'))) {
|
||||
console.error('Usage: node tools/release-dates.js <library> [--manga=<folder>] [--cache=<dir>] [--apply --writers-stopped]');
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const sources = new ReleaseDateSources({ cacheDir });
|
||||
const totals = { manga: 0, matched: 0, chapters: 0, accepted: 0, written: 0, cleared: 0, outsideRun: 0, earlier: 0, outOfOrder: 0, noRun: 0 };
|
||||
const names = (await fs.readdir(root, { withFileTypes: true })).filter(e => e.isDirectory() && !e.name.startsWith('.')).map(e => e.name).sort();
|
||||
for (const name of names) {
|
||||
if (only && name !== only) continue;
|
||||
try {
|
||||
const s = await refreshMangaReleaseDates(path.join(root, name), sources, { apply });
|
||||
totals.manga++; totals.chapters += s.chapters;
|
||||
if (s.ambiguous) { console.log(`${name.slice(0, 44).padEnd(44)} skipped: chapter numbers repeat across books`); continue; }
|
||||
if (!s.series) { console.log(`${name.slice(0, 44).padEnd(44)} no MangaUpdates match`); continue; }
|
||||
totals.matched++; totals.accepted += s.accepted; totals.written += s.written; totals.cleared += s.cleared;
|
||||
for (const k of ['outsideRun', 'earlier', 'outOfOrder', 'noRun']) totals[k] += s.rejected[k];
|
||||
console.log(`${name.slice(0, 44).padEnd(44)} ${String(s.chapters).padStart(5)} ch official ${String(s.official).padStart(4)} accepted ${String(s.accepted).padStart(4)}`
|
||||
+ ` rejected: outside run ${s.rejected.outsideRun}, earlier evidence ${s.rejected.earlier}, out of order ${s.rejected.outOfOrder}`
|
||||
+ `${s.rejected.noRun ? `, no AniList run ${s.rejected.noRun}` : ''} (${s.series.title})`);
|
||||
} catch (error) { console.warn(`${name}: ${error.message}`); }
|
||||
}
|
||||
console.log(JSON.stringify({ apply, ...totals }));
|
||||
}
|
||||
|
||||
main().catch(error => { console.error(error); process.exit(1); });
|
||||
Reference in new issue
Block a user