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,71 @@
|
||||
'use strict';
|
||||
|
||||
// Shared by the scanner and publisher. Dimensions identify strip layout, not
|
||||
// language or the reading order of a printed page. RTL is only a default.
|
||||
const KEY = 'x-reading-direction';
|
||||
const aliases = { rtl: 'rtl', ltr: 'ltr', ttb: 'ttb', vertical: 'ttb', webtoon: 'ttb' };
|
||||
const normalizeDirection = value => aliases[String(value || '').trim().toLowerCase()] || null;
|
||||
|
||||
function manualDirection(meta = {}) {
|
||||
const override = normalizeDirection(meta.directionOverride);
|
||||
if (override) return override;
|
||||
const value = normalizeDirection(meta.direction);
|
||||
if (!value) return null;
|
||||
const record = meta[KEY];
|
||||
// Legacy plain directions are ambiguous: never assume a human didn't set one.
|
||||
// Editing a generated value without its provenance is also a manual override.
|
||||
if (!record || record.version !== 1 || record.value !== value ||
|
||||
!['detected', 'fallback'].includes(record.source)) return value;
|
||||
return null;
|
||||
}
|
||||
|
||||
function detectVerticalStrip(pages = []) {
|
||||
const dimensions = pages.map(p => {
|
||||
const rotated = p.r === 90 || p.r === 270;
|
||||
return { w: Number(rotated ? p.h : p.w), h: Number(rotated ? p.w : p.h) };
|
||||
}).filter(p => Number.isFinite(p.w) && Number.isFinite(p.h) && p.w > 0 && p.h > 0);
|
||||
const tall = dimensions.filter(p => p.h / p.w >= 4);
|
||||
const widths = tall.map(p => p.w).sort((a, b) => a - b);
|
||||
const middle = widths.length ? widths[Math.floor(widths.length / 2)] : 0;
|
||||
const consistent = tall.filter(p => Math.abs(p.w - middle) <= middle * .25).length;
|
||||
const evidence = { pages: pages.length, knownPages: dimensions.length, tallPages: tall.length,
|
||||
consistentTallPages: consistent, medianStripWidth: middle };
|
||||
// At least three coherent strips, >=75% of known pages, and >=75% known
|
||||
// dimensions. A landscape credits card may coexist with the vertical body.
|
||||
const detected = tall.length >= 3 && dimensions.length >= pages.length * .75 &&
|
||||
tall.length >= dimensions.length * .75 && consistent >= tall.length * .75;
|
||||
return detected ? { value: 'ttb', source: 'detected', evidence } : null;
|
||||
}
|
||||
|
||||
function fallbackDirection() {
|
||||
return { direction: 'rtl', [KEY]: { version: 1, value: 'rtl', source: 'fallback' } };
|
||||
}
|
||||
|
||||
// Scopes are chapter -> book -> manga (or existing -> incoming when publishing).
|
||||
// Any explicit choice beats inference; a more specific explicit choice wins.
|
||||
function resolveReadingDirection(scopes = [], pages = []) {
|
||||
for (let i = 0; i < scopes.length; i++) {
|
||||
const value = manualDirection(scopes[i]);
|
||||
if (value) return { value, source: 'manual', scope: i };
|
||||
}
|
||||
const detected = detectVerticalStrip(pages);
|
||||
if (detected) return detected;
|
||||
for (let i = 0; i < scopes.length; i++) {
|
||||
const meta = scopes[i] || {}, record = meta[KEY];
|
||||
if (record?.version === 1 && record.source === 'detected' &&
|
||||
record.value === normalizeDirection(meta.direction) && record.value === 'ttb') {
|
||||
return { value: 'ttb', source: 'detected', scope: i, evidence: record.evidence };
|
||||
}
|
||||
}
|
||||
return { value: 'rtl', source: 'fallback' };
|
||||
}
|
||||
|
||||
function directionFields(scopes, pages) {
|
||||
const { value, source, evidence } = resolveReadingDirection(scopes, pages);
|
||||
return { direction: value,
|
||||
...(source === 'manual' && scopes.some(m => normalizeDirection(m?.directionOverride)) ? { directionOverride: value } : {}),
|
||||
[KEY]: { version: 1, value, source, ...(evidence ? { evidence } : {}) } };
|
||||
}
|
||||
|
||||
module.exports = { KEY, normalizeDirection, manualDirection, detectVerticalStrip,
|
||||
fallbackDirection, resolveReadingDirection, directionFields };
|
||||
Reference in new issue
Block a user