Fix YouTube autoplay block from stale localStorage gesture flag

userHasInteracted was initialized from localStorage('rd_audio_unlocked')
on every page load. Browser autoplay policy is per-document, so a flag
from a prior session does not actually grant autoplay rights — but the
player code used it to decide whether to start the YouTube embed muted
(autoplay-able) or unmuted (blocked). Result: kiosks with the flag set
loaded a YT embed with mute=0 that the browser refused to start.

- userHasInteracted now always starts as false. The cold-load tap
  overlay flips it to true on real gesture; the 5s auto-dismiss leaves
  it false and playback stays muted (still allowed).
- unlockAudio() now also calls activeYtPlayer.unMute() so the muted
  embed unmutes immediately when the user finally taps the overlay.
- Removed the now-unused localStorage writes of rd_audio_unlocked.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
ScreenTinker 2026-04-28 14:56:49 -05:00
parent f951d51214
commit fb58256b1c

View file

@ -108,7 +108,12 @@
let streamTimer = null;
let layout = null;
let zones = {};
let userHasInteracted = !!localStorage.getItem('rd_audio_unlocked');
// Tracks whether the user has gestured in *this* page load. Browser autoplay
// policy is per-document — a flag from a previous session does NOT grant
// autoplay rights here, so we always start as false. The cold-load tap overlay
// is the only thing that flips this to true (or its 5s timeout, which keeps
// playback muted).
let userHasInteracted = false;
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
@ -123,7 +128,6 @@
['click', 'touchstart', 'keydown'].forEach(evt => {
document.addEventListener(evt, () => {
userHasInteracted = true;
localStorage.setItem('rd_audio_unlocked', '1');
// Try to unmute any playing HTML5 video
const video = document.querySelector('#playerContainer video');
if (video && video.muted) {
@ -229,7 +233,6 @@
// Unlock audio on any user interaction
function unlockAudio() {
userHasInteracted = true;
localStorage.setItem('rd_audio_unlocked', '1');
// Create and resume AudioContext (unlocks audio for the session)
try {
const ctx = new (window.AudioContext || window.webkitAudioContext)();
@ -241,8 +244,15 @@
src.connect(ctx.destination);
src.start(0);
} catch(e) { console.warn('Audio unlock failed:', e); }
// Unmute any playing video
// Unmute any playing HTML5 video
document.querySelectorAll('video').forEach(v => { v.muted = false; });
// Unmute the active YouTube embed (iframe — querySelectorAll('video') misses it)
try {
if (activeYtPlayer && typeof activeYtPlayer.unMute === 'function') {
activeYtPlayer.unMute();
activeYtPlayer.setVolume(100);
}
} catch (e) { console.warn('YT unmute failed:', e); }
}
document.getElementById('connectBtn').onclick = () => {