mirror of
https://github.com/denizsafak/abogen.git
synced 2026-07-18 13:40:27 +02:00
feat: Enhance spine href resolution and normalization in chapter handling
This commit is contained in:
@@ -251,6 +251,55 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let spineHrefList = [];
|
||||||
|
const spineHrefLookup = new Map();
|
||||||
|
|
||||||
|
const refreshSpineLookup = (items) => {
|
||||||
|
spineHrefList = [];
|
||||||
|
spineHrefLookup.clear();
|
||||||
|
if (!Array.isArray(items)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
items.forEach((entry) => {
|
||||||
|
const href = typeof entry === 'string' ? entry : entry?.href;
|
||||||
|
const normalized = removeLeadingSlash(href || '');
|
||||||
|
if (!normalized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
spineHrefList.push(normalized);
|
||||||
|
const key = normalized.toLowerCase();
|
||||||
|
if (!spineHrefLookup.has(key)) {
|
||||||
|
spineHrefLookup.set(key, normalized);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const resolveSpineHref = (value) => {
|
||||||
|
if (!value) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const normalized = removeLeadingSlash(value);
|
||||||
|
if (!normalized) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const direct = spineHrefLookup.get(normalized.toLowerCase());
|
||||||
|
if (direct) {
|
||||||
|
return direct;
|
||||||
|
}
|
||||||
|
const segments = normalized.split('/');
|
||||||
|
for (let index = 1; index < segments.length; index += 1) {
|
||||||
|
const candidate = segments.slice(index).join('/');
|
||||||
|
if (!candidate) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const match = spineHrefLookup.get(candidate.toLowerCase());
|
||||||
|
if (match) {
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
|
};
|
||||||
|
|
||||||
const formatClock = (value) => {
|
const formatClock = (value) => {
|
||||||
if (!Number.isFinite(value) || value < 0) {
|
if (!Number.isFinite(value) || value < 0) {
|
||||||
return '--:--';
|
return '--:--';
|
||||||
@@ -456,6 +505,7 @@
|
|||||||
href: cleanedHref,
|
href: cleanedHref,
|
||||||
normalizedHref: normalized,
|
normalizedHref: normalized,
|
||||||
title: chapter.title || `Chapter ${idx + 1}`,
|
title: chapter.title || `Chapter ${idx + 1}`,
|
||||||
|
spineHref: chapter.spineHref ? removeLeadingSlash(chapter.spineHref) : null,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
chapters = dedupeChapters(chapters);
|
chapters = dedupeChapters(chapters);
|
||||||
@@ -812,22 +862,26 @@
|
|||||||
await book.ready;
|
await book.ready;
|
||||||
const fragment = typeof options.fragment === 'string' ? options.fragment : '';
|
const fragment = typeof options.fragment === 'string' ? options.fragment : '';
|
||||||
const baseHref = target.href.split('#')[0];
|
const baseHref = target.href.split('#')[0];
|
||||||
const displayHref = fragment ? `${baseHref}#${fragment}` : target.href;
|
const displayResolved = resolveSpineHref(target.spineHref || target.href);
|
||||||
const canonicalCandidate = typeof book.canonical === 'function' ? book.canonical(displayHref) : displayHref;
|
const fallbackDisplay = removeLeadingSlash(target.href);
|
||||||
|
const displayBase = displayResolved || fallbackDisplay;
|
||||||
|
const displayHref = fragment ? `${displayBase}#${fragment}` : displayBase;
|
||||||
|
const canonicalSource = fragment ? displayBase : displayHref;
|
||||||
|
const canonicalCandidate = typeof book.canonical === 'function' ? book.canonical(canonicalSource) : canonicalSource;
|
||||||
const isBlobCanonical = typeof canonicalCandidate === 'string' && canonicalCandidate.startsWith('blob:');
|
const isBlobCanonical = typeof canonicalCandidate === 'string' && canonicalCandidate.startsWith('blob:');
|
||||||
const canonicalHref = isBlobCanonical ? null : removeLeadingSlash(canonicalCandidate);
|
const canonicalHref = isBlobCanonical ? null : removeLeadingSlash(canonicalCandidate);
|
||||||
const targetHref = removeLeadingSlash(canonicalHref || displayHref);
|
|
||||||
const syncHref = removeLeadingSlash((canonicalHref || baseHref).split('#')[0]);
|
const syncHref = removeLeadingSlash((canonicalHref || baseHref).split('#')[0]);
|
||||||
console.info('[reader] Displaying chapter', {
|
console.info('[reader] Displaying chapter', {
|
||||||
requestedIndex: normalizedIndex,
|
requestedIndex: normalizedIndex,
|
||||||
href: target.href,
|
href: target.href,
|
||||||
|
spineHref: target.spineHref,
|
||||||
|
displayBase,
|
||||||
displayHref,
|
displayHref,
|
||||||
canonicalHref,
|
canonicalHref,
|
||||||
targetHref,
|
|
||||||
syncHref,
|
syncHref,
|
||||||
});
|
});
|
||||||
suppressRelocate = true;
|
suppressRelocate = true;
|
||||||
await rendition.display(targetHref);
|
await rendition.display(displayHref);
|
||||||
suppressRelocate = false;
|
suppressRelocate = false;
|
||||||
currentChapterIndex = normalizedIndex;
|
currentChapterIndex = normalizedIndex;
|
||||||
updateControls();
|
updateControls();
|
||||||
@@ -1022,8 +1076,9 @@
|
|||||||
await book.ready;
|
await book.ready;
|
||||||
console.info('[reader] Book ready resolved');
|
console.info('[reader] Book ready resolved');
|
||||||
try {
|
try {
|
||||||
const spineEntries = (book.spine?.items || []).map((item) => item?.href || '(unknown)');
|
const spineItems = Array.isArray(book.spine?.items) ? book.spine.items : [];
|
||||||
console.info('[reader] Spine hrefs', spineEntries);
|
refreshSpineLookup(spineItems);
|
||||||
|
console.info('[reader] Spine hrefs', spineHrefList);
|
||||||
} catch (spineError) {
|
} catch (spineError) {
|
||||||
console.warn('[reader] Unable to log spine hrefs', spineError);
|
console.warn('[reader] Unable to log spine hrefs', spineError);
|
||||||
}
|
}
|
||||||
@@ -1062,11 +1117,17 @@
|
|||||||
...chapter,
|
...chapter,
|
||||||
href: effectiveHref,
|
href: effectiveHref,
|
||||||
normalizedHref: effectiveNormalized,
|
normalizedHref: effectiveNormalized,
|
||||||
|
spineHref: resolveSpineHref(effectiveHref),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
chapters = dedupeChapters(chapters);
|
chapters = dedupeChapters(chapters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chapters = chapters.map((chapter) => ({
|
||||||
|
...chapter,
|
||||||
|
spineHref: resolveSpineHref(chapter.spineHref || chapter.href),
|
||||||
|
}));
|
||||||
|
|
||||||
currentChapterIndex = Math.min(currentChapterIndex, Math.max(chapters.length - 1, 0));
|
currentChapterIndex = Math.min(currentChapterIndex, Math.max(chapters.length - 1, 0));
|
||||||
initializeChapters();
|
initializeChapters();
|
||||||
updateControls();
|
updateControls();
|
||||||
|
|||||||
Reference in New Issue
Block a user