To make the "surpass Tartube" roadmap concrete, document Tartube's v2.5.231 codebase as a specification we can refer to: - Module map: 146k lines of Python across 19 modules, with per-module responsibilities (mainapp / mainwin / config / downloads / media / options / wizwin / process / refresh / tidy / info / updates / ffmpeg_tartube / formats / ttutils / dialogue / files / xdg). - Data model: container hierarchy (Folder → Channel | Playlist → Video) with N-level Folder nesting, system folders that act as smart filters (Bookmarks, Favourites, Waiting, New, Live, Missing, Recent, Temporary), and the full per-video flag inventory. - OptionsManager: the headline feature — 164 distinct yt-dlp flags attachable to any container or video with cascading resolution. The spec lists the option groups (Behaviour, Network, Playlist, Filters, Download, Filesystem, Auth, Anti-bot, Format, Subtitles, Post-processing, Cookies, Output, Tartube-specific) and points to a concrete SQLite + Rust struct design for our Phase 1.1. - Seven threaded operation managers (Download, Update, Refresh, Tidy, Info, Process, Livestream/Stream) and three downloader strategies (VideoDownloader, ClipDownloader, StreamDownloader). - Custom downloads (named recipes) and profiles (saved container groups) — feeding our Phase 1 + 3. - UI surface inventory: five primary tabs (Videos, Progress, Classic Mode, Drag and Drop, Errors), ~80 specialised dialogs, three wizards (Setup, Import YT subs, Tutorial), and the ~30-tab SystemPrefWin. - SponsorBlock + chapter persistence (slice_list / stamp_list) — a Phase 1 add-on after per-channel options ship. - Notable corners: master/slave dbid dedup, RSS-driven discovery, external_dir per-channel storage, livestream message parsing, full gettext i18n. - Things Tartube does better (15 items, mapped to roadmap entries), things we already do better (10 items, to keep momentum honest). - A 12-checkbox "Tartube parity" milestone definition — when all are ticked, the comparison table at the top of ROADMAP.md goes from 8-ahead-8-behind to 8-ahead-0-behind, and "surpass" begins. ROADMAP.md gains a pointer to the spec just under the north-star line. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|---|---|---|
| .vscode | ||
| docs | ||
| src | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| icon.png | ||
| LICENSE | ||
| PKGBUILD | ||
| README.md | ||
| ROADMAP.md | ||
| SECURITY_AUDIT.md | ||
| youtube-backup.desktop | ||
| yt-offline-0.1.0-1-x86_64.pkg.tar.zst | ||
yt-offline
A self-hosted media archive for YouTube and friends. Pastes any URL, routes it to the right folder by source, tracks what you've watched, and lets you play everything back from a desktop GUI or browser — even when you're offline or the source video has been taken down.
Built on yt-dlp; written in Rust.
What it backs up
| Platform | Channels | Playlists | Single videos |
|---|---|---|---|
| YouTube | ✅ | ✅ | ✅ |
| TikTok | ✅ | — | ✅ |
| Twitch (VODs + clips) | ✅ | — | ✅ |
| Vimeo | ✅ | ✅ | ✅ |
| Bandcamp | ✅ (artist) | ✅ (albums) | ✅ (tracks) |
| SoundCloud | ✅ | ✅ (sets) | ✅ |
| Odysee | ✅ | — | ✅ |
| Anything else yt-dlp accepts | other/ |
other/ |
other/ |
Each source lands in its own sibling folder under your backup directory
(channels/ for YouTube, tiktok/, twitch/, etc.). A .source-url
sidecar is dropped in every creator folder so re-checks always know the
exact URL to refresh from.
Features
Library
- Multi-platform sidebar grouped by source, with platform icons.
- Search across your whole library, instant.
- Sort by: Newest / Oldest (upload date), Largest / Smallest, Longest / Shortest, Title.
- Watched tracking + resume positions persisted in SQLite.
- Continue watching view of partially-played videos.
- Subtitles (auto + manual, SRT and WebVTT) + chapters + SponsorBlock marks embedded into the video file.
- Statistics — totals, top channels by size/count, weekly downloads histogram, upload-year histogram.
- Maintenance — finds duplicate video IDs across folders and missing sidecars (thumbnail / info.json / description), with one-click repair.
Playback
- Desktop GUI launches your configured player (mpv by default; mpv gets resume-position tracking via JSON-IPC).
- Web UI plays videos inline in any browser, with subtitle tracks and a chapters panel. Optional on-the-fly ffmpeg transcoding for browsers that can't decode MKV.
Downloads
- Bundled yt-dlp + curl_cffi + deno — one click in Settings sets up a
self-contained Python venv with
yt-dlp[default]pluscurl_cffi(browser-impersonation for bot-detection bypass) anddenofor player-JS evaluation. No system installation required. - Or use system yt-dlp — toggleable in Settings.
- Concurrent-download limit (default 3) with a visible queue.
- Quality picker: Best / 1080p / 720p / 480p / 360p, or Music mode
for audio-only extraction into
music/<artist>/. - Retry hardening:
--retries 30 --fragment-retries 30 --retry-sleep linear=1:30:2 --sleep-requests 1so connection resets self-heal instead of failing the job. - Scheduler — periodically re-check every channel for new uploads.
- Cookies — paste / file-pick a Netscape
cookies.txt, or fall back to--cookies-from-browserfor whatever browser you pick.
Web server
- Single binary, no Node / Python / Docker required (Python only for the optional bundled yt-dlp venv).
- Bind interface picker — localhost only (default), Tailscale, LAN, or all interfaces.
- Password-gated UI when enabled — Argon2 hashed, 256-bit session
tokens, 30-day TTL with lazy pruning, per-IP rate-limit on
/api/login(5 failures → 60s lockout). - Security headers: Content-Security-Policy, X-Frame-Options DENY, X-Content-Type-Options nosniff, Referrer-Policy no-referrer.
Securecookie flag whenX-Forwarded-Proto: httpsis present (i.e. behind a reverse proxy doing TLS).- 4 MiB request body limit on every route.
Plex integration
- One click generates a symlink tree your Plex "TV Shows" library can ingest
directly:
<plex_root>/<show>/Season 2024/<show> - S2024E001 - title.mkv. - Writes
.nfosidecars per episode (title, season, episode, aired date, runtime, plot) plus a show-leveltvshow.nfo, so Plex's "Personal Media (TV Shows)" agent picks up YouTube metadata correctly. - Symlinks the thumbnail as
<stem>-thumb.jpgso Plex shows episode art. - Non-YouTube creators get
<Platform> - <handle>show folders to avoid collisions across sources.
Themes
Ten themes shared across desktop and web — Dark, Light, Dracula, Trans, plus three Emo/Scene flavours (Nocturnal, Coffin, Scene Queen).
Misc
- Native notifications when downloads finish (notify-rust / zbus, no GTK build dep).
/api/stats,/api/ytdlp/update,/api/scheduler/run— every UI button has an equivalent JSON endpoint.
Quick start
git clone https://codeberg.org/anassaeneroi/yt-offline
cd yt-offline
cargo build --release
# Desktop GUI
./target/release/yt-offline
# Or web server only (headless)
./target/release/yt-offline --web 8080
On first run a config.toml is created in the working directory. Settings
can also be changed from inside either UI — no manual editing required.
Bundled yt-dlp setup
- Open Settings.
- Under yt-dlp binary, choose Bundled and click Install.
- The installer creates
~/.local/share/yt-offline/venv/withyt-dlp[default]+curl_cffi, plus~/.local/share/yt-offline/bin/deno. Progress streams into a regular job entry.
Updates are the same button. Switching to System uses whatever yt-dlp
is on PATH instead.
Building
Arch / CachyOS / Manjaro
sudo pacman -S --needed rust mpv # python3 + python-pip already present
git clone https://codeberg.org/anassaeneroi/yt-offline
cd yt-offline
makepkg -si # or: cargo build --release
A PKGBUILD is included.
Debian / Ubuntu
sudo apt install \
build-essential pkg-config curl git python3-venv \
libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev \
libxkbcommon-dev libssl-dev
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"
cargo build --release
python3-venv is required for the bundled yt-dlp install path (skipable
if you only ever use system yt-dlp).
macOS
xcode-select --install
brew install mpv
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"
cargo build --release
Windows
Install Rust (MSVC toolchain), Visual Studio Build Tools with the Desktop development with C++ workload, then:
winget install mpv.net python.python.3.12
git clone https://codeberg.org/anassaeneroi/yt-offline
cd yt-offline
cargo build --release
Configuration
config.toml lives next to the binary (or in the working directory). All
fields are also editable in Settings.
[backup]
directory = "/path/to/library/channels" # YouTube root; siblings hold other platforms
max_concurrent = 3 # parallel yt-dlp processes
use_bundled_ytdlp = false # true = use the venv set up by the Install button
[player]
command = "mpv" # any executable that takes a file path as last arg
browser = "firefox" # used by --cookies-from-browser when no cookies.txt is set
[ui]
theme = "dark" # dark | light | dracula | trans | emo-nocturnal | emo-coffin | emo-scene-queen
[scheduler]
enabled = false
interval_hours = 24
[web]
port = 8080
bind = "127.0.0.1" # 127.0.0.1 | 0.0.0.0 | a Tailscale/LAN address
transcode = false # MKV → MP4 on the fly for browsers (needs ffmpeg)
source_url = "https://codeberg.org/anassaeneroi/yt-offline" # AGPL §13 footer link
[plex]
library_path = "/path/to/plex/TV/youtube" # leave unset to disable
Usage
Desktop GUI
- Click ⬇ Downloads, paste any URL — channel, video, playlist, or profile from any supported platform. The dialog shows the detected source and target folder before you confirm.
- Choose quality (or 🎵 Music for audio-only).
- Pick Fast mode to stop at the first already-archived video, or leave it off for a full back-fill.
The sidebar groups channels by platform. Right-click any channel for Check for new videos and Open folder. The download bar shows the active job count plus what's queued.
Other top-bar buttons:
- ⟳ Rescan — re-read the library directory.
- 📊 Stats — totals, top channels, weekly download histogram.
- 🩺 Maintenance — find and resolve duplicates / missing sidecars.
- ⚙ Settings — everything in
config.toml, plus cookies, password, bundled-yt-dlp install/update, and starting the web server.
Web UI
Start the server (--web CLI flag or Start button in Settings →
Web server), open http://localhost:8080 (or your configured bind
address). The UI mirrors the desktop one and adds inline video playback.
If a download password is set, you'll be redirected to a login page; the session cookie is HttpOnly + SameSite=Strict, valid 30 days.
Library layout
/path/to/library/
├── channels/ ← YouTube
│ ├── @creator-name/
│ │ ├── .source-url ← original URL, for re-checks
│ │ ├── archive.txt ← yt-dlp's downloaded-ID record
│ │ ├── Video Title [abc123].mkv
│ │ ├── Video Title [abc123].webp
│ │ ├── Video Title [abc123].info.json
│ │ ├── Video Title [abc123].description
│ │ └── Video Title [abc123].en.vtt
│ └── @another/
├── tiktok/
├── twitch/
├── vimeo/
├── bandcamp/
├── soundcloud/
├── odysee/
├── other/
├── music/
│ └── <artist>/
│ └── Track Title [xyz].opus
└── yt-offline.db ← watched + positions + password hash
Troubleshooting
"Impersonate target ... is not available" You're on bundled mode but the venv install hasn't completed. Open Settings → yt-dlp binary → click Install and watch the job for the "impersonation targets available" line.
yt-dlp not found (system mode)
Install yt-dlp via your package manager or pip install yt-dlp, or
switch to Bundled in Settings.
Web UI says "authentication required" but no password is set Sessions cleared after the password was changed. Refresh the page.
Videos play but seeking jumps to the start
That's the transcoding mode (web.transcode = true). MKV streams can't be
seeked while transcoding live; turn it off if your browser can play MKV
directly.
Connection-reset / "Recv failure" errors on download The defaults already retry 30× with linear backoff. If they're persistent, your IP is being rate-limited — paste fresh cookies from a browser session into Settings → Cookies.
Build fails on Debian/Ubuntu
Make sure all packages from the build dependencies block are installed,
plus python3-venv if you want the bundled yt-dlp install path.
Security
See SECURITY_AUDIT.md — the codebase has been audited end-to-end, covering command/SQL injection, path traversal, XSS, session management, rate-limiting, supply-chain (bundled binary SHA verification), and dependency status.
License
AGPL-3.0-or-later. When you run this software as a network
service, the AGPL requires that you offer network users access to the
Corresponding Source — the running version, with any modifications.
Set web.source_url in config to a public URL where the source is
available; the web UI surfaces it in the footer and GET /api/settings.