Files
gui-video-clipper/chat-summaries/2026-09-21_22-06-fix-burnin-karaoke-preview-summary.md
cottongin 8ad2f1c800 chore: stage all pending work — caption styling, media server, processing modal, docs, summaries
Includes:
- Extended caption styling (font, shadow, dimmed color, bg toggle)
- Media server, subtitle downloader, VTT parser, processing modal
- Waveform tiers, thumbnail/timeline improvements, transport controls
- Hybrid download model, dependency management, clip export enhancements
- 21 chat summaries, 2 implementation plans, 2 design specs

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 10:48:16 -04:00

75 lines
4.1 KiB
Markdown

# Fix Burn-In Export and Re-Introduce Karaoke Preview
**Date:** 2026-09-21 22:06
**Task:** Implement graceful burn-in fallback and re-introduce karaoke word-by-word highlighting in preview captions.
## Changes Made
### 1. Detect `subtitles` Filter Availability (Burn-In Guard)
**Problem:** The user's ffmpeg build (Homebrew 9.0.1_1) lacks `libass`, so the `subtitles` filter is unavailable. Attempting burn-in export caused ffmpeg to crash with a filter parse error.
**Fix:**
- **`src-tauri/src/services/dependency_manager.rs`** — Added `check_subtitles_filter()` that runs `ffmpeg -filters` and checks for `subtitles V->V` in the output.
- **`src-tauri/src/commands/dependencies.rs`** — Added `check_subtitles_filter_available()` Tauri command.
- **`src-tauri/src/lib.rs`** — Registered the new command.
- **`src/lib/bindings/dependencies.ts`** — Added `checkSubtitlesFilterAvailable()` frontend binding.
- **`src/lib/components/ExportDialog.svelte`** — On mount, checks filter availability via the new command. If unavailable, the "Burn into video" checkbox is disabled with a help message telling the user how to install libass.
### 2. Parse Word-Level Timings from VTT
**Problem:** YouTube auto-generated VTT files contain word-level timestamps in `<timestamp><c> word</c>` patterns. The old parser stripped ALL tags, losing this timing data.
**Fix:**
- **`src/lib/utils/vttParser.ts`** — Complete rewrite:
- Added `WordSegment` interface (`{ text: string; startTime: number }`).
- Added optional `words?: WordSegment[]` to `VttCue`.
- Added `parseWordTimings()` that extracts `<HH:MM:SS.mmm><c> word</c>` patterns.
- Added `getActiveWords()` helper that returns each word marked as `spoken` or upcoming based on `currentTime`.
- The plain `text` field is preserved (stripped) for backward compat.
### 3. Render Karaoke Word-by-Word Highlights
**Fix:**
- **`src/lib/components/VideoPlayer.svelte`** — Updated caption rendering:
- When `wordHighlight` is enabled and the cue has word segments, each word is rendered as a separate `<span>`.
- Spoken words display at full opacity; upcoming words display at 40% opacity.
- CSS transition smooths the opacity change.
- When disabled or no word data available, falls back to plain text rendering.
### 4. Add Word Highlight Toggle
**Fix:**
- **`src/lib/stores/preferences.svelte.ts`** — Added `wordHighlight: boolean` to `CaptionSettings` interface (default: `true`).
- **`src/lib/components/CaptionSettingsPanel.svelte`** — Added "Word-by-word highlight" checkbox toggle.
## Files Modified
| File | Change |
|------|--------|
| `src-tauri/src/services/dependency_manager.rs` | Added `check_subtitles_filter()` |
| `src-tauri/src/commands/dependencies.rs` | Added `check_subtitles_filter_available` command |
| `src-tauri/src/lib.rs` | Registered new command |
| `src/lib/bindings/dependencies.ts` | Added `checkSubtitlesFilterAvailable()` binding |
| `src/lib/components/ExportDialog.svelte` | Conditional burn-in disable + help text |
| `src/lib/utils/vttParser.ts` | Word-level timing parser + `getActiveWords()` |
| `src/lib/components/VideoPlayer.svelte` | Karaoke word rendering |
| `src/lib/stores/preferences.svelte.ts` | Added `wordHighlight` to `CaptionSettings` |
| `src/lib/components/CaptionSettingsPanel.svelte` | Added word highlight toggle |
## Build Verification
- `cargo check` — passes (only pre-existing warnings)
- `svelte-check` — passes (only pre-existing `vite.config.ts` type errors)
## Lessons Learned
- YouTube VTT word-timing format: leading text has no `<c>` wrapper, only subsequent words do. The first word inherits the cue's start time.
- The `subtitles` filter requires libass at ffmpeg compile time — it's not enough to have ffmpeg installed. Homebrew's default build may or may not include it depending on the formula version.
## Follow-Up Items
- Manual smoke test: Load a video with captions, verify karaoke highlighting works during playback.
- Test export with captions enabled (muxed track) to confirm no regressions.
- If user installs libass and reinstalls ffmpeg, burn-in should automatically become available next time ExportDialog opens.