Skip to content

Detect and recover from Panopto caption injection race - #1

Open
Silverarmor wants to merge 6 commits into
masterfrom
fix/caption-injection-race
Open

Detect and recover from Panopto caption injection race#1
Silverarmor wants to merge 6 commits into
masterfrom
fix/caption-injection-race

Conversation

@Silverarmor

Copy link
Copy Markdown
Owner

Problem

Custom SRT captions intermittently fail to apply: the viewer shows Panopto''s original ASR captions ("Uh, we''re going to...") while the script''s banner still claims "Custom SRT is active". Reloading sometimes fixes it; a cache-clearing reload reliably fixes it.

Root cause

The script works by proxying window.fetch and answering the viewer''s DeliveryInfo.aspx + getCaptions=true request with the stored SRT. That only works if Tampermonkey injects the script before the viewer issues that request. On slow loads (cold cache, or Panopto''s current server slowness) the script wins the race; on fast cached loads it can lose, so the real captions load and the substitution silently never happens. The "Custom SRT is active" banner is driven purely by GM storage, so it lies when the race is lost.

Verified live on the Auckland tenant: when injection wins, the transcript pane and docked CC overlay both show the custom SRT (946 cues vs the server''s 549); when it loses, the server captions render end-to-end.

Fix

  • Track whether the fetch proxy actually intercepted a captions request (interceptedCaptions).
  • After the transcript renders, if custom SRT is active but nothing was intercepted, the race was lost: auto-reload to retry, at most twice per video (sessionStorage counter, cleared on success or new upload).
  • If it still fails after retries, replace the banner with a red "Custom SRT failed to apply - Panopto''s captions are showing. Reload to retry." instead of the misleading active state.

Unrelated observations from debugging, not addressed here: Panopto''s viewer itself is currently taking minutes to boot at times (reproduced with the script not injected), and the "Auto-play is disabled" toast is standard Chrome autoplay policy.

Panopto's viewer requests captions via fetch during boot. The custom SRT
only applies if the userscript's fetch proxy is installed before that
request fires; when Tampermonkey injects late (typically on fast cached
loads), the original Panopto captions render while the banner still
claims the custom SRT is active.

Track whether the proxy actually intercepted a getCaptions request. If
the transcript renders without interception, auto-reload up to twice
(sessionStorage counter, reset on success or new upload). If it still
fails, show a red failure banner instead of the misleading active one.
In Tampermonkey MV3 with Content Script API set to "UserScripts API
Dynamic" (needed for reliable document-start injection), GM values are
injected as a snapshot that updates asynchronously. A GM_setValue or
GM_deleteValue followed immediately by a reload therefore boots with the
previous value: reverting still shows the old SRT, and a fresh upload
does not apply until a second manual reload (Tampermonkey issue #2123).

Mirror the latest save/revert in sessionStorage, which is synchronous
and survives same-tab reloads, and prefer it over the GM snapshot at
boot. The mirror is dropped as soon as GM storage has caught up.
@Silverarmor

Copy link
Copy Markdown
Owner Author

Added a second commit (0bcd2fd): in Tampermonkey's 'UserScripts API Dynamic' mode (needed for reliable document-start injection), GM values are injected as a snapshot that lags one reload behind a fresh write, so Revert/Upload appeared to do nothing until a second manual reload. The latest save/revert is now mirrored in sessionStorage and preferred over a stale GM snapshot at boot; the mirror is dropped once GM storage catches up.

@Silverarmor

Copy link
Copy Markdown
Owner Author

Well, the race condition is a guess - but this branch seems to work - will test and merge after.

Long lecture titles squeezed the header so "Replace SRT" / "Revert to
Default" / "Download" wrapped to multiple lines and bled into the video
area. Hide the Panopto small logo to reclaim header width, shorten the
button labels to one word with the full text in a hover tooltip, and
force nowrap so the buttons can no longer wrap regardless of width.
Verified live: with the one-word buttons an extreme title no longer
wraps them into the player, but it pushed them off the right edge of
the viewport. Let .header-left shrink (min-width: 0) inside the
flex header and ellipsize #deliveryTitle so the buttons always remain
visible on a single line.
…s it

Buttons now default to their full labels ("Replace SRT", "Revert to
Default") with the logo visible. When the title actually truncates
(scrollWidth exceeds clientWidth), the script switches to one-word
labels and hides the logo; full labels stay available as hover
tooltips either way.

Expansion back uses a synchronous trial: restore full labels and logo,
force a reflow, and revert if the title truncates - nothing paints
mid-task so a failed trial is invisible. The title element is
shrink-to-fit (clientWidth always equals scrollWidth when it fits), so
truncation is the only reliable signal; a slack-based headroom check
can never fire. Trials are throttled to one per second because the
label swap itself retriggers the MutationObserver, and a resize
listener re-evaluates on window changes.

Verified live on the Auckland tenant: compact triggers on an inflated
title, stays stable while long, and expands back when the title fits.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant