Consolidate MangaCircus app, scraper, and Compose baseline
This commit is contained in:
1 parent
cfb2d79103
commit
eef4ffa07c
103 files changed
+9316
-172
No files matched your search
@@ -0,0 +1,74 @@
|
||||
'use strict';
|
||||
|
||||
const PUBLIC_MODES = new Set(['missing', 'latest', 'last', 'first', 'chapter', 'after', 'volume']);
|
||||
|
||||
function chapterNumber(value, field = 'chapter') {
|
||||
const raw = String(value ?? '').trim();
|
||||
if (!/^\d+(?:\.\d+)?$/.test(raw)) throw new Error(`${field} must be a numeric chapter`);
|
||||
const [whole, decimal = ''] = raw.split('.');
|
||||
const normalizedWhole = whole.replace(/^0+(?=\d)/, '') || '0';
|
||||
const normalizedDecimal = decimal.replace(/0+$/, '');
|
||||
return normalizedDecimal ? `${normalizedWhole}.${normalizedDecimal}` : normalizedWhole;
|
||||
}
|
||||
|
||||
function positiveCount(value) {
|
||||
const count = Number(value);
|
||||
if (!Number.isInteger(count) || count < 1 || count > 10000) throw new Error('count must be an integer from 1 to 10000');
|
||||
return count;
|
||||
}
|
||||
|
||||
function normalizeScope(input = {}) {
|
||||
const raw = input && typeof input === 'object' ? input : {};
|
||||
const mode = String(raw.mode || 'missing').toLowerCase();
|
||||
if (mode === 'ids') {
|
||||
if (!Array.isArray(raw.ids) || !raw.ids.length || raw.ids.length > 10000) throw new Error('ids scope requires 1 to 10000 source chapter ids');
|
||||
return { mode, ids: [...new Set(raw.ids.map(value => String(value).trim()).filter(Boolean))] };
|
||||
}
|
||||
if (!PUBLIC_MODES.has(mode)) throw new Error(`Unsupported queue scope: ${mode}`);
|
||||
if (mode === 'last' || mode === 'first') return { mode, count: positiveCount(raw.count) };
|
||||
if (mode === 'chapter' || mode === 'after') return { mode, chapter: chapterNumber(raw.chapter) };
|
||||
if (mode === 'volume') {
|
||||
const volume = String(raw.volume ?? '').trim();
|
||||
if (!/^\d+(?:\.\d+)?$/.test(volume)) throw new Error('volume must be numeric');
|
||||
return { mode, volume: chapterNumber(volume, 'volume') };
|
||||
}
|
||||
return { mode };
|
||||
}
|
||||
|
||||
function volumeOf(ref) {
|
||||
const value = ref.volume ?? ref.book?.number;
|
||||
if (value === undefined || value === null || value === '') return null;
|
||||
try { return chapterNumber(value, 'volume'); } catch { return null; }
|
||||
}
|
||||
|
||||
function selectByScope(chapters, input) {
|
||||
const scope = normalizeScope(input);
|
||||
const list = [...chapters];
|
||||
if (scope.mode === 'missing') return list;
|
||||
if (scope.mode === 'latest') return list.length ? [list[list.length - 1]] : [];
|
||||
if (scope.mode === 'last') return list.slice(-scope.count);
|
||||
if (scope.mode === 'first') return list.slice(0, scope.count);
|
||||
const numbered = list.filter(ref => /^\d+(?:\.\d+)?$/.test(String(ref.number)));
|
||||
if (scope.mode === 'chapter') return numbered.filter(ref => chapterNumber(ref.number) === scope.chapter);
|
||||
if (scope.mode === 'after') return numbered.filter(ref => Number(chapterNumber(ref.number)) > Number(scope.chapter));
|
||||
if (scope.mode === 'volume') return list.filter(ref => volumeOf(ref) === scope.volume);
|
||||
if (scope.mode === 'ids') {
|
||||
const ids = new Set(scope.ids);
|
||||
return list.filter(ref => ids.has(String(ref.id)));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function scopeLabel(input) {
|
||||
const scope = normalizeScope(input);
|
||||
if (scope.mode === 'missing') return 'all missing chapters';
|
||||
if (scope.mode === 'latest') return 'newest chapter';
|
||||
if (scope.mode === 'last') return `last ${scope.count} chapters`;
|
||||
if (scope.mode === 'first') return `first ${scope.count} chapters`;
|
||||
if (scope.mode === 'chapter') return `chapter ${scope.chapter}`;
|
||||
if (scope.mode === 'after') return `chapters after ${scope.chapter}`;
|
||||
if (scope.mode === 'volume') return `volume ${scope.volume}`;
|
||||
return `${scope.ids.length} discovered chapters`;
|
||||
}
|
||||
|
||||
module.exports = { normalizeScope, selectByScope, scopeLabel, chapterNumber, volumeOf };
|
||||
Reference in new issue
Block a user