From 7fac921afc66d876c06cc854f14ee7a1237e8ee3 Mon Sep 17 00:00:00 2001 From: BoulderBadgeDad Date: Sun, 21 Jun 2026 14:57:32 -0700 Subject: [PATCH] Video show detail (TMDB source): show the Watchlist + Trailer actions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TMDB-source show detail page rendered an empty action bar — renderActions early-returned for source='tmdb' (a stale "previews have no actions" assumption that predates the curated, tmdb_id-keyed watchlist), so the Watchlist button never showed and the rest was skipped. Now an AIRING show gets the Watchlist button whether it's owned or a TMDB preview (ended/cancelled stay terminal → no button); Trailer renders from the payload; Get Missing stays library-only. Also fixed toggleWatchlist sending a bogus library_id + 404 poster proxy for tmdb previews (data.id is the tmdb id there) — it now omits library_id and uses the proxied TMDB poster, mirroring the card-hover add. --- webui/static/video/video-detail.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/webui/static/video/video-detail.js b/webui/static/video/video-detail.js index 59e550b7..a3729ea3 100644 --- a/webui/static/video/video-detail.js +++ b/webui/static/video/video-detail.js @@ -410,7 +410,7 @@ var watching = !!d._vw_watched; // Lazily resolve the real watched state once (airing library shows are on // by default), then re-render — see the new curated watchlist system. - if (isAiringShow && d.source !== 'tmdb' && !d._vw_checked && window.VideoWatchlist) { + if (isAiringShow && !d._vw_checked && window.VideoWatchlist) { d._vw_checked = true; fetch('/api/video/watchlist/check', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ kind: 'show', tmdb_ids: [d.tmdb_id] }) }) @@ -436,9 +436,9 @@ html += ''; } - // Preview (tmdb, un-owned) items have no library row to monitor — acquisition - // (add-to-watchlist / get-missing) lands with the downloads phase. - if (d.source === 'tmdb') { a.innerHTML = html; return; } + // Watchlist (follow an AIRING show to wishlist its new episodes) applies whether + // the show is owned or a TMDB preview — the curated watchlist is keyed by + // tmdb_id. Ended/cancelled shows are terminal (isAiringShow=false) → no button. if (isAiringShow) { html += ''; } - if (d.kind === 'show') { // "Get Missing" filters the episode list (show-only) + // "Get Missing" filters the OWNED episode list — library shows only. + if (d.kind === 'show' && d.source !== 'tmdb') { html += ''; @@ -1224,10 +1225,14 @@ var watching = !!data._vw_watched; var apply = function () { var url = watching ? '/api/video/watchlist/remove' : '/api/video/watchlist/add'; + // On a TMDB preview, data.id is the tmdb id (NOT a library row) — don't send + // a bogus library_id or library poster proxy; use the TMDB poster instead. + var owned = data.source !== 'tmdb'; var body = watching ? { kind: 'show', tmdb_id: data.tmdb_id } : { kind: 'show', tmdb_id: data.tmdb_id, title: data.title, - library_id: data.id, poster_url: '/api/video/poster/show/' + data.id }; + poster_url: owned ? ('/api/video/poster/show/' + data.id) : proxied(data.poster_url) }; + if (owned) body.library_id = data.id; fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }) .then(function (r) { return r.json(); }) .then(function (res) {