From 0b0da86f1f9d6f0b1a27b5e1e1658c42de9f356a Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Mon, 24 Aug 2026 14:33:20 +0200 Subject: feat(node,hub): season-specific overviews, manual TMDB match correction, and wizard polish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two operator-facing fixes for a real 3-season show whose automatic TMDB match was wrong at the show level: per-season overview/air_date tabs in the detail modal (falling back to the show-level text when a season's own is empty), and a "Fix match…" search-and-correct affordance that re-resolves every file sharing the corrected show's display_title. New signed op OP_TMDB_OVERRIDE and two read-only pairs (season_meta_req/resp, tmdb_search_req/resp), MNP_VERSION 0.5 -> 0.6. Also: the create-group wizard gets a spinning indexing indicator and an app-selection step, group settings default the TMDB language to the operator's own locale (never as a global default), and a file renamed mid-session now re-triggers title parsing instead of being silently skipped by the enrichment dedup guard. Fixes two bugs found during this work: the search overlay's z-index lost to the base video-overlay class and rendered invisibly, and season_meta's own empty overview didn't fall back to the show-level one. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01LAmyXtc6dAADsH23ydXQpY --- docs/apps.md | 19 ++++++++----- docs/mediacenter.md | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 7 deletions(-) (limited to 'docs') diff --git a/docs/apps.md b/docs/apps.md index 931114d..a032f56 100644 --- a/docs/apps.md +++ b/docs/apps.md @@ -5,13 +5,18 @@ > `meshbay-draft-v6.md` §2.7 for why this exists and what it changes; this > document is the how-to. -A group has "applications" — Chat and Files today, Videos/Music/Photos planned -(a poster-grid browser, a music player, an album viewer). None of the -planned ones need an MNP protocol change: video/audio/image files are already -classified by the node's indexer (`meshbay_node/indexer/indexer.py`, `type: -video|audio|image`) and flow through the same `index_sync`/`file_req`/ -`stream_req` messages Files and `VideoPlayer` already use. Adding one is a new -file plus one registry entry — nothing about the group shell changes. +A group has "applications" — Chat, Files, and Videos today (a poster-grid +browser; see `docs/mediacenter.md`), Music/Photos planned (a music player, an +album viewer). Video/audio/image files are already classified by the node's +indexer (`meshbay_node/indexer/indexer.py`, `type: video|audio|image`) and +flow through the same `index_sync`/`file_req`/`stream_req` messages Files and +`VideoPlayer` already use — Music/Photos need no MNP change beyond that. +Videos itself did need one: TMDB metadata (`media_meta_req`/`resp`), per-season +overview (`season_meta_req`/`resp`), and operator match correction +(`tmdb_search_req`/`resp`, `tmdb_override`/`_ack`) are all additive message +pairs on top of the same index/chunk plumbing, not a replacement for it. +Adding a new app is still a new file plus one registry entry — nothing about +the group shell changes. --- diff --git a/docs/mediacenter.md b/docs/mediacenter.md index a165d64..66232f8 100644 --- a/docs/mediacenter.md +++ b/docs/mediacenter.md @@ -530,6 +530,85 @@ makes outbound third-party network calls (once TMDB is on) — the operator opts a group into it explicitly via the existing Settings checklist, same gesture as any other app. +### 5.7 Season-specific overview, and correcting a wrong automatic match + +Found live, 2026-08-24, on a real 3-season show: TMDB's own search +consistently resolved every season's folder to the same *season-3-specific* +promotional entry — a wrong `tmdb_id`, not a MeshBay grouping bug (§3.3's +`_best_match` deliberately trusts TMDB's own top result, per that section's +own postmortem). Two independent problems, two independent fixes: + +**A show's own `overview` (§5.4) is one static field that does not +necessarily describe every season alike.** New request/response pair, read +lazily per selected tab (same virtualization discipline as `media_meta_req`, +never fetched for a season the operator hasn't clicked): + +``` +season_meta_req { tmdb_id, season } # tmdb_id is whatever media_meta_resp + # already resolved — never re-searched here +season_meta_resp { tmdb_id, season, confidence, name, overview, air_date, + poster_thumb_hash } +``` + +`video-app.js`'s `VideoDetailModal` shows a season tab bar +(`Season 1` / `Season 2` / … / `Specials`) whenever a show has more than one +season, defaulting to whichever season the representative episode belongs +to. Selecting a tab both filters the episode list to that season and swaps +in that season's own `overview`/`air_date` — falling back to the show-level +`overview` when a season's own comes back empty (TMDB has no season-level +text for every show), the same per-field fallback shape §5.4's English +fallback already established, just one level further down when there is +nothing at all to show otherwise. + +**An operator needs a way to correct a wrong match** when TMDB's own +top-ranked result is simply wrong — no amount of local re-ranking fixes +this (§3.3's last row is exactly the mistake that would repeat). Two more +message pairs, the second an admin op: + +``` +tmdb_search_req { query, media_type } # media_type: "movie" | "tv" +tmdb_search_resp { query, media_type, results: [{ tmdb_id, title, year, + poster_thumb_hash }] } + +tmdb_override { path, tmdb_id, media_type } # admin op, subject = + # "path={path},tmdb_id={tmdb_id},media_type={media_type}" +tmdb_override_ack { path, tmdb_id, media_type } # broadcast to every connected peer +``` + +`tmdb_search_req` is deliberately **not** admin-gated — it is read-only (the +same TMDB lookup the automatic matcher already performs on everyone's +behalf) and returns nothing that isn't already visible in the search +results a browser could get by hand. `media_type` is echoed back in the +response, not only the query: a client that fires a movie search and a tv +search for the same title in close succession needs it to tell the two +responses apart for keyed matching (`transport.js`), the same reordering +hazard §5.4's first postmortem already covers for `media_meta_req`. + +`tmdb_override`, once signed, is applied to **every index entry sharing the +resolved file's `display_title`** (`webrtc_server.py`'s +`_admin_exec_tmdb_override`) — the same grouping the poster grid itself uses +(§3.4/V6) — not just the one file the operator happened to right-click, +so the correction actually sticks for every episode of the show, and +broadcasts a `tmdb_override_ack` to every connected peer so an already-open +grid/modal picks up the change without a reconnect (`video-app.js`'s +`useMediaMeta` subscribes to a module-level generation counter, bumped on a +successful override, that forces every mounted tile/modal to refetch). + +New adminop: `OP_TMDB_OVERRIDE = "tmdb_override"` (`adminop.py`), following +`OP_VIDEO_ROOT`/`OP_TMDB_CONFIG`'s exact shape — signed for the same reason: +`media_cache` is shared node-wide, not per-viewer, so an unsigned override +would let any member vandalize another show's metadata for everyone. + +**Bug found live, 2026-08-24**: the search overlay (a second, later +`.video-overlay` sibling, opened on top of the detail modal) rendered +completely invisibly the first time it shipped — present in the DOM +(confirmed via the accessibility tree), inert on screen. Cause: its own +`z-index: 1` lost to the base `.video-overlay` class's `z-index: 200` that +the detail modal underneath it already used; both are `position: fixed`, +so an explicit z-index always wins over DOM order regardless of which +element mounted later. Fixed by giving `.video-search-overlay` an explicit +`z-index: 210`. + --- ## 6. Node-side implementation, concretely @@ -620,6 +699,7 @@ centralization was for (one computation, reused by every member). | V4 | Multi-audio-track / subtitle-track surfacing in the detail view | Out of scope for this pass — `video-player.js`'s existing track handling is unchanged; Videos only adds discovery and metadata | | V5 | `Music`/`Photos` apps | Explicitly out of scope, per `apps.md` — this document only builds `video-app.js` and the shared node-side machinery (TMDB client, thumbnail cache, title parser) that a future audio/photo app could also reuse | | ~~V6~~ | ~~Two folders of the same show, named by different release groups, can produce two separate poster-grid cards~~ | **Closed, 2026-08-24.** Rather than fuzzy title matching (real design decision, still deferred), `PosterGrid` now merges raw show-groups client-side once each group's TMDB lookup resolves to the same confident `tmdb_id` (`onMetaResolved` reports each `PosterCard`'s resolved meta upward; a `useMemo` groups by id, combining episodes/seasons into one card). This only merges what TMDB already agrees is one show — a genuinely unmatched show still gets its own card, which is correct. Confirmed live: `OVNIs.S01...`/`Ovnis-S01...` now render as a single "OVNI(s)" card with both seasons | +| ~~V7~~ | ~~A show's automatic TMDB match can be wrong at the show level (not just mis-ranked locally), and a wrong match's `overview` can read as scoped to one season~~ | **Closed, 2026-08-24 — §5.7.** Per-season tabs (own `overview`/`air_date`, falling back to the show-level text when empty) plus an operator-only "Fix match…" search-and-correct affordance, applied to every file sharing the resolved `display_title`. Confirmed live on the operator's real "War of the Worlds" 3-season show, itself matched to a wrong season-3-specific 1988 promotional TMDB entry: season tabs correctly filtered episodes and swapped in each season's own air_date, and the search overlay returned real TMDB candidates for a manual correction | ## 11. Acceptance before shipping -- cgit v1.2.3