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>
75 lines
4.1 KiB
Markdown
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.
|