refactor: scope rehearser core

This commit is contained in:
mARTin-B78 2026-09-04 12:33:55 +02:00
parent 6c62a0f75e
commit c6db55e55b
7 changed files with 52 additions and 10 deletions

View File

@ -8,6 +8,8 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi
## [Unreleased] ## [Unreleased]
### Changed ### Changed
- **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 - **Rehearser recording namespace migration.** Microphone overlay, recording controls, and shared microphone errors now
use a private implementation scope with explicit compatibility exports. use a private implementation scope with explicit compatibility exports.
- **Rehearser I/O namespace migration.** Serialization, library persistence, import/export, and PDF helpers now use a - **Rehearser I/O namespace migration.** Serialization, library persistence, import/export, and PDF helpers now use a

View File

@ -1 +1 @@
1.24.61 1.24.62

View File

@ -52,6 +52,7 @@ Done incrementally as global-scope ordered files (no ES-module change needed)
- ✅ Rehearser playback uses a private scope with explicit transport/cache compatibility exports and a namespace-tested API. - ✅ Rehearser playback uses a private scope with explicit transport/cache compatibility exports and a namespace-tested API.
- ✅ Rehearser I/O uses a private scope with explicit serialization/library/import compatibility exports. - ✅ Rehearser I/O uses a private scope with explicit serialization/library/import compatibility exports.
- ✅ Rehearser recording uses a private scope with explicit microphone/overlay compatibility exports. - ✅ Rehearser recording uses a private scope with explicit microphone/overlay compatibility exports.
- ✅ Rehearser core uses a private scope with explicit state, pagination, and cast-management compatibility exports.
- ✅ `static/css/resource-diagnostics.css` — isolated Performance/resource diagnostic panel styles. - ✅ `static/css/resource-diagnostics.css` — isolated Performance/resource diagnostic panel styles.
- ✅ `static/css/background-jobs.css` — isolated background-job history and retry-panel styles. - ✅ `static/css/background-jobs.css` — isolated background-job history and retry-panel styles.
- ✅ `static/css/voice-design.css` — isolated Voice Design form, samples, and preview-match styles. - ✅ `static/css/voice-design.css` — isolated Voice Design form, samples, and preview-match styles.

View File

@ -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.61"> <meta name="app-version" content="1.24.62">
<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.61"> <link rel="stylesheet" href="/static/style.css?v=1.24.62">
<link rel="stylesheet" href="/static/css/resource-diagnostics.css?v=1.24.61"> <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.61"> <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.61"> <link rel="stylesheet" href="/static/css/voice-design.css?v=1.24.62">
<link rel="stylesheet" href="/static/css/rehearser.css?v=1.24.61"> <link rel="stylesheet" href="/static/css/rehearser.css?v=1.24.62">
<link rel="stylesheet" href="/static/css/audiobook.css?v=1.24.61"> <link rel="stylesheet" href="/static/css/audiobook.css?v=1.24.62">
<!-- ── 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.61"></script> <script src="/static/loader.js?v=1.24.62"></script>
</body> </body>
</html> </html>

View File

@ -145,6 +145,7 @@ Object.assign(root, {
hideRecOverlay, hideRecOverlay,
startRehMic, startRehMic,
stopRehMic, stopRehMic,
rehRenderMeter,
microphoneErrorMessage, microphoneErrorMessage,
}); });

View File

@ -1,5 +1,7 @@
// ── Script Rehearser ────────────────────────────────────────────────────── // ── Script Rehearser ──────────────────────────────────────────────────────
(function (root) {
// ── Constants ───────────────────────────────────────────────────────────── // ── Constants ─────────────────────────────────────────────────────────────
const SPEAKER_COLORS = ['#89b4fa','#a6e3a1','#f38ba8','#fab387','#f9e2af','#cba6f7','#89dceb','#74c7ec']; const SPEAKER_COLORS = ['#89b4fa','#a6e3a1','#f38ba8','#fab387','#f9e2af','#cba6f7','#89dceb','#74c7ec'];
@ -2800,3 +2802,37 @@ if (window._rehearserStartImpEx) {
delete window._rehearserStartPhase; delete window._rehearserStartPhase;
showPhase(_initPhase); showPhase(_initPhase);
} }
// Classic handlers still resolve these names, but the implementation now lives
// inside one explicit module scope. New integrations should use TTVC.rehearser.
Object.assign(root, {
SPEAKER_COLORS, REH_EMOTIONS, rehCustomEmotions, getEmotionInfo, renderMarkdownInline,
stripMarkdown, rehState, rehApplySharedCast, bookCover, rehLibView, rehTitleKey,
rehUniqueLibraryRecords, renderLibraryList, getVoiceData, _rehVoiceVisibleId,
voiceAvatarHtml, _rehCharAvatarHtml, showPhase, syncPhaseTabs, rehImportAnyFile,
castAvatarHtml, REH_NARRATOR_KEY, _ensureNarrator, REH_CAST_LANGS, REH_CAST_GENDERS,
_castApplyToLines, _safeDomId, _rehLibCharsCache, _rehLibCharsCacheBook,
_rehEnsureLibCharsCache, _castDeleteCharacter, _rehAllVoiceIds, populateNarratorSelect,
_BUILD_INSTRUCT_TEMPLATES, _BUILD_INSTRUCT_LANG_NAMES, _buildAccentClause, _buildInstruct,
_rehBackendIsFish, _REH_EMOTION_DE_EN, _rehEmotionEnglishTag, _rehInlineTone, REH_LANG_CODE,
rehDefaultLlmUrl, rehCollectLlmEndpoints, rehInitLlmField, REH_AVATAR_ICONS,
_pickVoiceAvatar, rehDesignCancelled, rehWriteCharacterNote, rehResearchCast, REH_FISH_LANG,
rehMarkCastDesigning, buildScriptPage, _toggleBulkSel, _refreshBulkLine, _updateBulkCount,
setBulkMode, _bulkApply, _bulkDelete, _reindexLineState, PAGE_MODES, _pageMode,
applyPageMode, _syncPageModeBtn, cyclePageMode, paginateScript, isPracticeRange,
startInlineEdit, openScriptEditorModal, updatePracticeRange, clearPracticeRange,
setPracticeRangeFromSelection, rehEmoPicker, openEmoPicker, _closePickerOnOutside,
closeEmoPicker, _markSynthDot, _showReSynthBtn, _rehSyncCastVoiceFromLibrary,
synthOneLine, selectEmotion, _rehToneCmpRow, _checkToneStyleSupport, renderSummary,
_downloadText, exportAsTxt, exportAsMd,
});
root.TTVC = root.TTVC || {};
root.TTVC.rehearser = root.TTVC.rehearser || {};
Object.assign(root.TTVC.rehearser, {
state: rehState,
core: {
showPhase, syncPhaseTabs, buildScriptPage, paginateScript,
renderLibraryList, renderSummary, synthOneLine,
},
});
})(window);

View File

@ -54,7 +54,9 @@ test('Rehearser playback module publishes transport APIs after loading', async (
exportSession: typeof window.TTVC?.rehearser?.io?.exportSession, exportSession: typeof window.TTVC?.rehearser?.io?.exportSession,
recording: typeof window.TTVC?.rehearser?.recording?.start, recording: typeof window.TTVC?.rehearser?.recording?.start,
training: typeof window.TTVC?.rehearser?.training?.enter, training: typeof window.TTVC?.rehearser?.training?.enter,
}))).toEqual({ start: 'function', stop: 'function', synthAll: 'function', loadRecord: 'function', exportSession: 'function', recording: 'function', training: 'function' }); core: typeof window.TTVC?.rehearser?.core?.buildScriptPage,
state: !!window.TTVC?.rehearser?.state,
}))).toEqual({ start: 'function', stop: 'function', synthAll: 'function', loadRecord: 'function', exportSession: 'function', recording: 'function', training: 'function', core: 'function', state: true });
}); });
test('pure leaf modules keep private declarations behind compatibility exports', async ({ page }) => { test('pure leaf modules keep private declarations behind compatibility exports', async ({ page }) => {