Commit graph

5 commits

Author SHA1 Message Date
BoulderBadgeDad
fc045cd74e youtube download: don't clobber target_dir → fixes double-nested folders
bug: process_youtube_download wrote the ORGANISED dir (channel/Season YYYY) back
to the row's target_dir, but target_dir is supposed to be the youtube ROOT — and
plan_destination re-derives channel/season UNDER it. so any re-processing re-nested:
Channel/Season 2026/Channel/Season 2026/. that hit the 1-2 videos per channel that
got interrupted mid-download and re-queued by the orphan reaper.

fix: only record the organised filename for display; never write target_dir. the
root stays put so re-runs are idempotent. regression test runs it twice + asserts
no target_dir clobber + a stable (non-nested) dest dir.
2026-06-26 08:37:47 -07:00
BoulderBadgeDad
7140b88948 youtube channels: per-channel overrides (custom show-name + quality) — core
storage + wiring + API for the channel settings modal (UI next):
- db.get/set_channel_settings(channel_id): per-channel {custom_name, quality}
  in the settings KV store (no schema change); blanks clear the override.
- enqueue applies them: custom_name overrides the $channel folder token; a
  quality override is stashed in the download row's search_ctx. the worker reads
  it back (quality_override_from_download) and uses it instead of the global
  youtube quality profile. global default still applies when no override.
- API GET/POST /youtube/channel/<id>/settings (GET also returns the global
  default quality for the modal's 'using default' hint).

pure helpers (enqueue_ctx, quality_override_from_download) + db + api seam-tested.
2026-06-25 22:53:45 -07:00
BoulderBadgeDad
5bb90053bf youtube fulfillment: orphan reaper for restart-stalled downloads
closes the real gap: a restart kills the yt-dlp worker threads but leaves their
rows at 'downloading', which the pump counts as busy -> the queue wedges and they
never finish.

track live worker dl_ids in _active_worker_ids (added at worker start, dropped in
finally). requeue_orphaned_youtube() puts any 'downloading' youtube row with no
live worker back to 'queued' so the pump re-runs it. after a restart the set is
empty, so all stuck rows recover; during normal operation active ones are
protected (no false positives, no timestamp guessing). the hourly drain calls it
before pumping + logs the count. seam-tested.
2026-06-25 22:48:54 -07:00
BoulderBadgeDad
7a90b008f0 youtube fulfillment: drain the whole wishlist, cap concurrency not total
ditch the per-run batch cap (a 200-video backlog would've taken weeks). now the
'Download YouTube Wishlist' automation queues the ENTIRE wishlist as 'queued'
rows, starts up to max_concurrent (default 3) right away, and each finished
download starts the next (one-out-one-in in the worker) so it all drains in a
controlled stream. the knob is 'max simultaneous downloads', not a total cap.

mirrors the music download worker's lesson (cap concurrency + space starts to
avoid yt-dlp 429s) but stays isolated on the video side:
- youtube_download: _pace() staggers fetch starts (3s); start_next_queued()
  claims+spawns the next; run_youtube_download chains on finish.
- db.count_active_youtube_downloads() + claim_next_youtube_queued() (atomic,
  race-safe). block field batch_size -> max_concurrent.

all seam-tested (pure select + pump); 680-test sweep green.
2026-06-25 20:10:45 -07:00
BoulderBadgeDad
8e071719f9 youtube fulfillment: download worker (pure core)
new core/video/youtube_download.py: fetch a wished youtube video end to end.
plans the organised dest (channel/year/date template), builds yt-dlp opts from
the quality profile (format_selection), runs the download (injectable factory),
then on success marks the video_downloads row completed + archives to history +
removes it from the wishlist; on failure archives failed and KEEPS the wish to
retry. orchestration is pure (yt-dlp run + all db writes injected) + seam-tested;
run_youtube_download binds the real seams for the worker thread.

flows through the SAME video_downloads queue as movies/tv (model B) so the
downloads page + history work for youtube for free.
2026-06-25 19:24:58 -07:00