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.