Commit graph

12 commits

Author SHA1 Message Date
Luna
8d1c274075 Tackle remaining unscoped items: cookies chmod, log redact, Bandcamp, ETag+gzip
Four items knocked off the unscoped list:

Auto-chmod 0600 cookies.txt
- web::write_cookies now sets mode 0600 on the file after writing, on Unix.
  Mirrors the same guard we put on yt-offline.db. cookies.txt carries
  live session credentials; no reason for it to stay umask-default.

Redact cookies path from job log
- Downloader::spawn_job now runs each stdout/stderr line through a small
  redactor that replaces the absolute cookies.txt path with the bare
  filename before forwarding to the Job log. yt-dlp can echo the path
  in error strings, which leaks $HOME into the UI and /api/progress
  responses.
- 2 new tests cover the strip + pass-through cases.

Bandcamp full-discography mode
- Bandcamp at the bare artist URL is already a Channel in our classifier
  and yt-dlp's BandcampUserIE returns the full discography. The output
  template for Bandcamp's channel case now organizes tracks into
  per-album subfolders via `%(album|Unknown)s` so a discography pull
  stays coherent instead of one flat directory.
- New `Downloader::apply_platform_extras` adds `--embed-thumbnail` for
  audio-first platforms (Bandcamp, SoundCloud) so music players see the
  cover art via embedded tags rather than scanning for a sidecar JPEG.

Library ETag + gzip
- WebState gains `library_version: AtomicU64`. `bump_library_version()`
  is called from post_rescan, post_watched, post_maintenance_remove, and
  post_resume (only when crossing the "Continue watching" >3.0 boundary
  so playback-time updates don't constantly invalidate the cache).
- get_library is now Response-returning; it consults `If-None-Match` and
  short-circuits with 304 Not Modified when the client's ETag matches.
  Otherwise it sends `ETag: "<n>"` alongside the JSON.
- JS `loadLibrary()` caches the ETag and sends it on subsequent calls.
  Returns early on 304 keeping the existing in-memory library array.
- Adds `tower_http::compression::CompressionLayer` (gzip). Already-
  compressed media served from ServeDir is auto-skipped by the layer;
  JSON responses get ~10× smaller. New `compression-gzip` feature on
  the tower-http dep.

46 unit tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 00:26:47 -07:00
Luna
c0be4bb533 README + Cargo description: cover every shipped feature
The README still described yt-offline as a YouTube-only desktop app.
Rewrite it to reflect what actually exists today:

- Multi-platform support (YouTube, TikTok, Twitch, Vimeo, Bandcamp,
  SoundCloud, Odysee, and yt-dlp's full fallback list) with a table
  of what each platform supports.
- Library, playback, downloads, web server, Plex integration, themes,
  and misc sections — each grouping the relevant features so a reader
  can spot what matters to them.
- Bundled-yt-dlp install walkthrough (venv + curl_cffi + deno).
- Updated config.toml example with every field the app reads.
- Library layout diagram showing the new platform sibling folders
  and the `.source-url` sidecar.
- Usage section split between desktop GUI and web UI.
- Troubleshooting now lists the impersonation error path, missing
  python3-venv, the transcoding-seek caveat, and rate-limit recovery.
- Pointer to SECURITY_AUDIT.md.
- AGPL §13 obligations spelled out.

Also expand the Cargo.toml description so `cargo metadata` and crates.io
listings convey the multi-platform / web UI scope at a glance.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 23:21:48 -07:00
Luna
1d72069913 Add full-scan mode, persist password in DB, fix channel re-check URLs, SRT subs, cookie clear, UI fixes
- Full-scan download toggle: omits --break-on-existing so all unarchived
  videos are fetched regardless of order, filling gaps in partial archives
- Filter "Aborting remaining downloads" from job logs (break-on-existing noise)
- Password hash moved from config.toml to SQLite settings table; survives
  git checkouts and rebuilds. config.toml and yt-offline.db added to .gitignore;
  config auto-generated on first run if absent
- Channel re-check URLs derived from folder name (/@handle or /channel/UCxxx)
  instead of info.json's canonical channel_url, preventing duplicate UCxxx folders
- SRT subtitles detected by library scanner and served via /api/sub-vtt/* endpoint
  that converts to WebVTT on the fly; browser <track> element can now play them
- Cookie clear button in both desktop and web UI (DELETE /api/cookies)
- Per-job X close button on finished download jobs in desktop GUI
- Fix widget ID clash when multiple download jobs are shown (push_id per job)
- Watched videos excluded from Continue Watching list and badge count
- settings table added to SQLite schema (key/value store)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 05:49:55 -07:00
Luna
1ef3fe56c6 Add web themes, network binding, UI auth, library maintenance; optimize + fix rescan
Features:
- Port all 7 desktop themes (Dracula, Trans, Emo variants, etc.) to the web UI
- Configurable bind interface (localhost/Tailscale/LAN/all) with detected IPs,
  settable from both the web UI and desktop GUI
- Optional password that gates the whole UI and all API access via session
  cookies (Argon2), with a login page, logout, and middleware; settable from
  both UIs
- Library maintenance: scan for duplicate video IDs and missing assets
  (thumbnail/info.json/description), remove duplicates (scan-and-confirm, with
  out-of-library path guard), and re-fetch missing sidecars via yt-dlp.
  Surfaced in both the web UI and a desktop GUI window.

Optimizations / cleanup:
- Cache has_chapters at scan time (library.rs) instead of re-reading and
  parsing every info.json on each /api/library request
- Use the cached channel size in get_library
- Pool a single SQLite connection in WebState instead of opening one per request
- Remove a 1.2 GB stray nested src/yt-offline duplicate tree

Fixes:
- Rescan no longer clears all thumbnail textures (caused thumbnails to unload);
  prune only removed entries and bump library_generation so the card grid
  refreshes correctly

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 02:58:09 -07:00
Luna
74b3efd990 Major update with lots of new features and fixes 2026-05-17 05:36:04 -07:00
Luna
8b4796b518 Fix web UI, sort labels, add channel right-click menu
Web UI:
- Replace SSE with simple 600ms polling (GET /api/progress) — SSE added
  complexity with no real benefit for a local tool and was the source of
  connection failures
- Poll task moved into request handler (dl.poll() on each /api/progress call)
  so no background goroutine needed; simplifies state greatly
- Remove tokio-stream dependency (no longer needed)
- Fix: create channels dir before opening DB in web serve()
- Rescan also refreshes watched set from DB
- Bulk watched, sort, channel download button all working in web UI

Sort labels:
- Rename "Dur ↑" / "Dur ↓" → "Shortest" / "Longest"
- Rename "Size ↑" / "Size ↓" → "Smallest" / "Largest"

Channel right-click context menu:
- Right-click any channel in sidebar → "Check for new videos" starts a
  yt-dlp job on the stored channel_url from its info.json
- Also shows "Open folder" shortcut
- Grayed out with tooltip if no URL is stored yet (channel has no info.json)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-14 07:25:54 -07:00
Luna
56f1f1bd80 Fix PKGBUILD and notify-rust backend to eliminate libdbus build dep
- notify-rust: switch feature d → z (zbus pure-Rust backend); removes the
  system libdbus/pkgconf dependency that caused makepkg build failure
- PKGBUILD: fix license GPL3 → AGPL-3.0-only, makedepends rustup → rust

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-14 07:10:17 -07:00
Luna
80cce00b99 Add web UI, AGPL3, notifications, continue watching, bulk watched, storage stats, scheduler
License:
- GPL3 → AGPL3

New features:
- Web interface (--web [port]): axum/tokio server with SSE progress, library browser,
  download trigger, watched toggle; embedded single-page HTML/JS UI
- Desktop notifications via notify-rust when downloads complete or fail
- Continue Watching sidebar entry showing videos with saved resume positions
- Bulk select mode: select multiple videos, mark all watched/unwatched at once
- Storage stats: channel disk usage shown in sidebar next to video count
- Scheduled channel checks: configurable interval (hours), auto re-downloads all
  tracked channels using channel_url from info.json; enabled in Settings

Theme fixes:
- Scene Queen: remove override_text_color so active button text uses fg_stroke
  (dark navy on neon green) instead of near-white — fixes unreadable contrast
- Trans: override_text_color → hot pink #cc0066 for pink-tinted text throughout

Settings additions:
- Auto-check channels toggle + interval_hours DragValue
- Web UI port setting

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-11 04:27:04 -07:00
Luna
5b3b8fc901 Add watched tracking, resume positions, sort, density slider, channel metadata, mpv IPC, browser selector, auto-rescan
- SQLite DB for watched/position persistence (database.rs)
- Mark watched toggle on cards and detail panel
- mpv IPC socket integration for resume position tracking (unix)
- Sort by title, duration, file size
- Thumbnail density slider in top bar
- Channel metadata banner (subscriber count, uploader, channel URL)
- Cookie browser selector dropdown in settings
- Auto-rescan library when a download job finishes
- Fix yt-dlp --no-progress-bar flag (does not exist; removed)
- Browser field wired through config → downloader

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-11 03:47:29 -07:00
Luna
c11d1c3366 add themes, settings GUI, URL-aware download routing, and playlist view 2026-05-11 03:18:16 -07:00
Luna
abf3af5768 First version of youtube-backup, a tool to backup your YouTube channel. 2026-05-11 02:33:52 -07:00
luna
acf188738a Add the Rust/egui app sources
- library.rs: scans channels/<name>/ into channels + videos by filename stem
- downloader.rs: runs yt-dlp in a background thread, streams progress to the UI
- app.rs / main.rs: channel sidebar, searchable thumbnail list, detail/description
  panel, downloads panel; plays videos via mpv (falls back to xdg-open)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-11 01:35:22 -07:00