diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-17 14:36:25 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-17 14:36:25 +0200 |
| commit | 4134729543139f4934c4ec4e4c6a2cda0606bcdf (patch) | |
| tree | 515480b5e4da5e1f5ba89eb36d90d6090c3f5271 /packages/meshbay-hub/src | |
| parent | c91082b173a61d93a71f9be2696db3684dbfe05e (diff) | |
| download | meshbay-4134729543139f4934c4ec4e4c6a2cda0606bcdf.tar.gz | |
fix(hub): trace the subtitle path end to end in the player
A subtitle button that spins for ever and never shows a track could not be
told apart from a node that answered, a blob that never arrived, or a track
attached with no cues in it: the whole path was silent. Every step of it
happens on someone else's machine, over a link, against a file that may be
gigabytes, so the only question worth asking when it does not finish is which
step did not — and nothing recorded that.
It now logs the request, the node's answer with hash, size and elapsed time,
the fetched blob and its chunk count, the attachment, and the live TextTrack's
mode and cue count. A failure says how long it took before failing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UGY17EPph5LsLzePPXhUVc
Diffstat (limited to 'packages/meshbay-hub/src')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/video-player.js | 26 |
1 files changed, 24 insertions, 2 deletions
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 a150512..596a848 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/video-player.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/video-player.js @@ -1100,21 +1100,39 @@ function VideoPlayer({ entry, transportRef, gekRef, onClose, onDownload }) { if (!transport) return; setSubtitleTrack(track.i); setSubtitleBusy(true); + // Traced end to end on purpose. Every step here happens on someone else's + // machine, over a link, against a file that may be gigabytes: when this + // does not finish, the only question worth asking is *which* step did not, + // and no other record of that exists. + const t0 = performance.now(); + console.log('[MeshBay] subtitle: asking for track', track.i, 'of', entry.id.slice(0, 12)); try { const info = await transport.requestSubtitle(entry.id, track.i); + console.log('[MeshBay] subtitle: node answered in', + Math.round(performance.now() - t0), 'ms —', + 'hash=', String(info.hash).slice(0, 12), 'size=', info.size, + 'mime=', info.mime); const chunks = await pipelinedDownload( transport, gekRef.current, info.hash, Math.ceil(info.size / CHUNK_SIZE)); + console.log('[MeshBay] subtitle: blob fetched in', + Math.round(performance.now() - t0), 'ms —', + chunks.length, 'chunk(s)'); const url = URL.createObjectURL( new Blob(chunks, { type: info.mime || 'text/vtt' })); // Someone changed their mind while this was in flight. Dropping the blob // rather than installing it is the whole point of the generation: the // reply that arrives last is not the choice that was made last. - if (subtitleGenRef.current !== gen) { URL.revokeObjectURL(url); return; } + if (subtitleGenRef.current !== gen) { + console.log('[MeshBay] subtitle: superseded, blob dropped'); + URL.revokeObjectURL(url); return; + } subtitleUrlRef.current = url; setSubtitleUrl(url); + console.log('[MeshBay] subtitle: track attached'); } catch (err) { if (subtitleGenRef.current !== gen) return; - console.warn('[MeshBay] subtitle track', track.i, 'failed:', err); + console.warn('[MeshBay] subtitle track', track.i, 'failed after', + Math.round(performance.now() - t0), 'ms:', err); setSubtitleTrack(null); setSubtitleError(true); } finally { @@ -1137,6 +1155,10 @@ function VideoPlayer({ entry, transportRef, gekRef, onClose, onDownload }) { for (let i = 0; i < v.textTracks.length; i++) { v.textTracks[i].mode = subtitleUrl ? 'showing' : 'disabled'; } + console.log('[MeshBay] subtitle: textTracks =', v.textTracks.length, + 'mode =', v.textTracks[0] && v.textTracks[0].mode, + 'cues =', v.textTracks[0] && v.textTracks[0].cues + ? v.textTracks[0].cues.length : 'none'); }, [subtitleUrl]); useEffect(() => { |