From 5efe06e6409332bad2ca97e71a426d512d9abb7b Mon Sep 17 00:00:00 2001 From: Yuri Tatishchev Date: Fri, 6 Feb 2026 02:04:21 -0800 Subject: [PATCH] global player pt. 7 works kinda --- src/lib/components/GlobalPlayer.svelte | 68 +++++++++++++++++++------- 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/src/lib/components/GlobalPlayer.svelte b/src/lib/components/GlobalPlayer.svelte index 83c8f74..a16fd9d 100644 --- a/src/lib/components/GlobalPlayer.svelte +++ b/src/lib/components/GlobalPlayer.svelte @@ -95,32 +95,64 @@ audioEl.volume = snap.volume; } + async function waitForEvent(el: HTMLMediaElement, eventName: string) { + await new Promise((resolve) => { + const onEvent = () => { + el.removeEventListener(eventName, onEvent); + resolve(); + }; + el.addEventListener(eventName, onEvent, { once: true }); + }); + } + async function syncAndAutoplay() { - if (!audioEl) return; + const el = audioEl; + if (!el) return; + + // Capture current src BEFORE syncing so we can detect changes reliably. + const beforeSrc = el.currentSrc; syncAudioToCurrentTrack(); - // If the source changed, playback may not start immediately on some browsers - // until we wait for the new media to be ready. - if (audioEl.readyState < 2) { - await new Promise((resolve) => { - const el = audioEl; - if (!el) { - resolve(); - return; - } - const onCanPlay = () => { - el.removeEventListener("canplay", onCanPlay); - resolve(); - }; - el.addEventListener("canplay", onCanPlay, { once: true }); - }); + // If the src changed, some browsers require a "load -> playing" sequence. + // Strategy: + // - if src changed: ensure load is kicked, then wait for loadedmetadata/canplay + // - call play() + // - if it's still paused, wait for 'playing' and retry play once + const afterSrc = el.currentSrc; + + if (afterSrc !== beforeSrc) { + // Ensure metadata exists (duration available, etc.) + if (el.readyState < 1) { + await waitForEvent(el, "loadedmetadata"); + } + // Ensure enough data to play. + if (el.readyState < 3) { + await waitForEvent(el, "canplay"); + } + } else { + // Even if src didn't change, allow a minimal yield to let state settle. + await Promise.resolve(); } try { - await audioEl.play(); + await el.play(); } catch { - // Autoplay may be blocked; user gesture will still allow manual play. + // Autoplay may be blocked; bail out quietly. + return; + } + + // If the browser didn't actually start playback, retry after 'canplay'/'playing'. + if (el.paused) { + if (el.readyState < 3) { + await waitForEvent(el, "canplay"); + } + await Promise.race([waitForEvent(el, "playing"), Promise.resolve()]); + try { + await el.play(); + } catch { + // ignore + } } }