Files
gui-video-clipper/chat-summaries/2026-09-21_20-25-fix-captions-cors-summary.md

21 lines
1.5 KiB
Markdown
Raw Permalink Normal View History

# 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.