From 4c877fd7f9aaa679bf92a2311f8f8fbfc6ed1732 Mon Sep 17 00:00:00 2001 From: vincent Date: Sat, 29 Aug 2026 02:19:23 +0200 Subject: [PATCH] Add FlightTube implementation plan --- .../plans/2026-08-29-flighttube.md | 533 ++++++++++++++++++ 1 file changed, 533 insertions(+) create mode 100644 docs/superpowers/plans/2026-08-29-flighttube.md diff --git a/docs/superpowers/plans/2026-08-29-flighttube.md b/docs/superpowers/plans/2026-08-29-flighttube.md new file mode 100644 index 0000000..8cdce73 --- /dev/null +++ b/docs/superpowers/plans/2026-08-29-flighttube.md @@ -0,0 +1,533 @@ +# FlightTube Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** A Tauri desktop app that merges the user's YouTube subscriptions into one newest-first feed, downloads videos locally, and shows only downloaded videos when offline. + +**Architecture:** Rust owns all I/O — Atom feed fetching, SQLite, the `yt-dlp` subprocess — and streams progress to the frontend over Tauri events. React renders and dispatches commands, holding no business logic. Pure parsing functions (CSV, XML, progress lines) are separated from I/O so they are unit-testable without a network or a subprocess. + +**Tech Stack:** Tauri 2.11 · Rust 1.98 · React 19.2 · TypeScript · Vite 8.2 · Tailwind CSS 4.3 (`@tailwindcss/vite`, no config file) · rusqlite 0.40 (bundled) · quick-xml 0.42 · reqwest 0.13 · tokio 1.53 · csv 1.4 · chrono 0.4 + +**Spec:** `docs/superpowers/specs/2026-08-29-flighttube-design.md` + +## Global Constraints + +- **Download format is fixed:** `-f "bv*[vcodec^=avc1]+ba[acodec^=mp4a]/bv*+ba/b" --merge-output-format mp4`. Validated live; resolves to `1920x1080 avc1.640028 + mp4a.40.2`. Never widen this — non-H.264 will not play in WKWebView, and in-app playback is a hard requirement. +- **No OAuth, no API keys, no secrets on disk.** Metadata comes only from the public Atom endpoint `https://www.youtube.com/feeds/videos.xml?channel_id=`. +- **Atom feeds return ~15 entries per channel.** No backfill exists. Never write code that assumes deeper history. +- **Refresh must upsert,** never delete-and-reinsert: download state lives alongside video rows and must survive a refresh. +- **Thumbnails must be cached to disk** on refresh, or the offline feed renders broken images. +- **Feed concurrency 8; download concurrency 2.** +- **Library path:** `~/Movies/FlightTube`, user-configurable. +- **Timestamps** are stored as Unix seconds (`INTEGER`) so sorting is an indexed `ORDER BY`. +- Verified toolchain: `yt-dlp 2026.08.19`, `ffmpeg 9.0.1`, `rustc 1.98.0`, Node 22.22.2. + +## File Structure + +``` +src-tauri/src/ + main.rs entry, builder, state registration + db.rs schema, migrations, all SQL + models.rs Channel, Video, DownloadState, FeedFilter — shared types + takeout.rs subscriptions.csv -> Vec (pure + tested) + feed.rs Atom XML -> Vec