tts-voice-creator-clone-and.../static/sections/s-rehearser.html
mARTin-B78 b64baf2d0b Script Rehearser: library with save / load / import / export
Storage: IndexedDB ('reh-library' DB, 'rehearsals' store).
Blobs (recorded mic audio) stored natively; no base64 overhead.

Library panel (Phase 1):
- List of saved rehearsals sorted by last update
- Each row: character-colour avatars, title, progress bar,
  line count, recorded-clip count, date
- Active record highlighted in accent colour
- Open / Export .reh / Delete per-row buttons
- Import .reh button at the top

Transport bar (Phase 3):
- Save button (updates existing record if savedId set, else creates new)
- Export button (downloads current state as .reh JSON file)

Phase 4 (session complete):
- Save to library and Export .reh buttons

Data format (.reh file):
- JSON with version=1, title, script text, cast map, backend, lineIndex
- clips serialized with audio as base64 strings (mime + b64 fields)
- clipsFromJson restores Blob objects on import

Behaviour:
- Parsing a brand-new script resets savedId → safe to save as new record
- loadRecord() restores script, cast, lineIndex, clips and jumps to Phase 2
- renderLibraryList() called on init, after save, after delete, after import

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 20:32:24 +02:00

157 lines
9.8 KiB
HTML

<div class="section-head">
<span class="section-icon"><span class="mdi mdi-theater"></span></span>
<div class="section-title">
<h2>Script Rehearser</h2>
<p>Upload a script, assign voices to characters, then rehearse with TTS synthesis and microphone recording.</p>
</div>
</div>
<div class="tab-content" id="tab-rehearser">
<!-- ── Phase 1: Library ───────────────────────────────────────── -->
<div class="reh-phase" id="reh-phase-1">
<div class="card">
<div class="reh-lib-header">
<h2 style="margin:0"><span class="mdi mdi-bookshelf"></span> Rehearsal library</h2>
<div class="btn-row" style="gap:8px;margin:0">
<label class="btn-secondary" style="cursor:pointer;display:inline-flex;align-items:center;gap:6px">
<span class="mdi mdi-import"></span> Import .reh
<input type="file" id="reh-lib-import-file" accept=".reh,.json" style="display:none">
</label>
</div>
</div>
<div id="reh-library-list" class="reh-lib-list">
<div class="reh-lib-empty"><span class="mdi mdi-book-open-outline"></span><p>No saved rehearsals yet.<br>Parse a script below to start a new one.</p></div>
</div>
</div>
<!-- Script input -->
<div class="card">
<h2><span class="mdi mdi-script-text-outline"></span> New script</h2>
<p class="card-subtitle">Format: <code>CHARACTER: dialog</code> on one line, or screenplay style (ALL-CAPS character name on its own line, dialog below). Lines starting with <code>#</code> are stage directions.</p>
<div class="reh-input-row">
<textarea id="reh-script-text" placeholder="ALICE&#10;Hello, how are you today?&#10;&#10;BOB&#10;I'm doing great, thank you for asking!&#10;&#10;ALICE&#10;That's wonderful to hear." spellcheck="false"></textarea>
<div class="reh-input-side">
<label class="btn-secondary" style="cursor:pointer;display:inline-flex;align-items:center;gap:6px">
<span class="mdi mdi-upload"></span> Upload .txt
<input type="file" id="reh-file-input" accept=".txt,.md" style="display:none">
</label>
<div class="field" style="margin-top:10px">
<label style="font-size:12px">Script title (optional)</label>
<input type="text" id="reh-script-title" placeholder="My Script">
</div>
<p class="note" style="margin-top:8px;font-size:12px">Supported formats:<br><code>CHARACTER: text</code><br>• All-caps name + dialog below<br><code># stage direction</code></p>
</div>
</div>
<div class="btn-row" style="margin-top:12px">
<button class="btn-primary" id="reh-parse-btn"><span class="mdi mdi-auto-fix"></span> Parse characters</button>
</div>
</div>
</div>
<!-- ── Phase 2: Cast assignment ───────────────────────────────── -->
<div class="reh-phase" id="reh-phase-2" hidden>
<div class="card">
<h2><span class="mdi mdi-account-group-outline"></span> Step 2 — Cast your characters</h2>
<p class="card-subtitle">Assign a TTS voice to each character, or toggle <strong>I play this role</strong> — those lines will pause and wait for your microphone recording.</p>
<div class="field" style="margin-bottom:14px">
<label>TTS backend for synthesis</label>
<div style="display:flex;gap:8px;align-items:center">
<select id="reh-backend-select"><option value="">Checking…</option></select>
<button class="btn-secondary" id="reh-fetch-voices-btn"><span class="mdi mdi-refresh"></span> Fetch voices</button>
</div>
</div>
<div id="reh-cast-list" class="reh-cast-list"></div>
<div class="btn-row" style="margin-top:14px">
<button class="btn-secondary" id="reh-back-1-btn"><span class="mdi mdi-arrow-left"></span> Back</button>
<button class="btn-primary" id="reh-start-btn"><span class="mdi mdi-theater"></span> Open rehearsal</button>
</div>
</div>
</div>
<!-- ── Phase 3: Rehearsal — A4 script view ────────────────────── -->
<div class="reh-phase" id="reh-phase-3" hidden>
<!-- Transport controls -->
<div class="reh-transport-bar" id="reh-transport-bar">
<!-- Cast strip -->
<div class="reh-cast-strip" id="reh-cast-strip"></div>
<!-- Transport buttons -->
<div class="reh-transport-btns">
<button class="reh-tb-btn" id="reh-tb-prev" title="Previous line"><span class="mdi mdi-skip-previous"></span></button>
<button class="reh-tb-btn reh-tb-play" id="reh-tb-play" title="Play all"><span class="mdi mdi-play"></span></button>
<button class="reh-tb-btn" id="reh-tb-stop" title="Stop &amp; reset"><span class="mdi mdi-stop"></span></button>
<button class="reh-tb-btn" id="reh-tb-next" title="Next line"><span class="mdi mdi-skip-next"></span></button>
<button class="reh-tb-btn" id="reh-tb-repeat" title="Loop script"><span class="mdi mdi-repeat"></span></button>
</div>
<!-- Progress -->
<div class="reh-transport-progress">
<div class="reh-tb-progress-wrap"><div class="reh-tb-progress" id="reh-tb-progress"></div></div>
<span class="reh-tb-label" id="reh-tb-label">0 / 0</span>
</div>
<div style="display:flex;gap:6px;margin-left:auto">
<button class="btn-secondary btn-sm" id="reh-tb-save" title="Save rehearsal to library"><span class="mdi mdi-content-save-outline"></span> Save</button>
<button class="btn-secondary btn-sm" id="reh-tb-export" title="Export to .reh file"><span class="mdi mdi-export"></span></button>
<button class="btn-secondary btn-sm" id="reh-exit-btn">Exit</button>
</div>
</div>
<!-- A4 script page -->
<div class="reh-page-wrap">
<div class="reh-a4-page" id="reh-a4-page">
<div class="reh-page-title" id="reh-page-title"></div>
<div class="reh-script-lines" id="reh-script-lines"></div>
</div>
</div>
<!-- Recording overlay (visible when my turn) -->
<div class="reh-rec-overlay" id="reh-rec-overlay" hidden>
<div class="reh-rec-overlay-inner">
<div class="reh-rec-cue" id="reh-rec-cue"></div>
<div class="mic-monitor-box" style="margin-bottom:10px">
<div class="mic-monitor-head">
<span>Input level</span>
<span class="meter-readout" id="reh-db-readout">-∞ dB</span>
</div>
<div class="mic-meter" id="reh-mic-meter" aria-hidden="true"></div>
<canvas id="reh-live-wave" class="mic-live-wave" width="300" height="48" aria-hidden="true"></canvas>
</div>
<div class="btn-row" style="gap:8px">
<button class="btn-red" id="reh-rec-start"><span class="mdi mdi-record-circle-outline"></span> Record</button>
<button class="btn-secondary" id="reh-rec-stop" disabled><span class="mdi mdi-stop-circle-outline"></span> Stop</button>
<span class="mic-timer" id="reh-rec-time">0:00</span>
<button class="btn-secondary" id="reh-skip-line"><span class="mdi mdi-skip-next"></span> Skip</button>
</div>
<audio id="reh-rec-preview" controls style="display:none;margin-top:8px;width:100%"></audio>
<div class="btn-row" style="margin-top:6px" id="reh-rec-confirm-row" hidden>
<button class="btn-green" id="reh-rec-keep"><span class="mdi mdi-check"></span> Keep &amp; continue</button>
<button class="btn-secondary" id="reh-rec-redo"><span class="mdi mdi-refresh"></span> Re-record</button>
</div>
</div>
</div>
<!-- TTS playback status (slim bar below transport) -->
<div class="reh-tts-status-bar" id="reh-tts-status-bar" hidden>
<span id="reh-tts-status-txt"></span>
<audio id="reh-tts-audio" controls style="flex:1;min-width:0;max-width:320px"></audio>
</div>
</div><!-- /phase-3 -->
<!-- ── Phase 4: Session summary ────────────────────────────────── -->
<div class="reh-phase" id="reh-phase-4" hidden>
<div class="card">
<h2><span class="mdi mdi-check-circle-outline"></span> Rehearsal complete</h2>
<p class="card-subtitle">All recorded and synthesized clips from this session.</p>
<div id="reh-summary-list" class="reh-summary-list"></div>
<div class="btn-row" style="margin-top:14px">
<button class="btn-primary" id="reh-save-session-btn"><span class="mdi mdi-content-save"></span> Save to library</button>
<button class="btn-secondary" id="reh-export-session-btn"><span class="mdi mdi-export"></span> Export .reh</button>
<button class="btn-secondary" id="reh-resume-btn"><span class="mdi mdi-theater"></span> Resume</button>
<button class="btn-secondary" id="reh-new-session-btn"><span class="mdi mdi-refresh"></span> New script</button>
</div>
</div>
</div>
</div><!-- /tab-rehearser -->