click a card → it expands inline into a detail drawer (open state survives the in-place re-patches via _expanded): - big backdrop + synopsis + genres + a cast strip (photos/names/characters), lazily fetched from TMDB by the grab's tmdb id (new /downloads/meta/<kind>/<id> endpoint → engine.tmdb_full_detail). youtube shows channel + description instead. - a facts grid: status, quality target, release, format, source+queue, size, attempts, copyable dest path, full error. - big actions: open in library / open on youtube / copy path / cancel / retry. all type-themed (Cinema palette) and scoped to .vdpg-card. contract-tested + the meta route is registered.
52 lines
2.3 KiB
Python
52 lines
2.3 KiB
Python
"""Downloads page UX overhaul — string-contract level (like test_video_side_shell.py), so a
|
|
refactor that silently drops the per-type theming, the sidebar count, or the new statuses
|
|
fails here."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
_ROOT = Path(__file__).resolve().parent.parent
|
|
_JS = (_ROOT / "webui" / "static" / "video" / "video-downloads-page.js").read_text(encoding="utf-8")
|
|
_CSS = (_ROOT / "webui" / "static" / "video" / "video-side.css").read_text(encoding="utf-8")
|
|
_INDEX = (_ROOT / "webui" / "index.html").read_text(encoding="utf-8", errors="replace")
|
|
|
|
|
|
def test_cards_carry_a_type_for_cinema_theming():
|
|
assert "function dlType(" in _JS
|
|
assert "data-vtype" in _JS # set on each card
|
|
# the three Cinema palette colours are defined per type
|
|
for vt in ('[data-vtype="movie"]', '[data-vtype="tv"]', '[data-vtype="youtube"]'):
|
|
assert vt in _CSS, vt
|
|
assert "--vt: 79, 143, 247" in _CSS and "--vt: 240, 69, 75" in _CSS # azure + red
|
|
|
|
|
|
def test_importing_is_a_first_class_active_status():
|
|
assert "importing:" in _JS and "import_failed:" in _JS
|
|
assert "s === 'importing'" in _JS # counts as active
|
|
assert "vdpg-prog-indet" in _JS # indeterminate sweep for queued/searching/importing
|
|
|
|
|
|
def test_sidebar_has_a_live_downloads_count():
|
|
assert "data-video-downloads-badge" in _INDEX # the nav badge element
|
|
assert "function setDownloadsBadge(" in _JS
|
|
assert "function badgePoll(" in _JS # stays live off-page too
|
|
|
|
|
|
def test_cards_expand_into_a_detail_drawer():
|
|
assert "function drawerHTML(" in _JS and "function renderDrawer(" in _JS
|
|
assert "_expanded" in _JS # open state survives re-patches
|
|
assert "vdpg-dr-cast" in _JS and "vdpg-dr-syn" in _JS # cast + synopsis sections
|
|
assert "data-vdpg-copy" in _JS # copy-path action
|
|
# the lazy TMDB detail endpoint the drawer fetches synopsis/cast from
|
|
assert "/downloads/meta/" in _JS
|
|
|
|
|
|
def test_download_meta_route_is_registered():
|
|
import api.video as videoapi
|
|
from flask import Flask
|
|
app = Flask(__name__)
|
|
app.register_blueprint(videoapi.create_video_blueprint(), url_prefix="/api/video")
|
|
rules = {r.rule for r in app.url_map.iter_rules()}
|
|
assert "/api/video/downloads/meta/<kind>/<int:tmdb_id>" in rules
|
|
|