Self-hosted multi-platform media archiver — YouTube, TikTok, Twitch, Vimeo, Bandcamp, SoundCloud, Odysee. Desktop GUI + browser UI, one-click yt-dlp + curl_cffi setup, Plex export, SQLite resume tracking. Federation features in development. AGPL-3.0.
Find a file
Luna 59996735f3 Add bundled yt-dlp, music library, Plex metadata, sort by date; security + perf hardening
Bug fixes
- Desktop auto-rescan: snapshot was_running before check_notifications
  updates prev_job_states, so the post-download rescan actually fires.
- web::run shutdown: replace `let _ = tx;` (which dropped the sender
  immediately and short-circuited the shutdown select!) with
  std::mem::forget(tx); add an idle fallback so the `-> !` is honored.
- /api/preview now resolves the bundled yt-dlp path and extends PATH
  for deno discovery, matching the rest of the downloader.
- Scheduler interval clamped to >=1h on read so a manually-edited
  config.toml with 0 hours can't trigger every tick.
- maintenance::is_within canonicalizes the parent + filename when the
  target is missing; remove_files treats NotFound as success.

Security
- Session tokens stored with issued-at Instant and pruned past 30 day
  TTL on every touch (was: unbounded HashSet).
- Login rate-limited per source IP: 5 failures → 60s lockout (429).
- Secure cookie flag added when X-Forwarded-Proto: https is present.
- 4 MiB body size cap via DefaultBodyLimit.
- Security headers middleware: CSP, X-Content-Type-Options,
  X-Frame-Options, Referrer-Policy.
- JS safeUrl() defangs javascript:/vbscript:/data:text URLs before
  interpolation into src= attributes.
- Bundled yt-dlp install verifies SHA-256 against the release's
  SHA2-256SUMS; deno hash printed for visual inspection. Install also
  reports byte counts every 3s so users see live progress.
- yt-offline.db chmod 0600 at open time on Unix.

New features
- Bundled yt-dlp + deno mode: settings toggle (System/Bundled) plus
  one-click Install/Update from settings. Ensures executable bit on
  every launch in case the install chmod was missed.
- Download queue with configurable max_concurrent (1–10); pending
  jobs surfaced in both UIs.
- Music download mode: --extract-audio into music/<artist>/, separate
  sidebar entry, /api/music + /music-files/ endpoints, inline <audio>.
- Download quality selector: Best / 1080p / 720p / 480p / 360p.
- Sort videos by Newest / Oldest (upload_date from info.json with
  release_date fallback).
- Plex metadata: per-episode .nfo (title, season/episode, aired,
  runtime, plot from .description), <stem>-thumb.jpg symlink, and
  show-level tvshow.nfo.
- yt-dlp retry/throttle defaults: --retries 30 --fragment-retries 30
  --retry-sleep linear=1:30:2 --sleep-requests 1 to ride out the
  "Connection reset by peer" failures.

Performance
- password_required cached in AtomicBool; refreshed only on password
  change. Eliminates a SQLite query per static-file fetch.
- Job::log → VecDeque for O(1) front-pop instead of O(n) drain.
- Library scan parallelized across cores via stdlib parallel_map.
- Web UI poll: 600ms while active, 5s when idle, 2s after errors.
- Music scan now recursive (Artist/Album/Track.opus).
- percent_encode_segment uses write! to avoid per-byte String allocs.

Code quality
- 27 unit tests covering parse_progress, parse_stem, extract_after,
  detect_url_kind, srt_to_vtt, count_cookies, percent_encode_segment,
  bind_mode_of, hash_password, lang_label, is_within, sanitize,
  year_of, aired_date, xml_escape.
- Unified library::find_video + Channel::all_videos() iterator,
  replacing three duplicated linear searches.
- Downloader::browser wired to --cookies-from-browser as a fallback
  when no cookies.txt is present.
- mpv detection now matches the binary basename, not substring.
- Settings modal scroll fix; web settings expose all new fields.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 04:54:26 -07:00
.vscode Major update with lots of new features and fixes 2026-05-17 05:36:04 -07:00
src Add bundled yt-dlp, music library, Plex metadata, sort by date; security + perf hardening 2026-05-23 04:54:26 -07:00
.gitignore Add full-scan mode, persist password in DB, fix channel re-check URLs, SRT subs, cookie clear, UI fixes 2026-05-21 05:49:55 -07:00
Cargo.lock Add full-scan mode, persist password in DB, fix channel re-check URLs, SRT subs, cookie clear, UI fixes 2026-05-21 05:49:55 -07:00
Cargo.toml Add full-scan mode, persist password in DB, fix channel re-check URLs, SRT subs, cookie clear, UI fixes 2026-05-21 05:49:55 -07:00
icon.png First version of youtube-backup, a tool to backup your YouTube channel. 2026-05-11 02:33:52 -07:00
LICENSE Add web UI, AGPL3, notifications, continue watching, bulk watched, storage stats, scheduler 2026-05-11 04:27:04 -07:00
PKGBUILD PKGBUILD: disable LTO to fix bundled sqlite link errors 2026-05-14 08:28:56 -07:00
README.md add icon to README for link preview 2026-05-11 03:27:08 -07:00
SECURITY_AUDIT.md Add web themes, network binding, UI auth, library maintenance; optimize + fix rescan 2026-05-21 02:58:09 -07:00
youtube-backup.desktop Major update with lots of new features and fixes 2026-05-17 05:36:04 -07:00
yt-offline-0.1.0-1-x86_64.pkg.tar.zst Major update with lots of new features and fixes 2026-05-17 05:36:04 -07:00

yt-offline

yt-offline icon

A desktop app for archiving YouTube channels using yt-dlp. Browse your downloaded channels, manage downloads, and play videos — all from a native GUI.

Features

  • Channel Browser — Browse downloaded channels and videos with thumbnails
  • Smart Download Routing — Paste any YouTube URL; channels, playlists, and single videos are automatically routed to the right folder
  • Playlist View — Channels with playlist subdirectories show them in the sidebar
  • Themes — Dark, Light, Dracula, Trans, and three Emo/Scene themes
  • Settings GUI — Configure everything from inside the app
  • Video Playback — Launch videos in mpv, VLC, or any player
  • Search — Filter across your entire library in real time
  • System Tray — Minimize to tray

Building

Arch Linux / Manjaro

A PKGBUILD is included:

git clone https://codeberg.org/anassaeneroi/yt-offline
cd yt-offline
makepkg -si

Or build manually:

sudo pacman -S --needed rust yt-dlp mpv
cargo build --release
sudo install -Dm755 target/release/yt-offline /usr/bin/yt-offline

Debian / Ubuntu / Linux Mint

Install build dependencies:

sudo apt install \
  build-essential pkg-config curl git \
  libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev \
  libxkbcommon-dev libssl-dev \
  libgtk-3-dev libayatana-appindicator3-dev

Install Rust (if not already installed):

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"

Install runtime dependencies:

sudo apt install yt-dlp mpv

Build and install:

git clone https://codeberg.org/anassaeneroi/yt-offline
cd yt-offline
cargo build --release
sudo install -Dm755 target/release/yt-offline /usr/bin/yt-offline
cp youtube-backup.desktop ~/.local/share/applications/yt-offline.desktop

macOS

Install Xcode command line tools and Homebrew dependencies:

xcode-select --install
brew install yt-dlp mpv

Install Rust:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"

Build:

git clone https://codeberg.org/anassaeneroi/yt-offline
cd yt-offline
cargo build --release

The binary is at target/release/yt-offline. Copy it wherever you like, or run it in place.


Windows

  1. Install Rust — accept the default MSVC toolchain when prompted

  2. Install Visual Studio Build Tools with the Desktop development with C++ workload

  3. Install yt-dlp and mpv:

    winget install yt-dlp.yt-dlp
    winget install mpv.net
    
  4. Clone and build:

    git clone https://codeberg.org/anassaeneroi/yt-offline
    cd yt-offline
    cargo build --release
    

The binary is at target\release\yt-offline.exe. Copy it wherever you like and run it.

Note: The first build takes a while — Rust compiles all dependencies from scratch.


Configuration

On first run, create a config.toml next to the binary (or edit it from the Settings button inside the app):

[backup]
directory = "/path/to/your/video/library"

[player]
command = "mpv"

[ui]
theme = "dark"

Options

Setting Default Description
backup.directory ./channels Where downloaded videos are stored
player.command mpv Command used to launch the video player
ui.theme dark dark, light, dracula, trans, emo-nocturnal, emo-coffin, emo-scene-queen

Usage

  1. Download a channel/video/playlist — click ⬇ Downloads, paste a YouTube URL. The app detects the URL type and routes it automatically:

    • Channel URL → channels/<handle>/
    • Single video → channels/<channel-name>/
    • Playlist → channels/<channel-name>/<playlist-name>/
  2. Browse your library — channels appear in the left sidebar. If a channel has playlist subdirectories they show as collapsible sub-items.

  3. Play a video — click ▶ Play on any video card, or double-click the thumbnail.

  4. Change settings — click ⚙ Settings to change the backup directory, player, or theme without editing the file.


Troubleshooting

yt-dlp not found Make sure it's installed and on your $PATH. On Windows, restart your terminal after install.

Build fails on Debian/Ubuntu with missing headers Make sure you installed all packages in the build dependencies block above, especially libayatana-appindicator3-dev and libgtk-3-dev.

Build fails on Windows with linker errors Make sure Visual Studio Build Tools are installed with the C++ workload selected, not just the base tools.

Videos won't play Check player.command in config.toml (or Settings). The command must accept a file path as its last argument.

Thumbnails not loading Supported formats: JPEG, PNG, WebP. Other formats are silently skipped.


Project Structure

src/
  main.rs        entry point
  app.rs         UI and main loop
  downloader.rs  yt-dlp integration and URL detection
  library.rs     channel/playlist/video scanner
  config.rs      config file loading and saving
  theme.rs       all colour themes
  database.rs    SQLite (reserved for future use)
  tray.rs        system tray

License

See LICENSE.