Files
gui-video-clipper/chat-summaries/2026-09-21_20-25-fix-captions-cors-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

1.5 KiB

Fix Captions Missing Due to CORS

Task

Captions/subtitles were not appearing at all - the CC button and settings button were invisible because parsedCues was always empty.

Root Cause

The local media server (axum on http://127.0.0.1:<random_port>) had no CORS headers. The frontend WebView runs at a different origin (http://localhost:1420 in dev, tauri://localhost in prod). While <video> elements can load cross-origin media without CORS (they use "no-cors" mode), the fetch() call used to load the VTT caption file was blocked by the browser's same-origin policy.

The fetch() silently failed (caught by .catch()), setting parsedCues = [], which meant the {#if parsedCues.length > 0} conditional in VideoPlayer.svelte never rendered the CC controls.

Changes Made

  1. src-tauri/Cargo.toml: Added "cors" feature to tower-http dependency.
  2. src-tauri/src/services/media_server.rs: Added CorsLayer::permissive() to the axum router, enabling cross-origin fetch() from the WebView.

Lessons Learned

  • <video src="..."> does NOT require CORS for basic playback - the browser loads media in "no-cors" mode. But fetch() to the same URL WILL be blocked without CORS headers. This discrepancy is why video/audio played fine but caption loading silently failed.
  • When a fetch() fails silently in a .catch() handler, there's no visible error in the UI — only in the browser DevTools console. Adding CORS from the start would have prevented this class of issues.

Follow-up

None - this was a targeted 2-file fix.