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>
4.0 KiB
4.0 KiB
Styled Burn-In and Granular Export Progress
Date: 2026-09-21 23:00
Task: Apply user's caption style settings to burned-in subtitles via ffmpeg's ASS force_style, and add granular per-clip progress reporting during export.
Changes Made
1. CaptionStyle Model (Rust + TS)
src-tauri/src/models.rs— AddedCaptionStylestruct withfont_size,text_color,background_opacity,text_outline,position. Addedcaption_style: Option<CaptionStyle>toExportConfig.src/lib/bindings/export.ts— Added matchingCaptionStyleinterface andcaptionStyle: CaptionStyle | nulltoExportConfig. AddedclipProgressevent variant to the discriminated union. Added optionalonClipProgresscallback parameter toexportClips().
2. ASS force_style in clip_exporter.rs
src-tauri/src/services/clip_exporter.rs:hex_to_ass_color()— Converts CSS hex#RRGGBBto ASS&H00BBGGRRformat.opacity_to_ass_back_colour()— Converts 0-1 opacity to ASS alpha-prefixed BackColour.caption_style_to_force_style()— Builds the full ASS force_style string from CaptionStyle (Fontsize, PrimaryColour, BackColour, Outline, Shadow, Alignment, MarginV, BorderStyle).build_ffmpeg_args_burnin_subs()now acceptsOption<&CaptionStyle>and appends:force_style='...'to the subtitles filter when provided.parse_ffmpeg_time()— Extractstime=HH:MM:SS.mmfrom ffmpeg stderr progress output.run_ffmpeg_with_progress()— Runs ffmpeg with piped stderr, parses progress lines, and invokes a callback with 0.0-1.0 percent values.
3. Progress Callbacks Throughout Export Pipeline
All four export functions (export_single_clip, export_single_clip_with_subs, export_merged, export_merged_with_subs) now accept progress callbacks. They use run_ffmpeg_with_progress() instead of .output() for the encode step, streaming real-time progress.
4. export.rs Command Handler
src-tauri/src/commands/export.rs— AddedClipProgressevent variant withcurrent,total,label,percent. Wired progress callbacks for both Individual and Merged export paths. Passescaption_stylethrough to the exporter.
5. ExportDialog Frontend
src/lib/components/ExportDialog.svelte:- Populates
captionStylein config frompreferences.captionSettingswhen burn-in is enabled. - Shows a progress bar with percentage during each clip export.
- Displays note that karaoke word highlighting is preview-only for burn-in.
- Populates
Files Modified
| File | Change |
|---|---|
src-tauri/src/models.rs |
Added CaptionStyle struct, added field to ExportConfig |
src-tauri/src/services/clip_exporter.rs |
ASS helpers, force_style, ffmpeg progress streaming, progress callbacks |
src-tauri/src/commands/export.rs |
ClipProgress event, caption_style passthrough, progress wiring |
src/lib/bindings/export.ts |
CaptionStyle interface, clipProgress event, onClipProgress callback |
src/lib/components/ExportDialog.svelte |
captionStyle in config, progress bar UI, karaoke note |
Build Verification
cargo check— passes (only pre-existing warnings)cargo test— all 43 tests passsvelte-check— passes (only pre-existingvite.config.tserrors)
Lessons Learned
- ASS color format uses BGR byte order with alpha prefix (
&HAA_BB_GG_RR), where alpha00= opaque andFF= transparent (inverted from CSS). BorderStyle=4in ASS gives an opaque background box behind text (like CSS background), vsBorderStyle=1which uses outline+shadow only.- ffmpeg progress is on stderr, not stdout. The
time=field is the key metric for computing encode progress percentage. - For merged exports, progress is reported per-segment during encoding, plus a concat step at the end.
Follow-Up Items
- Smoke test burn-in export to verify styled subtitles render correctly.
- Karaoke word-by-word animation in burn-in would require converting VTT word timestamps to ASS
\koverride tags — complex and fragile, noted as preview-only limitation.