soulsync/tests/test_video_detail_yt_reset.py
BoulderBadgeDad 9a3ca6ba4e video downloads: header 'Auto' picks ONE best across all sources; fix YT playlist leak
Auto: replaced 'Manual all' + 'Auto all' (which fired auto on every source = up to
one download PER source = duplicate copies) with a single header 'Auto' button. It
searches every source, waits for them all to settle, compares the accepted+grabbable
hits across ALL sources by quality-profile score (tie-break on availability), and
grabs exactly ONE winner — the chosen row gets the auto ring + live tracker. Per-source
Manual/Auto buttons are unchanged.

Bug fix: viewing a YouTube channel populated the playlist section in the SHARED
show-detail DOM; opening a real movie/show afterward still showed those playlists,
because ytResetPlaylists() used the kind-scoped q() (pointing at the wrong root on a
movie load) and wasn't called on normal loads. Now it targets the show subpage
directly and runs from resetExtras() (every detail load), so stale playlists are
always cleared.

node --check clean; 20 wiring/regression tests green; all video-only.
2026-06-20 10:48:55 -07:00

42 lines
1.9 KiB
Python

"""Regression: a YouTube channel's playlists must not leak onto the next movie/show.
YouTube channels/playlists render into the SHOW-detail DOM (they reuse that page).
The playlist section is only in the show DOM, but a later movie/show load runs with
q() scoped to a different root — so the reset has to target the show subpage
directly AND run on every detail load (via resetExtras), or stale playlists show.
"""
from __future__ import annotations
from pathlib import Path
_ROOT = Path(__file__).resolve().parent.parent
_DETAIL = (_ROOT / "webui" / "static" / "video" / "video-detail.js").read_text(encoding="utf-8")
_INDEX = (_ROOT / "webui" / "index.html").read_text(encoding="utf-8")
def test_playlist_section_lives_only_in_show_detail():
# The section markup is in the show subpage; the movie subpage must not have it.
show_start = _INDEX.index('data-video-detail="show"')
movie_start = _INDEX.index('data-video-detail="movie"')
show_block = _INDEX[show_start:movie_start]
movie_block = _INDEX[movie_start:movie_start + 4000]
assert 'data-vd-yt-pl-section' in show_block
assert 'data-vd-yt-pl-section' not in movie_block
def test_reset_targets_the_show_dom_directly():
# ytResetPlaylists must NOT rely on the kind-scoped q() (which points at the
# movie root during a movie load) — it queries the show subpage explicitly.
i = _DETAIL.index('function ytResetPlaylists(')
body = _DETAIL[i:i + 700]
assert "document.querySelector('[data-video-detail=\"show\"]')" in body
assert 'data-vd-yt-playlists' in body
def test_every_detail_load_clears_stale_playlists():
# resetExtras() runs on loadMovie/loadShow/loadChannel/loadPlaylist, so wiring
# the clear there covers all navigations into a non-YouTube detail.
i = _DETAIL.index('function resetExtras(')
body = _DETAIL[i:i + 700]
assert 'ytResetPlaylists()' in body