Video detail page: follow control uses the new curated watchlist
The detail actions row still toggled the old shows.monitored flag via /api/video/monitor. Now it's consistent with the cards: - The 'Watchlist' button appears only for AIRING shows (movies + ended shows are terminal — they keep acquisition, not a watch-follow). - It reads/writes the new /api/video/watchlist add/remove, resolves the real watched state on load (airing library shows are on by default), confirms on remove (the standard dialog), toasts, and broadcasts the change so the nav badge + watchlist page stay in sync.
This commit is contained in:
parent
240e386871
commit
21163239da
1 changed files with 49 additions and 16 deletions
|
|
@ -317,7 +317,21 @@
|
||||||
function renderActions(d) {
|
function renderActions(d) {
|
||||||
var a = q('[data-vd-actions]');
|
var a = q('[data-vd-actions]');
|
||||||
if (!a) return;
|
if (!a) return;
|
||||||
var watching = !!d.monitored;
|
// The watchlist eye applies only to airing shows (movies + ended shows are
|
||||||
|
// terminal — they get acquisition, not a "watch for new" follow).
|
||||||
|
var isAiringShow = d.kind === 'show' && d.tmdb_id && (!window.VideoGet || VideoGet.isAiring(d.status));
|
||||||
|
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) {
|
||||||
|
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] }) })
|
||||||
|
.then(function (r) { return r.ok ? r.json() : null; })
|
||||||
|
.then(function (res) {
|
||||||
|
if (res && res.results) { d._vw_watched = !!res.results[String(d.tmdb_id)]; if (data === d) renderActions(d); }
|
||||||
|
}).catch(function () { /* keep default state */ });
|
||||||
|
}
|
||||||
var html = '';
|
var html = '';
|
||||||
// Primary CTA: play it on your media server (owned items; arrives with
|
// Primary CTA: play it on your media server (owned items; arrives with
|
||||||
// extras). The logo IS the brand name — "Play on <logo>" (no redundant word).
|
// extras). The logo IS the brand name — "Play on <logo>" (no redundant word).
|
||||||
|
|
@ -338,11 +352,13 @@
|
||||||
// Preview (tmdb, un-owned) items have no library row to monitor — acquisition
|
// Preview (tmdb, un-owned) items have no library row to monitor — acquisition
|
||||||
// (add-to-watchlist / get-missing) lands with the downloads phase.
|
// (add-to-watchlist / get-missing) lands with the downloads phase.
|
||||||
if (d.source === 'tmdb') { a.innerHTML = html; return; }
|
if (d.source === 'tmdb') { a.innerHTML = html; return; }
|
||||||
html +=
|
if (isAiringShow) {
|
||||||
'<button class="library-artist-watchlist-btn' + (watching ? ' watching' : '') +
|
html +=
|
||||||
'" type="button" data-vd-act="watchlist">' +
|
'<button class="library-artist-watchlist-btn' + (watching ? ' watching' : '') +
|
||||||
'<span class="watchlist-icon">' + (watching ? '✓' : '+') + '</span>' +
|
'" type="button" data-vd-act="watchlist">' +
|
||||||
'<span class="watchlist-text">' + (watching ? 'In Watchlist' : 'Watchlist') + '</span></button>';
|
'<span class="watchlist-icon">' + (watching ? '✓' : '+') + '</span>' +
|
||||||
|
'<span class="watchlist-text">' + (watching ? 'In Watchlist' : 'Watchlist') + '</span></button>';
|
||||||
|
}
|
||||||
if (d.kind === 'show') { // "Get Missing" filters the episode list (show-only)
|
if (d.kind === 'show') { // "Get Missing" filters the episode list (show-only)
|
||||||
html += '<button class="discog-download-btn discog-btn-compact" type="button" data-vd-act="missing">' +
|
html += '<button class="discog-download-btn discog-btn-compact" type="button" data-vd-act="missing">' +
|
||||||
'<span class="discog-btn-icon">⭳</span><span class="discog-btn-text">Get Missing</span>' +
|
'<span class="discog-btn-icon">⭳</span><span class="discog-btn-text">Get Missing</span>' +
|
||||||
|
|
@ -1026,17 +1042,34 @@
|
||||||
|
|
||||||
function showLoading(on) { var l = q('[data-vd-loading]'); if (l) l.hidden = !on; }
|
function showLoading(on) { var l = q('[data-vd-loading]'); if (l) l.hidden = !on; }
|
||||||
|
|
||||||
// ── watchlist (real monitor toggle) ───────────────────────────────────────
|
// ── watchlist (new curated system; airing shows only) ─────────────────────
|
||||||
function toggleWatchlist() {
|
function toggleWatchlist() {
|
||||||
if (!data) return;
|
if (!data || data.kind !== 'show' || !data.tmdb_id) return;
|
||||||
var next = data.monitored ? 0 : 1;
|
var watching = !!data._vw_watched;
|
||||||
fetch('/api/video/monitor', {
|
var apply = function () {
|
||||||
method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
|
var url = watching ? '/api/video/watchlist/remove' : '/api/video/watchlist/add';
|
||||||
body: JSON.stringify({ kind: data.kind, id: data.id, monitored: next }),
|
var body = watching
|
||||||
}).then(function (r) { return r.ok ? r.json() : null; })
|
? { kind: 'show', tmdb_id: data.tmdb_id }
|
||||||
.then(function (res) {
|
: { kind: 'show', tmdb_id: data.tmdb_id, title: data.title,
|
||||||
if (res && !res.error) { data.monitored = !!next; renderActions(data); }
|
library_id: data.id, poster_url: '/api/video/poster/show/' + data.id };
|
||||||
}).catch(function () { /* ignore */ });
|
fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) })
|
||||||
|
.then(function (r) { return r.json(); })
|
||||||
|
.then(function (res) {
|
||||||
|
if (!res || !res.success) return;
|
||||||
|
data._vw_watched = !watching;
|
||||||
|
renderActions(data);
|
||||||
|
if (typeof showToast === 'function')
|
||||||
|
showToast(!watching ? 'Added to watchlist' : 'Removed from watchlist', !watching ? 'success' : 'info');
|
||||||
|
document.dispatchEvent(new CustomEvent('soulsync:video-watchlist-changed',
|
||||||
|
{ detail: { kind: 'show', id: String(data.tmdb_id), watched: !watching } }));
|
||||||
|
}).catch(function () { if (typeof showToast === 'function') showToast('Watchlist update failed', 'error'); });
|
||||||
|
};
|
||||||
|
if (watching && typeof showConfirmDialog === 'function') {
|
||||||
|
showConfirmDialog({ title: 'Remove from Watchlist',
|
||||||
|
message: 'Remove “' + (data.title || 'this show') + '” from your watchlist?',
|
||||||
|
confirmText: 'Remove', cancelText: 'Cancel', destructive: true })
|
||||||
|
.then(function (ok) { if (ok) apply(); });
|
||||||
|
} else { apply(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── movie detail (flat) ───────────────────────────────────────────────────
|
// ── movie detail (flat) ───────────────────────────────────────────────────
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue