diff --git a/webui/static/video/video-detail.js b/webui/static/video/video-detail.js index c7503641..2f4d32c9 100644 --- a/webui/static/video/video-detail.js +++ b/webui/static/video/video-detail.js @@ -303,11 +303,14 @@ '' + esc(p.name) + '' + (p.character ? '' + esc(p.character) + '' : ''); // Clickable โ†’ in-app person page when we have a TMDB person id. + var cb = (p.tmdb_id && window.VideoGet) + ? VideoGet.cardButton({ kind: 'person', tmdbId: p.tmdb_id, title: p.name, poster: p.photo }) : ''; return p.tmdb_id ? '' + inner + '' + '" data-vd-person="' + p.tmdb_id + '">' + cb + inner + '' : '
' + inner + '
'; }).join(''); + if (window.VideoWatchlist) VideoWatchlist.hydrate(castHost); } } @@ -440,8 +443,10 @@ : '๐ŸŽฌ'; var simKind = s.kind === 'movie' ? 'movie' : 'show'; var yr = s.year ? '' + esc(s.year) + '' : ''; + var cb = window.VideoGet ? VideoGet.cardButton({ kind: simKind, tmdbId: s.tmdb_id, + title: s.title, poster: s.poster, status: s.status, source: 'tmdb' }) : ''; return '' + + '" data-vd-sim="' + simKind + '" data-vd-sim-id="' + s.tmdb_id + '">' + cb + poster + '' + esc(s.title) + '' + yr + ''; } function renderRow(sectionSel, hostSel, items) { @@ -450,6 +455,7 @@ if (!items || !items.length) { sec.hidden = true; return; } sec.hidden = false; host.innerHTML = items.map(simCard).join(''); + if (window.VideoWatchlist) VideoWatchlist.hydrate(host); } function renderExtras(kind, id, ex) { @@ -516,6 +522,7 @@ cs.hidden = false; if (ct) ct.textContent = coll.name || 'Collection'; ch.innerHTML = coll.items.map(simCard).join(''); + if (window.VideoWatchlist) VideoWatchlist.hydrate(ch); } else { cs.hidden = true; } } diff --git a/webui/static/video/video-get-modal.js b/webui/static/video/video-get-modal.js index d2185be2..50b4ea13 100644 --- a/webui/static/video/video-get-modal.js +++ b/webui/static/video/video-get-modal.js @@ -156,5 +156,28 @@ }); }, true); - window.VideoGet = { btn: btn, isAiring: isAiring, open: openModal }; + // Pick the right overlay control for any card: person โ†’ eye; movie โ†’ get; + // show โ†’ eye when airing (or status unknown = still followable), get when + // confirmed ended. One helper so every surface stays consistent. + function cardButton(o) { + if (!o || !o.kind) return ''; + if (o.kind === 'person') { + return window.VideoWatchlist + ? VideoWatchlist.btn({ kind: 'person', tmdbId: o.tmdbId, title: o.title, poster: o.poster }) : ''; + } + if (o.kind === 'show') { + var airing = !o.status ? true : isAiring(o.status); + if (airing && o.tmdbId && window.VideoWatchlist) { + return VideoWatchlist.btn({ kind: 'show', tmdbId: o.tmdbId, title: o.title, + poster: o.poster, libraryId: o.libraryId }); + } + return btn({ kind: 'show', source: o.source || 'tmdb', openId: o.libraryId || o.tmdbId, title: o.title }); + } + if (o.kind === 'movie') { + return btn({ kind: 'movie', source: o.source || 'tmdb', openId: o.libraryId || o.tmdbId, title: o.title }); + } + return ''; + } + + window.VideoGet = { btn: btn, isAiring: isAiring, open: openModal, cardButton: cardButton }; })(); diff --git a/webui/static/video/video-person.js b/webui/static/video/video-person.js index 0b2b94c7..27dfd971 100644 --- a/webui/static/video/video-person.js +++ b/webui/static/video/video-person.js @@ -48,8 +48,10 @@ var id = owned ? c.library_id : c.tmdb_id; var href = '/video-detail/' + source + '/' + c.kind + '/' + id; var sub = [c.year, c.role].filter(Boolean).join(' ยท '); + var cb = window.VideoGet ? VideoGet.cardButton({ kind: c.kind, tmdbId: c.tmdb_id, + libraryId: c.library_id, title: c.title, poster: c.poster, status: c.status, source: source }) : ''; return '' + + 'data-vp-open="' + c.kind + '" data-vp-source="' + source + '" data-vp-cid="' + id + '">' + cb + '
' + img + ribbon + '
' + '
' + esc(c.title) + @@ -130,6 +132,7 @@ var top = filtered().slice(0, 10); section.hidden = top.length < 3; // only worth a rail if there are a few host.innerHTML = top.map(creditCard).join(''); + if (window.VideoWatchlist) VideoWatchlist.hydrate(host); } function renderCredits() { @@ -144,6 +147,7 @@ credits.sort(function (a, b) { return (b.date || '').localeCompare(a.date || ''); }); } host.innerHTML = credits.map(creditCard).join(''); + if (window.VideoWatchlist) VideoWatchlist.hydrate(host); if (empty) { empty.hidden = credits.length > 0; if (!credits.length) { diff --git a/webui/static/video/video-search.js b/webui/static/video/video-search.js index 17909e2b..c5f8fb18 100644 --- a/webui/static/video/video-search.js +++ b/webui/static/video/video-search.js @@ -52,8 +52,10 @@ var id = owned ? it.library_id : it.tmdb_id; var href = '/video-detail/' + source + '/' + it.kind + '/' + id; var sub = [it.year, it.kind === 'movie' ? 'Movie' : 'TV'].filter(Boolean).join(' ยท '); + var cb = window.VideoGet ? VideoGet.cardButton({ kind: it.kind, tmdbId: it.tmdb_id, + libraryId: it.library_id, title: it.title, poster: it.poster, status: it.status, source: source }) : ''; return '' + + 'data-vsr-open="' + it.kind + '" data-vsr-source="' + source + '" data-vsr-id="' + id + '">' + cb + '
' + img + ribbon + rating + '
' + '
' + esc(it.title) + @@ -66,8 +68,10 @@ 'onerror="this.outerHTML=\'
๐Ÿ‘ค
\'">' : '
๐Ÿ‘ค
'; var sub = it.known_for ? it.known_for : (it.department || ''); + var cb = window.VideoGet ? VideoGet.cardButton({ kind: 'person', tmdbId: it.tmdb_id, + title: it.title, poster: it.poster }) : ''; return '
' + + 'data-vsr-open="person" data-vsr-id="' + it.tmdb_id + '">' + cb + '
' + img + '
' + '
' + esc(it.title) + '' + esc(sub) + '
'; @@ -93,6 +97,7 @@ '
'; }); host.innerHTML = html; + if (window.VideoWatchlist) VideoWatchlist.hydrate(host); } // Idle state: a "Trending this week" rail so the page isn't a blank box. @@ -104,6 +109,7 @@ host.innerHTML = '

' + 'Trending this week

' + '
' + trendingCache.map(titleCard).join('') + '
'; + if (window.VideoWatchlist) VideoWatchlist.hydrate(host); } function loadTrending() { if (trendingCache !== null) { if (!lastQuery) renderTrending(); return; } diff --git a/webui/static/video/video-side.css b/webui/static/video/video-side.css index 0a510846..92802ad9 100644 --- a/webui/static/video/video-side.css +++ b/webui/static/video/video-side.css @@ -1968,3 +1968,8 @@ body[data-side="video"] #soulsync-toggle { display: none; } cursor: pointer; outline: none; transition: border-color 0.15s ease; } .vwlp-sort:focus { border-color: rgba(var(--accent-rgb, 88 101 242), 0.6); } .vwlp-sort option { background: #16161d; color: #fff; } + +/* The eye/get button anchors to these card roots (other surfaces). Position is + additive (no flow change); buttons are absolute top-right within them. */ +.vsr-card, .vd-sim-card, .vd-cast-card { position: relative; } +.vd-cast-card:hover .vget-btn { opacity: 1; transform: none; }