diff --git a/static/app.js b/static/app.js index ebe21c4..4edcaca 100644 --- a/static/app.js +++ b/static/app.js @@ -822,23 +822,23 @@ async function play(ep_id, ep_no) { if (currentEp && !playerBroken && !v.ended) playerOverlay("Buffering\u2026"); }); v.addEventListener("ended", onEnded); - // NotAllowedError = the browser blocked autoplay: 'playing' will never - // fire, so the Loading… overlay (which only clears on 'playing') would - // sit forever over the unreachable native controls. Other rejection - // reasons (AbortError when the stream has no data yet, …) belong to the - // hls.js fatal-error path — leave its overlay alone. - v.play().catch(err => { - if (!err || err.name !== "NotAllowedError") return; - // Not fatal: a tap (a real gesture) usually starts playback. If the - // browser rejects even that (autoplay disallowed for the site, …), - // stay on the tappable overlay and say what to change — retrying - // play() would just hit the same wall - const tap = () => v.play().catch(() => blocked()); - const blocked = () => playerOverlay( - "Browser blocked playback. Tap Play, or allow autoplay for this " + - "site in the browser's site settings", tap, "Play"); - blocked(); + // ponytail: play() before first data can reject with NotAllowedError in + // Chrome — the same error a real autoplay block produces — so it used to + // show a scary "browser blocked" overlay on every initial play. Wait for + // first data (canplay; hls.js's recommended pattern), THEN play(). A + // NotAllowedError at that point is a genuine policy block (common on + // phones) — offer a simple tap-to-play; escalate to the settings hint + // only if the tap itself is rejected. 'playing' still clears the + // Loading… overlay either way. + const tap = () => v.play().catch(() => blocked(true)); + const blocked = (again) => playerOverlay( + again ? "Playback still blocked — allow autoplay for this site in " + + "the browser's site settings" : "Tap to play", tap, "\u25b6 Play"); + const doPlay = () => v.play().catch(err => { + if (err && err.name === "NotAllowedError") blocked(false); }); + if (v.readyState >= 2) doPlay(); + else v.addEventListener("canplay", doPlay, {once: true}); watchPos(v); setupIntro(v, ep_no); postHistory({...meta(v), title: detail.name, slug_id: detail.slug_id, season_id: seasonId,