ffmpeg only accepts -version (single dash); it exits 8 on --version and writes to stderr, so the status panel reported it missing even when installed. Version flags are now per-tool and both streams are read. The player used max-h-full inside a grid, which a 1080x1920 Short overflowed. Switched to absolute fill with object-contain so portrait and landscape both letterbox correctly. Also sized the window to 1180x780 centered, which fits a laptop display.
101 lines
3.7 KiB
Markdown
101 lines
3.7 KiB
Markdown
# FlightTube
|
|
|
|
A desktop app that merges all your YouTube subscriptions into one newest-first feed,
|
|
downloads the videos you pick, and — when you have no connection — shows only what you
|
|
already downloaded. Built for the flight.
|
|
|
|
Tauri 2 · Rust · React · Tailwind CSS 4 · SQLite
|
|
|
|
## How it works
|
|
|
|
**Subscriptions come from Google Takeout, not the API.** Export *YouTube subscriptions*
|
|
from [Takeout](https://takeout.google.com/) and import the `subscriptions.csv` in
|
|
Settings. No OAuth, no API key, no Google Cloud project, nothing secret on disk.
|
|
|
|
**Video metadata comes from YouTube's public Atom feed** — one request per channel to
|
|
`youtube.com/feeds/videos.xml?channel_id=…`, fetched 8 at a time and merged into a single
|
|
feed sorted by publish date. Thumbnails are mirrored to local disk so the feed still
|
|
renders with no network.
|
|
|
|
**Downloads shell out to `yt-dlp`,** pinned to H.264 video + AAC audio in an MP4
|
|
container. That caps quality at 1080p — YouTube only serves H.264 that high, and anything
|
|
above it is VP9 or AV1, which the app's own player cannot reliably decode. The tradeoff is
|
|
deliberate: every download is guaranteed to play inside FlightTube.
|
|
|
|
## Requirements
|
|
|
|
```bash
|
|
brew install yt-dlp ffmpeg
|
|
```
|
|
|
|
Both are checked at startup; Settings shows their versions and this command if either is
|
|
missing. `ffmpeg` is required because best-quality H.264 and AAC arrive as separate
|
|
streams that must be merged.
|
|
|
|
## Running it
|
|
|
|
```bash
|
|
npm install && npm run tauri dev
|
|
```
|
|
|
|
Build a real app bundle:
|
|
|
|
```bash
|
|
npm run tauri build
|
|
```
|
|
|
|
## Using it
|
|
|
|
1. **Settings → Import subscriptions.csv** — point it at your Takeout export.
|
|
2. **Refresh** — pulls the latest videos from every channel.
|
|
3. **Download** on any video — progress shows live on the button; click again to cancel.
|
|
4. Click a **downloaded** video to play it in the app. Click an undownloaded one to open
|
|
it on YouTube.
|
|
5. **Offline** — the app detects a lost connection and collapses the feed to your
|
|
downloads. The connectivity pill also toggles a forced offline mode for testing.
|
|
|
|
Videos land in `~/Movies/FlightTube` (changeable in Settings).
|
|
|
|
## Limitations
|
|
|
|
- The Atom feed returns only the **~15 most recent videos per channel**. There is no
|
|
backfill and no pagination — this is a rolling recent window, not an archive.
|
|
- Quality tops out at 1080p, by the deliberate choice described above.
|
|
- `yt-dlp` needs occasional updating (`brew upgrade yt-dlp`) as YouTube changes.
|
|
- Downloading videos is contrary to YouTube's Terms of Service.
|
|
|
|
## Tests
|
|
|
|
```bash
|
|
cd src-tauri && cargo test
|
|
```
|
|
|
|
37 unit tests cover the three places malformed input actually bites: Takeout CSV parsing,
|
|
Atom feed parsing (against a captured real response), and `yt-dlp` progress-line parsing —
|
|
plus the database rule that a refresh must never clobber download state.
|
|
|
|
Two network-dependent tests are excluded by default:
|
|
|
|
```bash
|
|
cargo test --test pipeline -- --ignored --nocapture # full pipeline vs. live feeds
|
|
cargo test --test seed_real_db -- --ignored --nocapture # populate the installed app's db
|
|
```
|
|
|
|
## Layout
|
|
|
|
```
|
|
src-tauri/src/
|
|
takeout.rs subscriptions.csv -> channels (pure, tested)
|
|
feed.rs Atom XML -> videos, plus fetching (parse is pure, tested)
|
|
downloader.rs yt-dlp arguments and progress lines (pure, tested)
|
|
db.rs schema and every SQL statement
|
|
thumbs.rs local thumbnail cache
|
|
net.rs reachability probe
|
|
commands.rs Tauri command surface — delegates only
|
|
src/
|
|
components/ Sidebar, TopBar, VideoRow, DownloadButton, Player, Settings
|
|
hooks/ useFeed, useDownloads, useConnectivity
|
|
```
|
|
|
|
Design notes and the implementation plan are in `docs/superpowers/`.
|