Commit graph

7 commits

Author SHA1 Message Date
BoulderBadgeDad
937f3094c6 video Downloads page: stop polling when off-page (incl. music side); 2s cadence
The active-downloads poll kept running in the background — the page-change event that
stops it only fires for video-side navigations, not when switching to the music side,
so /api/video/downloads/active was being hit forever. poll() now bails (and clears the
timer) whenever the Downloads page isn't on screen (data-side!=video or the subpage is
hidden). Also matched the music page's 2s active cadence (6s idle). Still HTTP polling,
same as the music downloads page (which polls /api/downloads/all every 2s — the app's
SocketIO is for other realtime, not the downloads list).
2026-06-19 17:28:45 -07:00
BoulderBadgeDad
3af3a1cd24 video downloads Phase C: auto-retry + alternate-query requery
When a grabbed release fails (transfer error / peer-cancel / never lands), the engine
now retries instead of giving up — the music-style depth:
- Grab stores the OTHER accepted results as a retry pool + the search context (schema
  v16: candidates / search_ctx / tried_queries / tried_files / attempts).
- core/video/retry.py (pure, tested): plan_retry() → try the next-best candidate; when
  the pool is dry, next_query() generates an ALTERNATE query (movie: drop the year; TV:
  numbering variants) to re-search; budget MAX_ATTEMPTS=6. merge_candidates dedupes
  against already-tried releases.
- Monitor: on failure, _fail_or_retry hops to the next candidate inline; if none, flips
  the row to a new 'searching' state and a background requery thread re-searches the
  alternate query, evaluates against the profile, and starts the best fresh hit — or
  marks failed once truly exhausted. 'searching' rows are owned by their thread.
- Page: 'Searching' status (Trying another release…) + a 'Nx' attempt badge.
16 tests (retry engine + candidate-retry transition); ruff clean on touched files.
2026-06-19 17:12:44 -07:00
BoulderBadgeDad
48f6cc5e3c video Downloads cards: poster + movie details + Open-page button
Grabs now carry the movie's identity so the Downloads cards are rich, not anonymous:
- video_downloads gains media_id / media_source / year / poster_url (schema v15 +
  migration); grab stores them (passed from the get-modal → download view → grab).
- Cards show the POSTER in the art tile (emoji fallback), 'Title (Year)', a quality
  chip (1080p · BluRay · X265), and an ↗ Open button that jumps to the movie/show
  detail page (dispatches soulsync:video-open-detail). Cancel/retry unchanged.
16 tests green, ruff + balance clean.
2026-06-19 16:29:27 -07:00
BoulderBadgeDad
1c3f255a66 video Downloads page: actually match the music page (.adl-* layout, full width)
Scrapped the bespoke centered .vdpg- design and reused the music downloads page's
.adl-* classes for real parity: full-width .adl-layout, the segmented .adl-filter-pills,
the title with the accent download glyph, and the compact .adl-row (44px art tile +
.adl-row-info title/meta/error + .adl-row-status dot+label) — driven by the video JS
via data-vdpg-* hooks (no #id clashes with the music page). Per-row cancel reuses the
music hover-reveal .adl-row-cancel; retry mirrors it in accent. Kept the smooth
in-place patching (slim progress line for active rows). Removed the old .vdpg-* block;
balance clean.
2026-06-19 15:47:02 -07:00
BoulderBadgeDad
d25be2c3c6 video downloads Phase B: page redesign — filter tabs, cancel/retry, depth
Brings the Downloads page up toward the music page's depth:
- Filter tabs (music-style pills): All / Active / Completed / Failed, each with a live
  count; clicking filters the list. Cancelled rolls under Failed.
- Header actions: Cancel all (active) + Clear finished, shown only when relevant; a
  live 'N active · N done · N failed' subline.
- Per-row actions: ✕ Cancel on active rows (→ /downloads/cancel), ↻ Retry on
  failed/cancelled rows (→ /downloads/retry, re-grabs the release).
- Cancelled status styling (pill + dimmed row). Still the smooth in-place patching
  (no blink), adaptive polling, empty + filtered-empty states.
Balance clean. Phase C (auto-retry + alternate-query retry) next.
2026-06-19 15:34:50 -07:00
BoulderBadgeDad
7e0726d5eb video Downloads page: smooth in-place updates (no more blink) + polish
The blink was every poll re-running each card's entrance animation via innerHTML
churn. Now cards are created ONCE and PATCHED in place (data-st attribute swaps,
progress width glides over a 1.4s transition, meta only rewrites when its text
changes), so nothing re-animates on a tick — the music-downloads smoothness.

Also: adaptive polling (1.5s while active, 6s idle), border/pill colours TRANSITION
on status change, downloading cards get an accent tint + glow, a relative 'started Xs
ago', and the % moved inline. Balance clean.
2026-06-19 15:10:04 -07:00
BoulderBadgeDad
fff6448a14 video downloads: wire Grab + build the live Downloads page
Phase 3 — the UX:
- Grab button now actually grabs (Soulseek results only — they carry the slskd
  username/filename): POSTs /downloads/grab with the result + search context, shows
  ✓ on success, toasts 'Sent to Downloads', fires a refresh event. Endpoint returns
  size_bytes for the payload.
- New Downloads PAGE (video-downloads-page.js, .vdpg-*): every grab lands here.
  Polls /downloads/active while open and shows live status — type icon (🎬/📺/▶️),
  title + release, a pulsing 'Downloading' pill with a shimmering progress bar, then
  'Completed' with the file's library destination (→ /media/movies/…), or 'Failed'
  with the reason. Clear-finished button, empty state, staggered entrance, vibes.
  Reduced-motion honored. JS/CSS/HTML balance clean (verified w/ a real tokenizer).
2026-06-19 14:59:22 -07:00