diff --git a/static/app.js b/static/app.js index f30b231..5627695 100644 --- a/static/app.js +++ b/static/app.js @@ -465,12 +465,17 @@ async function play(ep_id, ep_no) { if (currentEp && !playerBroken && !v.ended) playerOverlay("Buffering\u2026"); }); v.addEventListener("ended", onEnded); - // The overlay only clears on 'playing', so a blocked autoplay would leave - // "Loading…" parked over the (unreachable) native controls forever — the - // rejected play() is the signal to swap it for a tappable one. - v.play().catch(() => playerOverlay("Tap to play", () => { - v.play().catch(() => playerFail("playback blocked by the browser")); - }, "Play")); + // 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; + playerOverlay("Tap to play", () => { + v.play().catch(() => playerFail("playback blocked by the browser")); + }, "Play"); + }); watchPos(v); postHistory({...meta(v), title: detail.name, slug_id: detail.slug_id, season_id: seasonId, ep_id, lang, ep: ep_no, pos: saved?.pos || 0});