itube-modern-player 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/core.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { d as I } from "./labels-C3gAZEm-.js";
2
2
  function l(r, t, e) {
3
- const i = document.createElement(r);
4
- if (t && (i.className = t), e)
5
- for (const [s, n] of Object.entries(e)) i.setAttribute(s, n);
6
- return i;
3
+ const s = document.createElement(r);
4
+ if (t && (s.className = t), e)
5
+ for (const [i, n] of Object.entries(e)) s.setAttribute(i, n);
6
+ return s;
7
7
  }
8
8
  function m(r, t, e) {
9
- const i = l("button", `imp-btn ${r}`, { type: "button", "aria-label": t, title: t });
10
- return i.innerHTML = e, i;
9
+ const s = l("button", `imp-btn ${r}`, { type: "button", "aria-label": t, title: t });
10
+ return s.innerHTML = e, s;
11
11
  }
12
12
  function E(r, t, e) {
13
13
  r.innerHTML = t, e !== void 0 && (r.setAttribute("aria-label", e), r.setAttribute("title", e));
@@ -17,29 +17,29 @@ function y(r, t, e) {
17
17
  }
18
18
  function w(r) {
19
19
  if (!Number.isFinite(r) || r < 0) return "0:00";
20
- const t = Math.floor(r % 60), e = Math.floor(r / 60 % 60), i = Math.floor(r / 3600), s = i > 0 ? String(e).padStart(2, "0") : String(e), n = String(t).padStart(2, "0");
21
- return i > 0 ? `${i}:${s}:${n}` : `${s}:${n}`;
20
+ const t = Math.floor(r % 60), e = Math.floor(r / 60 % 60), s = Math.floor(r / 3600), i = s > 0 ? String(e).padStart(2, "0") : String(e), n = String(t).padStart(2, "0");
21
+ return s > 0 ? `${s}:${i}:${n}` : `${i}:${n}`;
22
22
  }
23
23
  function R(r) {
24
24
  const t = r.trim().match(/^(?:(\d+):)?(\d{1,2}):(\d{2})(?:[.,](\d{1,3}))?$/);
25
25
  if (!t) return null;
26
- const e = t[1] ? Number(t[1]) : 0, i = Number(t[2]), s = Number(t[3]), n = t[4] ? Number(t[4].padEnd(3, "0")) : 0;
27
- return e * 3600 + i * 60 + s + n / 1e3;
26
+ const e = t[1] ? Number(t[1]) : 0, s = Number(t[2]), i = Number(t[3]), n = t[4] ? Number(t[4].padEnd(3, "0")) : 0;
27
+ return e * 3600 + s * 60 + i + n / 1e3;
28
28
  }
29
29
  function U(r) {
30
30
  const t = [], e = r.replace(/\r\n?/g, `
31
31
  `).split(/\n\n+/);
32
- for (const i of e) {
33
- const s = i.split(`
32
+ for (const s of e) {
33
+ const i = s.split(`
34
34
  `).filter((f) => f.trim() !== "");
35
- if (s.length === 0) continue;
36
- let n = s.findIndex((f) => f.includes("-->"));
35
+ if (i.length === 0) continue;
36
+ let n = i.findIndex((f) => f.includes("-->"));
37
37
  if (n === -1) continue;
38
- const [o, a] = s[n].split("-->"), h = R(o), c = R((a ?? "").split(" ")[1] ?? a ?? "") ?? R(a ?? "");
39
- if (h === null || c === null) continue;
40
- const u = s.slice(n + 1).join(`
38
+ const [o, a] = i[n].split("-->"), c = R(o), h = R((a ?? "").split(" ")[1] ?? a ?? "") ?? R(a ?? "");
39
+ if (c === null || h === null) continue;
40
+ const u = i.slice(n + 1).join(`
41
41
  `).trim();
42
- u && t.push({ start: h, end: c, text: u });
42
+ u && t.push({ start: c, end: h, text: u });
43
43
  }
44
44
  return t;
45
45
  }
@@ -56,24 +56,24 @@ class Y {
56
56
  }
57
57
  /** Subscribe. Returns an unsubscribe function. */
58
58
  on(t, e) {
59
- let i = this.listeners.get(t);
60
- return i || (i = /* @__PURE__ */ new Set(), this.listeners.set(t, i)), i.add(e), () => this.off(t, e);
59
+ let s = this.listeners.get(t);
60
+ return s || (s = /* @__PURE__ */ new Set(), this.listeners.set(t, s)), s.add(e), () => this.off(t, e);
61
61
  }
62
62
  once(t, e) {
63
- const i = this.on(t, (s) => {
64
- i(), e(s);
63
+ const s = this.on(t, (i) => {
64
+ s(), e(i);
65
65
  });
66
- return i;
66
+ return s;
67
67
  }
68
68
  off(t, e) {
69
69
  this.listeners.get(t)?.delete(e);
70
70
  }
71
71
  emit(t, e) {
72
- const i = this.listeners.get(t);
73
- if (i)
74
- for (const s of [...i])
72
+ const s = this.listeners.get(t);
73
+ if (s)
74
+ for (const i of [...s])
75
75
  try {
76
- s(e);
76
+ i(e);
77
77
  } catch (n) {
78
78
  console.error("[itube-player] listener error", n);
79
79
  }
@@ -127,30 +127,30 @@ function xt() {
127
127
  }
128
128
  function et(r, t, e = 100) {
129
129
  if (r.length === 0 || !Number.isFinite(t) || t <= 0) return [];
130
- const i = new Array(e).fill(0);
131
- let s = !1;
132
- for (const c of r) {
133
- if (!Number.isFinite(c.time) || c.time < 0 || c.time > t) continue;
134
- const u = Math.max(0, c.value);
130
+ const s = new Array(e).fill(0);
131
+ let i = !1;
132
+ for (const h of r) {
133
+ if (!Number.isFinite(h.time) || h.time < 0 || h.time > t) continue;
134
+ const u = Math.max(0, h.value);
135
135
  if (u === 0) continue;
136
- const f = Math.min(e - 1, Math.floor(c.time / t * e));
137
- i[f] += u, s = !0;
136
+ const f = Math.min(e - 1, Math.floor(h.time / t * e));
137
+ s[f] += u, i = !0;
138
138
  }
139
- if (!s) return [];
140
- const n = [0.06, 0.24, 0.4, 0.24, 0.06], o = i.map(
141
- (c, u) => n.reduce((f, d, b) => f + d * (i[u + b - 2] ?? 0), 0)
139
+ if (!i) return [];
140
+ const n = [0.06, 0.24, 0.4, 0.24, 0.06], o = s.map(
141
+ (h, u) => n.reduce((f, d, b) => f + d * (s[u + b - 2] ?? 0), 0)
142
142
  ), a = Math.max(...o);
143
143
  if (a <= 0) return [];
144
- const h = 0.08;
145
- return o.map((c) => h + (1 - h) * (c / a));
144
+ const c = 0.08;
145
+ return o.map((h) => c + (1 - c) * (h / a));
146
146
  }
147
147
  function it(r, t = 1e3, e = 100) {
148
148
  if (r.length === 0) return "";
149
- const i = t / (r.length - 1 || 1);
150
- let s = `M 0 ${e}`;
149
+ const s = t / (r.length - 1 || 1);
150
+ let i = `M 0 ${e}`;
151
151
  return r.forEach((n, o) => {
152
- s += ` L ${(o * i).toFixed(1)} ${(e - n * e).toFixed(1)}`;
153
- }), s += ` L ${t} ${e} Z`, s;
152
+ i += ` L ${(o * s).toFixed(1)} ${(e - n * e).toFixed(1)}`;
153
+ }), i += ` L ${t} ${e} Z`, i;
154
154
  }
155
155
  async function st(r, t) {
156
156
  if (r.src)
@@ -164,8 +164,8 @@ async function st(r, t) {
164
164
  if (!r.vastTag) throw new Error('Ad roll has neither "vastTag" nor "src"');
165
165
  return j(r, r.vastTag, t, 0, { impressions: [], tracking: {} });
166
166
  }
167
- async function j(r, t, e, i, s) {
168
- if (i > e.maxWrapperDepth) throw new Error("VAST wrapper depth limit exceeded");
167
+ async function j(r, t, e, s, i) {
168
+ if (s > e.maxWrapperDepth) throw new Error("VAST wrapper depth limit exceeded");
169
169
  const n = new AbortController(), o = setTimeout(() => n.abort(), e.requestTimeout);
170
170
  let a;
171
171
  try {
@@ -175,18 +175,18 @@ async function j(r, t, e, i, s) {
175
175
  } finally {
176
176
  clearTimeout(o);
177
177
  }
178
- const h = new DOMParser().parseFromString(a, "text/xml");
179
- if (h.querySelector("parsererror")) throw new Error("VAST response is not valid XML");
180
- const c = h.querySelector("VAST > Ad");
181
- if (!c) throw new Error("VAST response contains no ads");
182
- nt(c, s);
183
- const u = c.querySelector(":scope > Wrapper");
178
+ const c = new DOMParser().parseFromString(a, "text/xml");
179
+ if (c.querySelector("parsererror")) throw new Error("VAST response is not valid XML");
180
+ const h = c.querySelector("VAST > Ad");
181
+ if (!h) throw new Error("VAST response contains no ads");
182
+ nt(h, i);
183
+ const u = h.querySelector(":scope > Wrapper");
184
184
  if (u) {
185
185
  const v = k(u.querySelector("VASTAdTagURI"));
186
186
  if (!v) throw new Error("VAST wrapper without VASTAdTagURI");
187
- return j(r, v, e, i + 1, s);
187
+ return j(r, v, e, s + 1, i);
188
188
  }
189
- const f = c.querySelector(":scope > InLine");
189
+ const f = h.querySelector(":scope > InLine");
190
190
  if (!f) throw new Error("VAST ad has neither InLine nor Wrapper");
191
191
  const d = f.querySelector("Creatives > Creative > Linear");
192
192
  if (!d) throw new Error("VAST ad has no Linear creative");
@@ -202,24 +202,24 @@ async function j(r, t, e, i, s) {
202
202
  d.getAttribute("skipoffset"),
203
203
  V(k(d.querySelector(":scope > Duration")))
204
204
  ),
205
- impressions: s.impressions,
206
- tracking: s.tracking,
205
+ impressions: i.impressions,
206
+ tracking: i.tracking,
207
207
  adTitle: k(f.querySelector(":scope > AdTitle")) ?? void 0
208
208
  };
209
209
  }
210
210
  function nt(r, t) {
211
- var e, i;
212
- for (const s of r.querySelectorAll("Impression")) {
213
- const n = k(s);
211
+ var e, s;
212
+ for (const i of r.querySelectorAll("Impression")) {
213
+ const n = k(i);
214
214
  n && t.impressions.push(n);
215
215
  }
216
- for (const s of r.querySelectorAll("Linear > TrackingEvents > Tracking")) {
217
- const n = s.getAttribute("event"), o = k(s);
216
+ for (const i of r.querySelectorAll("Linear > TrackingEvents > Tracking")) {
217
+ const n = i.getAttribute("event"), o = k(i);
218
218
  !n || !o || ["start", "firstQuartile", "midpoint", "thirdQuartile", "complete", "skip", "pause", "resume"].includes(n) && ((e = t.tracking)[n] ?? (e[n] = [])).push(o);
219
219
  }
220
- for (const s of r.querySelectorAll("Linear > VideoClicks > ClickTracking")) {
221
- const n = k(s);
222
- n && ((i = t.tracking).click ?? (i.click = [])).push(n);
220
+ for (const i of r.querySelectorAll("Linear > VideoClicks > ClickTracking")) {
221
+ const n = k(i);
222
+ n && ((s = t.tracking).click ?? (s.click = [])).push(n);
223
223
  }
224
224
  }
225
225
  function rt(r) {
@@ -234,7 +234,7 @@ function rt(r) {
234
234
  );
235
235
  if (e.length === 0) return null;
236
236
  e.sort((o, a) => o.bitrate - a.bitrate);
237
- const i = e.filter((o) => o.delivery !== "streaming"), s = i.length > 0 ? i : e, n = s[Math.floor(s.length / 2)];
237
+ const s = e.filter((o) => o.delivery !== "streaming"), i = s.length > 0 ? s : e, n = i[Math.floor(i.length / 2)];
238
238
  return { url: n.url, type: n.type };
239
239
  }
240
240
  function V(r) {
@@ -310,7 +310,7 @@ class lt {
310
310
  /** Called from timeupdate; fires due mid-rolls. */
311
311
  checkMidRolls(t) {
312
312
  if (this.adPlaying) return;
313
- const e = this.pending("midRoll").filter((i) => i.timer !== void 0 && t >= i.timer);
313
+ const e = this.pending("midRoll").filter((s) => s.timer !== void 0 && t >= s.timer);
314
314
  e.length > 0 && this.playRolls(e);
315
315
  }
316
316
  pending(t) {
@@ -321,8 +321,8 @@ class lt {
321
321
  if (this.activeBreak) return this.activeBreak;
322
322
  this.ensureAdVideo();
323
323
  const e = (async () => {
324
- const i = this.host.contentVideo, s = !i.paused && !i.ended;
325
- i.pause();
324
+ const s = this.host.contentVideo, i = !s.paused && !s.ended;
325
+ s.pause();
326
326
  for (const n of t) {
327
327
  this.playedRolls.add(n);
328
328
  try {
@@ -334,7 +334,7 @@ class lt {
334
334
  }
335
335
  if (this.destroyed) return;
336
336
  }
337
- (s || t[0].roll === "preRoll") && i.play().catch(() => {
337
+ (i || t[0].roll === "preRoll") && s.play().catch(() => {
338
338
  });
339
339
  })();
340
340
  return this.activeBreak = e.finally(() => {
@@ -343,17 +343,17 @@ class lt {
343
343
  }
344
344
  playAd(t) {
345
345
  return new Promise((e) => {
346
- const { labels: i } = this.host, s = l("div", "imp-ad"), n = this.ensureAdVideo(), o = new AbortController(), a = o.signal;
346
+ const { labels: s } = this.host, i = l("div", "imp-ad"), n = this.ensureAdVideo(), o = new AbortController(), a = o.signal;
347
347
  n.src = t.mediaUrl, n.muted = this.host.contentVideo.muted, n.volume = this.host.contentVideo.volume;
348
- const h = l("div", "imp-spinner imp-ad__spinner"), c = l("div", "imp-ad__hud"), u = l("span", "imp-ad__badge");
349
- u.textContent = t.adTitle ? `${i.adLabel} · ${t.adTitle}` : i.adLabel;
348
+ const c = l("div", "imp-spinner imp-ad__spinner"), h = l("div", "imp-ad__hud"), u = l("span", "imp-ad__badge");
349
+ u.textContent = t.adTitle ? `${s.adLabel} · ${t.adTitle}` : s.adLabel;
350
350
  const f = l("span", "imp-ad__countdown");
351
- c.append(u, f);
351
+ h.append(u, f);
352
352
  const d = l("div", "imp-ad__actions");
353
353
  let b = null;
354
- t.clickThrough && (b = l("button", "imp-ad__visit", { type: "button" }), b.textContent = i.visitAdvertiser, d.append(b));
354
+ t.clickThrough && (b = l("button", "imp-ad__visit", { type: "button" }), b.textContent = s.visitAdvertiser, d.append(b));
355
355
  const v = l("button", "imp-ad__skip", { type: "button" });
356
- v.hidden = !0, d.append(v), s.append(n, h, c, d), this.host.container.append(s), this.layer = s;
356
+ v.hidden = !0, d.append(v), i.append(n, c, h, d), this.host.container.append(i), this.layer = i;
357
357
  const H = t.skipOffset ?? this.opts.skipDelay, N = /* @__PURE__ */ new Set(), L = (g) => {
358
358
  N.has(g) || (N.add(g), C(t.tracking[g]));
359
359
  };
@@ -372,21 +372,21 @@ class lt {
372
372
  error: new Error(`Ad media stalled for ${this.opts.mediaTimeout} ms — skipping`)
373
373
  }), A());
374
374
  }, 500), A = () => {
375
- clearInterval(X), o.abort(), n.pause(), n.removeAttribute("src"), n.load(), s.remove(), this.layer = null, e();
375
+ clearInterval(X), o.abort(), n.pause(), n.removeAttribute("src"), n.load(), i.remove(), this.layer = null, e();
376
376
  }, O = (g) => {
377
377
  g ? (L("skip"), this.host.emitter.emit("adskip", { ad: t })) : L("complete"), this.host.emitter.emit("adend", { ad: t }), A();
378
378
  };
379
379
  n.addEventListener("playing", () => {
380
380
  C(t.impressions), L("start"), this.host.emitter.emit("adstart", { ad: t });
381
381
  }, { once: !0, signal: a }), n.addEventListener("playing", () => {
382
- h.hidden = !0;
382
+ c.hidden = !0;
383
383
  }, { signal: a }), n.addEventListener("waiting", () => {
384
- h.hidden = !1;
384
+ c.hidden = !1;
385
385
  }, { signal: a }), n.addEventListener("timeupdate", () => {
386
386
  const g = n.currentTime, x = n.duration;
387
387
  if (Number.isFinite(x) && x > 0 && (f.textContent = w(Math.max(0, x - g)), g / x >= 0.25 && L("firstQuartile"), g / x >= 0.5 && L("midpoint"), g / x >= 0.75 && L("thirdQuartile")), H >= 0) {
388
388
  const z = Math.ceil(H - g);
389
- z > 0 ? (v.hidden = !1, v.disabled = !0, v.textContent = `${i.skipAdIn} ${z}`) : (v.hidden = !1, v.disabled = !1, v.textContent = i.skipAd);
389
+ z > 0 ? (v.hidden = !1, v.disabled = !0, v.textContent = `${s.skipAdIn} ${z}`) : (v.hidden = !1, v.disabled = !1, v.textContent = s.skipAd);
390
390
  }
391
391
  }, { signal: a }), n.addEventListener("ended", () => O(!1), { signal: a }), n.addEventListener("error", () => {
392
392
  this.host.emitter.emit("aderror", {
@@ -402,14 +402,14 @@ class lt {
402
402
  n.addEventListener("playing", () => {
403
403
  W = !0;
404
404
  }, { once: !0, signal: a }), n.addEventListener("pause", () => {
405
- n.ended || !s.isConnected || (s.classList.add("imp-ad--paused"), W && !B && (B = !0, C(t.tracking.pause), this.host.emitter.emit("adpause", { ad: t })));
405
+ n.ended || !i.isConnected || (i.classList.add("imp-ad--paused"), W && !B && (B = !0, C(t.tracking.pause), this.host.emitter.emit("adpause", { ad: t })));
406
406
  }, { signal: a }), n.addEventListener("play", () => {
407
- s.classList.remove("imp-ad--paused"), B && (B = !1, C(t.tracking.resume), this.host.emitter.emit("adresume", { ad: t }));
408
- }, { signal: a }), s.addEventListener("click", (g) => {
409
- (g.target === s || s.classList.contains("imp-ad--paused")) && n.paused && n.play().catch(() => {
407
+ i.classList.remove("imp-ad--paused"), B && (B = !1, C(t.tracking.resume), this.host.emitter.emit("adresume", { ad: t }));
408
+ }, { signal: a }), i.addEventListener("click", (g) => {
409
+ (g.target === i || i.classList.contains("imp-ad--paused")) && n.paused && n.play().catch(() => {
410
410
  });
411
411
  }), n.play().catch(() => {
412
- s.classList.add("imp-ad--paused");
412
+ i.classList.add("imp-ad--paused");
413
413
  });
414
414
  });
415
415
  }
@@ -422,20 +422,20 @@ class lt {
422
422
  }
423
423
  }
424
424
  function at(r, t) {
425
- const e = [...r].sort((s, n) => s.start - n.start), i = [];
426
- for (let s = 0; s < e.length; s++) {
427
- const n = Math.max(0, e[s].start);
425
+ const e = [...r].sort((i, n) => i.start - n.start), s = [];
426
+ for (let i = 0; i < e.length; i++) {
427
+ const n = Math.max(0, e[i].start);
428
428
  if (Number.isFinite(t) && n >= t) continue;
429
- let o = e[s].end ?? e[s + 1]?.start ?? t;
430
- Number.isFinite(t) && (o = Math.min(o, t)), !(o <= n) && i.push({ start: n, end: o, title: e[s].title });
429
+ let o = e[i].end ?? e[i + 1]?.start ?? t;
430
+ Number.isFinite(t) && (o = Math.min(o, t)), !(o <= n) && s.push({ start: n, end: o, title: e[i].title });
431
431
  }
432
- return i;
432
+ return s;
433
433
  }
434
434
  async function ht(r) {
435
435
  const t = await fetch(r);
436
436
  if (!t.ok) throw new Error(`Failed to load chapters VTT (${t.status})`);
437
437
  const e = await t.text();
438
- return U(e).map((i) => ({ start: i.start, end: i.end, title: i.text }));
438
+ return U(e).map((s) => ({ start: s.start, end: s.end, title: s.text }));
439
439
  }
440
440
  function K(r, t) {
441
441
  for (const e of r)
@@ -452,16 +452,16 @@ async function dt() {
452
452
  if (r)
453
453
  return S = r, S;
454
454
  try {
455
- S = (await import("hls.js")).default;
455
+ S = (await import("hls.js/light")).default;
456
456
  } catch {
457
457
  S = null;
458
458
  }
459
459
  return S;
460
460
  }
461
- async function ut(r, t, e, i) {
461
+ async function ut(r, t, e, s) {
462
462
  if (ct(t, e)) {
463
- const s = r.canPlayType("application/vnd.apple.mpegurl"), n = s ? null : await dt();
464
- return n && n.isSupported() ? pt(n, r, t, i) : s ? (r.src = t, $(r)) : (i.onError("HLS is not supported in this browser and hls.js could not be loaded."), $(r));
463
+ const i = r.canPlayType("application/vnd.apple.mpegurl"), n = i ? null : await dt();
464
+ return n && n.isSupported() ? pt(n, r, t, s) : i ? (r.src = t, $(r)) : (s.onError("HLS is not supported in this browser and hls.js could not be loaded."), $(r));
465
465
  }
466
466
  return r.src = t, $(r);
467
467
  }
@@ -477,50 +477,50 @@ function $(r) {
477
477
  }
478
478
  };
479
479
  }
480
- function pt(r, t, e, i) {
481
- const s = new r({ enableWorker: !0 }), n = {
480
+ function pt(r, t, e, s) {
481
+ const i = new r({ enableWorker: !0 }), n = {
482
482
  kind: "hls",
483
483
  levels: [],
484
484
  selected: -1,
485
- setLevel(h) {
486
- n.selected = h, s.currentLevel = h;
485
+ setLevel(c) {
486
+ n.selected = c, i.currentLevel = c;
487
487
  },
488
488
  destroy() {
489
- s.destroy(), t.removeAttribute("src"), t.load();
489
+ i.destroy(), t.removeAttribute("src"), t.load();
490
490
  }
491
491
  };
492
- s.on(r.Events.MANIFEST_PARSED, () => {
493
- n.levels = s.levels.map((h, c) => ({
494
- index: c,
495
- label: h.height ? `${h.height}p` : `${Math.round(h.bitrate / 1e3)} kbps`
496
- })).reverse(), i.onLevels(n.levels);
497
- }), s.on(r.Events.LEVEL_SWITCHED, (h, c) => {
498
- const u = s.levels[c.level];
499
- u && i.onLevelSwitch(u.height ? `${u.height}p` : `${Math.round(u.bitrate / 1e3)} kbps`);
492
+ i.on(r.Events.MANIFEST_PARSED, () => {
493
+ n.levels = i.levels.map((c, h) => ({
494
+ index: h,
495
+ label: c.height ? `${c.height}p` : `${Math.round(c.bitrate / 1e3)} kbps`
496
+ })).reverse(), s.onLevels(n.levels);
497
+ }), i.on(r.Events.LEVEL_SWITCHED, (c, h) => {
498
+ const u = i.levels[h.level];
499
+ u && s.onLevelSwitch(u.height ? `${u.height}p` : `${Math.round(u.bitrate / 1e3)} kbps`);
500
500
  });
501
501
  let o = 0, a = !1;
502
- return s.on(r.Events.ERROR, (h, c) => {
503
- if (c.fatal)
504
- switch (c.type) {
502
+ return i.on(r.Events.ERROR, (c, h) => {
503
+ if (h.fatal)
504
+ switch (h.type) {
505
505
  case r.ErrorTypes.NETWORK_ERROR:
506
- s.startLoad();
506
+ i.startLoad();
507
507
  break;
508
508
  case r.ErrorTypes.MEDIA_ERROR:
509
- o < 3 ? (o++, s.recoverMediaError()) : (i.onError(`HLS media error: ${c.details}`, c), s.destroy());
509
+ o < 3 ? (o++, i.recoverMediaError()) : (s.onError(`HLS media error: ${h.details}`, h), i.destroy());
510
510
  break;
511
511
  default:
512
512
  if (a)
513
- i.onError(`HLS fatal error: ${c.details}`, c), s.destroy();
513
+ s.onError(`HLS fatal error: ${h.details}`, h), i.destroy();
514
514
  else {
515
515
  a = !0;
516
516
  try {
517
- s.loadSource(e), s.startLoad();
517
+ i.loadSource(e), i.startLoad();
518
518
  } catch {
519
- i.onError(`HLS fatal error: ${c.details}`, c), s.destroy();
519
+ s.onError(`HLS fatal error: ${h.details}`, h), i.destroy();
520
520
  }
521
521
  }
522
522
  }
523
- }), s.loadSource(e), s.attachMedia(t), n;
523
+ }), i.loadSource(e), i.attachMedia(t), n;
524
524
  }
525
525
  class q {
526
526
  constructor(t) {
@@ -529,25 +529,25 @@ class q {
529
529
  static async load(t) {
530
530
  const e = await fetch(t);
531
531
  if (!e.ok) throw new Error(`Failed to load thumbnails VTT (${e.status})`);
532
- const i = await e.text(), s = [];
533
- for (const n of U(i)) {
532
+ const s = await e.text(), i = [];
533
+ for (const n of U(s)) {
534
534
  const [o, a] = n.text.trim().split("#");
535
535
  if (!o) continue;
536
- const h = {
536
+ const c = {
537
537
  start: n.start,
538
538
  end: n.end,
539
539
  src: G(o, t)
540
- }, c = a?.match(/xywh=(\d+),(\d+),(\d+),(\d+)/);
541
- c && (h.xywh = { x: Number(c[1]), y: Number(c[2]), w: Number(c[3]), h: Number(c[4]) }), s.push(h);
540
+ }, h = a?.match(/xywh=(\d+),(\d+),(\d+),(\d+)/);
541
+ h && (c.xywh = { x: Number(h[1]), y: Number(h[2]), w: Number(h[3]), h: Number(h[4]) }), i.push(c);
542
542
  }
543
- return s.sort((n, o) => n.start - o.start), new q(s);
543
+ return i.sort((n, o) => n.start - o.start), new q(i);
544
544
  }
545
545
  cueAt(t) {
546
- let e = 0, i = this.cues.length - 1;
547
- for (; e <= i; ) {
548
- const s = e + i >> 1, n = this.cues[s];
549
- if (t < n.start) i = s - 1;
550
- else if (t >= n.end) e = s + 1;
546
+ let e = 0, s = this.cues.length - 1;
547
+ for (; e <= s; ) {
548
+ const i = e + s >> 1, n = this.cues[i];
549
+ if (t < n.start) s = i - 1;
550
+ else if (t >= n.end) e = i + 1;
551
551
  else return n;
552
552
  }
553
553
  return null;
@@ -569,27 +569,27 @@ class M {
569
569
  this.root.textContent = "";
570
570
  for (const e of t) {
571
571
  if (e.items.length === 0) continue;
572
- const i = l("div", "imp-menu__section");
572
+ const s = l("div", "imp-menu__section");
573
573
  if (e.title) {
574
- const s = l("div", "imp-menu__title");
575
- s.textContent = e.title, i.append(s);
574
+ const i = l("div", "imp-menu__title");
575
+ i.textContent = e.title, s.append(i);
576
576
  }
577
- for (const s of e.items) {
577
+ for (const i of e.items) {
578
578
  const n = l("button", "imp-menu__item", { type: "button", role: "menuitemradio" });
579
- if (n.setAttribute("aria-checked", String(s.active)), s.active && n.classList.add("imp-menu__item--active"), s.icon) {
579
+ if (n.setAttribute("aria-checked", String(i.active)), i.active && n.classList.add("imp-menu__item--active"), i.icon) {
580
580
  const a = l("span", "imp-menu__icon");
581
- s.icon.trimStart().startsWith("<svg") ? a.innerHTML = s.icon : a.append(l("img", "", { src: s.icon, alt: "" })), n.append(a);
581
+ i.icon.trimStart().startsWith("<svg") ? a.innerHTML = i.icon : a.append(l("img", "", { src: i.icon, alt: "" })), n.append(a);
582
582
  }
583
583
  const o = l("span", "imp-menu__label");
584
- o.textContent = s.label, n.append(o), n.addEventListener("click", () => {
585
- e.onSelect(s.value), this.close();
586
- }), i.append(n);
584
+ o.textContent = i.label, n.append(o), n.addEventListener("click", () => {
585
+ e.onSelect(i.value), this.close();
586
+ }), s.append(n);
587
587
  }
588
- this.root.append(i);
588
+ this.root.append(s);
589
589
  }
590
590
  this.root.hidden = !1, this.backdrop.hidden = !1, this.outsideListener = (e) => {
591
- const i = e.target;
592
- !this.root.contains(i) && !this.anchor.contains(i) && this.close();
591
+ const s = e.target;
592
+ !this.root.contains(s) && !this.anchor.contains(s) && this.close();
593
593
  }, setTimeout(() => {
594
594
  this.outsideListener && document.addEventListener("pointerdown", this.outsideListener);
595
595
  }, 0);
@@ -618,12 +618,12 @@ class mt {
618
618
  }
619
619
  setChapters(t) {
620
620
  this.chapters = t, this.track.textContent = "", this.segments = [];
621
- const e = t.length > 0 ? t : [{ start: 0, end: this.duration || 1, title: "" }], i = [];
622
- let s = 0;
621
+ const e = t.length > 0 ? t : [{ start: 0, end: this.duration || 1, title: "" }], s = [];
622
+ let i = 0;
623
623
  for (const n of e)
624
- n.start > s && i.push({ start: s, end: n.start, title: "" }), i.push(n), s = n.end;
625
- this.duration > 0 && s < this.duration && i.push({ start: s, end: this.duration, title: "" });
626
- for (const n of i) {
624
+ n.start > i && s.push({ start: i, end: n.start, title: "" }), s.push(n), i = n.end;
625
+ this.duration > 0 && i < this.duration && s.push({ start: i, end: this.duration, title: "" });
626
+ for (const n of s) {
627
627
  const o = l("div", "imp-progress__segment");
628
628
  o.style.flexGrow = String(Math.max(n.end - n.start, 0.01));
629
629
  const a = l("div", "imp-progress__fill");
@@ -633,16 +633,16 @@ class mt {
633
633
  setThumbnails(t) {
634
634
  this.thumbnails = t;
635
635
  }
636
- update(t, e, i) {
636
+ update(t, e, s) {
637
637
  if (e !== this.duration && Number.isFinite(e) && this.setDuration(e), this.scrubbing) return;
638
638
  this.render(t);
639
- const s = this.duration > 0 ? y(i / this.duration, 0, 1) : 0;
640
- this.buffered.style.width = `${s * 100}%`, this.root.setAttribute("aria-valuemin", "0"), this.root.setAttribute("aria-valuemax", String(Math.round(this.duration))), this.root.setAttribute("aria-valuenow", String(Math.round(t))), this.root.setAttribute("aria-valuetext", `${w(t)} / ${w(this.duration)}`);
639
+ const i = this.duration > 0 ? y(s / this.duration, 0, 1) : 0;
640
+ this.buffered.style.width = `${i * 100}%`, this.root.setAttribute("aria-valuemin", "0"), this.root.setAttribute("aria-valuemax", String(Math.round(this.duration))), this.root.setAttribute("aria-valuenow", String(Math.round(t))), this.root.setAttribute("aria-valuetext", `${w(t)} / ${w(this.duration)}`);
641
641
  }
642
642
  render(t) {
643
- for (const { chapter: i, fill: s } of this.segments) {
644
- const n = i.end - i.start, o = n > 0 ? y((t - i.start) / n, 0, 1) : 0;
645
- s.style.transform = `scaleX(${o})`;
643
+ for (const { chapter: s, fill: i } of this.segments) {
644
+ const n = s.end - s.start, o = n > 0 ? y((t - s.start) / n, 0, 1) : 0;
645
+ i.style.transform = `scaleX(${o})`;
646
646
  }
647
647
  const e = this.duration > 0 ? y(t / this.duration, 0, 1) : 0;
648
648
  this.handle.style.left = `${e * 100}%`;
@@ -665,10 +665,10 @@ class mt {
665
665
  showTooltip(t) {
666
666
  const e = this.timeFromEvent(t);
667
667
  this.tooltipTime.textContent = w(e);
668
- const i = K(this.chapters, e);
669
- this.tooltipChapter.textContent = i?.title ?? "", this.tooltipChapter.hidden = !i?.title;
670
- const s = this.thumbnails?.cueAt(e) ?? null;
671
- s ? (this.tooltipThumb.hidden = !1, this.tooltipThumb.style.backgroundImage = `url("${s.src}")`, s.xywh ? (this.tooltipThumb.style.width = `${s.xywh.w}px`, this.tooltipThumb.style.height = `${s.xywh.h}px`, this.tooltipThumb.style.backgroundPosition = `-${s.xywh.x}px -${s.xywh.y}px`, this.tooltipThumb.style.backgroundSize = "auto") : (this.tooltipThumb.style.width = "160px", this.tooltipThumb.style.height = "90px", this.tooltipThumb.style.backgroundPosition = "center", this.tooltipThumb.style.backgroundSize = "cover")) : this.tooltipThumb.hidden = !0, this.tooltip.classList.add("imp-progress__tooltip--visible");
668
+ const s = K(this.chapters, e);
669
+ this.tooltipChapter.textContent = s?.title ?? "", this.tooltipChapter.hidden = !s?.title;
670
+ const i = this.thumbnails?.cueAt(e) ?? null;
671
+ i ? (this.tooltipThumb.hidden = !1, this.tooltipThumb.style.backgroundImage = `url("${i.src}")`, i.xywh ? (this.tooltipThumb.style.width = `${i.xywh.w}px`, this.tooltipThumb.style.height = `${i.xywh.h}px`, this.tooltipThumb.style.backgroundPosition = `-${i.xywh.x}px -${i.xywh.y}px`, this.tooltipThumb.style.backgroundSize = "auto") : (this.tooltipThumb.style.width = "160px", this.tooltipThumb.style.height = "90px", this.tooltipThumb.style.backgroundPosition = "center", this.tooltipThumb.style.backgroundSize = "cover")) : this.tooltipThumb.hidden = !0, this.tooltip.classList.add("imp-progress__tooltip--visible");
672
672
  const n = this.root.getBoundingClientRect(), o = y(t.clientX - n.left, 0, n.width), a = this.tooltip.offsetWidth / 2;
673
673
  this.tooltip.style.left = `${y(o, a, Math.max(a, n.width - a))}px`;
674
674
  }
@@ -679,7 +679,7 @@ class mt {
679
679
  const _ = class _ {
680
680
  constructor(t) {
681
681
  this.player = t, this.subtitlesBtn = null, this.settingsBtn = null, this.settingsMenu = null, this.subtitlesMenu = null, this.moreMenu = null, this.moreWrap = null, this.qualityBtn = null, this.qualityMenu = null, this.scenesBtn = null, this.likeBtn = null, this.dislikeBtn = null, this.likeCountEl = null, this.dislikeCountEl = null, this.prevBtn = null, this.nextBtn = null, this.seekBackBtn = null, this.seekFwdBtn = null, this.centerPlayBtn = null, this.centerPrevBtn = null, this.centerNextBtn = null, this.collapsibles = [], this.overflowed = /* @__PURE__ */ new Set(), this.resizeObserver = null, this.reflowScheduled = !1, this.actionItems = [], this.wasPlayingBeforeScrub = !1, this.disposers = [], this.onWindowResize = null;
682
- const { labels: e, icons: i } = t, s = t.controlsOptions;
682
+ const { labels: e, icons: s } = t, i = t.controlsOptions;
683
683
  this.root = l("div", "imp-controls"), this.progress = new mt({
684
684
  onSeek: (d) => t.seek(d),
685
685
  onScrubStart: () => {
@@ -688,17 +688,17 @@ const _ = class _ {
688
688
  onScrubEnd: () => {
689
689
  this.wasPlayingBeforeScrub && t.play();
690
690
  }
691
- }), s.progress && this.root.append(this.progress.root);
691
+ }), i.progress && this.root.append(this.progress.root);
692
692
  const n = l("div", "imp-controls__row");
693
693
  this.row = n, this.root.append(n);
694
694
  const o = l("div", "imp-controls__group"), a = l("div", "imp-controls__group");
695
695
  this.rightGroup = a;
696
- const h = l("div", "imp-controls__spacer");
697
- this.chapterLabel = l("div", "imp-controls__chapter"), n.append(o, h, a), h.append(this.chapterLabel);
698
- const c = typeof s.seekButtons == "object" ? s.seekButtons : {}, u = c.back ?? t.seekStep, f = c.forward ?? t.seekStep;
699
- if (s.playlist && t.hasPlaylist && (this.prevBtn = m("imp-btn--prev", e.previous, i.previous), this.prevBtn.addEventListener("click", () => t.previous()), o.append(this.prevBtn)), s.seekButtons && (this.seekBackBtn = m("imp-btn--seek-back", `${e.seekBack} ${u}s`, i.seekBack), this.seekBackBtn.addEventListener("click", () => t.skip(-u)), o.append(this.seekBackBtn)), s.play && (this.playBtn = m("imp-btn--play", e.play, i.play), this.playBtn.addEventListener("click", () => t.togglePlay()), o.append(this.playBtn)), s.seekButtons && (this.seekFwdBtn = m("imp-btn--seek-forward", `${e.seekForward} ${f}s`, i.seekForward), this.seekFwdBtn.addEventListener("click", () => t.skip(f)), o.append(this.seekFwdBtn)), s.playlist && t.hasPlaylist && (this.nextBtn = m("imp-btn--next", e.next, i.next), this.nextBtn.addEventListener("click", () => t.next()), o.append(this.nextBtn)), s.volume) {
696
+ const c = l("div", "imp-controls__spacer");
697
+ this.chapterLabel = l("div", "imp-controls__chapter"), n.append(o, c, a), c.append(this.chapterLabel);
698
+ const h = typeof i.seekButtons == "object" ? i.seekButtons : {}, u = h.back ?? t.seekStep, f = h.forward ?? t.seekStep;
699
+ if (i.playlist && t.hasPlaylist && (this.prevBtn = m("imp-btn--prev", e.previous, s.previous), this.prevBtn.addEventListener("click", () => t.previous()), o.append(this.prevBtn)), i.seekButtons && (this.seekBackBtn = m("imp-btn--seek-back", `${e.seekBack} ${u}s`, s.seekBack), this.seekBackBtn.addEventListener("click", () => t.skip(-u)), o.append(this.seekBackBtn)), i.play && (this.playBtn = m("imp-btn--play", e.play, s.play), this.playBtn.addEventListener("click", () => t.togglePlay()), o.append(this.playBtn)), i.seekButtons && (this.seekFwdBtn = m("imp-btn--seek-forward", `${e.seekForward} ${f}s`, s.seekForward), this.seekFwdBtn.addEventListener("click", () => t.skip(f)), o.append(this.seekFwdBtn)), i.playlist && t.hasPlaylist && (this.nextBtn = m("imp-btn--next", e.next, s.next), this.nextBtn.addEventListener("click", () => t.next()), o.append(this.nextBtn)), i.volume) {
700
700
  const d = l("div", "imp-volume");
701
- this.muteBtn = m("imp-btn--mute", e.mute, i.volumeHigh), this.muteBtn.addEventListener("click", () => t.toggleMute()), this.volumeSlider = l("input", "imp-volume__slider", {
701
+ this.muteBtn = m("imp-btn--mute", e.mute, s.volumeHigh), this.muteBtn.addEventListener("click", () => t.toggleMute()), this.volumeSlider = l("input", "imp-volume__slider", {
702
702
  type: "range",
703
703
  min: "0",
704
704
  max: "1",
@@ -708,8 +708,8 @@ const _ = class _ {
708
708
  t.setVolume(Number(this.volumeSlider.value));
709
709
  }), d.append(this.muteBtn, this.volumeSlider), o.append(d);
710
710
  }
711
- if (s.time && (this.timeLabel = l("div", "imp-controls__time"), this.liveBadge = l("span", "imp-controls__live"), this.liveBadge.textContent = e.live, this.liveBadge.hidden = !0, o.append(this.timeLabel, this.liveBadge)), this.buildLikeDislike(a), s.subtitles) {
712
- this.subtitlesBtn = m("imp-btn--subtitles", e.subtitles, i.subtitles), this.subtitlesMenu = new M(this.subtitlesBtn);
711
+ if (i.time && (this.timeLabel = l("div", "imp-controls__time"), this.liveBadge = l("span", "imp-controls__live"), this.liveBadge.textContent = e.live, this.liveBadge.hidden = !0, o.append(this.timeLabel, this.liveBadge)), this.buildLikeDislike(a), i.subtitles) {
712
+ this.subtitlesBtn = m("imp-btn--subtitles", e.subtitles, s.subtitles), this.subtitlesMenu = new M(this.subtitlesBtn);
713
713
  const d = l("div", "imp-controls__menu-anchor");
714
714
  d.append(this.subtitlesBtn, this.subtitlesMenu.root), this.subtitlesBtn.addEventListener("click", () => this.toggleSubtitlesMenu()), a.append(d), this.registerCollapsible({
715
715
  key: "subtitles",
@@ -719,8 +719,8 @@ const _ = class _ {
719
719
  section: () => this.subtitlesSection()
720
720
  });
721
721
  }
722
- if (s.settings) {
723
- this.settingsBtn = m("imp-btn--settings", e.settings, i.speed), this.settingsMenu = new M(this.settingsBtn);
722
+ if (i.settings) {
723
+ this.settingsBtn = m("imp-btn--settings", e.settings, s.speed), this.settingsMenu = new M(this.settingsBtn);
724
724
  const d = l("div", "imp-controls__menu-anchor");
725
725
  d.append(this.settingsBtn, this.settingsMenu.root), this.settingsBtn.addEventListener("click", () => this.toggleSettingsMenu()), a.append(d), this.registerCollapsible({
726
726
  key: "settings",
@@ -730,8 +730,8 @@ const _ = class _ {
730
730
  section: () => this.speedSection()
731
731
  });
732
732
  }
733
- if (s.quality) {
734
- this.qualityBtn = m("imp-btn--quality", e.quality, i.settings), this.qualityMenu = new M(this.qualityBtn);
733
+ if (i.quality) {
734
+ this.qualityBtn = m("imp-btn--quality", e.quality, s.settings), this.qualityMenu = new M(this.qualityBtn);
735
735
  const d = l("div", "imp-controls__menu-anchor");
736
736
  d.append(this.qualityBtn, this.qualityMenu.root), this.qualityBtn.addEventListener("click", () => this.toggleQualityMenu()), a.append(d), this.registerCollapsible({
737
737
  key: "quality",
@@ -741,44 +741,44 @@ const _ = class _ {
741
741
  section: () => this.qualitySection()
742
742
  });
743
743
  }
744
- if (s.scenes && (this.scenesBtn = m("imp-btn--scenes", e.scenes, i.scenes), this.scenesBtn.addEventListener("click", () => t.toggleScenesPanel()), a.append(this.scenesBtn), this.registerCollapsible({
744
+ if (i.scenes && (this.scenesBtn = m("imp-btn--scenes", e.scenes, s.scenes), this.scenesBtn.addEventListener("click", () => t.toggleScenesPanel()), a.append(this.scenesBtn), this.registerCollapsible({
745
745
  key: "scenes",
746
746
  el: this.scenesBtn,
747
747
  priority: 25,
748
748
  available: () => t.chapterList.length > 0,
749
- section: () => this.simpleSection("scenes", e.scenes, i.scenes, () => t.toggleScenesPanel())
750
- })), s.playlist && t.hasPlaylist) {
751
- const d = m("imp-btn--list", e.playlist, i.list);
749
+ section: () => this.simpleSection("scenes", e.scenes, s.scenes, () => t.toggleScenesPanel())
750
+ })), i.playlist && t.hasPlaylist) {
751
+ const d = m("imp-btn--list", e.playlist, s.list);
752
752
  d.addEventListener("click", () => t.togglePlaylistPanel()), a.append(d), this.registerCollapsible({
753
753
  key: "list",
754
754
  el: d,
755
755
  priority: 50,
756
756
  available: () => !0,
757
- section: () => this.simpleSection("list", e.playlist, i.list, () => t.togglePlaylistPanel())
757
+ section: () => this.simpleSection("list", e.playlist, s.list, () => t.togglePlaylistPanel())
758
758
  });
759
759
  }
760
- if (s.pip && "requestPictureInPicture" in HTMLVideoElement.prototype) {
761
- const d = m("imp-btn--pip", e.pip, i.pip);
760
+ if (i.pip && "requestPictureInPicture" in HTMLVideoElement.prototype) {
761
+ const d = m("imp-btn--pip", e.pip, s.pip);
762
762
  d.addEventListener("click", () => void t.togglePip()), a.append(d), this.registerCollapsible({
763
763
  key: "pip",
764
764
  el: d,
765
765
  priority: 20,
766
766
  available: () => !0,
767
- section: () => this.simpleSection("pip", e.pip, i.pip, () => void t.togglePip())
767
+ section: () => this.simpleSection("pip", e.pip, s.pip, () => void t.togglePip())
768
768
  });
769
769
  }
770
- if (s.fullscreen && (this.fullscreenBtn = m("imp-btn--fullscreen", e.fullscreen, i.fullscreen), this.fullscreenBtn.addEventListener("click", () => void t.toggleFullscreen()), a.append(this.fullscreenBtn)), this.prevBtn && this.registerCollapsible({
770
+ if (i.fullscreen && (this.fullscreenBtn = m("imp-btn--fullscreen", e.fullscreen, s.fullscreen), this.fullscreenBtn.addEventListener("click", () => void t.toggleFullscreen()), a.append(this.fullscreenBtn)), this.prevBtn && this.registerCollapsible({
771
771
  key: "prev",
772
772
  el: this.prevBtn,
773
773
  priority: 70,
774
774
  available: () => !0,
775
- section: () => t.hasPrevious ? this.simpleSection("prev", e.previous, i.previous, () => t.previous()) : null
775
+ section: () => t.hasPrevious ? this.simpleSection("prev", e.previous, s.previous, () => t.previous()) : null
776
776
  }), this.nextBtn && this.registerCollapsible({
777
777
  key: "next",
778
778
  el: this.nextBtn,
779
779
  priority: 72,
780
780
  available: () => !0,
781
- section: () => t.hasNext ? this.simpleSection("next", e.next, i.next, () => t.next()) : null
781
+ section: () => t.hasNext ? this.simpleSection("next", e.next, s.next, () => t.next()) : null
782
782
  }), this.seekBackBtn) {
783
783
  const d = this.seekBackBtn;
784
784
  this.registerCollapsible({
@@ -786,7 +786,7 @@ const _ = class _ {
786
786
  el: d,
787
787
  priority: 80,
788
788
  available: () => Number.isFinite(t.duration) && t.duration > 0,
789
- section: () => this.simpleSection("seekBack", `${e.seekBack} ${u}s`, i.seekBack, () => t.skip(-u))
789
+ section: () => this.simpleSection("seekBack", `${e.seekBack} ${u}s`, s.seekBack, () => t.skip(-u))
790
790
  });
791
791
  }
792
792
  if (this.seekFwdBtn) {
@@ -796,64 +796,64 @@ const _ = class _ {
796
796
  el: d,
797
797
  priority: 82,
798
798
  available: () => Number.isFinite(t.duration) && t.duration > 0,
799
- section: () => this.simpleSection("seekFwd", `${e.seekForward} ${f}s`, i.seekForward, () => t.skip(f))
799
+ section: () => this.simpleSection("seekFwd", `${e.seekForward} ${f}s`, s.seekForward, () => t.skip(f))
800
800
  });
801
801
  }
802
- if (this.center = l("div", "imp-center-controls"), s.playlist && t.hasPlaylist && (this.centerPrevBtn = this.makeCenterButton("prev", e.previous, i.previous), this.centerPrevBtn.addEventListener("click", () => t.previous()), this.center.append(this.centerPrevBtn)), s.seekButtons) {
803
- const d = this.makeCenterButton("seek-back", `${e.seekBack} ${u}s`, i.seekBack);
802
+ if (this.center = l("div", "imp-center-controls"), i.playlist && t.hasPlaylist && (this.centerPrevBtn = this.makeCenterButton("prev", e.previous, s.previous), this.centerPrevBtn.addEventListener("click", () => t.previous()), this.center.append(this.centerPrevBtn)), i.seekButtons) {
803
+ const d = this.makeCenterButton("seek-back", `${e.seekBack} ${u}s`, s.seekBack);
804
804
  d.addEventListener("click", () => t.skip(-u)), this.center.append(d);
805
805
  }
806
- if (s.play && (this.centerPlayBtn = this.makeCenterButton("play", e.play, i.play), this.centerPlayBtn.addEventListener("click", () => t.togglePlay()), this.center.append(this.centerPlayBtn)), s.seekButtons) {
807
- const d = this.makeCenterButton("seek-forward", `${e.seekForward} ${f}s`, i.seekForward);
806
+ if (i.play && (this.centerPlayBtn = this.makeCenterButton("play", e.play, s.play), this.centerPlayBtn.addEventListener("click", () => t.togglePlay()), this.center.append(this.centerPlayBtn)), i.seekButtons) {
807
+ const d = this.makeCenterButton("seek-forward", `${e.seekForward} ${f}s`, s.seekForward);
808
808
  d.addEventListener("click", () => t.skip(f)), this.center.append(d);
809
809
  }
810
- s.playlist && t.hasPlaylist && (this.centerNextBtn = this.makeCenterButton("next", e.next, i.next), this.centerNextBtn.addEventListener("click", () => t.next()), this.center.append(this.centerNextBtn)), this.center.style.display = "none", this.buildMoreDropdown(a), this.bind(), this.syncVolume(), this.syncPlayState(), this.setLikeState(t.actionsOptions.likeState ?? null), typeof ResizeObserver < "u" && (this.resizeObserver = new ResizeObserver(() => this.scheduleReflow()), this.resizeObserver.observe(t.container)), this.onWindowResize = () => this.scheduleReflow(), window.addEventListener("resize", this.onWindowResize);
810
+ i.playlist && t.hasPlaylist && (this.centerNextBtn = this.makeCenterButton("next", e.next, s.next), this.centerNextBtn.addEventListener("click", () => t.next()), this.center.append(this.centerNextBtn)), this.center.style.display = "none", this.buildMoreDropdown(a), this.bind(), this.syncVolume(), this.syncPlayState(), this.setLikeState(t.actionsOptions.likeState ?? null), typeof ResizeObserver < "u" && (this.resizeObserver = new ResizeObserver(() => this.scheduleReflow()), this.resizeObserver.observe(t.container)), this.onWindowResize = () => this.scheduleReflow(), window.addEventListener("resize", this.onWindowResize);
811
811
  }
812
812
  registerCollapsible(t) {
813
813
  this.collapsibles.push(t);
814
814
  }
815
815
  /** Center-cluster button — deliberately NOT `.imp-btn` (own sizing/look). */
816
- makeCenterButton(t, e, i) {
817
- const s = l("button", `imp-center-btn imp-center-btn--${t}`, { type: "button", "aria-label": e, title: e });
818
- return s.innerHTML = i, s;
816
+ makeCenterButton(t, e, s) {
817
+ const i = l("button", `imp-center-btn imp-center-btn--${t}`, { type: "button", "aria-label": e, title: e });
818
+ return i.innerHTML = s, i;
819
819
  }
820
820
  /** like/dislike — visible buttons (collapsible), highlightable via `setLikeState`. */
821
821
  buildLikeDislike(t) {
822
- const e = this.player, i = e.actionsOptions, { labels: s, icons: n } = e;
823
- if (i.like) {
824
- this.likeBtn = m("imp-btn--like", s.like, n.like), this.likeBtn.addEventListener("click", () => e.emit("action", { id: "like" })), this.likeCountEl = this.attachCountTooltip(this.likeBtn, i.likeCount);
822
+ const e = this.player, s = e.actionsOptions, { labels: i, icons: n } = e;
823
+ if (s.like) {
824
+ this.likeBtn = m("imp-btn--like", i.like, n.like), this.likeBtn.addEventListener("click", () => e.emit("action", { id: "like" })), this.likeCountEl = this.attachCountTooltip(this.likeBtn, s.likeCount);
825
825
  const o = this.wrapWithTooltip(this.likeBtn, this.likeCountEl);
826
826
  t.append(o), this.registerCollapsible({
827
827
  key: "like",
828
828
  el: o,
829
829
  priority: 62,
830
830
  available: () => !0,
831
- section: () => this.simpleSection("like", s.like, n.like, () => e.emit("action", { id: "like" }))
831
+ section: () => this.simpleSection("like", i.like, n.like, () => e.emit("action", { id: "like" }))
832
832
  });
833
833
  }
834
- if (i.dislike) {
835
- this.dislikeBtn = m("imp-btn--dislike", s.dislike, n.dislike), this.dislikeBtn.addEventListener("click", () => e.emit("action", { id: "dislike" })), this.dislikeCountEl = this.attachCountTooltip(this.dislikeBtn, i.dislikeCount);
834
+ if (s.dislike) {
835
+ this.dislikeBtn = m("imp-btn--dislike", i.dislike, n.dislike), this.dislikeBtn.addEventListener("click", () => e.emit("action", { id: "dislike" })), this.dislikeCountEl = this.attachCountTooltip(this.dislikeBtn, s.dislikeCount);
836
836
  const o = this.wrapWithTooltip(this.dislikeBtn, this.dislikeCountEl);
837
837
  t.append(o), this.registerCollapsible({
838
838
  key: "dislike",
839
839
  el: o,
840
840
  priority: 60,
841
841
  available: () => !0,
842
- section: () => this.simpleSection("dislike", s.dislike, n.dislike, () => e.emit("action", { id: "dislike" }))
842
+ section: () => this.simpleSection("dislike", i.dislike, n.dislike, () => e.emit("action", { id: "dislike" }))
843
843
  });
844
844
  }
845
845
  }
846
846
  attachCountTooltip(t, e) {
847
- const i = l("span", "imp-count-tooltip");
848
- return this.setCountText(i, e), i;
847
+ const s = l("span", "imp-count-tooltip");
848
+ return this.setCountText(s, e), s;
849
849
  }
850
850
  wrapWithTooltip(t, e) {
851
- const i = l("div", "imp-action");
852
- return i.append(t, e), i;
851
+ const s = l("div", "imp-action");
852
+ return s.append(t, e), s;
853
853
  }
854
854
  setCountText(t, e) {
855
- const i = e == null || e === "" ? "" : String(e);
856
- t.textContent = i, t.hidden = i === "";
855
+ const s = e == null || e === "" ? "" : String(e);
856
+ t.textContent = s, t.hidden = s === "";
857
857
  }
858
858
  setLikeCounts(t, e) {
859
859
  this.likeCountEl && t !== void 0 && this.setCountText(this.likeCountEl, t), this.dislikeCountEl && e !== void 0 && this.setCountText(this.dislikeCountEl, e);
@@ -863,11 +863,11 @@ const _ = class _ {
863
863
  }
864
864
  // === ⋯ menu ===========================================================
865
865
  buildMoreDropdown(t) {
866
- const e = this.player, i = e.actionsOptions, { labels: s, icons: n } = e;
867
- i.addTo && this.actionItems.push({ value: "addTo", label: s.addTo, icon: n.addTo, run: () => e.emit("action", { id: "addTo" }) }), i.share && this.actionItems.push({ value: "share", label: s.share, icon: n.share, run: () => void e.share() }), i.report && this.actionItems.push({ value: "report", label: s.report, icon: n.report, run: () => e.emit("action", { id: "report" }) });
868
- for (const h of i.custom ?? [])
869
- this.actionItems.push({ value: `custom:${h.id}`, label: h.title, icon: h.icon, run: () => e.emit("customaction", { id: h.id }) });
870
- const o = m("imp-btn--more", s.more, n.more);
866
+ const e = this.player, s = e.actionsOptions, { labels: i, icons: n } = e;
867
+ s.addTo && this.actionItems.push({ value: "addTo", label: i.addTo, icon: n.addTo, run: () => e.emit("action", { id: "addTo" }) }), s.share && this.actionItems.push({ value: "share", label: i.share, icon: n.share, run: () => void e.share() }), s.report && this.actionItems.push({ value: "report", label: i.report, icon: n.report, run: () => e.emit("action", { id: "report" }) });
868
+ for (const c of s.custom ?? [])
869
+ this.actionItems.push({ value: `custom:${c.id}`, label: c.title, icon: c.icon, run: () => e.emit("customaction", { id: c.id }) });
870
+ const o = m("imp-btn--more", i.more, n.more);
871
871
  this.moreMenu = new M(o);
872
872
  const a = l("div", "imp-controls__menu-anchor imp-controls__more");
873
873
  a.append(o, this.moreMenu.root), o.addEventListener("click", () => {
@@ -876,28 +876,28 @@ const _ = class _ {
876
876
  }
877
877
  /** ⋯ menu = overflowed controls (in display order) + consumer actions. */
878
878
  buildMoreSections() {
879
- const t = [], e = /* @__PURE__ */ new Map(), i = [], s = ["prev", "next", "seekBack", "seekFwd", "like", "dislike", "scenes", "pip", "list", "subtitles", "settings", "quality"], n = this.collapsibles.filter((o) => this.overflowed.has(o.key) && o.available()).sort((o, a) => s.indexOf(o.key) - s.indexOf(a.key));
879
+ const t = [], e = /* @__PURE__ */ new Map(), s = [], i = ["prev", "next", "seekBack", "seekFwd", "like", "dislike", "scenes", "pip", "list", "subtitles", "settings", "quality"], n = this.collapsibles.filter((o) => this.overflowed.has(o.key) && o.available()).sort((o, a) => i.indexOf(o.key) - i.indexOf(a.key));
880
880
  for (const o of n) {
881
881
  const a = o.section();
882
882
  if (a)
883
883
  if (!a.title && a.items.length === 1) {
884
- const h = a.items[0];
885
- i.push(h), e.set(h.value, () => a.onSelect(h.value));
884
+ const c = a.items[0];
885
+ s.push(c), e.set(c.value, () => a.onSelect(c.value));
886
886
  } else
887
887
  t.push(a);
888
888
  }
889
- if (i.length > 0 && t.unshift({ title: "", items: i, onSelect: (o) => e.get(o)?.() }), this.actionItems.length > 0) {
889
+ if (s.length > 0 && t.unshift({ title: "", items: s, onSelect: (o) => e.get(o)?.() }), this.actionItems.length > 0) {
890
890
  const o = new Map(this.actionItems.map((a) => [a.value, a.run]));
891
891
  t.push({
892
892
  title: "",
893
- items: this.actionItems.map(({ value: a, label: h, icon: c }) => ({ value: a, label: h, icon: c, active: !1 })),
893
+ items: this.actionItems.map(({ value: a, label: c, icon: h }) => ({ value: a, label: c, icon: h, active: !1 })),
894
894
  onSelect: (a) => o.get(a)?.()
895
895
  });
896
896
  }
897
897
  return t;
898
898
  }
899
- simpleSection(t, e, i, s) {
900
- return { title: "", items: [{ value: t, label: e, icon: i, active: !1 }], onSelect: () => s() };
899
+ simpleSection(t, e, s, i) {
900
+ return { title: "", items: [{ value: t, label: e, icon: s, active: !1 }], onSelect: () => i() };
901
901
  }
902
902
  speedSection() {
903
903
  const t = this.player;
@@ -928,7 +928,7 @@ const _ = class _ {
928
928
  title: t.labels.subtitles,
929
929
  items: [
930
930
  { label: t.labels.subtitlesOff, value: "-1", active: t.activeSubtitle === -1 },
931
- ...t.subtitleTracks.map((e, i) => ({ label: e.label, value: String(i), active: t.activeSubtitle === i }))
931
+ ...t.subtitleTracks.map((e, s) => ({ label: e.label, value: String(s), active: t.activeSubtitle === s }))
932
932
  ],
933
933
  onSelect: (e) => t.setSubtitle(Number(e))
934
934
  };
@@ -946,24 +946,24 @@ const _ = class _ {
946
946
  reflow() {
947
947
  const t = window.innerWidth <= 767;
948
948
  this.center.style.display = t ? "flex" : "none", this.playBtn && (this.playBtn.style.display = t ? "none" : ""), this.overflowed.clear();
949
- for (const s of this.collapsibles) {
950
- if (t && _.CENTER_KEYS.has(s.key)) {
951
- s.el.style.display = "none";
949
+ for (const i of this.collapsibles) {
950
+ if (t && _.CENTER_KEYS.has(i.key)) {
951
+ i.el.style.display = "none";
952
952
  continue;
953
953
  }
954
- const n = s.available();
955
- s.el.style.display = n ? "" : "none", s.el.classList.remove("imp-collapsed");
954
+ const n = i.available();
955
+ i.el.style.display = n ? "" : "none", i.el.classList.remove("imp-collapsed");
956
956
  }
957
- const e = this.collapsibles.filter((s) => s.available() && !(t && _.CENTER_KEYS.has(s.key))).sort((s, n) => s.priority - n.priority);
958
- let i = e.length;
959
- for (; i-- > 0 && this.overflowsRow(); ) {
960
- const s = e.find((n) => !this.overflowed.has(n.key));
961
- if (!s) break;
962
- s.el.style.display = "none", s.el.classList.add("imp-collapsed"), this.overflowed.add(s.key);
957
+ const e = this.collapsibles.filter((i) => i.available() && !(t && _.CENTER_KEYS.has(i.key))).sort((i, n) => i.priority - n.priority);
958
+ let s = e.length;
959
+ for (; s-- > 0 && this.overflowsRow(); ) {
960
+ const i = e.find((n) => !this.overflowed.has(n.key));
961
+ if (!i) break;
962
+ i.el.style.display = "none", i.el.classList.add("imp-collapsed"), this.overflowed.add(i.key);
963
963
  }
964
964
  if (this.moreWrap) {
965
- const s = this.actionItems.length > 0 || this.overflowed.size > 0;
966
- this.moreWrap.style.display = s ? "" : "none";
965
+ const i = this.actionItems.length > 0 || this.overflowed.size > 0;
966
+ this.moreWrap.style.display = i ? "" : "none";
967
967
  }
968
968
  }
969
969
  overflowsRow() {
@@ -973,8 +973,8 @@ const _ = class _ {
973
973
  bind() {
974
974
  const t = this.player;
975
975
  this.disposers.push(
976
- t.on("timeupdate", ({ currentTime: e, duration: i }) => {
977
- this.progress.update(e, i, t.bufferedEnd), this.timeLabel && (t.live ? (this.timeLabel.hidden = !0, this.liveBadge.hidden = !1) : (this.timeLabel.hidden = !1, this.liveBadge.hidden = !0, this.timeLabel.textContent = `${w(e)} / ${w(i)}`));
976
+ t.on("timeupdate", ({ currentTime: e, duration: s }) => {
977
+ this.progress.update(e, s, t.bufferedEnd), this.timeLabel && (t.live ? (this.timeLabel.hidden = !0, this.liveBadge.hidden = !1) : (this.timeLabel.hidden = !1, this.liveBadge.hidden = !0, this.timeLabel.textContent = `${w(e)} / ${w(s)}`));
978
978
  }),
979
979
  t.on("play", () => this.syncPlayState()),
980
980
  t.on("pause", () => this.syncPlayState()),
@@ -995,13 +995,13 @@ const _ = class _ {
995
995
  ), this.syncPlaylistButtons(), this.reflow();
996
996
  }
997
997
  syncPlayState() {
998
- const t = this.player, [e, i] = t.ended ? [t.icons.replay, t.labels.replay] : t.paused ? [t.icons.play, t.labels.play] : [t.icons.pause, t.labels.pause];
999
- this.playBtn && E(this.playBtn, e, i), this.centerPlayBtn && E(this.centerPlayBtn, e, i);
998
+ const t = this.player, [e, s] = t.ended ? [t.icons.replay, t.labels.replay] : t.paused ? [t.icons.play, t.labels.play] : [t.icons.pause, t.labels.pause];
999
+ this.playBtn && E(this.playBtn, e, s), this.centerPlayBtn && E(this.centerPlayBtn, e, s);
1000
1000
  }
1001
1001
  syncVolume() {
1002
1002
  if (!this.muteBtn) return;
1003
- const t = this.player, e = t.muted ? 0 : t.volume, i = e === 0 ? t.icons.volumeMute : e < 0.5 ? t.icons.volumeLow : t.icons.volumeHigh;
1004
- E(this.muteBtn, i, t.muted ? t.labels.unmute : t.labels.mute), this.volumeSlider.value = String(e), this.volumeSlider.style.setProperty("--imp-volume-fill", `${e * 100}%`);
1003
+ const t = this.player, e = t.muted ? 0 : t.volume, s = e === 0 ? t.icons.volumeMute : e < 0.5 ? t.icons.volumeLow : t.icons.volumeHigh;
1004
+ E(this.muteBtn, s, t.muted ? t.labels.unmute : t.labels.mute), this.volumeSlider.value = String(e), this.volumeSlider.style.setProperty("--imp-volume-fill", `${e * 100}%`);
1005
1005
  }
1006
1006
  /** Called by the player when per-source data (chapters/quality/subtitles) changes. */
1007
1007
  syncFeatureButtons() {
@@ -1033,14 +1033,14 @@ _.CENTER_KEYS = /* @__PURE__ */ new Set(["seekBack", "seekFwd", "prev", "next"])
1033
1033
  let F = _;
1034
1034
  class ft {
1035
1035
  constructor(t) {
1036
- this.root = l("div", "imp-poster"), this.image = l("div", "imp-poster__image");
1036
+ this.root = l("div", "imp-poster"), this.image = l("img", "imp-poster__image", { alt: "", decoding: "async" }), this.image.hidden = !0;
1037
1037
  const e = m("imp-poster__play", t.labels.play, t.icons.bigPlay);
1038
- e.addEventListener("click", () => void t.play()), this.root.append(this.image, e), this.root.addEventListener("click", (i) => {
1039
- (i.target === this.root || i.target === this.image) && t.play();
1038
+ e.addEventListener("click", () => void t.play()), this.root.append(this.image, e), this.root.addEventListener("click", (s) => {
1039
+ (s.target === this.root || s.target === this.image) && t.play();
1040
1040
  });
1041
1041
  }
1042
1042
  setSource(t) {
1043
- this.image.style.backgroundImage = t?.poster ? `url("${t.poster}")` : "";
1043
+ t?.poster ? (this.image.src = t.poster, this.image.fetchPriority = "high", this.image.hidden = !1) : (this.image.removeAttribute("src"), this.image.hidden = !0);
1044
1044
  }
1045
1045
  show() {
1046
1046
  this.root.hidden = !1;
@@ -1055,7 +1055,7 @@ class vt {
1055
1055
  this.channelUrl && window.open(this.channelUrl, "_blank", "noopener");
1056
1056
  });
1057
1057
  const e = l("div", "imp-pause-screen__heading");
1058
- this.title = l("div", "imp-pause-screen__title"), this.description = l("div", "imp-pause-screen__description"), this.sponsor = l("a", "imp-sponsor", { target: "_blank", rel: "nofollow noopener" }), this.sponsor.hidden = !0, this.sponsorLabel = l("span", "imp-sponsor__label"), this.sponsorText = l("span", "imp-sponsor__text"), this.sponsor.append(this.sponsorLabel, this.sponsorText), this.sponsor.addEventListener("click", (i) => i.stopPropagation()), e.append(this.title, this.description, this.sponsor), this.defaultContent.append(e, this.channel), this.root.append(this.defaultContent);
1058
+ this.title = l("div", "imp-pause-screen__title"), this.description = l("div", "imp-pause-screen__description"), this.sponsor = l("a", "imp-sponsor", { target: "_blank", rel: "nofollow noopener" }), this.sponsor.hidden = !0, this.sponsorLabel = l("span", "imp-sponsor__label"), this.sponsorText = l("span", "imp-sponsor__text"), this.sponsor.append(this.sponsorLabel, this.sponsorText), this.sponsor.addEventListener("click", (s) => s.stopPropagation()), e.append(this.title, this.description, this.sponsor), this.defaultContent.append(e, this.channel), this.root.append(this.defaultContent);
1059
1059
  }
1060
1060
  setCustomContent(t) {
1061
1061
  this.custom?.remove(), this.custom = t, t && (t.classList.add("imp-pause-screen__custom"), this.root.append(t)), this.defaultContent.hidden = t !== null, this.root.classList.toggle("imp-pause-screen--custom", t !== null);
@@ -1068,8 +1068,8 @@ class vt {
1068
1068
  this.title.textContent = t?.title ?? "", this.description.textContent = t?.description ?? "";
1069
1069
  const e = t?.sponsor;
1070
1070
  this.sponsor.hidden = !e, e && (this.sponsor.href = e.url, this.sponsorText.textContent = e.text, this.sponsorLabel.textContent = e.label ?? this.labels.sponsored);
1071
- const i = t?.channel;
1072
- this.channel.hidden = !i, this.channelUrl = i?.url ?? null, this.channel.classList.toggle("imp-channel--link", !!i?.url), i && (this.channelName.textContent = i.name, this.channelAvatar.className = `imp-channel__avatar imp-channel__avatar--${i.avatarShape ?? "circle"}`, i.avatar ? (this.channelAvatar.textContent = "", this.channelAvatar.style.backgroundImage = `url("${i.avatar}")`) : (this.channelAvatar.style.backgroundImage = "", this.channelAvatar.textContent = (i.name.trim()[0] ?? "?").toUpperCase()));
1071
+ const s = t?.channel;
1072
+ this.channel.hidden = !s, this.channelUrl = s?.url ?? null, this.channel.classList.toggle("imp-channel--link", !!s?.url), s && (this.channelName.textContent = s.name, this.channelAvatar.className = `imp-channel__avatar imp-channel__avatar--${s.avatarShape ?? "circle"}`, s.avatar ? (this.channelAvatar.textContent = "", this.channelAvatar.style.backgroundImage = `url("${s.avatar}")`) : (this.channelAvatar.style.backgroundImage = "", this.channelAvatar.textContent = (s.name.trim()[0] ?? "?").toUpperCase()));
1073
1073
  }
1074
1074
  show() {
1075
1075
  this.root.hidden = !1;
@@ -1080,28 +1080,43 @@ class vt {
1080
1080
  }
1081
1081
  class gt {
1082
1082
  constructor(t) {
1083
- this.player = t, this.root = l("div", "imp-related"), this.root.hidden = !0, this.heading = l("div", "imp-related__title"), this.grid = l("div", "imp-related__grid");
1083
+ this.player = t, this.clickBehavior = "player", this.root = l("div", "imp-related"), this.root.hidden = !0, this.heading = l("div", "imp-related__title"), this.grid = l("div", "imp-related__grid");
1084
1084
  const e = m("imp-related__close", "Close", t.icons.close);
1085
1085
  e.addEventListener("click", () => this.hide()), this.root.append(e, this.heading, this.grid);
1086
1086
  }
1087
1087
  setOptions(t) {
1088
1088
  if (this.grid.textContent = "", !!t) {
1089
- this.heading.textContent = t.title ?? this.player.labels.related;
1089
+ this.clickBehavior = t.clickBehavior ?? "player", this.heading.textContent = t.title ?? this.player.labels.related;
1090
1090
  for (const e of t.items)
1091
1091
  this.grid.append(this.buildCard(e));
1092
1092
  }
1093
1093
  }
1094
1094
  buildCard(t) {
1095
- const e = l("button", "imp-related__card", { type: "button" }), i = l("div", "imp-related__thumb");
1096
- if (t.poster && (i.style.backgroundImage = `url("${t.poster}")`), t.duration) {
1095
+ const e = l("button", "imp-related__card", { type: "button" }), s = l("div", "imp-related__thumb");
1096
+ if (t.poster && (s.style.backgroundImage = `url("${t.poster}")`), t.duration) {
1097
1097
  const n = l("span", "imp-related__duration");
1098
- n.textContent = t.duration, i.append(n);
1098
+ n.textContent = t.duration, s.append(n);
1099
1099
  }
1100
- const s = l("div", "imp-related__card-title");
1101
- return s.textContent = t.title, e.append(i, s), e.addEventListener("click", () => {
1102
- this.player.emit("relatedclick", { item: t }), this.hide(), t.source ? (this.player.load(t.source), this.player.play()) : t.url && window.open(t.url, "_blank", "noopener");
1100
+ const i = l("div", "imp-related__card-title");
1101
+ return i.textContent = t.title, e.append(s, i), e.addEventListener("click", () => {
1102
+ this.player.emit("relatedclick", { item: t }), this.hide(), this.activate(t);
1103
1103
  }), e;
1104
1104
  }
1105
+ /** Apply the configured click behavior. */
1106
+ activate(t) {
1107
+ const e = t.url ?? t.source?.src;
1108
+ switch (this.clickBehavior) {
1109
+ case "newWindow":
1110
+ e && window.open(e, "_blank", "noopener");
1111
+ break;
1112
+ case "currentTab":
1113
+ e && (window.location.href = e);
1114
+ break;
1115
+ case "player":
1116
+ default:
1117
+ t.source ? (this.player.load(t.source), this.player.play()) : t.url && window.open(t.url, "_blank", "noopener");
1118
+ }
1119
+ }
1105
1120
  get visible() {
1106
1121
  return !this.root.hidden;
1107
1122
  }
@@ -1113,14 +1128,14 @@ class gt {
1113
1128
  }
1114
1129
  }
1115
1130
  class yt {
1116
- constructor(t, e = "sidebar", i) {
1131
+ constructor(t, e = "sidebar", s) {
1117
1132
  this.player = t, this.root = l("div", `imp-playlist imp-playlist--${e}`), this.root.hidden = !0;
1118
- const s = l("div", "imp-playlist__header"), n = l("div", "imp-playlist__heading");
1119
- if (i) {
1120
- const h = l("div", "imp-playlist__kicker");
1121
- h.textContent = t.labels.playlist;
1122
- const c = l("div", "imp-playlist__name");
1123
- c.textContent = i, n.append(h, c);
1133
+ const i = l("div", "imp-playlist__header"), n = l("div", "imp-playlist__heading");
1134
+ if (s) {
1135
+ const c = l("div", "imp-playlist__kicker");
1136
+ c.textContent = t.labels.playlist;
1137
+ const h = l("div", "imp-playlist__name");
1138
+ h.textContent = s, n.append(c, h);
1124
1139
  } else
1125
1140
  n.textContent = t.labels.playlist;
1126
1141
  const o = l("div", "imp-playlist__tools");
@@ -1130,25 +1145,25 @@ class yt {
1130
1145
  t.setRepeat(!t.repeat), this.syncModes();
1131
1146
  });
1132
1147
  const a = m("imp-playlist__close", "Close", t.icons.close);
1133
- a.addEventListener("click", () => this.hide()), o.append(this.shuffleBtn, this.repeatBtn, a), s.append(n, o), this.list = l("div", "imp-playlist__list"), this.root.append(s, this.list), this.rebuild(), this.syncModes();
1148
+ a.addEventListener("click", () => this.hide()), o.append(this.shuffleBtn, this.repeatBtn, a), i.append(n, o), this.list = l("div", "imp-playlist__list"), this.root.append(i, this.list), this.rebuild(), this.syncModes();
1134
1149
  }
1135
1150
  syncModes() {
1136
1151
  this.shuffleBtn.classList.toggle("imp-btn--active", this.player.shuffle), this.repeatBtn.classList.toggle("imp-btn--active", this.player.repeat);
1137
1152
  }
1138
1153
  rebuild() {
1139
1154
  this.list.textContent = "", this.player.playlist.forEach((t, e) => {
1140
- const i = l("button", "imp-playlist__item", { type: "button" });
1141
- e === this.player.index && i.classList.add("imp-playlist__item--active");
1142
- const s = l("div", "imp-playlist__thumb");
1143
- t.poster && (s.style.backgroundImage = `url("${t.poster}")`);
1155
+ const s = l("button", "imp-playlist__item", { type: "button" });
1156
+ e === this.player.index && s.classList.add("imp-playlist__item--active");
1157
+ const i = l("div", "imp-playlist__thumb");
1158
+ t.poster && (i.style.backgroundImage = `url("${t.poster}")`);
1144
1159
  const n = l("div", "imp-playlist__meta"), o = l("div", "imp-playlist__title");
1145
1160
  if (o.textContent = t.title ?? `#${e + 1}`, n.append(o), t.duration) {
1146
1161
  const a = l("div", "imp-playlist__duration");
1147
1162
  a.textContent = w(t.duration), n.append(a);
1148
1163
  }
1149
- i.append(s, n), i.addEventListener("click", () => {
1164
+ s.append(i, n), s.addEventListener("click", () => {
1150
1165
  this.player.playItem(e);
1151
- }), this.list.append(i);
1166
+ }), this.list.append(s);
1152
1167
  });
1153
1168
  }
1154
1169
  get visible() {
@@ -1167,34 +1182,34 @@ class yt {
1167
1182
  class bt {
1168
1183
  constructor(t, e = "bottom") {
1169
1184
  this.player = t, this.items = [], this.root = l("div", `imp-playlist imp-scenes imp-playlist--${e}`), this.root.hidden = !0;
1170
- const i = l("div", "imp-playlist__header"), s = l("span");
1171
- s.textContent = t.labels.scenes;
1185
+ const s = l("div", "imp-playlist__header"), i = l("span");
1186
+ i.textContent = t.labels.scenes;
1172
1187
  const n = m("imp-playlist__close", "Close", t.icons.close);
1173
- n.addEventListener("click", () => this.hide()), i.append(s, n), this.list = l("div", "imp-playlist__list"), this.root.append(i, this.list), t.on("chapterchange", () => this.syncActive());
1188
+ n.addEventListener("click", () => this.hide()), s.append(i, n), this.list = l("div", "imp-playlist__list"), this.root.append(s, this.list), t.on("chapterchange", () => this.syncActive());
1174
1189
  }
1175
1190
  /** Re-render from the player's current chapters + thumbnail track. */
1176
1191
  rebuild() {
1177
1192
  this.list.textContent = "", this.items = [];
1178
1193
  const t = this.player.thumbnails;
1179
1194
  for (const e of this.player.chapterList) {
1180
- const i = l("button", "imp-playlist__item", { type: "button" }), s = l("div", "imp-playlist__thumb"), n = t?.cueAt(e.start + 0.01) ?? null;
1195
+ const s = l("button", "imp-playlist__item", { type: "button" }), i = l("div", "imp-playlist__thumb"), n = t?.cueAt(e.start + 0.01) ?? null;
1181
1196
  if (n?.xywh) {
1182
- const c = l("div", "imp-scenes__sprite");
1183
- c.style.width = `${n.xywh.w}px`, c.style.height = `${n.xywh.h}px`, c.style.backgroundImage = `url("${n.src}")`, c.style.backgroundPosition = `-${n.xywh.x}px -${n.xywh.y}px`, c.style.setProperty("--imp-sprite-w", String(n.xywh.w)), s.append(c);
1184
- } else n && (s.style.backgroundImage = `url("${n.src}")`);
1197
+ const h = l("div", "imp-scenes__sprite");
1198
+ h.style.width = `${n.xywh.w}px`, h.style.height = `${n.xywh.h}px`, h.style.backgroundImage = `url("${n.src}")`, h.style.backgroundPosition = `-${n.xywh.x}px -${n.xywh.y}px`, h.style.setProperty("--imp-sprite-w", String(n.xywh.w)), i.append(h);
1199
+ } else n && (i.style.backgroundImage = `url("${n.src}")`);
1185
1200
  const o = l("div", "imp-playlist__meta"), a = l("div", "imp-playlist__title");
1186
1201
  a.textContent = e.title || w(e.start);
1187
- const h = l("div", "imp-playlist__duration");
1188
- h.textContent = w(e.start), o.append(a, h), i.append(s, o), i.addEventListener("click", () => {
1202
+ const c = l("div", "imp-playlist__duration");
1203
+ c.textContent = w(e.start), o.append(a, c), s.append(i, o), s.addEventListener("click", () => {
1189
1204
  this.player.seek(e.start), this.player.play();
1190
- }), this.list.append(i), this.items.push(i);
1205
+ }), this.list.append(s), this.items.push(s);
1191
1206
  }
1192
1207
  this.syncActive();
1193
1208
  }
1194
1209
  syncActive() {
1195
1210
  const t = this.player.chapter, e = this.player.chapterList;
1196
- this.items.forEach((i, s) => {
1197
- i.classList.toggle("imp-playlist__item--active", t !== null && e[s] === t);
1211
+ this.items.forEach((s, i) => {
1212
+ s.classList.toggle("imp-playlist__item--active", t !== null && e[i] === t);
1198
1213
  });
1199
1214
  }
1200
1215
  get visible() {
@@ -1231,20 +1246,26 @@ const kt = {
1231
1246
  };
1232
1247
  class _t {
1233
1248
  constructor(t, e = {}) {
1234
- this.scrubbing = !1, this.emitter = new Y(), this.abort = new AbortController(), this.sources = [], this.currentIndex = -1, this.sourceController = null, this.loadToken = 0, this.chapters = [], this.currentChapter = null, this.progressiveQuality = -1, this.thumbTrack = null, this.shuffleMode = !1, this.adManager = null, this.playedOnce = !1, this.idleTimer = null, this.destroyed = !1;
1235
- const i = typeof t == "string" ? document.querySelector(t) : t;
1236
- if (!i) throw new Error(`[itube-player] mount target not found: ${String(t)}`);
1237
- this.mount = i, this.options = e, this.labels = { ...I, ...tt(e.language), ...e.labels }, this.icons = { ...J, ...e.icons }, this.controlsOptions = { ...kt, ...e.controls }, this.actionsOptions = e.actions ?? {}, this.playbackRates = e.playbackRates ?? [0.5, 0.75, 1, 1.25, 1.5, 2], this.seekStep = e.seekStep ?? 10, this.playlistOptions = { title: "", autoAdvance: !0, loop: !1, shuffle: !1, startIndex: 0, layout: "sidebar", ...e.playlist }, this.shuffleMode = this.playlistOptions.shuffle, this.sources = e.source ? Array.isArray(e.source) ? [...e.source] : [e.source] : [], this.container = l("div", "imp-player", { tabindex: "0" }), e.className && this.container.classList.add(e.className), e.styling?.themeColor && this.container.style.setProperty("--imp-accent", e.styling.themeColor), e.styling?.likeColor && this.container.style.setProperty("--imp-like", e.styling.likeColor), e.styling?.dislikeColor && this.container.style.setProperty("--imp-dislike", e.styling.dislikeColor), this.video = l("video", "imp-video"), e.playsInline !== !1 && this.video.setAttribute("playsinline", ""), e.crossOrigin !== void 0 && (this.video.crossOrigin = e.crossOrigin), this.video.preload = "metadata", e.loop && (this.video.loop = !0), e.muted && (this.video.muted = !0), this.video.volume = y(e.volume ?? 1, 0, 1);
1238
- const s = l("div", "imp-layer");
1249
+ this.scrubbing = !1, this.emitter = new Y(), this.abort = new AbortController(), this.sources = [], this.currentIndex = -1, this.sourceController = null, this.loadToken = 0, this.chapters = [], this.currentChapter = null, this.progressiveQuality = -1, this.thumbTrack = null, this.shuffleMode = !1, this.decodeRecoveries = 0, this.adManager = null, this.playedOnce = !1, this.idleTimer = null, this.destroyed = !1;
1250
+ const s = typeof t == "string" ? document.querySelector(t) : t;
1251
+ if (!s) throw new Error(`[itube-player] mount target not found: ${String(t)}`);
1252
+ this.mount = s, this.options = e, this.labels = { ...I, ...tt(e.language), ...e.labels }, this.icons = { ...J, ...e.icons }, this.controlsOptions = { ...kt, ...e.controls }, this.actionsOptions = e.actions ?? {}, this.playbackRates = e.playbackRates ?? [0.5, 0.75, 1, 1.25, 1.5, 2], this.seekStep = e.seekStep ?? 10, this.playlistOptions = { title: "", autoAdvance: !0, loop: !1, shuffle: !1, startIndex: 0, layout: "sidebar", ...e.playlist }, this.shuffleMode = this.playlistOptions.shuffle, this.sources = e.source ? Array.isArray(e.source) ? [...e.source] : [e.source] : [], this.container = l("div", "imp-player", { tabindex: "0" }), e.className && this.container.classList.add(e.className);
1253
+ const i = e.styling;
1254
+ if (i?.themeColor && this.container.style.setProperty("--imp-accent", i.themeColor), i?.likeColor && this.container.style.setProperty("--imp-like", i.likeColor), i?.dislikeColor && this.container.style.setProperty("--imp-dislike", i.dislikeColor), i?.borderRadius !== void 0) {
1255
+ const h = typeof i.borderRadius == "number" ? `${i.borderRadius}px` : i.borderRadius;
1256
+ this.container.style.setProperty("--imp-radius", h);
1257
+ }
1258
+ i?.playButtonStyle === "inverted" && this.container.classList.add("imp-player--play-inverted"), this.video = l("video", "imp-video"), e.playsInline !== !1 && this.video.setAttribute("playsinline", ""), e.crossOrigin !== void 0 && (this.video.crossOrigin = e.crossOrigin), this.video.preload = "metadata", e.loop && (this.video.loop = !0), e.muted && (this.video.muted = !0), this.video.volume = y(e.volume ?? 1, 0, 1);
1259
+ const n = l("div", "imp-layer");
1239
1260
  this.spinner = l("div", "imp-spinner"), this.spinner.hidden = !0, this.errorBox = l("div", "imp-error"), this.errorBox.hidden = !0, this.pauseScreen = new vt(this.labels), this.poster = new ft(this), this.related = new gt(this), this.related.setOptions(e.related), this.controls = new F(this), this.playlistPanel = new yt(this, this.playlistOptions.layout, this.playlistOptions.title || void 0), this.scenesPanel = new bt(this, e.scenes?.layout ?? "bottom");
1240
- const n = l("div", "imp-layer__middle");
1241
- n.append(this.spinner, this.errorBox, this.controls.center);
1242
- const o = l("div", "imp-layer__bottom");
1243
- o.append(this.controls.root), s.append(this.pauseScreen.root, this.related.root, n, o), this.container.append(this.video, s, this.poster.root, this.playlistPanel.root, this.scenesPanel.root), this.mount.append(this.container), e.pauseScreen instanceof HTMLElement ? this.pauseScreen.setCustomContent(e.pauseScreen) : typeof e.pauseScreen == "function" && this.pauseScreen.setCustomContent(e.pauseScreen(this));
1244
- const a = e.adConfig ?? e.ads;
1245
- a && a.adList.length > 0 && (this.adManager = new lt(
1261
+ const o = l("div", "imp-layer__middle");
1262
+ o.append(this.spinner, this.errorBox, this.controls.center);
1263
+ const a = l("div", "imp-layer__bottom");
1264
+ a.append(this.controls.root), n.append(this.pauseScreen.root, this.related.root, o, a), this.container.append(this.video, n, this.poster.root, this.playlistPanel.root, this.scenesPanel.root), this.mount.append(this.container), e.pauseScreen instanceof HTMLElement ? this.pauseScreen.setCustomContent(e.pauseScreen) : typeof e.pauseScreen == "function" && this.pauseScreen.setCustomContent(e.pauseScreen(this));
1265
+ const c = e.adConfig ?? e.ads;
1266
+ c && c.adList.length > 0 && (this.adManager = new lt(
1246
1267
  { container: this.container, contentVideo: this.video, emitter: this.emitter, labels: this.labels, closeIcon: this.icons.close },
1247
- a
1268
+ c
1248
1269
  )), this.emitter.on("error", ({ message: h }) => {
1249
1270
  this.errorBox.textContent = h, this.errorBox.hidden = !1, this.spinner.hidden = !0, this.poster.hide();
1250
1271
  }), this.bindVideoEvents(), this.bindIdleHide(), e.keyboard !== !1 && this.bindKeyboard(), this.video.addEventListener("click", () => {
@@ -1332,7 +1353,7 @@ class _t {
1332
1353
  get qualityLevels() {
1333
1354
  if (this.sourceController?.kind === "hls") return this.sourceController.levels;
1334
1355
  const t = this.source?.qualities;
1335
- return t ? t.map((e, i) => ({ index: i, label: e.label ?? String(e.quality ?? i) })) : [];
1356
+ return t ? t.map((e, s) => ({ index: s, label: e.label ?? String(e.quality ?? s) })) : [];
1336
1357
  }
1337
1358
  get qualityAutoAvailable() {
1338
1359
  return this.sourceController?.kind === "hls";
@@ -1349,8 +1370,8 @@ class _t {
1349
1370
  }
1350
1371
  const e = this.source?.qualities;
1351
1372
  if (!e || !e[t] || t === this.progressiveQuality) return;
1352
- const i = this.video.currentTime, s = !this.video.paused && !this.video.ended;
1353
- this.progressiveQuality = t, this.video.src = e[t].src, this.video.currentTime = i, s && this.video.play().catch(() => {
1373
+ const s = this.video.currentTime, i = !this.video.paused && !this.video.ended;
1374
+ this.progressiveQuality = t, this.video.src = e[t].src, this.video.currentTime = s, i && this.video.play().catch(() => {
1354
1375
  }), this.emitter.emit("qualitychange", { label: e[t].label ?? String(e[t].quality ?? t) });
1355
1376
  }
1356
1377
  // === subtitles ========================================================
@@ -1365,8 +1386,8 @@ class _t {
1365
1386
  }
1366
1387
  setSubtitle(t) {
1367
1388
  const e = this.video.textTracks;
1368
- for (let i = 0; i < e.length; i++)
1369
- e[i].mode = i === t ? "showing" : "disabled";
1389
+ for (let s = 0; s < e.length; s++)
1390
+ e[s].mode = s === t ? "showing" : "disabled";
1370
1391
  this.emitter.emit("subtitlechange", { track: this.subtitleTracks[t] ?? null });
1371
1392
  }
1372
1393
  // === playlist =========================================================
@@ -1496,56 +1517,56 @@ class _t {
1496
1517
  }
1497
1518
  // === internals ========================================================
1498
1519
  async loadItem(t, e) {
1499
- const i = ++this.loadToken, s = this.sources[t];
1500
- if (!s) return;
1520
+ const s = ++this.loadToken, i = this.sources[t];
1521
+ if (!i) return;
1501
1522
  this.currentIndex = t, this.sourceController?.destroy(), this.sourceController = null, this.chapters = [], this.currentChapter = null, this.progressiveQuality = -1, this.playedOnce = !1;
1502
- for (const h of [...this.video.querySelectorAll("track")]) h.remove();
1503
- this.adManager?.resetForNewSource(), this.related.hide(), this.pauseScreen.hide(), this.scenesPanel.hide(), this.thumbTrack = null, this.errorBox.hidden = !0, this.video.poster = s.poster ?? "", this.poster.setSource(s), this.pauseScreen.setSource(s), this.controls.progress.setChapters([]), this.controls.progress.setThumbnails(null), this.controls.progress.setHeatmap([]), e ? this.poster.hide() : this.poster.show(), this.playlistPanel.rebuild();
1504
- for (const h of Q(s.subtitles)) {
1505
- const c = l("track", "", {
1523
+ for (const c of [...this.video.querySelectorAll("track")]) c.remove();
1524
+ this.adManager?.resetForNewSource(), this.related.hide(), this.pauseScreen.hide(), this.scenesPanel.hide(), this.thumbTrack = null, this.errorBox.hidden = !0, this.decodeRecoveries = 0, this.video.poster = i.poster ?? "", this.poster.setSource(i), this.pauseScreen.setSource(i), this.controls.progress.setChapters([]), this.controls.progress.setThumbnails(null), this.controls.progress.setHeatmap([]), e ? this.poster.hide() : this.poster.show(), this.playlistPanel.rebuild();
1525
+ for (const c of Q(i.subtitles)) {
1526
+ const h = l("track", "", {
1506
1527
  kind: "subtitles",
1507
- src: h.src,
1508
- label: h.label,
1509
- ...h.srclang ? { srclang: h.srclang } : {}
1528
+ src: c.src,
1529
+ label: c.label,
1530
+ ...c.srclang ? { srclang: c.srclang } : {}
1510
1531
  });
1511
- h.default && c.setAttribute("default", ""), this.video.append(c);
1532
+ c.default && h.setAttribute("default", ""), this.video.append(h);
1512
1533
  }
1513
- let n = s.src, o = s.type;
1514
- if (s.qualities && s.qualities.length > 0) {
1515
- const h = Math.max(0, s.qualities.findIndex((c) => c.src === s.src));
1516
- this.progressiveQuality = h, n = s.qualities[h].src, o = s.qualities[h].type ?? o;
1534
+ let n = i.src, o = i.type;
1535
+ if (i.qualities && i.qualities.length > 0) {
1536
+ const c = Math.max(0, i.qualities.findIndex((h) => h.src === i.src));
1537
+ this.progressiveQuality = c, n = i.qualities[c].src, o = i.qualities[c].type ?? o;
1517
1538
  }
1518
1539
  this.video.preload = this.adManager?.hasPendingPreRoll ? "auto" : "metadata";
1519
1540
  const a = await ut(this.video, n, o, {
1520
1541
  onLevels: () => {
1521
- i === this.loadToken && this.controls.syncFeatureButtons();
1542
+ s === this.loadToken && this.controls.syncFeatureButtons();
1522
1543
  },
1523
- onLevelSwitch: (h) => this.emitter.emit("qualitychange", { label: h }),
1524
- onError: (h, c) => this.emitter.emit("error", { message: h, cause: c })
1544
+ onLevelSwitch: (c) => this.emitter.emit("qualitychange", { label: c }),
1545
+ onError: (c, h) => this.emitter.emit("error", { message: c, cause: h })
1525
1546
  });
1526
- if (i !== this.loadToken) {
1547
+ if (s !== this.loadToken) {
1527
1548
  a.destroy();
1528
1549
  return;
1529
1550
  }
1530
- if (this.sourceController = a, this.emitter.emit("sourcechange", { source: s, index: t }), s.thumbnails && q.load(s.thumbnails).then((h) => {
1531
- i === this.loadToken && (this.thumbTrack = h, this.controls.progress.setThumbnails(h), this.scenesPanel.visible && this.scenesPanel.rebuild());
1532
- }).catch((h) => this.emitter.emit("error", { message: "Failed to load thumbnails track", cause: h })), s.chapters) {
1533
- const h = (c) => {
1551
+ if (this.sourceController = a, this.emitter.emit("sourcechange", { source: i, index: t }), i.thumbnails && q.load(i.thumbnails).then((c) => {
1552
+ s === this.loadToken && (this.thumbTrack = c, this.controls.progress.setThumbnails(c), this.scenesPanel.visible && this.scenesPanel.rebuild());
1553
+ }).catch((c) => this.emitter.emit("error", { message: "Failed to load thumbnails track", cause: c })), i.chapters) {
1554
+ const c = (h) => {
1534
1555
  const u = () => {
1535
- i === this.loadToken && (this.chapters = at(c, this.video.duration), this.controls.progress.setChapters(this.chapters), this.controls.syncFeatureButtons(), this.scenesPanel.visible && this.scenesPanel.rebuild());
1556
+ s === this.loadToken && (this.chapters = at(h, this.video.duration), this.controls.progress.setChapters(this.chapters), this.controls.syncFeatureButtons(), this.scenesPanel.visible && this.scenesPanel.rebuild());
1536
1557
  };
1537
1558
  Number.isFinite(this.video.duration) && this.video.duration > 0 ? u() : this.video.addEventListener("loadedmetadata", u, { once: !0, signal: this.abort.signal });
1538
1559
  };
1539
- typeof s.chapters == "string" ? ht(s.chapters).then((c) => h(c)).catch((c) => this.emitter.emit("error", { message: "Failed to load chapters track", cause: c })) : h(s.chapters);
1560
+ typeof i.chapters == "string" ? ht(i.chapters).then((h) => c(h)).catch((h) => this.emitter.emit("error", { message: "Failed to load chapters track", cause: h })) : c(i.chapters);
1540
1561
  }
1541
- if (s.heatmap && s.heatmap.length > 0 && this.controlsOptions.heatmap) {
1542
- const h = s.heatmap, c = () => {
1543
- i === this.loadToken && this.controls.progress.setHeatmap(et(h, this.video.duration));
1562
+ if (i.heatmap && i.heatmap.length > 0 && this.controlsOptions.heatmap) {
1563
+ const c = i.heatmap, h = () => {
1564
+ s === this.loadToken && this.controls.progress.setHeatmap(et(c, this.video.duration));
1544
1565
  };
1545
- Number.isFinite(this.video.duration) && this.video.duration > 0 ? c() : this.video.addEventListener("loadedmetadata", c, { once: !0, signal: this.abort.signal });
1566
+ Number.isFinite(this.video.duration) && this.video.duration > 0 ? h() : this.video.addEventListener("loadedmetadata", h, { once: !0, signal: this.abort.signal });
1546
1567
  }
1547
1568
  e && this.play().catch(() => {
1548
- i === this.loadToken && this.poster.show();
1569
+ s === this.loadToken && this.poster.show();
1549
1570
  });
1550
1571
  }
1551
1572
  bindVideoEvents() {
@@ -1558,8 +1579,8 @@ class _t {
1558
1579
  this.handleEnded();
1559
1580
  }, { signal: t }), e.addEventListener("timeupdate", () => {
1560
1581
  this.emitter.emit("timeupdate", { currentTime: e.currentTime, duration: e.duration || 0 }), this.adManager?.checkMidRolls(e.currentTime);
1561
- const i = K(this.chapters, e.currentTime);
1562
- i !== this.currentChapter && (this.currentChapter = i, this.emitter.emit("chapterchange", { chapter: i }));
1582
+ const s = K(this.chapters, e.currentTime);
1583
+ s !== this.currentChapter && (this.currentChapter = s, this.emitter.emit("chapterchange", { chapter: s }));
1563
1584
  }, { signal: t }), e.addEventListener("progress", () => {
1564
1585
  this.emitter.emit("progress", { buffered: this.bufferedEnd });
1565
1586
  }, { signal: t }), e.addEventListener("volumechange", () => {
@@ -1567,13 +1588,29 @@ class _t {
1567
1588
  }, { signal: t }), e.addEventListener("seeking", () => this.emitter.emit("seeking", { currentTime: e.currentTime }), { signal: t }), e.addEventListener("seeked", () => this.emitter.emit("seeked", { currentTime: e.currentTime }), { signal: t }), e.addEventListener("waiting", () => {
1568
1589
  this.spinner.hidden = !1;
1569
1590
  }, { signal: t });
1570
- for (const i of ["playing", "canplay", "seeked"])
1571
- e.addEventListener(i, () => {
1572
- this.spinner.hidden = !0;
1591
+ for (const s of ["playing", "canplay", "seeked"])
1592
+ e.addEventListener(s, () => {
1593
+ this.spinner.hidden = !0, this.errorBox.hidden = !0, this.decodeRecoveries = 0;
1573
1594
  }, { signal: t });
1574
1595
  e.addEventListener("error", () => {
1575
- const i = e.error;
1576
- i && this.sourceController?.kind !== "hls" && (e.getAttribute("src") !== null || e.currentSrc) && this.emitter.emit("error", { message: i.message || `Media error (code ${i.code})`, cause: i });
1596
+ const s = e.error;
1597
+ if (!s || this.sourceController?.kind === "hls" || e.getAttribute("src") === null && !e.currentSrc) return;
1598
+ if ((s.code === MediaError.MEDIA_ERR_DECODE || /DEMUXER|PARSE|DECODE/i.test(s.message || "")) && this.decodeRecoveries < 2 && Number.isFinite(e.duration)) {
1599
+ this.decodeRecoveries++;
1600
+ const n = e.currentTime, o = !e.paused;
1601
+ e.load();
1602
+ const a = () => {
1603
+ try {
1604
+ e.currentTime = n;
1605
+ } catch {
1606
+ }
1607
+ o && e.play().catch(() => {
1608
+ });
1609
+ };
1610
+ e.readyState >= 1 ? a() : e.addEventListener("loadedmetadata", a, { once: !0, signal: this.abort.signal });
1611
+ return;
1612
+ }
1613
+ this.emitter.emit("error", { message: s.message || `Media error (code ${s.code})`, cause: s });
1577
1614
  }, { signal: t }), e.addEventListener("enterpictureinpicture", () => this.emitter.emit("pipchange", { active: !0 }), { signal: t }), e.addEventListener("leavepictureinpicture", () => this.emitter.emit("pipchange", { active: !1 }), { signal: t }), document.addEventListener("fullscreenchange", () => {
1578
1615
  this.emitter.emit("fullscreenchange", { active: this.isFullscreen }), this.container.classList.toggle("imp-player--fullscreen", this.isFullscreen);
1579
1616
  }, { signal: t });
@@ -1609,11 +1646,11 @@ class _t {
1609
1646
  this.container.addEventListener("keydown", (t) => {
1610
1647
  const e = t.target;
1611
1648
  if (e.closest("input, select, textarea, [contenteditable]")) return;
1612
- const s = e.closest("button") !== null;
1649
+ const i = e.closest("button") !== null;
1613
1650
  switch (t.key) {
1614
1651
  case " ":
1615
1652
  case "k":
1616
- if (t.key === " " && s) return;
1653
+ if (t.key === " " && i) return;
1617
1654
  t.preventDefault(), this.togglePlay();
1618
1655
  break;
1619
1656
  case "ArrowLeft":