fix: only surface tap-to-play on NotAllowedError (autoplay block)

The first version reacted to any play() rejection, which broke the
stream-failure path: with a dead stream play() rejects with AbortError
(no data), clobbering the hls.js 'Playback failed / Retry' overlay and
stealing the user's one click. Scope the swap to the autoplay policy
rejection; everything else stays with the fatal-error path.

test_stream_failure_retry caught it; test_autoplay_blocked_shows_tap_to_play
still passes (simulates NotAllowedError on the first gesture-less play).
This commit is contained in:
jozamudi committed 2026-08-24 02:54:40 +00:00
1 parent db715be54b
commit 3f8c387a48
1 file changed
+10 -5
+10 -5
View File
@@ -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", () => {
// 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"));
}, "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});