video: isolated worker-orbs idle animation on the video dashboard

Port of webui/static/worker-orbs.js into video/video-worker-orbs.js — same
exact animation (physics/draw copied verbatim), but pointed at the video
dashboard header + the TMDB/TVDB enrich buttons + Manage Workers hub. Own
window.videoWorkerOrbs global, activated by the video side's page events;
music's orbs file is untouched and never learns about the video side.

video-enrichment.js feeds it real status as telemetry for the inbound pulses.
7s idle → floating orbs around the SoulSync logo, just like music.
This commit is contained in:
BoulderBadgeDad 2026-06-14 13:34:10 -07:00
parent 9d2468a50f
commit a62e59dd3a
4 changed files with 1175 additions and 1 deletions

View file

@ -255,7 +255,12 @@ def test_video_enrichment_module_referenced_and_isolated():
src = (_ROOT / "webui" / "static" / "video" / "video-enrichment.js").read_text(encoding="utf-8")
assert src.strip().startswith("/*") or src.strip().startswith("(function")
assert "(function" in src and "})();" in src
assert "window." not in src
# The only window.* touch is the (optional) handoff to the VIDEO orbs global
# — never a music global, and it declares none of its own.
assert all(
ref == "window.videoWorkerOrbs"
for ref in re.findall(r"window\.\w+", src)
)
assert "/api/video/enrichment/" in src
# No music API/function calls (a comment may mention the music *side*).
assert "/api/enrichment/" not in src
@ -289,6 +294,34 @@ def test_video_settings_module_referenced_and_isolated():
assert "'change'" in _VSETTINGS_JS # saves on change, like the music selector
def test_video_worker_orbs_referenced_and_isolated():
assert "video/video-worker-orbs.js" in _INDEX
src = (_ROOT / "webui" / "static" / "video" / "video-worker-orbs.js").read_text(encoding="utf-8")
assert "(function" in src and "})();" in src
# Its own global namespace — never music's window.workerOrbs.
assert "window.videoWorkerOrbs" in src
assert "window.workerOrbs" not in src
# Activates only on the video dashboard (own page-awareness, not setPage).
assert "soulsync:video-page-shown" in src
assert 'data-video-subpage="video-dashboard"' in src
assert 'data-video-enrich="tmdb"' in src and 'data-video-enrich="tvdb"' in src
assert "data-video-manage-workers" in src
# Same 7-second idle that triggers the floating-orb collapse as music.
assert "COLLAPSE_DELAY_MS = 7000" in src
# Reuses the shared, generic orb CSS classes (design parity, no fork).
assert "worker-orb-hidden" in src and "worker-orb-canvas" in src
# Does NOT reach into the music dashboard or the music API.
assert "#dashboard-page" not in src
assert "/api/enrichment/" not in src
def test_music_worker_orbs_untouched_by_video():
# The video orbs are a separate file; the music orbs must not learn about
# the video side (one-way isolation — music never depends on video).
music = (_ROOT / "webui" / "static" / "worker-orbs.js").read_text(encoding="utf-8")
assert "video" not in music.lower()
def test_controller_is_isolated_iife_with_no_globals():
stripped = _JS.strip()
# Wrapped in an IIFE → declares no module-level globals that could collide

View file

@ -9064,6 +9064,9 @@
<script src="{{ url_for('static', filename='video/video-dashboard.js', v=static_v) }}"></script>
<!-- Video library page (isolated; lists movies/shows + scan trigger) -->
<script src="{{ url_for('static', filename='video/video-library.js', v=static_v) }}"></script>
<!-- Video worker orbs (isolated copy of the music orbs; idles into the
floating-orb animation around the SoulSync logo on the video dashboard) -->
<script src="{{ url_for('static', filename='video/video-worker-orbs.js', v=static_v) }}"></script>
</body>
</html>

View file

@ -53,6 +53,12 @@
}
}
setText(tip, '[data-video-enrich-progress]', 'Progress: ' + matched + ' / ' + total);
// Feed the idle worker-orbs animation real telemetry (isolated; no-op if
// the orbs script isn't present). Drives the inbound pulses to the hub.
if (window.videoWorkerOrbs && typeof window.videoWorkerOrbs.onStatus === 'function') {
window.videoWorkerOrbs.onStatus(svc, d);
}
}
function pollOne(svc) {

File diff suppressed because it is too large Load diff