Add first-party MangaPill source and distinct volume releases
This commit is contained in:
1 parent
a8df57f165
commit
a08e847932
20 files changed
+364
-34
No files matched your search
@@ -11,6 +11,7 @@ const { sizeFromBuffer, imageSize } = require('../../library');
|
||||
const { directionFields } = require('../../reading-direction');
|
||||
const { mergeImportedMetadata } = require('./metadata-merge');
|
||||
const { normalizeWorkIdentity } = require('./work-identity');
|
||||
const { parseKey } = require('../../chapter-identity');
|
||||
|
||||
const token = () => crypto.randomBytes(5).toString('hex');
|
||||
// Staging is a recovery asset, not disposable garbage. Legacy stages without an
|
||||
@@ -91,6 +92,15 @@ async function findManga(libraryRoot, sourceUrls) {
|
||||
return null;
|
||||
}
|
||||
|
||||
async function bookDirectory(mangaDir, bookNumber, bookTitle) {
|
||||
const names = (await fsp.readdir(mangaDir, { withFileTypes: true }))
|
||||
.filter(entry => entry.isDirectory() && parseKey(entry.name)?.key === String(bookNumber))
|
||||
.map(entry => entry.name);
|
||||
if (names.length > 1) throw new Error(`Ambiguous library book ${bookNumber}: ${names.join(', ')}`);
|
||||
const defaultName = `v${String(bookNumber).padStart(2, '0')}`;
|
||||
return path.join(mangaDir, names[0] || (bookTitle ? `${defaultName} ${cleanPart(bookTitle)}` : defaultName));
|
||||
}
|
||||
|
||||
function validateManifest(manifest) {
|
||||
if (!manifest || manifest.version !== 1) throw new Error('Manifest version must be 1');
|
||||
if (!manifest.series?.title) throw new Error('series.title is required');
|
||||
@@ -172,7 +182,10 @@ async function stageChapter(bookDir, chapter, http, onPage, priorMeta = {}) {
|
||||
title: chapter.title || '', source: chapter.source,
|
||||
added: chapter.added || new Date().toISOString(),
|
||||
priority: Number(chapter.priority || 0), extra: !!chapter.extra,
|
||||
...(chapter.special ? { special: true, label: chapter.label || 'Special', sourceId: chapter.sourceId, sourceNumber: chapter.sourceNumber ?? null } : {}),
|
||||
...(chapter.special ? { special: true, label: chapter.label || 'Special', sourceId: chapter.sourceId,
|
||||
sourceNumber: chapter.sourceNumber ?? null,
|
||||
...(chapter.releaseKind ? { releaseKind: chapter.releaseKind } : {}),
|
||||
...(chapter.volume ? { volume: chapter.volume } : {}) } : {}),
|
||||
...directionFields([priorMeta, chapter], dimensions),
|
||||
}, null, 2) + '\n', { mode: 0o644 });
|
||||
// A process interruption during a write can leave a hidden pending file.
|
||||
@@ -230,8 +243,7 @@ async function publishManifest(manifest, options = {}) {
|
||||
for (const chapter of manifest.chapters) {
|
||||
const bookNumber = Number(chapter.book?.number || 1);
|
||||
if (!Number.isInteger(bookNumber) || bookNumber < 1) throw new Error(`Invalid book number for chapter ${chapter.number}`);
|
||||
const bookName = `v${String(bookNumber).padStart(2, '0')}${chapter.book?.title ? ` ${cleanPart(chapter.book.title)}` : ''}`;
|
||||
const bookDir = path.join(mangaDir, bookName);
|
||||
const bookDir = await bookDirectory(mangaDir, bookNumber, chapter.book?.title);
|
||||
await fsp.mkdir(bookDir, { recursive: true, mode: 0o755 });
|
||||
await cleanupOwnTemps(bookDir);
|
||||
if (chapter.book?.title) {
|
||||
|
||||
Reference in new issue
Block a user