refactor: wire audiobook namespace APIs
This commit is contained in:
parent
6f2c0b7b3d
commit
e096b3e529
@ -8,6 +8,8 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi
|
|||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
- **Audiobook namespace wiring.** Network helpers and public casting, recast, export, and save actions now register
|
||||||
|
after their lazy modules load, completing the namespace bridge without removing legacy global entry points.
|
||||||
- **Audiobook live cast-view extraction.** The live cast feed, roster, settings, and prompt controls now live in
|
- **Audiobook live cast-view extraction.** The live cast feed, roster, settings, and prompt controls now live in
|
||||||
`audiobook-cast.js`; the legacy `audiobookCastView` entry point remains available for compatibility.
|
`audiobook-cast.js`; the legacy `audiobookCastView` entry point remains available for compatibility.
|
||||||
- **Rehearser voice-matching extraction.** Local voice matching, preview-line selection, fish.audio search/import,
|
- **Rehearser voice-matching extraction.** Local voice matching, preview-line selection, fish.audio search/import,
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
<meta name="format-detection" content="telephone=no">
|
<meta name="format-detection" content="telephone=no">
|
||||||
<meta name="color-scheme" content="light dark">
|
<meta name="color-scheme" content="light dark">
|
||||||
<meta name="theme-color" content="#2563EB">
|
<meta name="theme-color" content="#2563EB">
|
||||||
<meta name="app-version" content="1.24.48">
|
<meta name="app-version" content="1.24.49">
|
||||||
<link rel="manifest" href="/manifest.webmanifest">
|
<link rel="manifest" href="/manifest.webmanifest">
|
||||||
<link rel="icon" href="/static/icon.svg" type="image/svg+xml">
|
<link rel="icon" href="/static/icon.svg" type="image/svg+xml">
|
||||||
<link rel="apple-touch-icon" href="/static/icon.svg">
|
<link rel="apple-touch-icon" href="/static/icon.svg">
|
||||||
@ -27,12 +27,12 @@
|
|||||||
|
|
||||||
<!-- ── Core styles (local — no CDN dependency for first paint) ────────── -->
|
<!-- ── Core styles (local — no CDN dependency for first paint) ────────── -->
|
||||||
<link rel="stylesheet" href="/static/vendor/mdi/materialdesignicons.min.css">
|
<link rel="stylesheet" href="/static/vendor/mdi/materialdesignicons.min.css">
|
||||||
<link rel="stylesheet" href="/static/style.css?v=1.24.48">
|
<link rel="stylesheet" href="/static/style.css?v=1.24.49">
|
||||||
<link rel="stylesheet" href="/static/css/resource-diagnostics.css?v=1.24.48">
|
<link rel="stylesheet" href="/static/css/resource-diagnostics.css?v=1.24.49">
|
||||||
<link rel="stylesheet" href="/static/css/background-jobs.css?v=1.24.48">
|
<link rel="stylesheet" href="/static/css/background-jobs.css?v=1.24.49">
|
||||||
<link rel="stylesheet" href="/static/css/voice-design.css?v=1.24.48">
|
<link rel="stylesheet" href="/static/css/voice-design.css?v=1.24.49">
|
||||||
<link rel="stylesheet" href="/static/css/rehearser.css?v=1.24.48">
|
<link rel="stylesheet" href="/static/css/rehearser.css?v=1.24.49">
|
||||||
<link rel="stylesheet" href="/static/css/audiobook.css?v=1.24.48">
|
<link rel="stylesheet" href="/static/css/audiobook.css?v=1.24.49">
|
||||||
|
|
||||||
|
|
||||||
<!-- ── Flag icons — non-blocking (loaded async, icons appear after JS) ── -->
|
<!-- ── Flag icons — non-blocking (loaded async, icons appear after JS) ── -->
|
||||||
@ -397,7 +397,7 @@ window.toggleNavTree = function(treeId, chevronId) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- loader.js: fetches sections → loads JS modules → removes skeleton -->
|
<!-- loader.js: fetches sections → loads JS modules → removes skeleton -->
|
||||||
<script src="/static/loader.js?v=1.24.48"></script>
|
<script src="/static/loader.js?v=1.24.49"></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -3562,3 +3562,14 @@ function audiobookExportDialog() {
|
|||||||
modal.style.display = 'flex';
|
modal.style.display = 'flex';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.TTVC = window.TTVC || {};
|
||||||
|
window.TTVC.audiobook = window.TTVC.audiobook || {};
|
||||||
|
Object.assign(window.TTVC.audiobook, {
|
||||||
|
startCast: audiobookCast,
|
||||||
|
openCastView: audiobookOpenCastView,
|
||||||
|
recastUnknown: audiobookRecastUnknown,
|
||||||
|
recastSelectedCharacters: audiobookRecastSelectedCharacters,
|
||||||
|
export: audiobookExport,
|
||||||
|
saveAsRehearsal: audiobookSaveAsRehearsal,
|
||||||
|
});
|
||||||
|
|||||||
@ -85,3 +85,11 @@ async function audiobookAttributeStream(body, view, outerSignal, idleTimeoutMs =
|
|||||||
if (outerSignal) outerSignal.removeEventListener('abort', onAbort);
|
if (outerSignal) outerSignal.removeEventListener('abort', onAbort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.TTVC = window.TTVC || {};
|
||||||
|
window.TTVC.audiobook = window.TTVC.audiobook || {};
|
||||||
|
Object.assign(window.TTVC.audiobook, {
|
||||||
|
fetchWithTimeout: audiobookFetchWithTimeout,
|
||||||
|
attributeStream: audiobookAttributeStream,
|
||||||
|
timeoutSeconds: audiobookTimeoutSeconds,
|
||||||
|
});
|
||||||
|
|||||||
@ -23,3 +23,16 @@ test('heavy feature modules load on demand', async ({ page }) => {
|
|||||||
await page.waitForTimeout(100);
|
await page.waitForTimeout(100);
|
||||||
expect(requests.filter(url => url.includes('/rehearser.js')).length).toBe(countBeforeRepeat);
|
expect(requests.filter(url => url.includes('/rehearser.js')).length).toBe(countBeforeRepeat);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Audiobook lazy modules publish their namespace APIs after loading', async ({ page }) => {
|
||||||
|
await page.goto('/', { waitUntil: 'domcontentloaded' });
|
||||||
|
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 expect.poll(() => page.evaluate(() => ({
|
||||||
|
castView: typeof window.TTVC?.audiobook?.cast?.castView,
|
||||||
|
stream: typeof window.TTVC?.audiobook?.attributeStream,
|
||||||
|
startCast: typeof window.TTVC?.audiobook?.startCast,
|
||||||
|
}))).toEqual({ castView: 'function', stream: 'function', startCast: 'function' });
|
||||||
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user