Tartube is the mature open-source yt-dlp GUI in this space and the obvious benchmark. As of today we're 8-ahead / 8-behind / 1-tied across the comparison matrix at the top of the new ROADMAP.md. Four phases: 1. Tartube feature parity — the 8 items they have that we don't, ordered by user-visible impact. Per-channel custom download options is the single biggest gap; everything else (folder hierarchy, filter UI, comments capture, notes, system tray, format conversion pipeline, per-distro packaging) follows. 2. Polish where Tartube is mature — integration tests, docs site, structured error recovery / "rescue recipes", backup-restore, stability hardening. 3. Surpass — cross-compile mac+win, Android client, WebSocket-driven progress, smart auto-tagging, federation, a real comment viewer, perceptual-hash dedup, plugin/scripting hooks. 4. Stretch / blue-sky — TV-mode layout, AI summarisation, multi-user, Plex/Jellyfin source-plugin integration. The architectural wins we already have (single Rust binary, real web UI, bundled curl_cffi venv, Plex export with NFO sidecars, Argon2 auth + CSP + rate-limit, 10 themes, ETag+gzip on the library response) are called out so we keep building on them rather than re-litigating them. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
9.3 KiB
Roadmap
North star
Surpass Tartube in every dimension.
Tartube is the mature open-source yt-dlp GUI and the obvious benchmark for a project in this space. yt-offline has architectural advantages Tartube can't catch up on quickly (Rust + axum + a real web UI + bundled toolchain + a modern security model) but trails on feature breadth and years-of-edge-cases maturity. The plan below closes those gaps first, then pushes past.
Current state vs Tartube (2026-05-25)
| Area | Us | Tartube | Verdict |
|---|---|---|---|
| yt-dlp wrapping | ✅ | ✅ | Tied |
| Multi-platform sources | ✅ first-class per-platform routing | ✅ generic | We lead |
| Web UI accessible from any device | ✅ | ❌ desktop only | We lead |
| Single-binary distribution | ✅ Rust binary + venv installer | ❌ Python+GTK deps | We lead |
| Security model (auth, CSP, rate-limit) | ✅ | ❌ never network-facing | We lead |
| Plex export with NFO sidecars | ✅ | ❌ | We lead |
| Bundled curl_cffi for impersonation | ✅ | ❌ user-installed | We lead |
| Themes | ✅ 10 themes | ❌ GTK default | We lead |
| Live-stream recording | ✅ | ✅ recent | Tied |
| Per-channel custom download options | ❌ global only | ✅ deep | Tartube leads |
| Folder/group hierarchy | ❌ flat per-platform | ✅ N-level | Tartube leads |
| Filter UI (date range, size, watched) | partial sort only | ✅ rich | Tartube leads |
| Comments capture | ❌ | ✅ --write-comments |
Tartube leads |
| Per-channel notes / annotations | ❌ | ✅ | Tartube leads |
| System tray | ❌ removed early | ✅ | Tartube leads |
| Format conversion / re-encode | ❌ remux only | ✅ ffmpeg pipeline | Tartube leads |
| Maturity / edge cases | ~weeks | ~years | Tartube leads |
| Per-distro packaging | PKGBUILD only | .deb .rpm .pkg.tar.zst | Tartube leads |
Score: 8 ahead, 8 behind, 1 tied — i.e. we're already half the way there on features Tartube has, plus we have a real lead on architecture.
Phase 1 — Tartube feature parity
The eight items Tartube has that we don't, ordered by how visibly they change the user experience.
1.1 Per-channel custom download options
Tartube's headline feature. Each channel gets its own quality / format / extractor args / cookies override that take priority over the global config.
- New
channel_settingsSQLite table (channel_path → JSON blob). Downloader::startconsults overrides before applying global defaults.- Right-click → "Channel options…" opens a per-channel settings dialog.
- Settings cascade: channel override > group override (Phase 1.2) > global.
1.2 Folder / group hierarchy
Lets a user organize channels into "Music", "News", "Coding", etc., with per-group default download options.
channel_groupsSQLite table:(id, parent_id, name).Channelgainsgroup_id: Option<i64>.- Sidebar renders as a tree; drag-and-drop to reorganize (desktop) / right-click "Move to group…" (web).
- Group-level download options inherited by member channels unless overridden per-channel.
1.3 Filter UI (date / size / status)
Today we have sort. Tartube has full filtering with chips and saved sets.
- Filter chips above the video grid: "watched / unwatched / in-progress", "today / this week / this month / older", "< 100 MB / > 1 GB", "has subtitles", "has chapters".
- Saved filter presets — name a set of chips, restore later.
- Filter state persists across rescans within a session.
1.4 Comments capture
yt-dlp's --write-comments dumps the full comment tree as JSON sidecar.
- Toggle in download dialog: "Include comments (slow)".
- Stored as
<stem>.comments.jsonnext to the video. - New
/api/comments/:idendpoint returns paginated comments. - Web video player modal gets a "Comments" tab next to "Chapters".
1.5 Per-channel / per-video notes
Free-text user annotations on any channel or video.
- New
notestable:(target_kind, target_id, body, updated_at). - Pencil icon on the channel sidebar entry + video card.
- Notes are searchable from the global filter.
1.6 System tray
Resurrect the dropped tray module. Minimize to tray, show download progress overlay, click to open the main window.
- Conditional on a non-headless desktop session.
- Right-click → Show / Hide / Quit / Pause downloads.
1.7 Format conversion pipeline
Post-download re-encode option: H.264/AAC mp4 at a configurable CRF, or audio extraction at a target bitrate. Useful for shrinking large 4K files.
- New
post_processconfig field per quality preset. - ffmpeg job runs after the download completes, replaces the source file
(or keeps both with an
.original.mkvsuffix). - Visible in the job log as a separate "transcoding" phase.
1.8 Per-distro packaging
Tartube ships .deb, .rpm, .pkg.tar.zst, .exe, .dmg. We ship a PKGBUILD.
- Codeberg CI matrix for
cargo build --releaseon each target. - Helpers to generate .deb (via
cargo-deb), .rpm (viacargo-generate-rpm), Windows MSI (viacargo-wix), and macOS .app + .dmg. - GitHub-style release artifacts attached to each tag.
Phase 2 — Polish where Tartube is mature
Things we win on architecturally but lose on real-world ruggedness.
2.1 Integration test coverage
47 unit tests is good for parsers and helpers, useless for end-to-end correctness. We need real-yt-dlp integration tests against a recorded fixture corpus.
- Mock-server fixtures for yt-dlp's JSON output.
cargo test --features integrationexercises the full download pipeline against the mock.- Headless web-UI tests via
headless_chromeorplaywright.
2.2 Documentation site
README is the only user-facing doc. Need a real docs site with:
- Per-platform setup guide (deeper than current README sections).
- Troubleshooting playbook for the top 10 yt-dlp errors.
- Architecture page (for contributors).
- Hosted via Codeberg Pages or GitHub Pages mirror.
2.3 Error recovery / structured logging
Today: errors land in the job log and that's it. Tartube has a "rescue recipes" feature where common errors map to documented fixes.
Job::failure_reason: Option<ErrorClass>enum (RateLimited,MissingCookies,CodecMissing,DiskFull,Other).- UI surfaces the class with a one-click suggested action.
- Anonymous opt-in error telemetry to surface new patterns.
2.4 Backup / restore
Tartube has database export. We have nothing.
/api/backup→ tar ofyt-offline.db+config.toml+cookies.txt./api/restore(idempotent merge of watched + positions).- "Export library snapshot" button in settings.
2.5 Stability hardening
Long-running deployments will surface real bugs.
- Replace remaining
.lock().unwrap()with poisoning-aware accessors. - Watchdog: if a yt-dlp job hangs past
--socket-timeout * retries, kill and re-queue. - Disk-full preflight: refuse to start a download when target dir has less free space than the average video size on disk.
Phase 3 — Surpass
Once we're at parity, we push past Tartube on its own ground.
3.1 Cross-compile macOS + Windows binaries
The current "later" roadmap item, blocked behind 1.8.
3.2 Android client
Native client over the existing web API. Background download via WorkManager + JobScheduler. Push notifications via Tailscale-routed HTTPS or a userland push channel.
3.3 Real-time progress via WebSocket
Replace the adaptive HTTP poll with a persistent /ws/progress
connection. Server pushes job updates; client renders without polling.
Saves the per-second tick and gives instant feedback.
3.4 Smart auto-tagging
Cluster channels by uploader frequency, content type, and metadata. Suggest groups ("looks like a music channel — move to Music?"). Builds on Phase 1.2's group system.
3.5 Federation / multi-host
A "remote library" mode where one yt-offline instance can browse another's library (read-only) over the same axum API. Useful for a "home archive + travel laptop" setup.
3.6 Comment viewer with diff
The Phase 1.4 comments JSON is just data. We can build the viewer Tartube doesn't have: threaded display, search, "new since last visit" highlights, sentiment filter.
3.7 Library-wide deduplication
Right now maintenance finds duplicates by yt-dlp video ID. Surpass by
fingerprinting media bytes (ffmpeg-derived perceptual hashes) so the
same video re-uploaded under a different ID gets flagged.
3.8 Plugin / scripting hook
Lua or WASM-based hooks that run on download events: pre-download filename rewriter, post-download archive uploader, custom metadata enricher. Inverts the "we hardcode everything" model.
Phase 4 — Stretch / blue-sky
Probably never, or much later.
- A web UI built around a "TV mode" remote-friendly layout.
- AI summarisation of videos (transcript → bullet points).
- Multi-user accounts with per-user watched/positions (currently single-user).
- Integration with Plex / Jellyfin / Kodi as a source plugin rather than a symlink generator.
How to read this
- Phase 1 is the next ~3 months of work if pursued steadily.
- Phase 2 is concurrent polish — pick up between Phase 1 items.
- Phase 3 is the year-1 ambition.
- Phase 4 items might be valuable, but commit to nothing.
Items inside a phase are loosely ordered by user-visible impact, not strict prerequisite. 1.1 (per-channel options) is the single biggest gap and should be tackled first.