49 lines
3.6 KiB
Markdown
49 lines
3.6 KiB
Markdown
|
|
# Fix: Video Playback, Waveform, and Thumbnails Not Working
|
||
|
|
|
||
|
|
**Date:** 2026-09-21 12:21
|
||
|
|
**Task:** Diagnose and fix three user-reported issues after downloading a video: no playback, waveform/thumbnails stuck at "Generating...", scrubbing doesn't update the player frame.
|
||
|
|
|
||
|
|
## Root Causes
|
||
|
|
|
||
|
|
### 1. `[Merger]` line path not parsed (Primary Bug)
|
||
|
|
When `yt-dlp` downloads video+audio separately and merges them, it outputs:
|
||
|
|
```
|
||
|
|
[download] Destination: /path/to/file.f399.mp4 ← intermediate
|
||
|
|
[download] Destination: /path/to/file.f251.webm ← intermediate
|
||
|
|
[Merger] Merging formats into "/path/to/file.webm" ← final merged file
|
||
|
|
```
|
||
|
|
The old parsing used `line.split(": ").nth(1)` for all three cases. This works for `[download] Destination:` lines (which have `: ` delimiter) but **fails for `[Merger]`** lines (which use `into "path"` format — no `: `). As a result, `last_file_path` pointed to a deleted intermediate file. Both `triggerPostDownloadProcessing(path)` and `session.localFilePath` received the wrong path, causing:
|
||
|
|
- All ffmpeg post-processing (waveform, thumbnails, keyframes) to fail with file-not-found
|
||
|
|
- The video player to reference a non-existent file
|
||
|
|
|
||
|
|
### 2. Stream URL doesn't work in Tauri webview
|
||
|
|
The `yt-dlp -g` stream URL (googlevideo.com) has anti-hotlinking protections (referer/IP checks) that block playback in a Tauri/WKWebView context. The `<video>` element was present but silently failed to load the source.
|
||
|
|
|
||
|
|
### 3. "Already downloaded" case not handled
|
||
|
|
When `yt-dlp` finds an existing file, it outputs `[download] /path/file.webm has already been downloaded` — a format that matches neither `Destination:` nor `Merger` patterns. So re-loading the same URL would result in `localFilePath = ""`.
|
||
|
|
|
||
|
|
## Changes Made
|
||
|
|
|
||
|
|
### `src-tauri/src/commands/video.rs`
|
||
|
|
- **Fixed `[Merger]` parsing:** Replaced the broken `split(": ")` approach with `trim_start_matches("[Merger] Merging formats into ").trim().trim_matches('"')`.
|
||
|
|
- **Added "already downloaded" parsing:** New branch for `has already been downloaded` using `strip_prefix`/`strip_suffix` to extract the path.
|
||
|
|
|
||
|
|
### `src/lib/components/VideoPlayer.svelte`
|
||
|
|
- **Switched to local file for playback:** Uses `convertFileSrc(session.localFilePath)` via Tauri's asset protocol once download is complete, instead of the unreliable stream URL.
|
||
|
|
- **Added download progress UI:** Shows a progress bar with percentage while downloading, instead of a broken black video area.
|
||
|
|
- **Added video error handling:** `onerror`/`onloadeddata` handlers with an overlay error message.
|
||
|
|
- **Import:** Added `convertFileSrc` from `@tauri-apps/api/core`.
|
||
|
|
|
||
|
|
## Lessons Learned
|
||
|
|
|
||
|
|
1. **`yt-dlp` stderr output formats are inconsistent.** `[download] Destination:` uses `: ` delimiter, `[Merger]` uses `into "path"`, and "already downloaded" embeds the path mid-sentence. Each needs its own parser.
|
||
|
|
2. **googlevideo.com stream URLs don't work in embedded webviews** due to anti-hotlinking. The design's "hybrid streaming preview" approach needs a local proxy or must fall back to showing download progress until the file is available locally.
|
||
|
|
3. **Always test with cached files.** The "already downloaded" edge case only surfaces on the second load of the same URL.
|
||
|
|
|
||
|
|
## Follow-up Items
|
||
|
|
|
||
|
|
- [ ] Add progress indicators for post-download processing (waveform/thumbnail/keyframe extraction can take minutes on long videos)
|
||
|
|
- [ ] Consider pre-download preview via local proxy or lower-quality quick download
|
||
|
|
- [ ] The waveform extraction uses `aresample=8000` (sample rate) which produces ~26M samples for a 54-min video — consider optimizing to reduce to target count directly
|
||
|
|
- [ ] Add error surfacing for failed post-download processing (currently silent `console.error`)
|