From 30980ba0994d3e99d41c5252555320d6cbb1f5a9 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Thu, 17 Sep 2026 14:44:57 +0200 Subject: fix(hub): sample activeCues, the number that decides whether a subtitle shows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Attach-time state — one track, showing, cues parsed — was all correct while nothing appeared on screen, so it was measuring the wrong thing. A re-render can replace the and reset a mode nothing sets again, and a cue list that does not cover the playhead looks identical to one that does. The probe samples activeCues for ten seconds alongside the playhead, the mode, and the cue that ought to be on screen at that instant, so "no cue is active" and "a cue is active and is not painted" stop being the same observation. Verified beforehand that the mechanism itself is sound: a real Chrome driven over CDP, fed through MediaSource with timestampOffset 2690 and given a track appended after playback started, reports activeCues 1 on the cue bracketing the playhead. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01UGY17EPph5LsLzePPXhUVc --- .../src/meshbay_hub/static/video-player.js | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/packages/meshbay-hub/src/meshbay_hub/static/video-player.js b/packages/meshbay-hub/src/meshbay_hub/static/video-player.js index 596a848..3bb9124 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/video-player.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/video-player.js @@ -1159,6 +1159,33 @@ function VideoPlayer({ entry, transportRef, gekRef, onClose, onDownload }) { 'mode =', v.textTracks[0] && v.textTracks[0].mode, 'cues =', v.textTracks[0] && v.textTracks[0].cues ? v.textTracks[0].cues.length : 'none'); + if (!subtitleUrl) return; + // The state above is a single instant, and every part of it can be right + // there and wrong a second later: a re-render can replace the , + // which resets the mode nothing would set again. What decides whether a + // subtitle is on screen is `activeCues`, and that is the one number no + // log has ever carried. Sampled for ten seconds, with the cue that ought + // to be showing at this instant, so "none active" and "active but not + // painted" stop being the same observation. + let n = 0; + const probe = setInterval(() => { + const tt = v.textTracks[0]; + if (!tt) { console.log('[MeshBay] subtitle probe: the track is gone'); return; } + const cues = tt.cues ? Array.from(tt.cues) : []; + const now = v.currentTime; + const should = cues.find((c) => c.startTime <= now && c.endTime >= now); + console.log('[MeshBay] subtitle probe', ++n, + 't =', now.toFixed(1), 'mode =', tt.mode, + 'cues =', cues.length, + 'active =', tt.activeCues ? tt.activeCues.length : 'null', + 'due here =', should ? `[${should.startTime.toFixed(1)}-` + + `${should.endTime.toFixed(1)}] ${should.text.slice(0, 40)}` : 'none', + 'first/last =', cues.length + ? `${cues[0].startTime.toFixed(1)}..${cues[cues.length - 1].endTime.toFixed(1)}` + : '-'); + if (n >= 5) clearInterval(probe); + }, 2000); + return () => clearInterval(probe); }, [subtitleUrl]); useEffect(() => { -- cgit v1.2.3