refactor: scope audiobook core
This commit is contained in:
parent
c6db55e55b
commit
66c5dd6e0c
@ -8,6 +8,10 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
- **Audiobook parser compatibility boundary.** Speech-heuristic constants consumed by the scoped Audiobook core are now
|
||||
exported explicitly, preventing load-order regressions while preserving the parser namespace.
|
||||
- **Audiobook core namespace migration.** Reader-side audiobook state, attribution helpers, quote controls, and Rehearser
|
||||
handoff now use a private scope with explicit compatibility exports and a regression-tested core namespace.
|
||||
- **Rehearser core namespace migration.** Script state, pagination, cast-management, and summary APIs now live inside a
|
||||
private core scope with explicit legacy exports and a regression-tested `window.TTVC.rehearser.core` surface.
|
||||
- **Rehearser recording namespace migration.** Microphone overlay, recording controls, and shared microphone errors now
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<meta name="theme-color" content="#2563EB">
|
||||
<meta name="app-version" content="1.24.62">
|
||||
<meta name="app-version" content="1.24.64">
|
||||
<link rel="manifest" href="/manifest.webmanifest">
|
||||
<link rel="icon" href="/static/icon.svg" type="image/svg+xml">
|
||||
<link rel="apple-touch-icon" href="/static/icon.svg">
|
||||
@ -27,12 +27,12 @@
|
||||
|
||||
<!-- ── Core styles (local — no CDN dependency for first paint) ────────── -->
|
||||
<link rel="stylesheet" href="/static/vendor/mdi/materialdesignicons.min.css">
|
||||
<link rel="stylesheet" href="/static/style.css?v=1.24.62">
|
||||
<link rel="stylesheet" href="/static/css/resource-diagnostics.css?v=1.24.62">
|
||||
<link rel="stylesheet" href="/static/css/background-jobs.css?v=1.24.62">
|
||||
<link rel="stylesheet" href="/static/css/voice-design.css?v=1.24.62">
|
||||
<link rel="stylesheet" href="/static/css/rehearser.css?v=1.24.62">
|
||||
<link rel="stylesheet" href="/static/css/audiobook.css?v=1.24.62">
|
||||
<link rel="stylesheet" href="/static/style.css?v=1.24.64">
|
||||
<link rel="stylesheet" href="/static/css/resource-diagnostics.css?v=1.24.64">
|
||||
<link rel="stylesheet" href="/static/css/background-jobs.css?v=1.24.64">
|
||||
<link rel="stylesheet" href="/static/css/voice-design.css?v=1.24.64">
|
||||
<link rel="stylesheet" href="/static/css/rehearser.css?v=1.24.64">
|
||||
<link rel="stylesheet" href="/static/css/audiobook.css?v=1.24.64">
|
||||
|
||||
|
||||
<!-- ── Flag icons — non-blocking (loaded async, icons appear after JS) ── -->
|
||||
@ -397,7 +397,7 @@ window.toggleNavTree = function(treeId, chevronId) {
|
||||
</script>
|
||||
|
||||
<!-- loader.js: fetches sections → loads JS modules → removes skeleton -->
|
||||
<script src="/static/loader.js?v=1.24.62"></script>
|
||||
<script src="/static/loader.js?v=1.24.64"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -25,6 +25,15 @@ const AB_PERSON_NOUNS = new Set(['Mann','Frau','Junge','Mädchen','Alte','Alter'
|
||||
'Prinz','Prinzessin','Fürst','Fürstin','Baron','Baronin','Bote','Diener','Dienerin','Knabe','Kind','Reiter','Reiterin',
|
||||
'Bogenschütze','Schmied','Schmiedin','Heiler','Heilerin','Gelehrte','Gelehrter','Kapitän','Anführer','Anführerin']);
|
||||
|
||||
// Legacy audiobook.js still consumes these parser constants directly while
|
||||
// the implementation is migrated to the namespace boundary.
|
||||
Object.assign(root, {
|
||||
AB_DIALOGUE_RE,
|
||||
AB_SPEECH_VERBS,
|
||||
AB_NOTNAME,
|
||||
_AB_NAME,
|
||||
AB_PERSON_NOUNS,
|
||||
});
|
||||
root.audiobookHasDialogue = audiobookHasDialogue;
|
||||
root.audiobookDehyphenate = audiobookDehyphenate;
|
||||
root.TTVC = root.TTVC || {};
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
// ── Book → multi-speaker audiobook ──────────────────────────────────────────
|
||||
|
||||
(function (root) {
|
||||
//
|
||||
// Bridges the Read Aloud reader and the Script Rehearser: an LLM scans the
|
||||
// document (in the current scope — selection / page range / whole book),
|
||||
@ -1738,3 +1740,45 @@ function audiobookExportDialog() {
|
||||
modal.style.display = 'flex';
|
||||
}
|
||||
}
|
||||
|
||||
// Keep existing inline handlers and extracted modules working while the Reader
|
||||
// bridge adopts the namespaced API responsibility by responsibility.
|
||||
Object.assign(root, {
|
||||
AUDIOBOOK_CHUNK_CHARS, AUDIOBOOK_WARMUP_TIMEOUT_MS, AUDIOBOOK_ATTRIBUTION_TIMEOUT_MS,
|
||||
AUDIOBOOK_ATTRIBUTION_RETRY_TIMEOUT_MS, AUDIOBOOK_RECAST_TIMEOUT_MS,
|
||||
AUDIOBOOK_RECAST_CONTEXT_CHARS, AUDIOBOOK_RECAST_TARGETS_PER_CALL, AUDIOBOOK_DRAFT_AUTOSAVE_MS,
|
||||
_audiobook, _abHideCastingControl, _abDraftAutosaveTimer, _abLastServerDraftErrorAt,
|
||||
audiobookDialogueKey, audiobookSegmentText, _abWordRangeAtPoint, audiobookJoinSegmentText,
|
||||
_AB_INQUIT_VERBS, _abSuspectNarration, audiobookRecastGroups, audiobookRecastContext,
|
||||
audiobookRecastRecent, audiobookFindReturnedSegment, audiobookFindReturnedSegmentSequence,
|
||||
_abStr, _AB_DRAFT_KEY, _abBookId, _abDraftKey, _abTextId, _abSafeFilename, _abLastDraftSaveAt,
|
||||
AB_DRAFT_SAVE_THROTTLE_MS, _abSaveDraft, _abExportBusy, audiobookExportCastMd,
|
||||
_abStartDraftAutosave, _abStopDraftAutosave, _abEnsureLibraryBook, _abLoadDraftServer,
|
||||
_abLoadDraft, _abClearDraft, audiobookResolveUnknowns, _AB_TAG_NAME, AB_SPEECH_TAG_ONLY_RE,
|
||||
audiobookIsSpeechTagOnly, audiobookGuessSpeaker, AB_QUOTE_PAIRS, _AB_UNCLOSED_TAG_RE,
|
||||
_abUnclosedQuoteEnd, _abOrphanClosingQuoteSpan, AB_QUOTE_OPENERS, AB_QUOTE_CLOSERS,
|
||||
_audiobookFixOrphanedQuoteMarks, _abPrefixDupCut, _audiobookResolveRoleAliases,
|
||||
_AB_GENERIC_ROLE_WORDS, _abIsGenericRoleLabel, _abSegmentConfidence, _AB_CONF_BANDS,
|
||||
_abCalibrateConfidence, _abCheckBtnHtml, _abConfClass, _abConfBadgeHtml, _abStampConfidence,
|
||||
audiobookIsRouterModel, audiobookSafeLlmModel, audiobookLlmUrl, audiobookLlmModel,
|
||||
audiobookLang, audiobookAttributeBody, audiobookCurrentCastLlm, audiobookSaveLlmChoice,
|
||||
audiobookScopeText, audiobookProgress, _abNormalizeColor, _abDefaultCharacterColor,
|
||||
_abRecordColor, _abShowQuotes, _abDisplayText, _abMarkQuotes, audiobookToggleQuotes,
|
||||
highlightText, _abShowBusyOverlay, _abFootMenuEl, _abCloseFootMenu, _abFootMenuOutside,
|
||||
_abFootMenuKey, _abToggleFootMenu, _abOpenRecastSelectPopup, audiobookRecastSelectedCharacters,
|
||||
_abScrollIntoView, _audiobookBuildRehRecord, _abRehSaveTimer, audiobookSaveAsRehearsal,
|
||||
_audiobookDebouncedSave, audiobookExportDialog,
|
||||
});
|
||||
root.TTVC = root.TTVC || {};
|
||||
root.TTVC.audiobook = root.TTVC.audiobook || {};
|
||||
Object.assign(root.TTVC.audiobook, {
|
||||
state: _audiobook,
|
||||
core: {
|
||||
dialogueKey: audiobookDialogueKey,
|
||||
segmentText: audiobookSegmentText,
|
||||
resolveUnknowns: audiobookResolveUnknowns,
|
||||
toggleQuotes: audiobookToggleQuotes,
|
||||
saveAsRehearsal: audiobookSaveAsRehearsal,
|
||||
},
|
||||
});
|
||||
})(window);
|
||||
|
||||
@ -29,15 +29,16 @@ test('Audiobook lazy modules publish their namespace APIs after loading', async
|
||||
await page.waitForFunction(() => typeof window.navTo === 'function', null, { timeout: 15_000 });
|
||||
await page.waitForSelector('#app-skeleton', { state: 'detached', timeout: 15_000 });
|
||||
await page.evaluate(() => window.navTo('s-reader'));
|
||||
await page.waitForFunction(() => typeof window.audiobookCastView === 'function', null, { timeout: 15_000 });
|
||||
await page.waitForFunction(() => typeof window.TTVC?.audiobook?.core?.dialogueKey === 'function', null, { timeout: 15_000 });
|
||||
await expect.poll(() => page.evaluate(() => ({
|
||||
castView: typeof window.TTVC?.audiobook?.cast?.castView,
|
||||
stream: typeof window.TTVC?.audiobook?.attributeStream,
|
||||
startCast: typeof window.TTVC?.audiobook?.startCast,
|
||||
pipelineCast: typeof window.TTVC?.audiobook?.pipeline?.cast,
|
||||
core: typeof window.TTVC?.audiobook?.core?.dialogueKey,
|
||||
preview: typeof window.TTVC?.audiobook?.preview?.show,
|
||||
exportAudio: typeof window.TTVC?.audiobook?.exporting?.export,
|
||||
}))).toEqual({ castView: 'function', stream: 'function', startCast: 'function', pipelineCast: 'function', preview: 'function', exportAudio: 'function' });
|
||||
}))).toEqual({ castView: 'function', stream: 'function', startCast: 'function', pipelineCast: 'function', core: 'function', preview: 'function', exportAudio: 'function' });
|
||||
});
|
||||
|
||||
test('Rehearser playback module publishes transport APIs after loading', async ({ page }) => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user