iOS root cause: start playback on BUFFER_APPENDED, not canplay
The live timeline caught it: iPhone buffered 513s, readyState stuck at 1, canplay NEVER fired -> play() never called -> eternal Loading. Now: first BUFFER_APPENDED (hls.js's own 'data is in the pipe' signal) triggers play, canplay still works, plus a 3s safety retry if still paused with a non-empty buffer. play() calls are guarded + idempotent. Desktop + mobile emu regression: playing. assets v=14.
This commit is contained in:
1 parent
daac8d5256
commit
0315356f89
2 files changed
+14
-12
No files matched your search
+12
-10
@@ -1,5 +1,5 @@
|
||||
// app.js — ani-web frontend: search -> detail -> play, vanilla JS + hls.js
|
||||
const JSV = 13; // bump with every app.js change; play-probe reports it so a
|
||||
const JSV = 14; // bump with every app.js change; play-probe reports it so a
|
||||
// stale-cache phone is detectable server-side
|
||||
// BASE = this page's directory, so the app works at / or behind a
|
||||
// prefixing reverse proxy (e.g. https://host/ani/)
|
||||
@@ -932,7 +932,7 @@ async function play(ep_id, ep_no) {
|
||||
hls.on(Hls.Events.MANIFEST_LOADED, () => dbg("manifest-loaded"));
|
||||
hls.on(Hls.Events.LEVEL_LOADED, () => dbg("level-loaded"));
|
||||
let _fn = 0; hls.on(Hls.Events.FRAG_LOADED, () => { if (++_fn <= 2) dbg("frag-loaded", {n: _fn}); });
|
||||
let _ba = false; hls.on(Hls.Events.BUFFER_APPENDED, () => { if (!_ba) { _ba = true; dbg("buffer-appended"); } });
|
||||
let _ba = false; hls.on(Hls.Events.BUFFER_APPENDED, () => { if (!_ba) { _ba = true; dbg("buffer-appended"); doPlay(); } });
|
||||
dbg("new-hls-ok");
|
||||
hls.loadSource("/stream/" + s.token);
|
||||
dbg("loadsource-called");
|
||||
@@ -972,24 +972,26 @@ async function play(ep_id, ep_no) {
|
||||
v.addEventListener("ended", onEnded);
|
||||
// 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.
|
||||
// show a scary "browser blocked" overlay on every initial play. Start as
|
||||
// soon as data exists (first BUFFER_APPENDED; canplay too) — but NEVER
|
||||
// wait on canplay alone: the iPhone (iOS 18.7) once sat with 513s
|
||||
// buffered, readyState stuck at 1, and canplay never fired — so the
|
||||
// video never started. 3s safety net covers any remaining variant.
|
||||
let started = false;
|
||||
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 = () => {
|
||||
dbg("do-play");
|
||||
v.play().then(() => dbg("play-resolved"))
|
||||
if (started) return;
|
||||
dbg("do-play", {rs: v.readyState, buf: v.buffered.length});
|
||||
v.play().then(() => { started = true; dbg("play-resolved"); })
|
||||
.catch(err => { dbg("play-rejected", {name: err && err.name});
|
||||
if (err && err.name === "NotAllowedError") blocked(false); });
|
||||
};
|
||||
if (v.readyState >= 2) doPlay();
|
||||
else v.addEventListener("canplay", doPlay, {once: true});
|
||||
setTimeout(() => { if (v.paused && v.buffered.length) doPlay(); }, 3000);
|
||||
watchPos(v);
|
||||
setupIntro(v, ep_no);
|
||||
postHistory({...meta(v), title: detail.name, slug_id: detail.slug_id, season_id: seasonId,
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@
|
||||
<title>ani-web</title>
|
||||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%23f97316'/%3E%3Ctext x='32' y='45' font-family='sans-serif' font-size='42' font-weight='700' text-anchor='middle' fill='%230e0f13'%3Ea%3C/text%3E%3C/svg%3E">
|
||||
|
||||
<link rel="stylesheet" href="style.css?v=13">
|
||||
<link rel="stylesheet" href="style.css?v=14">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
@@ -30,6 +30,6 @@
|
||||
max-age=300 in browser AND possibly in your HTTPS proxy, and a stale
|
||||
copy is exactly how users keep seeing an old UI after a deploy -->
|
||||
<script src="hls.min.js"></script>
|
||||
<script src="app.js?v=13"></script>
|
||||
<script src="app.js?v=14"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user