From 0598f5fbda5a5cc9a751962910e889d09e18605b Mon Sep 17 00:00:00 2001 From: BoulderBadgeDad Date: Sun, 14 Jun 2026 22:13:51 -0700 Subject: [PATCH] video: real-link routing for detail pages (parity with music artist-detail) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors the music side instead of a custom scheme: library cards are genuine links, so reload / new-tab / Back / Forward all work. Left-clicks are intercepted into SPA nav + history.pushState; modifier-clicks fall through to the real URL. - popstate restores the detail from the URL; the '← Library' back button is real history.back(); deep-link / reload to a /video-detail/... URL is restored on load (path captured before applySide can clear it). Server already serves the SPA for these paths (permissive catch-all) — no backend change. - The path carries a SOURCE segment ('library' = a video.db id today; 'tmdb' / search results not yet in the library come later) — your library-vs-search split. - Coexists with music's pathname router (only touches /video-detail/* and its own popstate); music's link/popstate handlers ignore these paths. Tests: real-link cards, pushState/popstate routing, source segment. --- tests/test_video_side_shell.py | 24 ++++++-- webui/index.html | 4 +- webui/static/video/video-library.js | 15 +++-- webui/static/video/video-side.js | 90 ++++++++++++++++++++++++++--- 4 files changed, 114 insertions(+), 19 deletions(-) diff --git a/tests/test_video_side_shell.py b/tests/test_video_side_shell.py index 5a329803..227cc5bf 100644 --- a/tests/test_video_side_shell.py +++ b/tests/test_video_side_shell.py @@ -341,8 +341,8 @@ def test_show_detail_subpage_present(): 'data-vd-season-nav', 'data-vd-episodes', 'data-vd-cast', 'data-vd-crew', 'data-vd-logo', 'data-vd-providers', 'data-vd-similar'): 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 + # Back button is real browser Back (history), not a hardcoded nav. + assert 'data-video-detail-back' in block assert "onclick" not in block @@ -352,13 +352,27 @@ def test_movie_detail_subpage_present(): assert 'data-video-detail="movie"' in block for hook in ('data-vd-backdrop', 'data-vd-title', 'data-vd-details', 'data-vd-cast'): assert hook in block, hook - assert 'data-video-goto="video-library"' in block and "onclick" not in block + assert 'data-video-detail-back' in block and "onclick" not in block -def test_library_movie_cards_are_clickable(): - # Both kinds drill in now (no show-only gate). +def test_library_cards_are_real_detail_links(): + # Cards are genuine (parity with + # the music artist cards) so reload / new-tab / Back work. assert 'data-video-card-open="' in _LIB_JS + assert "/video-detail/library/" in _LIB_JS assert "kind === 'show' ?" not in _LIB_JS # the old show-only gate is gone + # Modifier-clicks fall through to the real href (open in new tab). + assert "metaKey" in _LIB_JS and "ctrlKey" in _LIB_JS + + +def test_video_side_has_real_url_routing(): + # Mirrors music: real /video-detail/// URLs with pushState + + # popstate so Back/Forward/reload restore the same item. + assert "/video-detail/" in _JS + assert "history.pushState" in _JS and "popstate" in _JS + assert "parseDetailPath" in _JS and "buildDetailPath" in _JS + # Source segment for library-vs-search (search lands later). + assert "'library'" in _JS def test_video_detail_module_referenced_and_isolated(): diff --git a/webui/index.html b/webui/index.html index 5595b1de..34f35d99 100644 --- a/webui/index.html +++ b/webui/index.html @@ -820,7 +820,7 @@ Isolated .vd-*; --vd-accent-rgb is extracted from the poster at load for a per-show glow. Built by video/video-detail.js. -->
- @@ -876,7 +876,7 @@ show page — the renderer targets the active page by kind). -->