From 5a2113bd03bf6dac6c92db8c2f963d867523387d Mon Sep 17 00:00:00 2001 From: BoulderBadgeDad Date: Sun, 14 Jun 2026 15:59:29 -0700 Subject: [PATCH] video: TV-show detail page (hero + season/episode tree), isolated MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drill-in from a show card: full-bleed backdrop + poster + title/badges/overview + stat tiles, then seasons->episodes as collapsible accordions with owned/missing state and per-season coverage bars (season = album, episode = track β€” inspired by the music artist page, premium vibe). - video-detail.js (isolated IIFE) renders from /api/video/detail/show/; backdrop/poster via the proxy. - Show cards dispatch soulsync:video-open-detail; video-side.js navigates to the (non-nav) detail subpage; back button reuses data-video-goto. - Movies stay non-clickable until the movie-detail page lands next. - .vd-* CSS scoped to the detail page; music untouched. Shell + isolation tests. --- tests/test_video_side_shell.py | 33 +++++ webui/index.html | 30 +++++ webui/static/video/video-detail.js | 183 ++++++++++++++++++++++++++++ webui/static/video/video-library.js | 19 ++- webui/static/video/video-side.css | 106 ++++++++++++++++ webui/static/video/video-side.js | 12 ++ 6 files changed, 382 insertions(+), 1 deletion(-) create mode 100644 webui/static/video/video-detail.js diff --git a/tests/test_video_side_shell.py b/tests/test_video_side_shell.py index 60359e11..21070534 100644 --- a/tests/test_video_side_shell.py +++ b/tests/test_video_side_shell.py @@ -327,6 +327,39 @@ def test_video_worker_orbs_referenced_and_isolated(): assert "/api/enrichment/" not in src +def test_show_detail_subpage_present(): + block = _block( + _INDEX, r'
") + # Hero + season tree containers the renderer fills. + for hook in ('data-vd-backdrop', 'data-vd-poster', 'data-vd-title', 'data-vd-badges', + 'data-vd-overview', 'data-vd-stats', 'data-vd-seasons'): + assert hook in block, hook + # Back button reuses the shared data-video-goto nav (no inline handler). + assert 'data-video-goto="video-library"' in block + assert "onclick" not in block + + +def test_video_detail_module_referenced_and_isolated(): + assert "video/video-detail.js" in _INDEX + src = (_ROOT / "webui" / "static" / "video" / "video-detail.js").read_text(encoding="utf-8") + assert "(function" in src and "})();" in src + assert "window." not in src # declares no globals + assert "/api/video/detail/" in src # video API only + assert "/api/enrichment/" not in src and "artist-detail" not in src + assert "soulsync:video-open-detail" in src # opened via the shared event + + +def test_library_cards_open_detail(): + src = _LIB_JS + assert "soulsync:video-open-detail" in src # show cards drill in + assert "data-video-card-open" in src + + +def test_video_side_registers_detail_pages_and_open_event(): + assert "video-show-detail" in _JS and "video-movie-detail" in _JS + assert "soulsync:video-open-detail" in _JS # navigates on the event + + 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). diff --git a/webui/index.html b/webui/index.html index b5ca5f61..fb7d80d4 100644 --- a/webui/index.html +++ b/webui/index.html @@ -812,6 +812,34 @@
+ +