autoplay first episode by default, resume watched
- no ?ep= param: resume last watched ep of the season from history, else start at ep 1 (verified in headless Chromium, no click needed) - if the browser blocks autoplay (no user gesture yet), show a 'click to play' overlay instead of a silent black screen
This commit is contained in:
1 parent
a3a58e7d3c
commit
32f93c0f65
2 files changed
+18
No files matched your search
@@ -126,6 +126,14 @@ async function showAnime(slug_id, opts = {}) {
|
|||||||
if (opts.ep) {
|
if (opts.ep) {
|
||||||
const cur = [...eps.children].find(b => +b.dataset.ep === opts.ep);
|
const cur = [...eps.children].find(b => +b.dataset.ep === opts.ep);
|
||||||
if (cur) { markActive(cur); play(opts.ep, cur.dataset.no); }
|
if (cur) { markActive(cur); play(opts.ep, cur.dataset.no); }
|
||||||
|
} else {
|
||||||
|
// default: resume last watched ep of this season, else start at ep 1
|
||||||
|
const h = hist().find(x => x.slug_id === slug_id && x.season_id === seasonId);
|
||||||
|
const auto = h ? h.ep_id : +eps.querySelector(".ep")?.dataset.ep;
|
||||||
|
if (auto) {
|
||||||
|
const cur = [...eps.children].find(b => +b.dataset.ep === auto);
|
||||||
|
if (cur) { markActive(cur); play(auto, cur.dataset.no); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (detail.synopsis) main.append(el("p", "synopsis bottom", detail.synopsis));
|
if (detail.synopsis) main.append(el("p", "synopsis bottom", detail.synopsis));
|
||||||
@@ -164,6 +172,7 @@ async function play(ep_id, ep_no) {
|
|||||||
hls.loadSource("/stream/" + s.token);
|
hls.loadSource("/stream/" + s.token);
|
||||||
hls.attachMedia(v);
|
hls.attachMedia(v);
|
||||||
v.onerror = () => showStreamError("media error: " + (v.error?.message || v.error?.code));
|
v.onerror = () => showStreamError("media error: " + (v.error?.message || v.error?.code));
|
||||||
|
v.play().catch(() => showPlayOverlay(v)); // autoplay blocked (no user gesture) -> visible prompt
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showStreamError(e.message);
|
showStreamError(e.message);
|
||||||
}
|
}
|
||||||
@@ -172,6 +181,12 @@ async function play(ep_id, ep_no) {
|
|||||||
document.title = `${detail.name} E${ep_no} — ani-web`;
|
document.title = `${detail.name} E${ep_no} — ani-web`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showPlayOverlay(v) {
|
||||||
|
const o = el("button", "play-overlay", "▶ click to play");
|
||||||
|
o.onclick = () => { v.play(); o.remove(); };
|
||||||
|
v.parentElement.append(o);
|
||||||
|
}
|
||||||
|
|
||||||
// ---------- boot ----------
|
// ---------- boot ----------
|
||||||
(async () => {
|
(async () => {
|
||||||
const p = new URLSearchParams(location.search);
|
const p = new URLSearchParams(location.search);
|
||||||
|
|||||||
@@ -23,7 +23,10 @@ h2 { margin: 0.4rem 0; }
|
|||||||
.detail-head { margin-bottom: 1rem; }
|
.detail-head { margin-bottom: 1rem; }
|
||||||
.synopsis { color: var(--muted); max-width: 70ch; margin: 0.3rem 0; }
|
.synopsis { color: var(--muted); max-width: 70ch; margin: 0.3rem 0; }
|
||||||
|
|
||||||
|
.player { position: relative; }
|
||||||
.player video { width: 100%; max-height: 70vh; background: #000; border-radius: 10px; aspect-ratio: 16/9; }
|
.player video { width: 100%; max-height: 70vh; background: #000; border-radius: 10px; aspect-ratio: 16/9; }
|
||||||
|
.play-overlay { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
|
||||||
|
font-size: 1.1rem; padding: 0.8rem 1.4rem; background: rgba(0, 0, 0, 0.75); }
|
||||||
.controls { display: flex; align-items: center; gap: 0.4rem; margin: 0.6rem 0; }
|
.controls { display: flex; align-items: center; gap: 0.4rem; margin: 0.6rem 0; }
|
||||||
button { background: var(--card); color: var(--fg); border: 1px solid var(--bd);
|
button { background: var(--card); color: var(--fg); border: 1px solid var(--bd);
|
||||||
border-radius: 8px; padding: 0.4rem 0.7rem; cursor: pointer; }
|
border-radius: 8px; padding: 0.4rem 0.7rem; cursor: pointer; }
|
||||||
|
|||||||
Reference in new issue
Block a user