video automations: seed the three new ones as system automations

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.
This commit is contained in:
BoulderBadgeDad 2026-06-25 20:56:37 -07:00
parent 7a90b008f0
commit b83f314617
3 changed files with 43 additions and 7 deletions

View file

@ -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')

View file

@ -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',
},
]

View file

@ -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():