dual triggers on one automation aren't a thing (one trigger per row, same as music), so
this adds a second automation sharing the handler — like Auto-Deep Scan TV/Movie already
do. 'Auto-Update Video Database (Hourly)' runs the same cheap incremental server-read on
an hourly schedule, so MANUAL library additions (which Plex auto-scans) appear within the
hour instead of waiting for the weekly deep scan; the existing after-scan one still gives
instant updates for SoulSync-initiated scans.
new action_type video_update_database_hourly (seeder keys on action_type) reusing
auto_video_update_database in incremental mode; registered, seeded (schedule 1h, 15m
initial delay), UI block, label/icon, sort order. tested.
the video-prefixed maintenance actions (clean_search_history, clean_completed_downloads,
full_cleanup, backup_database) + the new refresh_airing_schedules weren't in the action
label/icon maps, so they fell back to the gear + raw action_type ('⚙️ video_full_cleanup').
added all five to both maps (🗓️/🗑️/✅/🧹/💾, mirroring the music side). regression test
asserts every seeded video automation resolves a label AND an icon, so this can't recur.
two issues:
1. slskd search gave up at 22s (then stopped the search), but slskd gathers peers
over its full ~60s window — so most movie searches were killed before results
arrived. now waits up to 55s but returns early once results SETTLE (12+ hits, or
no new hits for ~12s) so fast searches don't burn the whole window. matches the
music side's longer wait.
2. the automations page re-rendered the WHOLE system section every 8s poll
(replaceChild) → blink + wiped the socket's live progress. now it skips the
rebuild unless something structural changed (added/removed/toggled/ran); live
progress comes via socket, the countdown ticks locally.
the API returns system automations newest-created-first, so a re-seeded row
(e.g. the just-migrated movie/episode processors) jumps to the top and jumbles
the grouping. the video page now re-sorts its System list by an explicit order:
scans (fill) → processors (drain) → library scan/sync → maintenance. scoped to
the video page only (music ordering untouched); unknown/future actions fall to
the end keeping API order. string-contract test pins the scan<proc<maint order.
The video automations page had no way to CREATE automations and its card cog did
nothing — it called the music global showAutomationBuilder(), which swaps views
inside the (hidden-on-video) music page, so the builder 'opened' on the music tab
instead. Now the video side has its own builder.
- index.html: the video automations subpage gets its own list-view + builder-view
(vauto- prefixed ids) and a '+ New Automation' button, swapping exactly like the
music page. Save/Cancel/Back reuse the shared builder functions.
- stats-automations.js: the builder is now context-aware. A builder context holds
the element ids + blocks endpoint + owned_by + reload callback. Music context is
the default and byte-identical (all 17 id lookups go through _bEl() resolving the
music ids). showVideoAutomationBuilder() sets a video context (vauto- ids,
/api/video/automations/blocks, owned_by='video'); editAutomation() routes the
card cog to the right builder by active side. Opening clears BOTH builders'
canvases so cfg-* ids can't collide. Save tags owned_by from context and calls
the context's reload. A generic config_fields renderer/reader (video-gated so
music keeps its bespoke renderers) drives video block config like the mode select.
- video-automations.js: exposes window._reloadVideoAutomations so a save refreshes
the video list.
11 wiring tests (test_video_automations_builder.py); node --check clean; music
builder path unchanged.