Fix web player TDZ crash on cached-playlist startup

The cached-playlist restore at the top of the script synchronously calls
playCurrentItem -> renderContent -> createYoutubeEmbed, which references
ytGeneration / activeYtPlayer / ytApiReady / ytApiCallbacks. Those were
declared with `let` further down in the script, so the references hit
the temporal dead zone and threw on every cold start with a YouTube
item in the cached playlist:

  Uncaught ReferenceError: can't access lexical declaration
  'ytGeneration' before initialization

Hoisted the four declarations to the top of the script alongside the
other player state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
ScreenTinker 2026-04-28 14:51:35 -05:00
parent f8cc62308f
commit 06ba054898

View file

@ -110,6 +110,14 @@
let zones = {}; let zones = {};
let userHasInteracted = !!localStorage.getItem('rd_audio_unlocked'); let userHasInteracted = !!localStorage.getItem('rd_audio_unlocked');
let advanceTimer = null; let advanceTimer = null;
// YouTube player state. Declared up front because the cached-playlist restore
// (a few lines below) may synchronously call into createYoutubeEmbed before the
// script reaches the original declaration site, which used to throw a temporal
// dead zone error.
let ytApiReady = false;
let ytApiCallbacks = [];
let activeYtPlayer = null;
let ytGeneration = 0;
// Track user interaction for autoplay policy // Track user interaction for autoplay policy
['click', 'touchstart', 'keydown'].forEach(evt => { ['click', 'touchstart', 'keydown'].forEach(evt => {
@ -608,9 +616,8 @@
} catch { return null; } } catch { return null; }
} }
// Load YouTube IFrame API once // Load YouTube IFrame API once. (ytApiReady / ytApiCallbacks are declared at the
let ytApiReady = false; // top of the script alongside the other player state.)
let ytApiCallbacks = [];
function loadYoutubeApi(cb) { function loadYoutubeApi(cb) {
if (ytApiReady) { cb(); return; } if (ytApiReady) { cb(); return; }
ytApiCallbacks.push(cb); ytApiCallbacks.push(cb);
@ -627,9 +634,6 @@
} }
} }
let activeYtPlayer = null;
let ytGeneration = 0; // Incremented on each new YouTube embed to ignore stale callbacks
function createYoutubeEmbed(src, item, container) { function createYoutubeEmbed(src, item, container) {
const videoId = extractVideoId(src); const videoId = extractVideoId(src);
if (!videoId) { if (!videoId) {