From 32318a64b12c83429c156a36c228769492e41d4e Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Sat, 29 Aug 2026 16:42:18 +0200 Subject: fix: on restart, serve a video's cached TMDB match instead of re-searching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root of the 2026-08-29 demo35 storms. `_do_media_meta_request` could not tell "this is a movie" from "this video isn't enriched yet" — both have season/episode None — so during a slow initial scan with a browser on the Videos tab, every show episode requested was run through the *movie* search path with its raw filename as the query (`search/movie?query=Show S01E01 1080p WEB DL ...`), hundreds per second, until TMDB rate-limited and posters stopped loading. Worse, an un-enriched show episode's own valid cached "tv" match was treated as stale (its provisional kind was "movie"), so a file already resolved got re-queried anyway. - While a video is un-enriched (no display_title — enrich.py always sets one), never run a TMDB *search*. Serve the cached match if the content hash has one, honouring the cached kind ("tv"/"movie") rather than the provisional split; otherwise answer confidence 0. - Once enriched, the strict `cached_media_type == media_type` check is unchanged: an enrichment fix that reclassifies a folder movie->tv still drops the stale match and re-resolves. - video-app.js: `useMediaMeta` gains an `enrichSig` dependency (`entry.display_title`) so the client refetches once the enriched fields arrive on an index delta — the fileId is a content hash and never changes, so nothing else would retrigger it. Not caused by the V8-V13 work; it raised the per-file call count so the pre-existing race became a visible storm. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_018BMLQjqFGCize2KtNBT79v --- .../src/meshbay_node/transport/webrtc_server.py | 44 ++++++++++++++++------ 1 file changed, 33 insertions(+), 11 deletions(-) (limited to 'packages/meshbay-node/src/meshbay_node') diff --git a/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py b/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py index af6bf08..1bd7203 100644 --- a/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py +++ b/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py @@ -2915,6 +2915,17 @@ class WebRTCPeerSession: "file_id": file_id, "confidence": 0}) return + # A video the indexer has seen but not yet *enriched* has no + # display_title (enrich.py always sets one) and season/episode still + # None — so the movie/show split reads "movie" and would hand its raw + # filename to TMDB's movie search. During a slow initial scan with a + # browser on the Videos tab that is a storm of + # `search/movie?query=` (found live 2026-08-29, an + # 8-minute scan). While un-enriched we never *search*: we serve a + # cached match if there is one (§ below), else confidence 0 and the + # client refetches once the index delta carries the enriched fields. + enriched = bool(entry.display_title) + is_show = entry.season is not None and entry.episode is not None media_type = "tv" if is_show else "movie" @@ -2923,21 +2934,32 @@ class WebRTCPeerSession: tmdb_id = None if cached is not None: cached_tmdb_id, cached_media_type = cached - # Trustworthy only if it still agrees with what this file - # resolves to *now*. season/episode come from index-time - # enrichment (enrich.py), which can reclassify a file between - # movie and show on a later scan without this cache knowing — - # it is keyed by the file's content hash alone, which a - # reclassification never changes. Found live: an enrichment fix - # to a Specials-folder bug reclassified hundreds of files from - # "movie" to "tv", and every one kept answering with its - # stale movie-era match forever, because this was trusted - # before ever comparing media_type against the current one. - if cached_media_type == media_type: + # Serve the cached match when its kind still agrees with the + # entry's current classification — OR when the entry is not + # enriched yet: its season/episode aren't populated, so the + # movie/show split above is not meaningful, and the cached kind + # (set when this file WAS enriched) is the reliable one. This is + # what keeps a restart from re-querying TMDB for everything + # already resolved: the storm was an un-enriched show episode + # looking like a "movie" and treating its own valid "tv" match + # as stale. + # + # Once enriched, the strict `cached_media_type == media_type` + # check still stands: an enrichment fix that reclassifies a + # folder movie->tv must drop the stale movie-era match and + # re-resolve (found live — a Specials-folder fix left hundreds + # of files answering with their wrong-kind match forever). + if cached_media_type == media_type or not enriched: + media_type = cached_media_type + is_show = media_type == "tv" tmdb_id = cached_tmdb_id meta = await media_cache.get_tmdb_meta(tmdb_id, media_type) if meta is None: + if not enriched: + self._send({"type": MNP.MEDIA_META_RESP, "v": MNP_VERSION, + "file_id": file_id, "confidence": 0}) + return result, ratio = await self._tmdb_search(tmdb_client, entry, is_show) if result is None or ratio < 0.6: self._send({"type": MNP.MEDIA_META_RESP, "v": MNP_VERSION, -- cgit v1.2.3