summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-08 02:17:00 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-08 02:17:00 +0200
commit2ac1f1f704d44e2b20f9598044f7e266ffae4d36 (patch)
tree097bacad72e76f0ff8ed93622903e489c91aed3c /packages/meshbay-hub
parentf7b1111c250902315e454c155c147e58d69ee9f0 (diff)
downloadmeshbay-2ac1f1f704d44e2b20f9598044f7e266ffae4d36.tar.gz
fix(hub): stop badging every poster "unmatched" when TMDB is off
The dashed warning outline and the "?" flag say a TMDB lookup ran and came back with nothing — that is how an operator finds the titles worth a "Fix match". With TMDB switched off for the group no lookup is made at all: media_meta_req answers confidence 0 for the whole library by design, so the poster grid drew every card as a failure of the very thing the operator chose, with no poster ever coming to clear it. Poster mode now shows the file's own thumbnail plainly in that case, the same as Flat does, and keeps the badge for what it was built for. - PosterCard takes tmdbEnabled and gates both the outline and the "?" on `tmdbEnabled && !confident`. The title still falls back to the parsed filename exactly as before, and the ready/imageReady anti-flash gating is untouched. - VideoDetailModal gates its "no confident match" paragraph the same way. A show still opens that modal with TMDB off — it is where the season list lives — so the card alone would have left the claim one click deeper. - Its operator-only "Fix match" / "Rematch" buttons are gated too: both act on a match that does not exist, one opening a search the node answers empty, the other dropping a cached match never made. Those buttons are the only entry points to TmdbSearchOverlay and doRematch. - Both props default to true, so a call site that forgets one keeps the badge rather than silently losing it. search-page.js is deliberately left passing `enabled: true`: a cross-group view has no single group's switch to read, and it never showed the operator buttons anyway (isNodeAdmin={false}). Recorded as §10.7 in docs/mediacenter.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V8EDjk6pkYZrCbo63m2x87
Diffstat (limited to 'packages/meshbay-hub')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/video-app.js37
1 files changed, 30 insertions, 7 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/video-app.js b/packages/meshbay-hub/src/meshbay_hub/static/video-app.js
index 57da9ff..f590d20 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/video-app.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/video-app.js
@@ -321,7 +321,7 @@ function useSeasonMeta(transportRef, tmdbId, season, active) {
function PosterCard({
title, subtitle, repEntry, transportRef, gekRef, onOpen, groupKey, onMetaResolved, onNeedConn,
- sourceEntries,
+ sourceEntries, tmdbEnabled = true,
}) {
const tRef = repEntry._tRef || transportRef;
const gRef = repEntry._gRef || gekRef;
@@ -341,6 +341,16 @@ function PosterCard({
const confident = Boolean(meta && meta.confidence && meta.tmdb_id);
const metaReady = meta !== null;
+ // "Unmatched" is a statement about a lookup that ran and came back with
+ // nothing — it tells an operator which titles are worth a "Fix match".
+ // With TMDB switched off for this group no lookup was ever made, so every
+ // card would carry the dashed outline and the "?" at once, flagging as a
+ // failure exactly the thing the operator chose. The poster grid then just
+ // shows what it does have — the file's own frame, presented plainly, the
+ // same as Flat does. Defaults to `true` so a caller that forgets the prop
+ // keeps the badge rather than silently losing it.
+ const flagUnmatched = tmdbEnabled && !confident;
+
// Reports this tile's own resolution upward so PosterGrid can notice two
// differently-parsed folders (a show split across release groups that
// named its seasons inconsistently, §3.4/V6) resolving to the same TMDB
@@ -382,7 +392,7 @@ function PosterCard({
const ready = metaReady && imageReady;
return html`
- <div class="video-card ${ready && !confident ? 'video-card-unmatched' : ''}" onClick=${onOpen}>
+ <div class="video-card ${ready && flagUnmatched ? 'video-card-unmatched' : ''}" onClick=${onOpen}>
${!ready && html`
<div class="video-poster video-poster-loading"><span class="spinner"></span></div>
`}
@@ -398,7 +408,7 @@ function PosterCard({
<div class="video-card-info">
<div class="video-card-title">
${(confident && meta.title) || title}
- ${!confident && html`<span class="video-card-flag" title=${t('video.no_match')}>?</span>`}
+ ${flagUnmatched && html`<span class="video-card-flag" title=${t('video.no_match')}>?</span>`}
</div>
<div class="video-card-sub">
${confident && meta.release_date ? yearOf(meta.release_date) : ''}
@@ -690,6 +700,7 @@ function TmdbSearchOverlay({
function VideoDetailModal({
title, meta, repEntry, show, transportRef, gekRef, onClose, onPlay, isNodeAdmin,
+ tmdbEnabled = true,
}) {
const confident = Boolean(meta && meta.confidence && meta.tmdb_id);
const [searching, setSearching] = useState(false);
@@ -743,7 +754,12 @@ function VideoDetailModal({
<${Icon} name="close" /></button>
</div>
<div class="video-detail-body">
- ${meta !== null && !confident && html`
+ ${/* Same reason as PosterCard's flagUnmatched: with TMDB off for
+ this group nothing was looked up, so "no confident match" is
+ not a fact about this title. A show still opens this modal
+ with TMDB off — it is where its season list lives — so the
+ notice has to be suppressed here too, not only on the card. */''}
+ ${tmdbEnabled && meta !== null && !confident && html`
<p class="video-detail-nomatch">${t('video.no_match')}</p>
`}
<p class="video-detail-source">
@@ -760,7 +776,13 @@ function VideoDetailModal({
</p>
`}
`}
- ${isNodeAdmin && html`
+ ${/* Both of these act on a TMDB match, and with TMDB off for this
+ group there is none to act on: "Fix match" opens a search the
+ node answers with an empty result list (§5.7's silent
+ degradation), and "Rematch" drops a cached match that was
+ never made. Two buttons that cannot do anything, offered to
+ the one person who already knows why. */''}
+ ${isNodeAdmin && tmdbEnabled && html`
<div class="video-admin-actions">
<button class="admin-btn video-fix-match" onClick=${() => setSearching(true)}>
${t('video.fix_match')}
@@ -895,7 +917,7 @@ function PosterGrid({
groupKey=${`movie:${e.id}`}
sourceEntries=${e}
transportRef=${transportRef} gekRef=${gekRef}
- onNeedConn=${onNeedConn}
+ onNeedConn=${onNeedConn} tmdbEnabled=${tmdbEnabled}
onOpen=${() => (tmdbEnabled
// With TMDB off there is nothing the detail modal would show
// for a movie (no overview, no season list to pick from,
@@ -930,7 +952,7 @@ function PosterGrid({
sourceEntries=${s.episodes}
groupKey=${s.title}
onMetaResolved=${handleMetaResolved}
- onNeedConn=${onNeedConn}
+ onNeedConn=${onNeedConn} tmdbEnabled=${tmdbEnabled}
transportRef=${transportRef} gekRef=${gekRef}
onOpen=${() => openDetail(s.title, repEntry, s)} />
</${LazyTile}>
@@ -940,6 +962,7 @@ function PosterGrid({
<${VideoDetailModal} title=${detail.title} meta=${detailMeta}
repEntry=${detail.repEntry} show=${detail.show}
transportRef=${detailTRef} gekRef=${detailGRef} isNodeAdmin=${isNodeAdmin}
+ tmdbEnabled=${tmdbEnabled}
onClose=${() => setDetail(null)}
onPlay=${(entry) => { setDetail(null); onPreview(entry); }} />
`}