From b83f314617bbac85b3323d2c81ef3c45424def38 Mon Sep 17 00:00:00 2001 From: BoulderBadgeDad Date: Thu, 25 Jun 2026 20:56:37 -0700 Subject: [PATCH] video automations: seed the three new ones as system automations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit they were only builder blocks (not in the Active list). seed them like the airing job so they appear + run out of the box: - Auto-Scan Watchlist People — daily 03:00 - Auto-Scan Watchlist Channels — every 6h - Auto-Download YouTube Wishlist — every 1h scans no-op cleanly if you follow nothing. softened the download handler: an unset youtube folder is now a quiet skip (status completed), not a per-run error, so non-youtube users don't see a recurring failure. --- .../video_process_youtube_wishlist.py | 11 ++++--- core/automation_engine.py | 31 +++++++++++++++++++ tests/test_video_process_youtube_wishlist.py | 8 +++-- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/core/automation/handlers/video_process_youtube_wishlist.py b/core/automation/handlers/video_process_youtube_wishlist.py index 0eccd501..df8d2dbf 100644 --- a/core/automation/handlers/video_process_youtube_wishlist.py +++ b/core/automation/handlers/video_process_youtube_wishlist.py @@ -117,10 +117,13 @@ def auto_video_process_youtube_wishlist( try: root = youtube_root() if not root: - msg = 'Set the YouTube library folder on Settings → Downloads first' - deps.update_progress(automation_id, status='error', phase='Error', - log_line=msg, log_type='error') - return {'status': 'error', 'error': msg, '_manages_own_progress': True} + # Always-on automation: a missing folder isn't a failure, it's "not set up for + # YouTube" — skip quietly so non-YouTube users don't see a recurring error. + deps.update_progress(automation_id, status='finished', progress=100, phase='Complete', + log_line='YouTube library folder not set — skipping (Settings → Downloads)', + log_type='info') + return {'status': 'completed', 'queued': 0, 'started': 0, 'running': 0, + 'skipped': 'no_youtube_folder', '_manages_own_progress': True} deps.update_progress(automation_id, phase='Checking the YouTube wishlist…', progress=15, log_line='Queueing new videos for download', log_type='info') diff --git a/core/automation_engine.py b/core/automation_engine.py index 6ab0646c..f2686bfb 100644 --- a/core/automation_engine.py +++ b/core/automation_engine.py @@ -239,6 +239,37 @@ SYSTEM_AUTOMATIONS = [ 'action_config': {'mode': 'deep', 'media_type': 'movie'}, 'owned_by': 'video', }, + # Watchlist scans — keep the wishlist fed from the people + channels you follow. + # People: daily (filmographies change slowly) at 03:00, after the airing/deep-scan + # jobs so they don't overlap. No-ops cleanly if you follow nobody. + { + 'name': 'Auto-Scan Watchlist People', + 'trigger_type': 'daily_time', + 'trigger_config': {'time': '03:00'}, + 'action_type': 'video_scan_watchlist_people', + 'owned_by': 'video', + }, + # Channels: every 6h (YouTube posts at all hours). No-ops cleanly if you follow none. + { + 'name': 'Auto-Scan Watchlist Channels', + 'trigger_type': 'schedule', + 'trigger_config': {'interval': 6, 'unit': 'hours'}, + 'action_type': 'video_scan_watchlist_channels', + 'action_config': {'backfill_count': 10}, + 'initial_delay': 1200, + 'owned_by': 'video', + }, + # Drain side: download wished YouTube videos hourly (queues the whole wishlist, runs a + # few at a time). Skips quietly until a YouTube library folder is set. + { + 'name': 'Auto-Download YouTube Wishlist', + 'trigger_type': 'schedule', + 'trigger_config': {'interval': 1, 'unit': 'hours'}, + 'action_type': 'video_process_youtube_wishlist', + 'action_config': {'max_concurrent': 3}, + 'initial_delay': 1500, + 'owned_by': 'video', + }, ] diff --git a/tests/test_video_process_youtube_wishlist.py b/tests/test_video_process_youtube_wishlist.py index 6796ec61..91d62359 100644 --- a/tests/test_video_process_youtube_wishlist.py +++ b/tests/test_video_process_youtube_wishlist.py @@ -101,10 +101,12 @@ def test_stops_starting_when_queue_drains_early(): assert started == 2 -def test_missing_youtube_folder_is_an_error(): +def test_missing_youtube_folder_is_a_quiet_skip(): + # always-on automation: no folder set → skip cleanly (not an error every run) res, enq, started, deps = _run([_v("a")], root="") - assert res["status"] == "error" and "library folder" in res["error"] - assert enq == [] and any(p.get("status") == "error" for p in deps.progress) + assert res["status"] == "completed" and res.get("skipped") == "no_youtube_folder" + assert enq == [] and started == 0 + assert not any(p.get("status") == "error" for p in deps.progress) def test_nothing_wanted_and_empty_queue_is_a_clean_noop():