itube-modern-player 0.6.0 → 0.7.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,75 +1,79 @@
1
- import { d as H } from "./labels-DRuCG6N8.js";
1
+ import { d as Z } from "./labels-CCjOCBKU.js";
2
2
  function l(o, t, e) {
3
3
  const i = document.createElement(o);
4
4
  if (t && (i.className = t), e)
5
5
  for (const [s, n] of Object.entries(e)) i.setAttribute(s, n);
6
6
  return i;
7
7
  }
8
- function B(o, t) {
8
+ function T(o, t) {
9
9
  if (o.textContent = "", typeof t == "object") {
10
10
  "url" in t ? o.append(l("img", "imp-icon-img", { src: t.url, alt: "" })) : o.innerHTML = t.svg;
11
11
  return;
12
12
  }
13
13
  /^\s*</.test(t) ? o.innerHTML = t : o.append(l("img", "imp-icon-img", { src: t, alt: "" }));
14
14
  }
15
+ function S(o, t = "") {
16
+ const e = l("img", "imp-cover-img", { alt: t, decoding: "async" });
17
+ return e.src = o, e;
18
+ }
15
19
  function g(o, t, e) {
16
20
  const i = l("button", `imp-btn ${o}`, { type: "button", "aria-label": t, title: t });
17
- return B(i, e), i;
21
+ return T(i, e), i;
18
22
  }
19
- function U(o, t) {
23
+ function j(o, t) {
20
24
  const e = l("div", `${t}__meta`);
21
25
  return o.forEach((i, s) => {
22
26
  s > 0 && e.append(document.createTextNode(" "));
23
27
  const n = typeof i == "string" ? i : i.text, r = typeof i == "string" ? void 0 : i.icon, a = l("span", `${t}__meta-chunk`);
24
28
  if (r) {
25
29
  const h = l("span", `${t}__meta-icon`);
26
- B(h, r), a.append(h);
30
+ T(h, r), a.append(h);
27
31
  }
28
32
  a.append(document.createTextNode(n)), e.append(a);
29
33
  }), e;
30
34
  }
31
35
  function I(o, t, e) {
32
- B(o, t), e !== void 0 && (o.setAttribute("aria-label", e), o.setAttribute("title", e));
36
+ T(o, t), e !== void 0 && (o.setAttribute("aria-label", e), o.setAttribute("title", e));
33
37
  }
34
- function w(o, t, e) {
38
+ function x(o, t, e) {
35
39
  return Math.min(e, Math.max(t, o));
36
40
  }
37
- function x(o) {
41
+ function _(o) {
38
42
  if (!Number.isFinite(o) || o < 0) return "0:00";
39
43
  const t = Math.floor(o % 60), e = Math.floor(o / 60 % 60), i = Math.floor(o / 3600), s = i > 0 ? String(e).padStart(2, "0") : String(e), n = String(t).padStart(2, "0");
40
44
  return i > 0 ? `${i}:${s}:${n}` : `${s}:${n}`;
41
45
  }
42
- function F(o) {
46
+ function V(o) {
43
47
  const t = o.trim().match(/^(?:(\d+):)?(\d{1,2}):(\d{2})(?:[.,](\d{1,3}))?$/);
44
48
  if (!t) return null;
45
49
  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;
46
50
  return e * 3600 + i * 60 + s + n / 1e3;
47
51
  }
48
- function j(o) {
52
+ function K(o) {
49
53
  const t = [], e = o.replace(/\r\n?/g, `
50
54
  `).split(/\n\n+/);
51
55
  for (const i of e) {
52
56
  const s = i.split(`
53
- `).filter((u) => u.trim() !== "");
57
+ `).filter((m) => m.trim() !== "");
54
58
  if (s.length === 0) continue;
55
- let n = s.findIndex((u) => u.includes("-->"));
59
+ let n = s.findIndex((m) => m.includes("-->"));
56
60
  if (n === -1) continue;
57
- const [r, a] = s[n].split("-->"), h = F(r), c = F((a ?? "").split(" ")[1] ?? a ?? "") ?? F(a ?? "");
61
+ const [r, a] = s[n].split("-->"), h = V(r), c = V((a ?? "").split(" ")[1] ?? a ?? "") ?? V(a ?? "");
58
62
  if (h === null || c === null) continue;
59
- const p = s.slice(n + 1).join(`
63
+ const u = s.slice(n + 1).join(`
60
64
  `).trim();
61
- p && t.push({ start: h, end: c, text: p });
65
+ u && t.push({ start: h, end: c, text: u });
62
66
  }
63
67
  return t;
64
68
  }
65
- function Y(o, t) {
69
+ function it(o, t) {
66
70
  try {
67
71
  return new URL(o, new URL(t, window.location.href)).toString();
68
72
  } catch {
69
73
  return o;
70
74
  }
71
75
  }
72
- class tt {
76
+ class st {
73
77
  constructor() {
74
78
  this.listeners = /* @__PURE__ */ new Map();
75
79
  }
@@ -101,56 +105,56 @@ class tt {
101
105
  this.listeners.clear();
102
106
  }
103
107
  }
104
- const f = (o, t = "0 0 24 24") => `<svg viewBox="${t}" fill="currentColor" aria-hidden="true" focusable="false">${o}</svg>`, et = {
105
- play: f('<path d="M8 5.14v13.72c0 .8.87 1.3 1.56.88l10.54-6.86a1.05 1.05 0 0 0 0-1.76L9.56 4.26C8.87 3.84 8 4.34 8 5.14Z"/>'),
106
- pause: f('<rect x="6" y="5" width="4" height="14" rx="1"/><rect x="14" y="5" width="4" height="14" rx="1"/>'),
107
- replay: f('<path d="M12 5V2.5L7.5 6 12 9.5V7a5 5 0 1 1-5 5H5a7 7 0 1 0 7-7Z"/>'),
108
- bigPlay: f('<path d="M8 5.14v13.72c0 .8.87 1.3 1.56.88l10.54-6.86a1.05 1.05 0 0 0 0-1.76L9.56 4.26C8.87 3.84 8 4.34 8 5.14Z"/>'),
109
- volumeHigh: f('<path d="M4 9v6h3.5L12 19.5v-15L7.5 9H4Z"/><path d="M14.5 8.6a4.5 4.5 0 0 1 0 6.8v-1.9a2.5 2.5 0 0 0 0-3v-1.9Z"/><path d="M14.5 5.2a8 8 0 0 1 0 13.6v-2a6 6 0 0 0 0-9.6v-2Z"/>'),
110
- volumeLow: f('<path d="M4 9v6h3.5L12 19.5v-15L7.5 9H4Z"/><path d="M14.5 8.6a4.5 4.5 0 0 1 0 6.8v-1.9a2.5 2.5 0 0 0 0-3v-1.9Z"/>'),
111
- volumeMute: f('<path d="M4 9v6h3.5L12 19.5v-15L7.5 9H4Z"/><path d="m15.3 9.3 1.4 1.4 1.4-1.4 1.4 1.4-1.4 1.4 1.4 1.4-1.4 1.4-1.4-1.4-1.4 1.4-1.4-1.4 1.4-1.4-1.4-1.4 1.4-1.4Z"/>'),
112
- fullscreen: f('<path d="M5 5h5v2H7v3H5V5Zm9 0h5v5h-2V7h-3V5ZM5 14h2v3h3v2H5v-5Zm12 0h2v5h-5v-2h3v-3Z"/>'),
113
- fullscreenExit: f('<path d="M10 10H5V8h3V5h2v5Zm4 0V5h2v3h3v2h-5Zm-4 4v5H8v-3H5v-2h5Zm4 0h5v2h-3v3h-2v-5Z"/>'),
114
- pip: f('<path d="M3 5h18v14H3V5Zm2 2v10h14V7H5Z"/><rect x="12" y="11" width="6" height="4"/>'),
115
- settings: f('<path d="M12 8.5A3.5 3.5 0 1 0 12 15.5 3.5 3.5 0 0 0 12 8.5Zm0 2a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3Z"/><path d="M10.3 2.8 9.9 5.1a7 7 0 0 0-1.5.86l-2.2-.8-1.7 3 1.8 1.5a7 7 0 0 0 0 1.7l-1.8 1.5 1.7 3 2.2-.8c.46.36.97.65 1.5.86l.4 2.3h3.4l.4-2.3a7 7 0 0 0 1.5-.86l2.2.8 1.7-3-1.8-1.5a7 7 0 0 0 0-1.7l1.8-1.5-1.7-3-2.2.8a7 7 0 0 0-1.5-.86l-.4-2.3h-3.4Zm1.7 5.7a3.5 3.5 0 1 1 0 7 3.5 3.5 0 0 1 0-7Z"/>'),
116
- speed: f('<path d="M12 4a9 9 0 0 0-9 9 8.96 8.96 0 0 0 1.62 5.16l1.64-1.15A7 7 0 0 1 5 13a7 7 0 1 1 12.74 4.01l1.64 1.15A8.96 8.96 0 0 0 21 13a9 9 0 0 0-9-9Z"/><path d="m15.6 8.3-3.95 3.13a1.5 1.5 0 1 0 1.92 1.92L16.7 9.4a.78.78 0 0 0-1.1-1.1Z"/>'),
117
- scenes: f('<path d="M3 5h18v14H3V5Zm2 2v10h3V7H5Zm5 0v10h9V7h-9Zm-5 3h3v1H5v-1Zm0 3h3v1H5v-1Z"/>'),
118
- shuffle: f('<path d="M4 6h2.6c1.5 0 2.9.7 3.8 1.9l4.1 5.4a2.75 2.75 0 0 0 2.2 1.1H19l-1.8-1.8 1.4-1.4 4.2 4.2-4.2 4.2-1.4-1.4L19 16.4h-2.3a4.75 4.75 0 0 1-3.8-1.9L8.8 9.1A2.75 2.75 0 0 0 6.6 8H4V6Z"/><path d="M19 7.6h-2.3c-.86 0-1.67.41-2.18 1.1l-.93 1.23-1.25-1.65.58-.77A4.75 4.75 0 0 1 16.7 5.6H19L17.2 3.8l1.4-1.4 4.2 4.2-4.2 4.2-1.4-1.4L19 7.6Z" transform="translate(0 1.2)"/>'),
119
- repeat: f('<path d="M7 7h10v2.5L21 6l-4-3.5V5H5v6h2V7Zm10 10H7v-2.5L3 18l4 3.5V19h12v-6h-2v4Z"/>'),
120
- subtitles: f('<path d="M3 5h18v14H3V5Zm2 2v10h14V7H5Zm2 3h6v2H7v-2Zm8 0h2v2h-2v-2ZM7 14h2v2H7v-2Zm4 0h6v2h-6v-2Z"/>'),
121
- list: f('<path d="M4 6h2v2H4V6Zm4 0h12v2H8V6ZM4 11h2v2H4v-2Zm4 0h12v2H8v-2ZM4 16h2v2H4v-2Zm4 0h12v2H8v-2Z"/>'),
122
- next: f('<path d="M6 5.5v13c0 .77.84 1.25 1.5.85l9-6.5a1 1 0 0 0 0-1.7l-9-6.5c-.66-.4-1.5.08-1.5.85Z"/><rect x="17" y="5" width="2.5" height="14" rx="1"/>'),
123
- previous: f('<path d="M18 5.5v13c0 .77-.84 1.25-1.5.85l-9-6.5a1 1 0 0 1 0-1.7l9-6.5c.66-.4 1.5.08 1.5.85Z"/><rect x="4.5" y="5" width="2.5" height="14" rx="1"/>'),
108
+ const y = (o, t = "0 0 24 24") => `<svg viewBox="${t}" fill="currentColor" aria-hidden="true" focusable="false">${o}</svg>`, nt = {
109
+ play: y('<path d="M8 5.14v13.72c0 .8.87 1.3 1.56.88l10.54-6.86a1.05 1.05 0 0 0 0-1.76L9.56 4.26C8.87 3.84 8 4.34 8 5.14Z"/>'),
110
+ pause: y('<rect x="6" y="5" width="4" height="14" rx="1"/><rect x="14" y="5" width="4" height="14" rx="1"/>'),
111
+ replay: y('<path d="M12 5V2.5L7.5 6 12 9.5V7a5 5 0 1 1-5 5H5a7 7 0 1 0 7-7Z"/>'),
112
+ bigPlay: y('<path d="M8 5.14v13.72c0 .8.87 1.3 1.56.88l10.54-6.86a1.05 1.05 0 0 0 0-1.76L9.56 4.26C8.87 3.84 8 4.34 8 5.14Z"/>'),
113
+ volumeHigh: y('<path d="M4 9v6h3.5L12 19.5v-15L7.5 9H4Z"/><path d="M14.5 8.6a4.5 4.5 0 0 1 0 6.8v-1.9a2.5 2.5 0 0 0 0-3v-1.9Z"/><path d="M14.5 5.2a8 8 0 0 1 0 13.6v-2a6 6 0 0 0 0-9.6v-2Z"/>'),
114
+ volumeLow: y('<path d="M4 9v6h3.5L12 19.5v-15L7.5 9H4Z"/><path d="M14.5 8.6a4.5 4.5 0 0 1 0 6.8v-1.9a2.5 2.5 0 0 0 0-3v-1.9Z"/>'),
115
+ volumeMute: y('<path d="M4 9v6h3.5L12 19.5v-15L7.5 9H4Z"/><path d="m15.3 9.3 1.4 1.4 1.4-1.4 1.4 1.4-1.4 1.4 1.4 1.4-1.4 1.4-1.4-1.4-1.4 1.4-1.4-1.4 1.4-1.4-1.4-1.4 1.4-1.4Z"/>'),
116
+ fullscreen: y('<path d="M5 5h5v2H7v3H5V5Zm9 0h5v5h-2V7h-3V5ZM5 14h2v3h3v2H5v-5Zm12 0h2v5h-5v-2h3v-3Z"/>'),
117
+ fullscreenExit: y('<path d="M10 10H5V8h3V5h2v5Zm4 0V5h2v3h3v2h-5Zm-4 4v5H8v-3H5v-2h5Zm4 0h5v2h-3v3h-2v-5Z"/>'),
118
+ pip: y('<path d="M3 5h18v14H3V5Zm2 2v10h14V7H5Z"/><rect x="12" y="11" width="6" height="4"/>'),
119
+ settings: y('<path d="M12 8.5A3.5 3.5 0 1 0 12 15.5 3.5 3.5 0 0 0 12 8.5Zm0 2a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3Z"/><path d="M10.3 2.8 9.9 5.1a7 7 0 0 0-1.5.86l-2.2-.8-1.7 3 1.8 1.5a7 7 0 0 0 0 1.7l-1.8 1.5 1.7 3 2.2-.8c.46.36.97.65 1.5.86l.4 2.3h3.4l.4-2.3a7 7 0 0 0 1.5-.86l2.2.8 1.7-3-1.8-1.5a7 7 0 0 0 0-1.7l1.8-1.5-1.7-3-2.2.8a7 7 0 0 0-1.5-.86l-.4-2.3h-3.4Zm1.7 5.7a3.5 3.5 0 1 1 0 7 3.5 3.5 0 0 1 0-7Z"/>'),
120
+ speed: y('<path d="M12 4a9 9 0 0 0-9 9 8.96 8.96 0 0 0 1.62 5.16l1.64-1.15A7 7 0 0 1 5 13a7 7 0 1 1 12.74 4.01l1.64 1.15A8.96 8.96 0 0 0 21 13a9 9 0 0 0-9-9Z"/><path d="m15.6 8.3-3.95 3.13a1.5 1.5 0 1 0 1.92 1.92L16.7 9.4a.78.78 0 0 0-1.1-1.1Z"/>'),
121
+ scenes: y('<path d="M3 5h18v14H3V5Zm2 2v10h3V7H5Zm5 0v10h9V7h-9Zm-5 3h3v1H5v-1Zm0 3h3v1H5v-1Z"/>'),
122
+ shuffle: y('<path d="M4 6h2.6c1.5 0 2.9.7 3.8 1.9l4.1 5.4a2.75 2.75 0 0 0 2.2 1.1H19l-1.8-1.8 1.4-1.4 4.2 4.2-4.2 4.2-1.4-1.4L19 16.4h-2.3a4.75 4.75 0 0 1-3.8-1.9L8.8 9.1A2.75 2.75 0 0 0 6.6 8H4V6Z"/><path d="M19 7.6h-2.3c-.86 0-1.67.41-2.18 1.1l-.93 1.23-1.25-1.65.58-.77A4.75 4.75 0 0 1 16.7 5.6H19L17.2 3.8l1.4-1.4 4.2 4.2-4.2 4.2-1.4-1.4L19 7.6Z" transform="translate(0 1.2)"/>'),
123
+ repeat: y('<path d="M7 7h10v2.5L21 6l-4-3.5V5H5v6h2V7Zm10 10H7v-2.5L3 18l4 3.5V19h12v-6h-2v4Z"/>'),
124
+ subtitles: y('<path d="M3 5h18v14H3V5Zm2 2v10h14V7H5Zm2 3h6v2H7v-2Zm8 0h2v2h-2v-2ZM7 14h2v2H7v-2Zm4 0h6v2h-6v-2Z"/>'),
125
+ list: y('<path d="M4 6h2v2H4V6Zm4 0h12v2H8V6ZM4 11h2v2H4v-2Zm4 0h12v2H8v-2ZM4 16h2v2H4v-2Zm4 0h12v2H8v-2Z"/>'),
126
+ next: y('<path d="M6 5.5v13c0 .77.84 1.25 1.5.85l9-6.5a1 1 0 0 0 0-1.7l-9-6.5c-.66-.4-1.5.08-1.5.85Z"/><rect x="17" y="5" width="2.5" height="14" rx="1"/>'),
127
+ previous: y('<path d="M18 5.5v13c0 .77-.84 1.25-1.5.85l-9-6.5a1 1 0 0 1 0-1.7l9-6.5c.66-.4 1.5.08 1.5.85Z"/><rect x="4.5" y="5" width="2.5" height="14" rx="1"/>'),
124
128
  // Thin circular-arrow ("rotate") icons — open center so the step number reads
125
129
  // clearly inside the ring (matches the reference skip ±N look).
126
130
  seekForward: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/></svg>',
127
131
  seekBack: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"/></svg>',
128
- like: f('<path d="M9 21H5a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h4v11Zm2 0h7.1a2 2 0 0 0 2-1.6l1.3-7a2 2 0 0 0-2-2.4H14V5.5A2.5 2.5 0 0 0 11.5 3l-.5.1V10h-.9L11 21Z"/>'),
129
- dislike: f('<path d="M15 3h4a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2h-4V3Zm-2 0H5.9a2 2 0 0 0-2 1.6l-1.3 7a2 2 0 0 0 2 2.4H10v4.5A2.5 2.5 0 0 0 12.5 21l.5-.1V14h.9L13 3Z"/>'),
130
- addTo: f('<path d="M4 6h12v2H4V6Zm0 4h12v2H4v-2Zm0 4h8v2H4v-2Zm14 0v-4h2v4h4v2h-4v4h-2v-4h-4v-2h4Z"/>'),
131
- share: f('<path d="M18 8a3 3 0 1 0-2.83-4H15a3 3 0 0 0 .14 1.06L8.4 8.94a3 3 0 1 0 0 6.12l6.74 3.88A3 3 0 1 0 16 16.6l-6.74-3.88a3.03 3.03 0 0 0 0-1.44L16 7.4c.55.38 1.24.6 2 .6Z"/>'),
132
- report: f('<path d="M5 3h2v18H5V3Zm4 1h10l-2.5 4L19 12H9V4Z"/>'),
133
- more: f('<circle cx="12" cy="5" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="12" cy="19" r="2"/>'),
134
- close: f('<path d="m6.4 5 5.6 5.6L17.6 5 19 6.4 13.4 12l5.6 5.6-1.4 1.4-5.6-5.6L6.4 19 5 17.6 10.6 12 5 6.4 6.4 5Z"/>'),
132
+ like: y('<path d="M9 21H5a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h4v11Zm2 0h7.1a2 2 0 0 0 2-1.6l1.3-7a2 2 0 0 0-2-2.4H14V5.5A2.5 2.5 0 0 0 11.5 3l-.5.1V10h-.9L11 21Z"/>'),
133
+ dislike: y('<path d="M15 3h4a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2h-4V3Zm-2 0H5.9a2 2 0 0 0-2 1.6l-1.3 7a2 2 0 0 0 2 2.4H10v4.5A2.5 2.5 0 0 0 12.5 21l.5-.1V14h.9L13 3Z"/>'),
134
+ addTo: y('<path d="M4 6h12v2H4V6Zm0 4h12v2H4v-2Zm0 4h8v2H4v-2Zm14 0v-4h2v4h4v2h-4v4h-2v-4h-4v-2h4Z"/>'),
135
+ share: y('<path d="M18 8a3 3 0 1 0-2.83-4H15a3 3 0 0 0 .14 1.06L8.4 8.94a3 3 0 1 0 0 6.12l6.74 3.88A3 3 0 1 0 16 16.6l-6.74-3.88a3.03 3.03 0 0 0 0-1.44L16 7.4c.55.38 1.24.6 2 .6Z"/>'),
136
+ report: y('<path d="M5 3h2v18H5V3Zm4 1h10l-2.5 4L19 12H9V4Z"/>'),
137
+ more: y('<circle cx="12" cy="5" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="12" cy="19" r="2"/>'),
138
+ close: y('<path d="m6.4 5 5.6 5.6L17.6 5 19 6.4 13.4 12l5.6 5.6-1.4 1.4-5.6-5.6L6.4 19 5 17.6 10.6 12 5 6.4 6.4 5Z"/>'),
135
139
  // Generic "uploaded by a user" glyph (head + shoulders) for preview meta.
136
- user: f('<path d="M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm0 2c-3.6 0-8 1.8-8 4.4V21h16v-2.6c0-2.6-4.4-4.4-8-4.4Z"/>'),
140
+ user: y('<path d="M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm0 2c-3.6 0-8 1.8-8 4.4V21h16v-2.6c0-2.6-4.4-4.4-8-4.4Z"/>'),
137
141
  // Generic "channel" glyph (play badge) for preview meta when a channel is set.
138
- channel: f('<path d="M3 5h18a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1Zm7 3.5v7l6-3.5-6-3.5Z"/>')
139
- }, N = { en: H };
140
- function Et(o, t) {
141
- N[o] = t;
142
+ channel: y('<path d="M3 5h18a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1Zm7 3.5v7l6-3.5-6-3.5Z"/>')
143
+ }, q = { en: Z };
144
+ function It(o, t) {
145
+ q[o] = t;
142
146
  }
143
- function Pt(o) {
147
+ function $t(o) {
144
148
  for (const [t, e] of Object.entries(o))
145
- e && (N[t] = e);
149
+ e && (q[t] = e);
146
150
  }
147
- function it(o) {
148
- return o && N[o] || H;
151
+ function rt(o) {
152
+ return o && q[o] || Z;
149
153
  }
150
- function At() {
151
- return Object.keys(N);
154
+ function qt() {
155
+ return Object.keys(q);
152
156
  }
153
- function st(o) {
157
+ function ot(o) {
154
158
  const t = [0.06, 0.24, 0.4, 0.24, 0.06], e = o.length;
155
159
  return o.map(
156
160
  (i, s) => t.reduce((n, r, a) => {
@@ -159,19 +163,19 @@ function st(o) {
159
163
  }, 0)
160
164
  );
161
165
  }
162
- function nt(o, t) {
166
+ function lt(o, t) {
163
167
  if (o.length === 0) return 0;
164
168
  const e = Math.min(o.length - 1, Math.max(0, Math.round((o.length - 1) * t)));
165
169
  return o[e];
166
170
  }
167
- function K(o, t) {
171
+ function X(o, t) {
168
172
  if (o.length === 0 || o.every((n) => n <= 0)) return [];
169
- const e = st(o), i = t === "retention" ? nt([...e].sort((n, r) => n - r), 0.95) : Math.max(...e);
173
+ const e = ot(o), i = t === "retention" ? lt([...e].sort((n, r) => n - r), 0.95) : Math.max(...e);
170
174
  if (i <= 0) return [];
171
175
  const s = 0.08;
172
176
  return e.map((n) => s + (1 - s) * Math.min(1, Math.max(0, n / i)));
173
177
  }
174
- function rt(o, t, e = 100) {
178
+ function at(o, t, e = 100) {
175
179
  if (o.length === 0 || !Number.isFinite(t) || t <= 0) return [];
176
180
  const i = new Array(e).fill(0);
177
181
  let s = !1;
@@ -180,27 +184,35 @@ function rt(o, t, e = 100) {
180
184
  const r = Math.max(0, n.value);
181
185
  r !== 0 && (i[Math.min(e - 1, Math.floor(n.time / t * e))] += r, s = !0);
182
186
  }
183
- return s ? K(i, "peaks") : [];
187
+ return s ? X(i, "peaks") : [];
184
188
  }
185
- function ot(o, t = "peaks") {
186
- const e = o.map((i) => Number.isFinite(i) ? Math.max(0, i) : 0);
187
- return K(e, t);
189
+ function ht(o, t = "peaks", e = 200) {
190
+ let i = o.map((s) => Number.isFinite(s) ? Math.max(0, s) : 0);
191
+ if (i.length > e) {
192
+ const s = new Array(e).fill(0), n = new Array(e).fill(0);
193
+ for (let r = 0; r < i.length; r++) {
194
+ const a = Math.min(e - 1, Math.floor(r / i.length * e));
195
+ s[a] += i[r], n[a]++;
196
+ }
197
+ i = s.map((r, a) => n[a] > 0 ? r / n[a] : 0);
198
+ }
199
+ return X(i, t);
188
200
  }
189
- function lt(o, t = 1, e = 1e3, i = 100) {
201
+ function ct(o, t = 1, e = 1e3, i = 100) {
190
202
  const s = o.length;
191
203
  if (s === 0) return "";
192
- const n = e / (s - 1 || 1), r = Math.max(0, t) / 6, a = (p) => {
193
- const u = Math.min(s - 1, Math.max(0, p));
194
- return [u * n, i - o[u] * i];
204
+ const n = e / (s - 1 || 1), r = Math.max(0, t) / 6, a = (u) => {
205
+ const m = Math.min(s - 1, Math.max(0, u));
206
+ return [m * n, i - o[m] * i];
195
207
  }, [, h] = a(0);
196
208
  let c = `M 0 ${i} L 0 ${h.toFixed(1)}`;
197
- for (let p = 0; p < s - 1; p++) {
198
- const [u, m] = a(p - 1), [v, y] = a(p), [_, d] = a(p + 1), [b, M] = a(p + 2), P = v + (_ - u) * r, V = y + (d - m) * r, E = _ - (b - v) * r, A = d - (M - y) * r;
199
- c += ` C ${P.toFixed(1)} ${V.toFixed(1)} ${E.toFixed(1)} ${A.toFixed(1)} ${_.toFixed(1)} ${d.toFixed(1)}`;
209
+ for (let u = 0; u < s - 1; u++) {
210
+ const [m, p] = a(u - 1), [v, f] = a(u), [b, d] = a(u + 1), [k, C] = a(u + 2), A = v + (b - m) * r, F = Math.min(i, Math.max(0, f + (d - p) * r)), P = b - (k - v) * r, R = Math.min(i, Math.max(0, d - (C - f) * r));
211
+ c += ` C ${A.toFixed(1)} ${F.toFixed(1)} ${P.toFixed(1)} ${R.toFixed(1)} ${b.toFixed(1)} ${d.toFixed(1)}`;
200
212
  }
201
213
  return c += ` L ${e} ${i} Z`, c;
202
214
  }
203
- async function at(o, t) {
215
+ async function dt(o, t) {
204
216
  if (o.src)
205
217
  return {
206
218
  roll: o.roll,
@@ -210,16 +222,16 @@ async function at(o, t) {
210
222
  tracking: {}
211
223
  };
212
224
  if (!o.vastTag) throw new Error('Ad roll has neither "vastTag" nor "src"');
213
- return X(o, o.vastTag, t, 0, { impressions: [], tracking: {} });
225
+ return J(o, o.vastTag, t, 0, { impressions: [], tracking: {} });
214
226
  }
215
- async function X(o, t, e, i, s) {
227
+ async function J(o, t, e, i, s) {
216
228
  if (i > e.maxWrapperDepth) throw new Error("VAST wrapper depth limit exceeded");
217
229
  const n = new AbortController(), r = setTimeout(() => n.abort(), e.requestTimeout);
218
230
  let a;
219
231
  try {
220
- const y = await fetch(t, { signal: n.signal, credentials: "omit" });
221
- if (!y.ok) throw new Error(`VAST request failed (${y.status})`);
222
- a = await y.text();
232
+ const f = await fetch(t, { signal: n.signal, credentials: "omit" });
233
+ if (!f.ok) throw new Error(`VAST request failed (${f.status})`);
234
+ a = await f.text();
223
235
  } finally {
224
236
  clearTimeout(r);
225
237
  }
@@ -227,52 +239,52 @@ async function X(o, t, e, i, s) {
227
239
  if (h.querySelector("parsererror")) throw new Error("VAST response is not valid XML");
228
240
  const c = h.querySelector("VAST > Ad");
229
241
  if (!c) throw new Error("VAST response contains no ads");
230
- ht(c, s);
231
- const p = c.querySelector(":scope > Wrapper");
232
- if (p) {
233
- const y = S(p.querySelector("VASTAdTagURI"));
234
- if (!y) throw new Error("VAST wrapper without VASTAdTagURI");
235
- return X(o, y, e, i + 1, s);
236
- }
237
- const u = c.querySelector(":scope > InLine");
238
- if (!u) throw new Error("VAST ad has neither InLine nor Wrapper");
239
- const m = u.querySelector("Creatives > Creative > Linear");
240
- if (!m) throw new Error("VAST ad has no Linear creative");
241
- const v = ct(m);
242
+ ut(c, s);
243
+ const u = c.querySelector(":scope > Wrapper");
244
+ if (u) {
245
+ const f = L(u.querySelector("VASTAdTagURI"));
246
+ if (!f) throw new Error("VAST wrapper without VASTAdTagURI");
247
+ return J(o, f, e, i + 1, s);
248
+ }
249
+ const m = c.querySelector(":scope > InLine");
250
+ if (!m) throw new Error("VAST ad has neither InLine nor Wrapper");
251
+ const p = m.querySelector("Creatives > Creative > Linear");
252
+ if (!p) throw new Error("VAST ad has no Linear creative");
253
+ const v = pt(p);
242
254
  if (!v) throw new Error("VAST ad has no playable MediaFile");
243
255
  return {
244
256
  roll: o.roll,
245
257
  mediaUrl: v.url,
246
258
  mediaType: v.type,
247
- clickThrough: S(m.querySelector("VideoClicks > ClickThrough")) ?? o.clickUrl,
248
- duration: O(S(m.querySelector(":scope > Duration"))),
249
- skipOffset: dt(
250
- m.getAttribute("skipoffset"),
251
- O(S(m.querySelector(":scope > Duration")))
259
+ clickThrough: L(p.querySelector("VideoClicks > ClickThrough")) ?? o.clickUrl,
260
+ duration: H(L(p.querySelector(":scope > Duration"))),
261
+ skipOffset: mt(
262
+ p.getAttribute("skipoffset"),
263
+ H(L(p.querySelector(":scope > Duration")))
252
264
  ),
253
265
  impressions: s.impressions,
254
266
  tracking: s.tracking,
255
- adTitle: S(u.querySelector(":scope > AdTitle")) ?? void 0
267
+ adTitle: L(m.querySelector(":scope > AdTitle")) ?? void 0
256
268
  };
257
269
  }
258
- function ht(o, t) {
270
+ function ut(o, t) {
259
271
  var e, i;
260
272
  for (const s of o.querySelectorAll("Impression")) {
261
- const n = S(s);
273
+ const n = L(s);
262
274
  n && t.impressions.push(n);
263
275
  }
264
276
  for (const s of o.querySelectorAll("Linear > TrackingEvents > Tracking")) {
265
- const n = s.getAttribute("event"), r = S(s);
277
+ const n = s.getAttribute("event"), r = L(s);
266
278
  !n || !r || ["start", "firstQuartile", "midpoint", "thirdQuartile", "complete", "skip", "pause", "resume"].includes(n) && ((e = t.tracking)[n] ?? (e[n] = [])).push(r);
267
279
  }
268
280
  for (const s of o.querySelectorAll("Linear > VideoClicks > ClickTracking")) {
269
- const n = S(s);
281
+ const n = L(s);
270
282
  n && ((i = t.tracking).click ?? (i.click = [])).push(n);
271
283
  }
272
284
  }
273
- function ct(o) {
285
+ function pt(o) {
274
286
  const e = [...o.querySelectorAll("MediaFiles > MediaFile")].map((r) => ({
275
- url: S(r) ?? "",
287
+ url: L(r) ?? "",
276
288
  type: r.getAttribute("type") ?? void 0,
277
289
  delivery: r.getAttribute("delivery") ?? "",
278
290
  bitrate: Number(r.getAttribute("bitrate") ?? 0),
@@ -285,16 +297,16 @@ function ct(o) {
285
297
  const i = e.filter((r) => r.delivery !== "streaming"), s = i.length > 0 ? i : e, n = s[Math.floor(s.length / 2)];
286
298
  return { url: n.url, type: n.type };
287
299
  }
288
- function O(o) {
300
+ function H(o) {
289
301
  if (!o) return;
290
302
  const t = o.trim().match(/^(?:(\d+):)?(\d{1,2}):(\d{2})(?:\.(\d{1,3}))?$/);
291
303
  if (t)
292
304
  return (t[1] ? Number(t[1]) * 3600 : 0) + Number(t[2]) * 60 + Number(t[3]) + (t[4] ? Number(t[4].padEnd(3, "0")) / 1e3 : 0);
293
305
  }
294
- function dt(o, t) {
306
+ function mt(o, t) {
295
307
  if (!o) return;
296
308
  const e = o.trim().match(/^(\d+(?:\.\d+)?)%$/);
297
- return e ? t !== void 0 ? Number(e[1]) / 100 * t : void 0 : O(o);
309
+ return e ? t !== void 0 ? Number(e[1]) / 100 * t : void 0 : H(o);
298
310
  }
299
311
  function $(o) {
300
312
  if (o)
@@ -304,10 +316,10 @@ function $(o) {
304
316
  } catch {
305
317
  }
306
318
  }
307
- function S(o) {
319
+ function L(o) {
308
320
  return o?.textContent?.trim().replace(/^<!\[CDATA\[|\]\]>$/g, "").trim() || null;
309
321
  }
310
- class ut {
322
+ class vt {
311
323
  constructor(t, e) {
312
324
  this.host = t, this.playedRolls = /* @__PURE__ */ new Set(), this.sourcesSeen = 0, this.activeBreak = null, this.layer = null, this.adVideo = null, this.destroyed = !1, this.opts = {
313
325
  skipDelay: 5,
@@ -374,7 +386,7 @@ class ut {
374
386
  for (const n of t) {
375
387
  this.playedRolls.add(n);
376
388
  try {
377
- const r = await at(n, this.opts);
389
+ const r = await dt(n, this.opts);
378
390
  await this.playAd(r);
379
391
  } catch (r) {
380
392
  const a = r instanceof Error ? r : new Error(String(r));
@@ -393,68 +405,68 @@ class ut {
393
405
  return new Promise((e) => {
394
406
  const { labels: i } = this.host, s = l("div", "imp-ad"), n = this.ensureAdVideo(), r = new AbortController(), a = r.signal;
395
407
  n.src = t.mediaUrl, n.muted = this.host.contentVideo.muted, n.volume = this.host.contentVideo.volume;
396
- const h = l("div", "imp-spinner imp-ad__spinner"), c = l("div", "imp-ad__hud"), p = l("span", "imp-ad__badge");
397
- p.textContent = t.adTitle ? `${i.adLabel} · ${t.adTitle}` : i.adLabel;
398
- const u = l("span", "imp-ad__countdown");
399
- c.append(p, u);
400
- const m = l("div", "imp-ad__actions");
408
+ const h = l("div", "imp-spinner imp-ad__spinner"), c = l("div", "imp-ad__hud"), u = l("span", "imp-ad__badge");
409
+ u.textContent = t.adTitle ? `${i.adLabel} · ${t.adTitle}` : i.adLabel;
410
+ const m = l("span", "imp-ad__countdown");
411
+ c.append(u, m);
412
+ const p = l("div", "imp-ad__actions");
401
413
  let v = null;
402
- t.clickThrough && (v = l("button", "imp-ad__visit", { type: "button" }), v.textContent = i.visitAdvertiser, m.append(v));
403
- const y = l("button", "imp-ad__skip", { type: "button" });
404
- y.hidden = !0, m.append(y), s.append(n, h, c, m), this.host.container.append(s), this.layer = s;
405
- const _ = t.skipOffset ?? this.opts.skipDelay, d = /* @__PURE__ */ new Set(), b = (k) => {
406
- d.has(k) || (d.add(k), $(t.tracking[k]));
414
+ t.clickThrough && (v = l("button", "imp-ad__visit", { type: "button" }), v.textContent = i.visitAdvertiser, p.append(v));
415
+ const f = l("button", "imp-ad__skip", { type: "button" });
416
+ f.hidden = !0, p.append(f), s.append(n, h, c, p), this.host.container.append(s), this.layer = s;
417
+ const b = t.skipOffset ?? this.opts.skipDelay, d = /* @__PURE__ */ new Set(), k = (w) => {
418
+ d.has(w) || (d.add(w), $(t.tracking[w]));
407
419
  };
408
- let M = Date.now(), P = -1;
409
- const V = setInterval(() => {
420
+ let C = Date.now(), A = -1;
421
+ const F = setInterval(() => {
410
422
  if (n.paused) {
411
- M = Date.now();
423
+ C = Date.now();
412
424
  return;
413
425
  }
414
- if (n.currentTime !== P) {
415
- P = n.currentTime, M = Date.now();
426
+ if (n.currentTime !== A) {
427
+ A = n.currentTime, C = Date.now();
416
428
  return;
417
429
  }
418
- Date.now() - M >= this.opts.mediaTimeout && (this.host.emitter.emit("aderror", {
430
+ Date.now() - C >= this.opts.mediaTimeout && (this.host.emitter.emit("aderror", {
419
431
  roll: { roll: t.roll },
420
432
  error: new Error(`Ad media stalled for ${this.opts.mediaTimeout} ms — skipping`)
421
- }), E());
422
- }, 500), E = () => {
423
- clearInterval(V), r.abort(), n.pause(), n.removeAttribute("src"), n.load(), s.remove(), this.layer = null, e();
424
- }, A = (k) => {
425
- k ? (b("skip"), this.host.emitter.emit("adskip", { ad: t })) : b("complete"), this.host.emitter.emit("adend", { ad: t }), E();
433
+ }), P());
434
+ }, 500), P = () => {
435
+ clearInterval(F), r.abort(), n.pause(), n.removeAttribute("src"), n.load(), s.remove(), this.layer = null, e();
436
+ }, R = (w) => {
437
+ w ? (k("skip"), this.host.emitter.emit("adskip", { ad: t })) : k("complete"), this.host.emitter.emit("adend", { ad: t }), P();
426
438
  };
427
439
  n.addEventListener("playing", () => {
428
- $(t.impressions), b("start"), this.host.emitter.emit("adstart", { ad: t });
440
+ $(t.impressions), k("start"), this.host.emitter.emit("adstart", { ad: t });
429
441
  }, { once: !0, signal: a }), n.addEventListener("playing", () => {
430
442
  h.hidden = !0;
431
443
  }, { signal: a }), n.addEventListener("waiting", () => {
432
444
  h.hidden = !1;
433
445
  }, { signal: a }), n.addEventListener("timeupdate", () => {
434
- const k = n.currentTime, T = n.duration;
435
- if (Number.isFinite(T) && T > 0 && (u.textContent = x(Math.max(0, T - k)), k / T >= 0.25 && b("firstQuartile"), k / T >= 0.5 && b("midpoint"), k / T >= 0.75 && b("thirdQuartile")), _ >= 0) {
436
- const W = Math.ceil(_ - k);
437
- W > 0 ? (y.hidden = !1, y.disabled = !0, y.textContent = `${i.skipAdIn} ${W}`) : (y.hidden = !1, y.disabled = !1, y.textContent = i.skipAd);
446
+ const w = n.currentTime, B = n.duration;
447
+ if (Number.isFinite(B) && B > 0 && (m.textContent = _(Math.max(0, B - w)), w / B >= 0.25 && k("firstQuartile"), w / B >= 0.5 && k("midpoint"), w / B >= 0.75 && k("thirdQuartile")), b >= 0) {
448
+ const z = Math.ceil(b - w);
449
+ z > 0 ? (f.hidden = !1, f.disabled = !0, f.textContent = `${i.skipAdIn} ${z}`) : (f.hidden = !1, f.disabled = !1, f.textContent = i.skipAd);
438
450
  }
439
- }, { signal: a }), n.addEventListener("ended", () => A(!1), { signal: a }), n.addEventListener("error", () => {
451
+ }, { signal: a }), n.addEventListener("ended", () => R(!1), { signal: a }), n.addEventListener("error", () => {
440
452
  this.host.emitter.emit("aderror", {
441
453
  roll: { roll: t.roll },
442
454
  error: new Error("Ad media failed to play")
443
- }), E();
444
- }, { signal: a }), y.addEventListener("click", () => A(!0));
445
- const D = () => {
446
- t.clickThrough && (b("click"), this.host.emitter.emit("adclick", { ad: t }), window.open(t.clickThrough, "_blank", "noopener"), n.pause());
455
+ }), P();
456
+ }, { signal: a }), f.addEventListener("click", () => R(!0));
457
+ const G = () => {
458
+ t.clickThrough && (k("click"), this.host.emitter.emit("adclick", { ad: t }), window.open(t.clickThrough, "_blank", "noopener"), n.pause());
447
459
  };
448
- n.addEventListener("click", D, { signal: a }), v?.addEventListener("click", D);
449
- let G = !1, R = !1;
460
+ n.addEventListener("click", G, { signal: a }), v?.addEventListener("click", G);
461
+ let W = !1, N = !1;
450
462
  n.addEventListener("playing", () => {
451
- G = !0;
463
+ W = !0;
452
464
  }, { once: !0, signal: a }), n.addEventListener("pause", () => {
453
- n.ended || !s.isConnected || (s.classList.add("imp-ad--paused"), G && !R && (R = !0, $(t.tracking.pause), this.host.emitter.emit("adpause", { ad: t })));
465
+ n.ended || !s.isConnected || (s.classList.add("imp-ad--paused"), W && !N && (N = !0, $(t.tracking.pause), this.host.emitter.emit("adpause", { ad: t })));
454
466
  }, { signal: a }), n.addEventListener("play", () => {
455
- s.classList.remove("imp-ad--paused"), R && (R = !1, $(t.tracking.resume), this.host.emitter.emit("adresume", { ad: t }));
456
- }, { signal: a }), s.addEventListener("click", (k) => {
457
- (k.target === s || s.classList.contains("imp-ad--paused")) && n.paused && n.play().catch(() => {
467
+ s.classList.remove("imp-ad--paused"), N && (N = !1, $(t.tracking.resume), this.host.emitter.emit("adresume", { ad: t }));
468
+ }, { signal: a }), s.addEventListener("click", (w) => {
469
+ (w.target === s || s.classList.contains("imp-ad--paused")) && n.paused && n.play().catch(() => {
458
470
  });
459
471
  }), n.play().catch(() => {
460
472
  s.classList.add("imp-ad--paused");
@@ -469,7 +481,7 @@ class ut {
469
481
  this.destroyed = !0, this.adVideo?.pause(), this.layer?.remove(), this.layer = null, this.adVideo = null;
470
482
  }
471
483
  }
472
- function z(o, t) {
484
+ function Q(o, t) {
473
485
  const e = [...o].sort((s, n) => s.start - n.start), i = [];
474
486
  for (let s = 0; s < e.length; s++) {
475
487
  const n = Math.max(0, e[s].start);
@@ -479,41 +491,40 @@ function z(o, t) {
479
491
  }
480
492
  return i;
481
493
  }
482
- async function pt(o) {
494
+ async function ft(o) {
483
495
  const t = await fetch(o);
484
496
  if (!t.ok) throw new Error(`Failed to load chapters VTT (${t.status})`);
485
497
  const e = await t.text();
486
- return j(e).map((i) => ({ start: i.start, end: i.end, title: i.text }));
498
+ return K(e).map((i) => ({ start: i.start, end: i.end, title: i.text }));
487
499
  }
488
- function J(o, t) {
500
+ function Y(o, t) {
489
501
  for (const e of o)
490
502
  if (t >= e.start && t < e.end) return e;
491
503
  return null;
492
504
  }
493
- function mt(o, t) {
505
+ function yt(o, t) {
494
506
  return t ? /application\/(x-mpegurl|vnd\.apple\.mpegurl)/i.test(t) : /\.m3u8(\?|#|$)/i.test(o);
495
507
  }
496
- let L;
497
- async function vt() {
498
- if (L !== void 0) return L;
508
+ let E;
509
+ async function gt() {
510
+ if (E !== void 0) return E;
499
511
  const o = globalThis.Hls;
500
512
  if (o)
501
- return L = o, L;
513
+ return E = o, E;
502
514
  try {
503
- L = (await import("hls.js/light")).default;
515
+ return E = (await import("hls.js/light")).default, E;
504
516
  } catch {
505
- L = null;
517
+ return null;
506
518
  }
507
- return L;
508
519
  }
509
- async function ft(o, t, e, i) {
510
- if (mt(t, e)) {
511
- const s = o.canPlayType("application/vnd.apple.mpegurl"), n = s ? null : await vt();
512
- return n && n.isSupported() ? gt(n, o, t, i) : s ? (o.src = t, q(o)) : (i.onError("HLS is not supported in this browser and hls.js could not be loaded."), q(o));
520
+ async function bt(o, t, e, i) {
521
+ if (yt(t, e)) {
522
+ const s = o.canPlayType("application/vnd.apple.mpegurl"), n = s ? null : await gt();
523
+ return n && n.isSupported() ? kt(n, o, t, i) : s ? (o.src = t, O(o)) : (i.onError("HLS is not supported in this browser and hls.js could not be loaded."), O(o));
513
524
  }
514
- return o.src = t, q(o);
525
+ return o.src = t, O(o);
515
526
  }
516
- function q(o) {
527
+ function O(o) {
517
528
  return {
518
529
  kind: "native",
519
530
  levels: [],
@@ -525,52 +536,54 @@ function q(o) {
525
536
  }
526
537
  };
527
538
  }
528
- function gt(o, t, e, i) {
539
+ function kt(o, t, e, i) {
529
540
  const s = new o({ enableWorker: !0 }), n = {
530
541
  kind: "hls",
531
542
  levels: [],
532
543
  selected: -1,
533
- setLevel(h) {
534
- n.selected = h, s.currentLevel = h;
544
+ setLevel(c) {
545
+ n.selected = c, s.currentLevel = c;
535
546
  },
536
547
  destroy() {
537
548
  s.destroy(), t.removeAttribute("src"), t.load();
538
549
  }
539
550
  };
540
551
  s.on(o.Events.MANIFEST_PARSED, () => {
541
- n.levels = s.levels.map((h, c) => ({
542
- index: c,
543
- label: h.height ? `${h.height}p` : `${Math.round(h.bitrate / 1e3)} kbps`
552
+ n.levels = s.levels.map((c, u) => ({
553
+ index: u,
554
+ label: c.height ? `${c.height}p` : `${Math.round(c.bitrate / 1e3)} kbps`
544
555
  })).reverse(), i.onLevels(n.levels);
545
- }), s.on(o.Events.LEVEL_SWITCHED, (h, c) => {
546
- const p = s.levels[c.level];
547
- p && i.onLevelSwitch(p.height ? `${p.height}p` : `${Math.round(p.bitrate / 1e3)} kbps`);
556
+ }), s.on(o.Events.LEVEL_SWITCHED, (c, u) => {
557
+ const m = s.levels[u.level];
558
+ m && i.onLevelSwitch(m.height ? `${m.height}p` : `${Math.round(m.bitrate / 1e3)} kbps`);
548
559
  });
549
- let r = 0, a = !1;
550
- return s.on(o.Events.ERROR, (h, c) => {
551
- if (c.fatal)
552
- switch (c.type) {
560
+ let r = 0, a = 0, h = !1;
561
+ return s.on(o.Events.FRAG_BUFFERED, () => {
562
+ a = 0;
563
+ }), s.on(o.Events.ERROR, (c, u) => {
564
+ if (u.fatal)
565
+ switch (u.type) {
553
566
  case o.ErrorTypes.NETWORK_ERROR:
554
- s.startLoad();
567
+ a < 3 ? (a++, s.startLoad()) : (i.onError(`HLS network error: ${u.details}`, u), s.destroy());
555
568
  break;
556
569
  case o.ErrorTypes.MEDIA_ERROR:
557
- r < 3 ? (r++, s.recoverMediaError()) : (i.onError(`HLS media error: ${c.details}`, c), s.destroy());
570
+ r < 3 ? (r++, s.recoverMediaError()) : (i.onError(`HLS media error: ${u.details}`, u), s.destroy());
558
571
  break;
559
572
  default:
560
- if (a)
561
- i.onError(`HLS fatal error: ${c.details}`, c), s.destroy();
573
+ if (h)
574
+ i.onError(`HLS fatal error: ${u.details}`, u), s.destroy();
562
575
  else {
563
- a = !0;
576
+ h = !0;
564
577
  try {
565
578
  s.loadSource(e), s.startLoad();
566
579
  } catch {
567
- i.onError(`HLS fatal error: ${c.details}`, c), s.destroy();
580
+ i.onError(`HLS fatal error: ${u.details}`, u), s.destroy();
568
581
  }
569
582
  }
570
583
  }
571
584
  }), s.loadSource(e), s.attachMedia(t), n;
572
585
  }
573
- class Z {
586
+ class D {
574
587
  constructor(t) {
575
588
  this.cues = t;
576
589
  }
@@ -578,17 +591,17 @@ class Z {
578
591
  const e = await fetch(t);
579
592
  if (!e.ok) throw new Error(`Failed to load thumbnails VTT (${e.status})`);
580
593
  const i = await e.text(), s = [];
581
- for (const n of j(i)) {
594
+ for (const n of K(i)) {
582
595
  const [r, a] = n.text.trim().split("#");
583
596
  if (!r) continue;
584
597
  const h = {
585
598
  start: n.start,
586
599
  end: n.end,
587
- src: Y(r, t)
600
+ src: it(r, t)
588
601
  }, c = a?.match(/xywh=(\d+),(\d+),(\d+),(\d+)/);
589
602
  c && (h.xywh = { x: Number(c[1]), y: Number(c[2]), w: Number(c[3]), h: Number(c[4]) }), s.push(h);
590
603
  }
591
- return s.sort((n, r) => n.start - r.start), new Z(s);
604
+ return s.sort((n, r) => n.start - r.start), new D(s);
592
605
  }
593
606
  cueAt(t) {
594
607
  let e = 0, i = this.cues.length - 1;
@@ -601,12 +614,12 @@ class Z {
601
614
  return null;
602
615
  }
603
616
  }
604
- const yt = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 6 6 6-6 6"/></svg>', bt = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m15 6-6 6 6 6"/></svg>';
605
- class C {
617
+ const wt = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 6 6 6-6 6"/></svg>', xt = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m15 6-6 6 6 6"/></svg>';
618
+ class M {
606
619
  constructor(t) {
607
- this.anchor = t, this.outsideListener = null, this.root = l("div", "imp-menu"), this.root.hidden = !0, this.backdrop = l("div", "imp-menu__backdrop"), this.backdrop.hidden = !0, this.backdrop.addEventListener("pointerdown", (e) => {
620
+ this.anchor = t, this.outsideListener = null, this.escListener = null, this.root = l("div", "imp-menu"), this.root.hidden = !0, this.backdrop = l("div", "imp-menu__backdrop"), this.backdrop.hidden = !0, this.backdrop.addEventListener("pointerdown", (e) => {
608
621
  e.preventDefault(), this.close();
609
- }), t.append(this.backdrop);
622
+ });
610
623
  }
611
624
  get open() {
612
625
  return !this.root.hidden;
@@ -640,7 +653,7 @@ class C {
640
653
  const r = l("span", "imp-menu__value");
641
654
  r.textContent = i.value ?? "";
642
655
  const a = l("span", "imp-menu__chevron");
643
- a.innerHTML = yt, s.append(n, r, a), s.addEventListener("click", () => this.renderSettingsDetail(t, i)), e.append(s);
656
+ a.innerHTML = wt, s.append(n, r, a), s.addEventListener("click", () => this.renderSettingsDetail(t, i)), e.append(s);
644
657
  }
645
658
  this.root.append(e);
646
659
  }
@@ -662,7 +675,7 @@ class C {
662
675
  if (!e.section) return;
663
676
  this.root.textContent = "";
664
677
  const i = l("button", "imp-menu__item imp-menu__back", { type: "button" }), s = l("span", "imp-menu__chevron");
665
- s.innerHTML = bt;
678
+ s.innerHTML = xt;
666
679
  const n = l("span", "imp-menu__label");
667
680
  n.textContent = e.label, i.append(s, n), i.addEventListener("click", () => this.renderSettingsRoot(t)), this.root.append(i), this.root.append(this.renderSection(e.section())), this.root.scrollTop = 0;
668
681
  }
@@ -677,7 +690,7 @@ class C {
677
690
  const s = l("button", "imp-menu__item", { type: "button", role: "menuitemradio" });
678
691
  if (s.setAttribute("aria-checked", String(i.active)), i.active && s.classList.add("imp-menu__item--active"), i.icon) {
679
692
  const r = l("span", "imp-menu__icon");
680
- B(r, i.icon), s.append(r);
693
+ T(r, i.icon), s.append(r);
681
694
  }
682
695
  const n = l("span", "imp-menu__label");
683
696
  n.textContent = i.label, s.append(n), s.addEventListener("click", () => {
@@ -686,25 +699,28 @@ class C {
686
699
  }
687
700
  return e;
688
701
  }
689
- /** Reveal the populated menu + backdrop and arm the outside-click listener. */
702
+ /** Reveal the populated menu + backdrop and arm outside-click / Escape. */
690
703
  reveal() {
691
- this.root.hidden = !1, this.backdrop.hidden = !1, this.outsideListener = (t) => {
692
- const e = t.target;
693
- !this.root.contains(e) && !this.anchor.contains(e) && this.close();
694
- }, setTimeout(() => {
704
+ const t = this.root.parentElement;
705
+ t && this.backdrop.parentElement !== t && t.insertBefore(this.backdrop, this.root), this.root.hidden = !1, this.backdrop.hidden = !1, this.outsideListener = (e) => {
706
+ const i = e.target;
707
+ !this.root.contains(i) && !this.anchor.contains(i) && this.close();
708
+ }, this.escListener = (e) => {
709
+ e.key === "Escape" && this.close();
710
+ }, document.addEventListener("keydown", this.escListener), setTimeout(() => {
695
711
  this.outsideListener && document.addEventListener("pointerdown", this.outsideListener);
696
712
  }, 0);
697
713
  }
698
714
  close() {
699
- this.root.hidden = !0, this.root.classList.remove("imp-menu--wide"), this.backdrop.hidden = !0, this.outsideListener && (document.removeEventListener("pointerdown", this.outsideListener), this.outsideListener = null);
715
+ this.root.hidden = !0, this.root.classList.remove("imp-menu--wide"), this.backdrop.hidden = !0, this.outsideListener && (document.removeEventListener("pointerdown", this.outsideListener), this.outsideListener = null), this.escListener && (document.removeEventListener("keydown", this.escListener), this.escListener = null);
700
716
  }
701
717
  destroy() {
702
- this.close(), this.root.remove();
718
+ this.close(), this.backdrop.remove(), this.root.remove();
703
719
  }
704
720
  }
705
- class kt {
706
- constructor(t) {
707
- this.cb = t, this.segments = [], this.duration = 0, this.chapters = [], this.thumbnails = null, this.scrubbing = !1, this.root = l("div", "imp-progress", { role: "slider", "aria-label": "Seek", tabindex: "-1" }), this.buffered = l("div", "imp-progress__buffered"), this.track = l("div", "imp-progress__track"), this.handle = l("div", "imp-progress__handle"), this.tooltipThumb = l("div", "imp-progress__thumb"), this.tooltipChapter = l("div", "imp-progress__tooltip-chapter"), this.tooltipTime = l("div", "imp-progress__tooltip-time"), this.tooltipCaption = l("div", "imp-progress__caption"), this.tooltipCaption.append(this.tooltipChapter, this.tooltipTime), this.tooltip = l("div", "imp-progress__tooltip"), this.tooltip.append(this.tooltipThumb, this.tooltipCaption), this.heatmap = l("div", "imp-progress__heatmap"), this.heatmap.hidden = !0, this.root.append(this.heatmap, this.buffered, this.track, this.handle, this.tooltip), this.setChapters([]), this.bindPointer();
721
+ class _t {
722
+ constructor(t, e = "Seek") {
723
+ this.cb = t, this.segments = [], this.duration = 0, this.chapters = [], this.thumbnails = null, this.scrubbing = !1, this.root = l("div", "imp-progress", { role: "slider", "aria-label": e, tabindex: "-1" }), this.buffered = l("div", "imp-progress__buffered"), this.track = l("div", "imp-progress__track"), this.handle = l("div", "imp-progress__handle"), this.tooltipThumb = l("div", "imp-progress__thumb"), this.tooltipChapter = l("div", "imp-progress__tooltip-chapter"), this.tooltipTime = l("div", "imp-progress__tooltip-time"), this.tooltipCaption = l("div", "imp-progress__caption"), this.tooltipCaption.append(this.tooltipChapter, this.tooltipTime), this.tooltip = l("div", "imp-progress__tooltip"), this.tooltip.append(this.tooltipThumb, this.tooltipCaption), this.heatmap = l("div", "imp-progress__heatmap"), this.heatmap.hidden = !0, this.root.append(this.heatmap, this.buffered, this.track, this.handle, this.tooltip), this.setChapters([]), this.bindPointer();
708
724
  }
709
725
  /** Render the popularity curve (empty array hides it). */
710
726
  setHeatmap(t, e = 1) {
@@ -712,7 +728,7 @@ class kt {
712
728
  this.heatmap.hidden = !0, this.heatmap.textContent = "";
713
729
  return;
714
730
  }
715
- this.heatmap.innerHTML = `<svg viewBox="0 0 1000 100" preserveAspectRatio="none" aria-hidden="true"><path d="${lt(t, e)}"/></svg>`, this.heatmap.hidden = !1;
731
+ this.heatmap.innerHTML = `<svg viewBox="0 0 1000 100" preserveAspectRatio="none" aria-hidden="true"><path d="${ct(t, e)}"/></svg>`, this.heatmap.hidden = !1;
716
732
  }
717
733
  setDuration(t) {
718
734
  this.duration = Number.isFinite(t) ? t : 0, this.root.classList.toggle("imp-progress--live", !Number.isFinite(t)), this.chapters.length === 0 && this.setChapters([]);
@@ -737,20 +753,20 @@ class kt {
737
753
  update(t, e, i) {
738
754
  if (e !== this.duration && Number.isFinite(e) && this.setDuration(e), this.scrubbing) return;
739
755
  this.render(t);
740
- const s = this.duration > 0 ? w(i / this.duration, 0, 1) : 0;
741
- 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", `${x(t)} / ${x(this.duration)}`);
756
+ const s = this.duration > 0 ? x(i / this.duration, 0, 1) : 0;
757
+ 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", `${_(t)} / ${_(this.duration)}`);
742
758
  }
743
759
  render(t) {
744
760
  for (const { chapter: i, fill: s } of this.segments) {
745
- const n = i.end - i.start, r = n > 0 ? w((t - i.start) / n, 0, 1) : 0;
761
+ const n = i.end - i.start, r = n > 0 ? x((t - i.start) / n, 0, 1) : 0;
746
762
  s.style.transform = `scaleX(${r})`;
747
763
  }
748
- const e = this.duration > 0 ? w(t / this.duration, 0, 1) : 0;
764
+ const e = this.duration > 0 ? x(t / this.duration, 0, 1) : 0;
749
765
  this.handle.style.left = `${e * 100}%`;
750
766
  }
751
767
  timeFromEvent(t) {
752
768
  const e = this.root.getBoundingClientRect();
753
- return (e.width > 0 ? w((t.clientX - e.left) / e.width, 0, 1) : 0) * this.duration;
769
+ return (e.width > 0 ? x((t.clientX - e.left) / e.width, 0, 1) : 0) * this.duration;
754
770
  }
755
771
  bindPointer() {
756
772
  this.root.addEventListener("pointerdown", (t) => {
@@ -765,64 +781,64 @@ class kt {
765
781
  }
766
782
  showTooltip(t) {
767
783
  const e = this.timeFromEvent(t);
768
- this.tooltipTime.textContent = x(e);
769
- const i = J(this.chapters, e), s = !!i?.title;
784
+ this.tooltipTime.textContent = _(e);
785
+ const i = Y(this.chapters, e), s = !!i?.title;
770
786
  this.tooltipChapter.textContent = i?.title ?? "", this.tooltipChapter.hidden = !s, this.tooltipCaption.classList.toggle("imp-progress__caption--time-only", !s);
771
787
  const n = this.thumbnails?.cueAt(e) ?? null;
772
788
  this.tooltip.classList.toggle("imp-progress__tooltip--thumb", !!n), n ? (this.tooltipThumb.hidden = !1, this.tooltipThumb.style.backgroundImage = `url("${n.src}")`, n.xywh ? (this.tooltipThumb.style.width = `${n.xywh.w}px`, this.tooltipThumb.style.height = `${n.xywh.h}px`, this.tooltipThumb.style.backgroundPosition = `-${n.xywh.x}px -${n.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");
773
- const r = this.root.getBoundingClientRect(), a = w(t.clientX - r.left, 0, r.width), h = this.tooltip.offsetWidth / 2;
774
- this.tooltip.style.left = `${w(a, h, Math.max(h, r.width - h))}px`;
789
+ const r = this.root.getBoundingClientRect(), a = x(t.clientX - r.left, 0, r.width), h = this.tooltip.offsetWidth / 2;
790
+ this.tooltip.style.left = `${x(a, h, Math.max(h, r.width - h))}px`;
775
791
  }
776
792
  hideTooltip() {
777
793
  this.tooltip.classList.remove("imp-progress__tooltip--visible");
778
794
  }
779
795
  }
780
- class wt {
796
+ class Lt {
781
797
  constructor(t) {
782
798
  this.player = t, this.rightItems = /* @__PURE__ */ new Map(), 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.gearBtn = null, this.gearMenu = null, this.gear = { speed: !1, quality: !1, subtitles: !1 }, this.nextPreviewEl = null, this.nextPreviewOpts = null, this.scenesBtn = null, this.sceneTypeBtn = null, this.sceneTypeMenu = 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;
783
799
  const { labels: e, icons: i } = t, s = t.controlsOptions;
784
- this.root = l("div", "imp-controls"), this.progress = new kt({
800
+ this.root = l("div", "imp-controls"), this.progress = new _t({
785
801
  onSeek: (d) => t.seek(d),
786
802
  onScrubStart: () => {
787
- this.wasPlayingBeforeScrub = !t.paused, t.pause();
803
+ t.scrubbing = !0, this.wasPlayingBeforeScrub = !t.paused, t.pause();
788
804
  },
789
805
  onScrubEnd: () => {
790
- this.wasPlayingBeforeScrub && t.play();
806
+ t.scrubbing = !1, this.wasPlayingBeforeScrub && t.play(!0);
791
807
  }
792
- }), s.progress && this.root.append(this.progress.root);
808
+ }, t.labels.seek), s.progress && this.root.append(this.progress.root);
793
809
  const n = l("div", "imp-controls__row");
794
810
  this.row = n, this.root.append(n);
795
811
  const r = l("div", "imp-controls__group"), a = l("div", "imp-controls__group");
796
812
  this.rightGroup = a;
797
813
  const h = l("div", "imp-controls__spacer");
798
814
  this.chapterLabel = l("div", "imp-controls__chapter"), n.append(r, h, a), h.append(this.chapterLabel);
799
- const c = typeof s.seekButtons == "object" ? s.seekButtons : {}, p = c.back ?? t.seekStep, u = c.forward ?? t.seekStep;
800
- if (this.seekLabelFn = c.label, s.playlist && t.hasPlaylist && !s.hidePrev && (this.prevBtn = g("imp-btn--prev", e.previous, i.previous), this.prevBtn.addEventListener("click", () => t.previous()), r.append(this.prevBtn)), s.seekButtons && (this.seekBackBtn = g("imp-btn--seek-back", `${e.seekBack} ${p}s`, i.seekBack), this.addStepBadge(this.seekBackBtn, p, "back"), this.seekBackBtn.addEventListener("click", () => t.skip(-p)), r.append(this.seekBackBtn)), s.play && (this.playBtn = g("imp-btn--play", e.play, i.play), this.playBtn.addEventListener("click", () => t.togglePlay()), r.append(this.playBtn)), s.seekButtons && (this.seekFwdBtn = g("imp-btn--seek-forward", `${e.seekForward} ${u}s`, i.seekForward), this.addStepBadge(this.seekFwdBtn, u, "forward"), this.seekFwdBtn.addEventListener("click", () => t.skip(u)), r.append(this.seekFwdBtn)), s.playlist && t.hasPlaylist && (this.nextBtn = g("imp-btn--next", e.next, i.next), this.nextBtn.addEventListener("click", () => t.next()), r.append(this.nextBtn)), s.volume) {
815
+ const c = typeof s.seekButtons == "object" ? s.seekButtons : {}, u = c.back ?? t.seekStep, m = c.forward ?? t.seekStep;
816
+ if (this.seekLabelFn = c.label, s.playlist && t.hasPlaylist && !s.hidePrev && (this.prevBtn = g("imp-btn--prev", e.previous, i.previous), this.prevBtn.addEventListener("click", () => t.previous()), r.append(this.prevBtn)), s.seekButtons && (this.seekBackBtn = g("imp-btn--seek-back", `${e.seekBack} ${u}s`, i.seekBack), this.addStepBadge(this.seekBackBtn, u, "back"), this.seekBackBtn.addEventListener("click", () => t.skip(-u)), r.append(this.seekBackBtn)), s.play && (this.playBtn = g("imp-btn--play", e.play, i.play), this.playBtn.addEventListener("click", () => t.togglePlay()), r.append(this.playBtn)), s.seekButtons && (this.seekFwdBtn = g("imp-btn--seek-forward", `${e.seekForward} ${m}s`, i.seekForward), this.addStepBadge(this.seekFwdBtn, m, "forward"), this.seekFwdBtn.addEventListener("click", () => t.skip(m)), r.append(this.seekFwdBtn)), s.playlist && t.hasPlaylist && !s.hideNext && (this.nextBtn = g("imp-btn--next", e.next, i.next), this.nextBtn.addEventListener("click", () => t.next()), r.append(this.nextBtn)), s.volume) {
801
817
  const d = l("div", "imp-volume");
802
818
  this.muteBtn = g("imp-btn--mute", e.mute, i.volumeHigh), this.muteBtn.addEventListener("click", () => t.toggleMute()), this.volumeSlider = l("input", "imp-volume__slider", {
803
819
  type: "range",
804
820
  min: "0",
805
821
  max: "1",
806
822
  step: "0.05",
807
- "aria-label": "Volume"
823
+ "aria-label": e.volume
808
824
  }), this.volumeSlider.addEventListener("input", () => {
809
825
  t.setVolume(Number(this.volumeSlider.value));
810
826
  }), d.append(this.muteBtn, this.volumeSlider), r.append(d);
811
827
  }
812
828
  s.time && (this.timeLabel = l("div", "imp-controls__time"), this.timeCurrent = l("span", "imp-controls__time-current"), this.timeTotal = l("span", "imp-controls__time-total"), this.timeLabel.append(this.timeCurrent, this.timeTotal), this.liveBadge = l("span", "imp-controls__live"), this.liveBadge.textContent = e.live, this.liveBadge.hidden = !0, r.append(this.timeLabel, this.liveBadge)), this.buildLikeDislike();
813
- for (const d of (t.actionsOptions.custom ?? []).filter((b) => b.placement === "bar")) {
814
- const b = g(`imp-btn--custom imp-btn--custom-${d.id}`, d.title, d.icon ?? i.more);
815
- b.addEventListener("click", () => t.emit("customaction", { id: d.id })), this.rightItems.set(`custom:${d.id}`, b), this.registerCollapsible({
829
+ for (const d of (t.actionsOptions.custom ?? []).filter((k) => k.placement === "bar")) {
830
+ const k = g(`imp-btn--custom imp-btn--custom-${d.id}`, d.title, d.icon ?? i.more);
831
+ k.addEventListener("click", () => t.emit("customaction", { id: d.id })), this.rightItems.set(`custom:${d.id}`, k), this.registerCollapsible({
816
832
  key: `custom:${d.id}`,
817
- el: b,
833
+ el: k,
818
834
  priority: 55,
819
835
  available: () => !0,
820
836
  section: () => this.simpleSection(`custom:${d.id}`, d.title, d.icon ?? i.more, () => t.emit("customaction", { id: d.id }))
821
837
  });
822
838
  }
823
- const m = (d) => d === !1 ? "off" : d === "bar" ? "bar" : "gear", v = m(s.subtitles), y = m(s.quality), _ = m(s.speed);
824
- if (this.gear = { speed: _ === "gear", quality: y === "gear", subtitles: v === "gear" }, v === "bar") {
825
- this.subtitlesBtn = g("imp-btn--subtitles", e.subtitles, i.subtitles), this.subtitlesMenu = new C(this.subtitlesBtn);
839
+ const p = (d) => d === !1 ? "off" : d === "bar" ? "bar" : "gear", v = p(s.subtitles), f = p(s.quality), b = p(s.speed);
840
+ if (this.gear = { speed: b === "gear", quality: f === "gear", subtitles: v === "gear" }, v === "bar") {
841
+ this.subtitlesBtn = g("imp-btn--subtitles", e.subtitles, i.subtitles), this.subtitlesMenu = new M(this.subtitlesBtn);
826
842
  const d = l("div", "imp-controls__menu-anchor");
827
843
  d.append(this.subtitlesBtn, this.subtitlesMenu.root), this.subtitlesBtn.addEventListener("click", () => this.toggleSubtitlesMenu()), this.rightItems.set("subtitles", d), this.registerCollapsible({
828
844
  key: "subtitles",
@@ -832,8 +848,8 @@ class wt {
832
848
  section: () => this.subtitlesSection()
833
849
  });
834
850
  }
835
- if (y === "bar") {
836
- this.qualityBtn = g("imp-btn--quality", e.quality, i.settings), this.qualityMenu = new C(this.qualityBtn);
851
+ if (f === "bar") {
852
+ this.qualityBtn = g("imp-btn--quality", e.quality, i.settings), this.qualityMenu = new M(this.qualityBtn);
837
853
  const d = l("div", "imp-controls__menu-anchor");
838
854
  d.append(this.qualityBtn, this.qualityMenu.root), this.qualityBtn.addEventListener("click", () => this.toggleQualityMenu()), this.rightItems.set("quality", d), this.registerCollapsible({
839
855
  key: "quality",
@@ -843,8 +859,8 @@ class wt {
843
859
  section: () => this.qualitySection()
844
860
  });
845
861
  }
846
- if (_ === "bar") {
847
- this.settingsBtn = g("imp-btn--speed", e.speed, i.speed), this.settingsMenu = new C(this.settingsBtn);
862
+ if (b === "bar") {
863
+ this.settingsBtn = g("imp-btn--speed", e.speed, i.speed), this.settingsMenu = new M(this.settingsBtn);
848
864
  const d = l("div", "imp-controls__menu-anchor");
849
865
  d.append(this.settingsBtn, this.settingsMenu.root), this.settingsBtn.addEventListener("click", () => this.toggleSettingsMenu()), this.rightItems.set("speed", d), this.registerCollapsible({
850
866
  key: "speed",
@@ -861,7 +877,7 @@ class wt {
861
877
  available: () => t.chapterList.length > 0,
862
878
  section: () => this.simpleSection("scenes", e.scenes, i.scenes, () => t.toggleScenesPanel())
863
879
  })), s.sceneTypes !== !1) {
864
- this.sceneTypeBtn = l("button", "imp-btn imp-btn--scene-types", { type: "button" }), this.sceneTypeMenu = new C(this.sceneTypeBtn);
880
+ this.sceneTypeBtn = l("button", "imp-btn imp-btn--scene-types", { type: "button" }), this.sceneTypeMenu = new M(this.sceneTypeBtn);
865
881
  const d = l("div", "imp-controls__menu-anchor");
866
882
  d.append(this.sceneTypeBtn, this.sceneTypeMenu.root), this.sceneTypeBtn.addEventListener("click", () => this.toggleSceneTypeMenu()), this.rightItems.set("sceneTypes", d), this.refreshSceneTypeButton(), this.registerCollapsible({
867
883
  key: "sceneTypes",
@@ -871,7 +887,7 @@ class wt {
871
887
  section: () => this.sceneTypeSection()
872
888
  });
873
889
  }
874
- if (s.playlist && t.hasPlaylist) {
890
+ if (s.playlist && t.hasPlaylist && s.playlistButton !== !1) {
875
891
  const d = g("imp-btn--list", e.playlist, i.list);
876
892
  d.addEventListener("click", () => t.togglePlaylistPanel()), this.rightItems.set("playlist", d), this.registerCollapsible({
877
893
  key: "list",
@@ -910,7 +926,7 @@ class wt {
910
926
  el: d,
911
927
  priority: 80,
912
928
  available: () => Number.isFinite(t.duration) && t.duration > 0,
913
- section: () => this.simpleSection("seekBack", `${e.seekBack} ${p}s`, i.seekBack, () => t.skip(-p))
929
+ section: () => this.simpleSection("seekBack", `${e.seekBack} ${u}s`, i.seekBack, () => t.skip(-u))
914
930
  });
915
931
  }
916
932
  if (this.seekFwdBtn) {
@@ -920,19 +936,19 @@ class wt {
920
936
  el: d,
921
937
  priority: 82,
922
938
  available: () => Number.isFinite(t.duration) && t.duration > 0,
923
- section: () => this.simpleSection("seekFwd", `${e.seekForward} ${u}s`, i.seekForward, () => t.skip(u))
939
+ section: () => this.simpleSection("seekFwd", `${e.seekForward} ${m}s`, i.seekForward, () => t.skip(m))
924
940
  });
925
941
  }
926
942
  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) {
927
- const d = this.makeCenterButton("seek-back", `${e.seekBack} ${p}s`, i.seekBack);
928
- this.addStepBadge(d, p, "back"), d.addEventListener("click", () => t.skip(-p)), this.center.append(d);
943
+ const d = this.makeCenterButton("seek-back", `${e.seekBack} ${u}s`, i.seekBack);
944
+ this.addStepBadge(d, u, "back"), d.addEventListener("click", () => t.skip(-u)), this.center.append(d);
929
945
  }
930
946
  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) {
931
- const d = this.makeCenterButton("seek-forward", `${e.seekForward} ${u}s`, i.seekForward);
932
- this.addStepBadge(d, u, "forward"), d.addEventListener("click", () => t.skip(u)), this.center.append(d);
947
+ const d = this.makeCenterButton("seek-forward", `${e.seekForward} ${m}s`, i.seekForward);
948
+ this.addStepBadge(d, m, "forward"), d.addEventListener("click", () => t.skip(m)), this.center.append(d);
933
949
  }
934
950
  if (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.setupNextPreview(), this.gear.speed || this.gear.quality || this.gear.subtitles) {
935
- this.gearBtn = g("imp-btn--settings", e.settings, i.settings), this.gearMenu = new C(this.gearBtn);
951
+ this.gearBtn = g("imp-btn--settings", e.settings, i.settings), this.gearMenu = new M(this.gearBtn);
936
952
  const d = l("div", "imp-controls__menu-anchor");
937
953
  d.append(this.gearBtn, this.gearMenu.root), this.gearBtn.addEventListener("click", () => this.toggleGearMenu()), this.rightItems.set("gear", d), this.registerCollapsible({
938
954
  key: "gear",
@@ -970,7 +986,7 @@ class wt {
970
986
  /** Center-cluster button — deliberately NOT `.imp-btn` (own sizing/look). */
971
987
  makeCenterButton(t, e, i) {
972
988
  const s = l("button", `imp-center-btn imp-center-btn--${t}`, { type: "button", "aria-label": e, title: e });
973
- return B(s, i), s;
989
+ return T(s, i), s;
974
990
  }
975
991
  /** Caption under the seek arrow. Default "−15s"/"+15s"; overridable via `controls.seekButtons.label`. */
976
992
  addStepBadge(t, e, i) {
@@ -996,7 +1012,7 @@ class wt {
996
1012
  }
997
1013
  if (this.gear.speed) {
998
1014
  const i = t.playbackRate;
999
- e.push({ key: "speed", label: t.labels.speed, value: i === 1 ? "Normal" : `${i}×`, section: () => this.speedSection() });
1015
+ e.push({ key: "speed", label: t.labels.speed, value: i === 1 ? t.labels.speedNormal : `${i}×`, section: () => this.speedSection() });
1000
1016
  }
1001
1017
  if (this.gear.subtitles && t.subtitleTracks.length > 0) {
1002
1018
  const i = t.activeSubtitle === -1 ? t.labels.subtitlesOff : t.subtitleTracks[t.activeSubtitle]?.label ?? t.labels.subtitlesOff;
@@ -1013,7 +1029,7 @@ class wt {
1013
1029
  if (t.textContent = "", !e) return;
1014
1030
  if (e.icon) {
1015
1031
  const s = l("span", "imp-scene-type__icon");
1016
- B(s, e.icon), t.append(s);
1032
+ T(s, e.icon), t.append(s);
1017
1033
  }
1018
1034
  const i = l("span", "imp-scene-type__label");
1019
1035
  i.textContent = e.title, t.append(i), t.setAttribute("aria-label", `${this.player.labels.sceneTypes}: ${e.title}`), t.title = e.title;
@@ -1066,20 +1082,20 @@ class wt {
1066
1082
  e.textContent = "";
1067
1083
  const n = l("div", "imp-next-preview__kicker");
1068
1084
  if (n.textContent = this.player.labels.next, e.append(n), i.thumbnail && s.poster) {
1069
- const m = l("div", "imp-next-preview__thumb");
1070
- if (m.style.backgroundImage = `url("${s.poster}")`, i.duration && s.duration) {
1085
+ const p = l("div", "imp-next-preview__thumb");
1086
+ if (p.append(S(s.poster)), i.duration && s.duration) {
1071
1087
  const v = l("span", "imp-next-preview__duration");
1072
- v.textContent = x(s.duration), m.append(v);
1088
+ v.textContent = _(s.duration), p.append(v);
1073
1089
  }
1074
- e.append(m);
1090
+ e.append(p);
1075
1091
  }
1076
1092
  if (i.title && s.title) {
1077
- const m = l("div", "imp-next-preview__title");
1078
- m.textContent = s.title, e.append(m);
1093
+ const p = l("div", "imp-next-preview__title");
1094
+ p.textContent = s.title, e.append(p);
1079
1095
  }
1080
- i.meta && s.previewMeta?.length && e.append(U(s.previewMeta, "imp-next-preview")), e.hidden = !1;
1081
- const r = this.player.container.getBoundingClientRect(), a = t.getBoundingClientRect(), h = 8, c = e.offsetWidth, p = a.left - r.left + a.width / 2 - c / 2, u = Math.max(h, Math.min(p, r.width - c - h));
1082
- e.style.left = `${u}px`, e.style.bottom = `${r.height - (a.top - r.top) + 10}px`;
1096
+ i.meta && s.previewMeta?.length && e.append(j(s.previewMeta, "imp-next-preview")), e.hidden = !1;
1097
+ const r = this.player.container.getBoundingClientRect(), a = t.getBoundingClientRect(), h = 8, c = e.offsetWidth, u = a.left - r.left + a.width / 2 - c / 2, m = Math.max(h, Math.min(u, r.width - c - h));
1098
+ e.style.left = `${m}px`, e.style.bottom = `${r.height - (a.top - r.top) + 10}px`;
1083
1099
  }
1084
1100
  hideNextPreview() {
1085
1101
  this.nextPreviewEl && (this.nextPreviewEl.hidden = !0);
@@ -1135,7 +1151,7 @@ class wt {
1135
1151
  for (const h of (i.custom ?? []).filter((c) => c.placement !== "bar"))
1136
1152
  this.actionItems.push({ value: `custom:${h.id}`, label: h.title, icon: h.icon, run: () => e.emit("customaction", { id: h.id }) });
1137
1153
  const r = g("imp-btn--more", s.more, n.more);
1138
- this.moreMenu = new C(r);
1154
+ this.moreMenu = new M(r);
1139
1155
  const a = l("div", "imp-controls__menu-anchor imp-controls__more");
1140
1156
  a.append(r, this.moreMenu.root), r.addEventListener("click", () => {
1141
1157
  this.closeMenus(this.moreMenu), this.moreMenu?.toggle(this.buildMoreSections());
@@ -1152,8 +1168,8 @@ class wt {
1152
1168
  if (h)
1153
1169
  for (const c of Array.isArray(h) ? h : [h])
1154
1170
  if (!c.title && c.items.length === 1) {
1155
- const p = c.items[0];
1156
- i.push(p), e.set(p.value, () => c.onSelect(p.value));
1171
+ const u = c.items[0];
1172
+ i.push(u), e.set(u.value, () => c.onSelect(u.value));
1157
1173
  } else
1158
1174
  t.push(c);
1159
1175
  }
@@ -1161,7 +1177,7 @@ class wt {
1161
1177
  const a = new Map(this.actionItems.map((h) => [h.value, h.run]));
1162
1178
  t.push({
1163
1179
  title: "",
1164
- items: this.actionItems.map(({ value: h, label: c, icon: p }) => ({ value: h, label: c, icon: p, active: !1 })),
1180
+ items: this.actionItems.map(({ value: h, label: c, icon: u }) => ({ value: h, label: c, icon: u, active: !1 })),
1165
1181
  onSelect: (h) => a.get(h)?.()
1166
1182
  });
1167
1183
  }
@@ -1175,7 +1191,7 @@ class wt {
1175
1191
  return {
1176
1192
  title: t.labels.speed,
1177
1193
  items: t.playbackRates.map((e) => ({
1178
- label: e === 1 ? "Normal" : `${e}×`,
1194
+ label: e === 1 ? t.labels.speedNormal : `${e}×`,
1179
1195
  value: String(e),
1180
1196
  active: t.playbackRate === e
1181
1197
  })),
@@ -1247,7 +1263,7 @@ class wt {
1247
1263
  const t = this.player;
1248
1264
  this.disposers.push(
1249
1265
  t.on("timeupdate", ({ currentTime: e, duration: i }) => {
1250
- 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.timeCurrent.textContent = x(e), this.timeTotal.textContent = ` / ${x(i)}`));
1266
+ 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.timeCurrent.textContent = _(e), this.timeTotal.textContent = ` / ${_(i)}`));
1251
1267
  }),
1252
1268
  t.on("play", () => this.syncPlayState()),
1253
1269
  t.on("pause", () => this.syncPlayState()),
@@ -1306,16 +1322,16 @@ class wt {
1306
1322
  this.disposers = [], this.resizeObserver?.disconnect(), this.onWindowResize && window.removeEventListener("resize", this.onWindowResize), this.gearMenu?.destroy(), this.sceneTypeMenu?.destroy(), this.settingsMenu?.destroy(), this.subtitlesMenu?.destroy(), this.qualityMenu?.destroy(), this.moreMenu?.destroy(), this.nextPreviewEl?.remove(), this.root.remove();
1307
1323
  }
1308
1324
  }
1309
- class xt {
1325
+ class Tt {
1310
1326
  constructor(t) {
1311
- this.root = l("div", "imp-poster"), this.image = l("img", "imp-poster__image", { alt: "", decoding: "async" }), this.image.hidden = !0;
1327
+ this.root = l("div", "imp-poster"), this.image = l("div", "imp-poster__image"), this.image.hidden = !0, this.img = S(""), this.image.append(this.img);
1312
1328
  const e = g("imp-poster__play", t.labels.play, t.icons.bigPlay);
1313
1329
  e.addEventListener("click", () => void t.play()), this.root.append(this.image, e), this.root.addEventListener("pointerup", (i) => {
1314
- i.target !== this.root && i.target !== this.image || i.pointerType === "touch" && t.posterTapReveal() || t.play();
1330
+ i.target !== this.root && i.target !== this.image && i.target !== this.img || i.pointerType === "touch" && t.posterTapReveal() || t.play();
1315
1331
  });
1316
1332
  }
1317
1333
  setSource(t) {
1318
- t?.poster ? (this.image.src = t.poster, this.image.fetchPriority = "high", this.image.hidden = !1) : (this.image.removeAttribute("src"), this.image.hidden = !0);
1334
+ t?.poster ? (this.img.src = t.poster, this.img.fetchPriority = "high", this.image.hidden = !1) : (this.img.removeAttribute("src"), this.image.hidden = !0);
1319
1335
  }
1320
1336
  show() {
1321
1337
  this.root.hidden = !1;
@@ -1324,7 +1340,7 @@ class xt {
1324
1340
  this.root.hidden = !0;
1325
1341
  }
1326
1342
  }
1327
- class _t {
1343
+ class St {
1328
1344
  constructor(t) {
1329
1345
  this.labels = t, this.channelUrl = null, this.custom = null, this.visible = { title: !0, description: !0, sponsor: !0 }, this.root = l("div", "imp-pause-screen"), this.root.hidden = !0, this.defaultContent = l("div", "imp-pause-screen__default"), this.channel = l("button", "imp-channel", { type: "button" }), this.channel.hidden = !0, this.channelAvatar = l("div", "imp-channel__avatar"), this.channelName = l("div", "imp-channel__name"), this.channel.append(this.channelName, this.channelAvatar), this.channel.addEventListener("click", () => {
1330
1346
  this.channelUrl && window.open(this.channelUrl, "_blank", "noopener");
@@ -1352,7 +1368,7 @@ class _t {
1352
1368
  const e = this.visible.sponsor ? t?.sponsor : void 0;
1353
1369
  this.sponsor.hidden = !e, e && (this.sponsor.href = e.url, this.sponsorText.textContent = e.text, this.sponsorLabel.textContent = e.label ?? this.labels.sponsored);
1354
1370
  const i = t?.channel;
1355
- 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()));
1371
+ 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.append(S(i.avatar, i.name))) : this.channelAvatar.textContent = (i.name.trim()[0] ?? "?").toUpperCase());
1356
1372
  }
1357
1373
  show() {
1358
1374
  this.root.hidden = !1;
@@ -1361,10 +1377,10 @@ class _t {
1361
1377
  this.root.hidden = !0;
1362
1378
  }
1363
1379
  }
1364
- class St {
1380
+ class Bt {
1365
1381
  constructor(t) {
1366
1382
  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");
1367
- const e = g("imp-related__close", "Close", t.icons.close);
1383
+ const e = g("imp-related__close", t.labels.close, t.icons.close);
1368
1384
  e.addEventListener("click", () => this.hide()), this.root.append(e, this.heading, this.grid);
1369
1385
  }
1370
1386
  setOptions(t) {
@@ -1376,7 +1392,7 @@ class St {
1376
1392
  }
1377
1393
  buildCard(t) {
1378
1394
  const e = l("button", "imp-related__card", { type: "button" }), i = l("div", "imp-related__thumb");
1379
- if (t.poster && (i.style.backgroundImage = `url("${t.poster}")`), t.duration) {
1395
+ if (t.poster && i.append(S(t.poster)), t.duration) {
1380
1396
  const n = l("span", "imp-related__duration");
1381
1397
  n.textContent = t.duration, i.append(n);
1382
1398
  }
@@ -1410,7 +1426,7 @@ class St {
1410
1426
  this.root.hidden = !0;
1411
1427
  }
1412
1428
  }
1413
- class Lt {
1429
+ class Et {
1414
1430
  constructor(t) {
1415
1431
  this.player = t, this.root = l("div", "imp-upnext"), this.root.hidden = !0;
1416
1432
  }
@@ -1425,18 +1441,18 @@ class Lt {
1425
1441
  const i = l("div", "imp-upnext__card"), s = l("div", "imp-upnext__kicker");
1426
1442
  if (s.textContent = e.nextVideo, i.append(s), t.poster) {
1427
1443
  const r = l("button", "imp-upnext__thumb", { type: "button", "aria-label": e.playNext });
1428
- if (r.style.backgroundImage = `url("${t.poster}")`, t.duration) {
1444
+ if (r.append(S(t.poster)), t.duration) {
1429
1445
  const h = l("span", "imp-upnext__duration");
1430
- h.textContent = x(t.duration), r.append(h);
1446
+ h.textContent = _(t.duration), r.append(h);
1431
1447
  }
1432
1448
  const a = l("span", "imp-upnext__thumb-play");
1433
- B(a, this.player.icons.bigPlay), r.append(a), r.addEventListener("click", () => this.player.next()), i.append(r);
1449
+ T(a, this.player.icons.bigPlay), r.append(a), r.addEventListener("click", () => this.player.next()), i.append(r);
1434
1450
  }
1435
1451
  if (t.title) {
1436
1452
  const r = l("div", "imp-upnext__title");
1437
1453
  r.textContent = t.title, i.append(r);
1438
1454
  }
1439
- t.previewMeta?.length && i.append(U(t.previewMeta, "imp-upnext"));
1455
+ t.previewMeta?.length && i.append(j(t.previewMeta, "imp-upnext"));
1440
1456
  const n = l("button", "imp-upnext__btn", { type: "button" });
1441
1457
  n.textContent = e.playNext, n.addEventListener("click", () => this.player.next()), i.append(n), this.root.append(i), this.root.hidden = !1;
1442
1458
  }
@@ -1444,7 +1460,7 @@ class Lt {
1444
1460
  this.root.hidden = !0;
1445
1461
  }
1446
1462
  }
1447
- class Bt {
1463
+ class Mt {
1448
1464
  constructor(t, e = "sidebar", i) {
1449
1465
  this.player = t, this.root = l("div", `imp-playlist imp-playlist--${e}`), this.root.hidden = !0;
1450
1466
  const s = l("div", "imp-playlist__header"), n = l("div", "imp-playlist__heading");
@@ -1461,7 +1477,7 @@ class Bt {
1461
1477
  }), this.repeatBtn = g("imp-playlist__repeat", t.labels.repeat, t.icons.repeat), this.repeatBtn.addEventListener("click", () => {
1462
1478
  t.setRepeat(!t.repeat), this.syncModes();
1463
1479
  });
1464
- const a = g("imp-playlist__close", "Close", t.icons.close);
1480
+ const a = g("imp-playlist__close", t.labels.close, t.icons.close);
1465
1481
  a.addEventListener("click", () => this.hide()), r.append(this.shuffleBtn, this.repeatBtn, a), s.append(n, r), this.list = l("div", "imp-playlist__list"), this.root.append(s, this.list), this.rebuild(), this.syncModes();
1466
1482
  }
1467
1483
  syncModes() {
@@ -1472,11 +1488,11 @@ class Bt {
1472
1488
  const i = l("button", "imp-playlist__item", { type: "button" });
1473
1489
  e === this.player.index && i.classList.add("imp-playlist__item--active");
1474
1490
  const s = l("div", "imp-playlist__thumb");
1475
- t.poster && (s.style.backgroundImage = `url("${t.poster}")`);
1491
+ t.poster && s.append(S(t.poster));
1476
1492
  const n = l("div", "imp-playlist__meta"), r = l("div", "imp-playlist__title");
1477
1493
  if (r.textContent = t.title ?? `#${e + 1}`, n.append(r), t.duration) {
1478
1494
  const a = l("div", "imp-playlist__duration");
1479
- a.textContent = x(t.duration), n.append(a);
1495
+ a.textContent = _(t.duration), n.append(a);
1480
1496
  }
1481
1497
  i.append(s, n), i.addEventListener("click", () => {
1482
1498
  this.player.playItem(e), window.innerWidth <= 767 && this.hide();
@@ -1496,12 +1512,12 @@ class Bt {
1496
1512
  this.visible ? this.hide() : this.show();
1497
1513
  }
1498
1514
  }
1499
- class Tt {
1515
+ class Ct {
1500
1516
  constructor(t, e = "bottom") {
1501
1517
  this.player = t, this.items = [], this.root = l("div", `imp-playlist imp-scenes imp-playlist--${e}`), this.root.hidden = !0;
1502
1518
  const i = l("div", "imp-playlist__header"), s = l("span");
1503
1519
  s.textContent = t.labels.scenes;
1504
- const n = g("imp-playlist__close", "Close", t.icons.close);
1520
+ const n = g("imp-playlist__close", t.labels.close, t.icons.close);
1505
1521
  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());
1506
1522
  }
1507
1523
  /** Re-render from the player's current chapters + thumbnail track. */
@@ -1513,11 +1529,11 @@ class Tt {
1513
1529
  if (n?.xywh) {
1514
1530
  const c = l("div", "imp-scenes__sprite");
1515
1531
  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);
1516
- } else n && (s.style.backgroundImage = `url("${n.src}")`);
1532
+ } else n && s.append(S(n.src));
1517
1533
  const r = l("div", "imp-playlist__meta"), a = l("div", "imp-playlist__title");
1518
- a.textContent = e.title || x(e.start);
1534
+ a.textContent = e.title || _(e.start);
1519
1535
  const h = l("div", "imp-playlist__duration");
1520
- h.textContent = x(e.start), r.append(a, h), i.append(s, r), i.addEventListener("click", () => {
1536
+ h.textContent = _(e.start), r.append(a, h), i.append(s, r), i.addEventListener("click", () => {
1521
1537
  this.player.seek(e.start), this.player.play(), window.innerWidth <= 767 && this.hide();
1522
1538
  }), this.list.append(i), this.items.push(i);
1523
1539
  }
@@ -1542,10 +1558,21 @@ class Tt {
1542
1558
  this.visible ? this.hide() : this.show();
1543
1559
  }
1544
1560
  }
1545
- function Q(o) {
1561
+ let tt = 0;
1562
+ function et(o) {
1563
+ const t = o.reason;
1564
+ t?.name === "AbortError" && /interrupted by a (new load request|call to pause)/i.test(t.message ?? "") && o.preventDefault();
1565
+ }
1566
+ function Pt() {
1567
+ typeof window < "u" && ++tt === 1 && window.addEventListener("unhandledrejection", et);
1568
+ }
1569
+ function At() {
1570
+ typeof window < "u" && --tt === 0 && window.removeEventListener("unhandledrejection", et);
1571
+ }
1572
+ function U(o) {
1546
1573
  return o ? typeof o == "string" ? [{ src: o, label: "Subtitles" }] : Array.isArray(o) ? o : [o] : [];
1547
1574
  }
1548
- const Ct = {
1575
+ const Rt = {
1549
1576
  play: !0,
1550
1577
  progress: !0,
1551
1578
  time: !0,
@@ -1568,54 +1595,66 @@ const Ct = {
1568
1595
  // empty → built-in right-cluster order
1569
1596
  playlist: !0,
1570
1597
  hidePrev: !0,
1598
+ hideNext: !1,
1599
+ playlistButton: !0,
1571
1600
  nextPreview: !0,
1572
1601
  hideDelay: 2500,
1573
1602
  revealBeforePlay: !0
1574
1603
  };
1575
- class Rt {
1604
+ class Ft {
1576
1605
  constructor(t, e = {}) {
1577
- this.scrubbing = !1, this.emitter = new tt(), this.abort = new AbortController(), this.sources = [], this.currentIndex = -1, this.sourceController = null, this.loadToken = 0, this.chapters = [], this.currentChapter = null, this.sceneGroupList = [], this.activeSceneGroupId = "", this.progressiveQuality = -1, this.thumbTrack = null, this.shuffleMode = !1, this.autoAdvanceEnabled = !0, this.persistKey = null, this.persistVolume = !1, this.persistAutoAdvance = !1, this.decodeRecoveries = 0, this.adManager = null, this.playedOnce = !1, this.idleTimer = null, this.peekTimer = null, this.destroyed = !1;
1606
+ this.scrubbing = !1, this.emitter = new st(), this.externalAdvance = !1, this.abort = new AbortController(), this.sources = [], this.currentIndex = -1, this.sourceController = null, this.loadToken = 0, this.chapters = [], this.currentChapter = null, this.sceneGroupList = [], this.activeSceneGroupId = "", this.progressiveQuality = -1, this.thumbTrack = null, this.shuffleMode = !1, this.autoAdvanceEnabled = !0, this.persistKey = null, this.persistVolume = !1, this.persistAutoAdvance = !1, this.decodeRecoveries = 0, this.adManager = null, this.playedOnce = !1, this.idleTimer = null, this.peekTimer = null, this.lastRetryAt = 0, this.retryTimer = null, this.errorResumeTime = 0, this.lastPlayheadTime = 0, this.destroyed = !1, this.persistTimer = null;
1578
1607
  const i = typeof t == "string" ? document.querySelector(t) : t;
1579
1608
  if (!i) throw new Error(`[itube-player] mount target not found: ${String(t)}`);
1580
- this.mount = i, this.options = e, this.labels = { ...H, ...it(e.language), ...e.labels }, this.icons = { ...et, ...e.icons };
1609
+ this.mount = i, this.options = e, this.labels = { ...Z, ...rt(e.language), ...e.labels }, this.icons = { ...nt, ...e.icons };
1581
1610
  const s = e.controls ?? {}, n = s.speed ?? s.settings ?? "gear";
1582
- if (this.controlsOptions = { ...Ct, ...s, speed: n, settings: n }, this.actionsOptions = e.actions ?? {}, this.playbackRates = e.playbackRates ?? [0.5, 1, 1.5, 2], this.seekStep = e.seekStep ?? 15, this.playlistOptions = { title: "", autoAdvance: !0, loop: !1, shuffle: !1, startIndex: 0, layout: "sidebar", ...e.playlist }, this.shuffleMode = this.playlistOptions.shuffle, e.persist) {
1583
- const v = e.persist === !0 ? {} : e.persist;
1584
- this.persistKey = v.key ?? "itube-player", this.persistVolume = v.volume !== !1, this.persistAutoAdvance = v.autoAdvance !== !1;
1611
+ if (this.controlsOptions = { ...Rt, ...s, speed: n, settings: n }, this.actionsOptions = e.actions ?? {}, this.playbackRates = e.playbackRates ?? [0.5, 1, 1.5, 2], this.seekStep = e.seekStep ?? 15, this.playlistOptions = { title: "", autoAdvance: !0, loop: !1, shuffle: !1, startIndex: 0, layout: "sidebar", externalAdvance: !1, ...e.playlist }, this.shuffleMode = this.playlistOptions.shuffle, this.externalAdvance = this.playlistOptions.externalAdvance, e.persist) {
1612
+ const b = e.persist === !0 ? {} : e.persist;
1613
+ this.persistKey = b.key ?? "itube-player", this.persistVolume = b.volume !== !1, this.persistAutoAdvance = b.autoAdvance !== !1;
1585
1614
  }
1586
1615
  const r = this.readPersisted();
1587
1616
  this.autoAdvanceEnabled = this.persistAutoAdvance && typeof r?.autoAdvance == "boolean" ? r.autoAdvance : this.playlistOptions.autoAdvance, 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);
1588
1617
  const a = e.styling;
1589
1618
  if (a?.themeColor && this.container.style.setProperty("--imp-accent", a.themeColor), a?.likeColor && this.container.style.setProperty("--imp-like", a.likeColor), a?.dislikeColor && this.container.style.setProperty("--imp-dislike", a.dislikeColor), a?.fontFamily && this.container.style.setProperty("--imp-font", a.fontFamily), a?.borderRadius !== void 0) {
1590
- const v = typeof a.borderRadius == "number" ? `${a.borderRadius}px` : a.borderRadius;
1591
- this.container.style.setProperty("--imp-radius", v);
1619
+ const b = typeof a.borderRadius == "number" ? `${a.borderRadius}px` : a.borderRadius;
1620
+ this.container.style.setProperty("--imp-radius", b);
1592
1621
  }
1593
1622
  a?.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);
1594
1623
  const h = this.persistVolume ? r : null;
1595
- this.video.volume = w(h?.volume ?? e.volume ?? 1, 0, 1), (h?.muted ?? e.muted) && (this.video.muted = !0);
1624
+ this.video.volume = x(h?.volume ?? e.volume ?? 1, 0, 1), (h?.muted ?? e.muted) && (this.video.muted = !0);
1596
1625
  const c = l("div", "imp-layer");
1597
- this.spinner = l("div", "imp-spinner"), this.spinner.hidden = !0, this.errorBox = l("div", "imp-error"), this.errorBox.hidden = !0, this.pauseScreen = new _t(this.labels), this.poster = new xt(this), this.related = new St(this), this.related.setOptions(e.related), this.upNext = new Lt(this), this.controls = new wt(this), this.playlistPanel = new Bt(this, this.playlistOptions.layout, this.playlistOptions.title || void 0), this.scenesPanel = new Tt(this, e.scenes?.layout ?? "bottom");
1626
+ this.spinner = l("div", "imp-spinner"), this.spinner.hidden = !0, this.errorBox = l("div", "imp-error"), this.errorBox.hidden = !0, this.errorText = l("div", "imp-error__text"), this.retryBtn = l("button", "imp-error__retry", { type: "button" });
1627
+ const u = l("span", "imp-error__retry-label");
1628
+ u.textContent = this.labels.tryAgain, this.retryBtn.append(u, l("span", "imp-error__retry-spinner")), this.retryBtn.addEventListener("click", () => this.retry()), this.errorNextBtn = l("button", "imp-error__next", { type: "button" }), this.errorNextBtn.textContent = this.labels.nextVideo, this.errorNextBtn.addEventListener("click", () => {
1629
+ this.clearError(), this.next();
1630
+ });
1631
+ const m = l("div", "imp-error__actions");
1632
+ m.append(this.retryBtn, this.errorNextBtn), this.errorBox.append(this.errorText, m), this.pauseScreen = new St(this.labels), this.poster = new Tt(this), this.related = new Bt(this), this.related.setOptions(e.related), this.upNext = new Et(this), this.controls = new Lt(this), this.playlistPanel = new Mt(this, this.playlistOptions.layout, this.playlistOptions.title || void 0), this.scenesPanel = new Ct(this, e.scenes?.layout ?? "bottom");
1598
1633
  const p = l("div", "imp-layer__middle");
1599
1634
  p.append(this.spinner, this.errorBox, this.controls.center);
1600
- const u = l("div", "imp-layer__bottom");
1601
- u.append(this.controls.root), c.append(this.pauseScreen.root, this.related.root, this.upNext.root, p, u), this.container.append(this.video, c, 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)) : e.pauseScreen && typeof e.pauseScreen == "object" && this.pauseScreen.setVisibility(e.pauseScreen);
1602
- const m = e.adConfig ?? e.ads;
1603
- m && m.adList.length > 0 && (this.adManager = new ut(
1635
+ const v = l("div", "imp-layer__bottom");
1636
+ v.append(this.controls.root), c.append(this.pauseScreen.root, this.related.root, this.upNext.root, p, v), this.container.append(this.video, c, 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)) : e.pauseScreen && typeof e.pauseScreen == "object" && this.pauseScreen.setVisibility(e.pauseScreen);
1637
+ const f = e.adConfig ?? e.ads;
1638
+ f && f.adList.length > 0 && (this.adManager = new vt(
1604
1639
  { container: this.container, contentVideo: this.video, emitter: this.emitter, labels: this.labels, closeIcon: this.icons.close },
1605
- m
1606
- )), this.emitter.on("error", ({ message: v }) => {
1607
- this.errorBox.textContent = v, this.errorBox.hidden = !1, this.spinner.hidden = !0, this.poster.hide();
1608
- }), this.bindVideoEvents(), this.bindIdleHide(), e.keyboard !== !1 && this.bindKeyboard(), this.video.addEventListener("pointerup", (v) => {
1640
+ f
1641
+ )), this.emitter.on("error", ({ fatal: b }) => {
1642
+ if (!b) return;
1643
+ const d = this.lastPlayheadTime || this.video.currentTime;
1644
+ Number.isFinite(d) && d > 0 && (this.errorResumeTime = d), this.errorText.textContent = this.labels.videoNotFound, this.errorNextBtn.hidden = !this.hasNext, this.errorBox.hidden = !1, this.spinner.hidden = !0, this.poster.hide(), this.container.classList.add("imp-player--error");
1645
+ }), Pt(), this.bindVideoEvents(), this.bindIdleHide(), e.keyboard !== !1 && this.bindKeyboard(), this.video.addEventListener("pointerup", (b) => {
1609
1646
  if (!(this.adPlaying || !this.playedOnce)) {
1610
- if (v.pointerType === "mouse") {
1647
+ if (b.pointerType === "mouse") {
1611
1648
  this.togglePlay();
1612
1649
  return;
1613
1650
  }
1614
1651
  this.container.classList.contains("imp-player--idle") ? (this.showControlsNow(), this.scheduleIdle()) : this.video.paused || this.container.classList.add("imp-player--idle");
1615
1652
  }
1616
- }, { signal: this.abort.signal }), this.pauseScreen.root.addEventListener("click", (v) => {
1617
- this.pauseScreen.hasCustom || v.target === this.pauseScreen.root && this.togglePlay();
1618
- }, { signal: this.abort.signal }), this.sources.length > 0 && this.loadItem(w(this.playlistOptions.startIndex, 0, this.sources.length - 1), !!e.autoplay), this.emitter.emit("ready", { player: this });
1653
+ }, { signal: this.abort.signal }), this.pauseScreen.root.addEventListener("click", (b) => {
1654
+ this.pauseScreen.hasCustom || b.target === this.pauseScreen.root && this.togglePlay();
1655
+ }, { signal: this.abort.signal }), this.sources.length > 0 && this.loadItem(x(this.playlistOptions.startIndex, 0, this.sources.length - 1), !!e.autoplay), queueMicrotask(() => {
1656
+ this.destroyed || this.emitter.emit("ready", { player: this });
1657
+ });
1619
1658
  }
1620
1659
  // === events ===========================================================
1621
1660
  on(t, e) {
@@ -1654,8 +1693,22 @@ class Rt {
1654
1693
  get adPlaying() {
1655
1694
  return this.adManager?.adPlaying ?? !1;
1656
1695
  }
1657
- async play() {
1658
- this.destroyed || this.adPlaying || this.adManager && (await this.adManager.playPreRoll(), this.destroyed || !this.video.paused) || await this.video.play();
1696
+ async play(t = !1) {
1697
+ if (!(this.destroyed || this.adPlaying) && !(this.adManager && !t && (await this.adManager.playPreRoll(), this.destroyed || !this.video.paused)))
1698
+ try {
1699
+ await this.video.play();
1700
+ } catch (e) {
1701
+ const i = e?.name;
1702
+ if (i === "NotSupportedError" && this.video.readyState === 0) {
1703
+ const s = this.loadToken;
1704
+ this.video.addEventListener("loadedmetadata", () => {
1705
+ s === this.loadToken && this.video.play().catch(() => {
1706
+ });
1707
+ }, { once: !0, signal: this.abort.signal });
1708
+ return;
1709
+ }
1710
+ i !== "AbortError" && !this.playedOnce && this.poster.show();
1711
+ }
1659
1712
  }
1660
1713
  pause() {
1661
1714
  this.adPlaying || this.video.pause();
@@ -1663,8 +1716,34 @@ class Rt {
1663
1716
  togglePlay() {
1664
1717
  this.video.paused || this.video.ended ? this.play() : this.pause();
1665
1718
  }
1719
+ /**
1720
+ * Clear a fatal-error overlay and reload the current source, resuming from
1721
+ * where playback broke. Rate-limited by `options.retryThrottle` (default 5s):
1722
+ * the button is disabled for that window after each press.
1723
+ */
1724
+ retry() {
1725
+ const t = this.options.retryThrottle ?? 5e3, e = Date.now();
1726
+ if (e - this.lastRetryAt < t) return;
1727
+ this.lastRetryAt = e, this.retryBtn.disabled = !0, this.retryBtn.classList.add("imp-error__retry--loading"), this.retryTimer && clearTimeout(this.retryTimer), this.retryTimer = setTimeout(() => {
1728
+ this.destroyed || (this.retryBtn.disabled = !1, this.retryBtn.classList.remove("imp-error__retry--loading"));
1729
+ }, t);
1730
+ const i = this.errorResumeTime;
1731
+ if (this.loadItem(this.currentIndex, !0, !0), this.errorResumeTime = i, i > 0) {
1732
+ const s = this.loadToken;
1733
+ this.video.addEventListener("loadedmetadata", () => {
1734
+ if (s === this.loadToken)
1735
+ try {
1736
+ this.video.currentTime = i;
1737
+ } catch {
1738
+ }
1739
+ }, { once: !0, signal: this.abort.signal });
1740
+ }
1741
+ }
1742
+ clearError() {
1743
+ this.errorBox.hidden = !0, this.container.classList.remove("imp-player--error");
1744
+ }
1666
1745
  seek(t) {
1667
- Number.isFinite(this.video.duration) && (this.video.currentTime = w(t, 0, this.video.duration));
1746
+ Number.isFinite(this.video.duration) && (this.video.currentTime = x(t, 0, this.video.duration));
1668
1747
  }
1669
1748
  /** Relative seek, e.g. `skip(-10)`. */
1670
1749
  skip(t) {
@@ -1678,7 +1757,7 @@ class Rt {
1678
1757
  return this.video.muted;
1679
1758
  }
1680
1759
  setVolume(t) {
1681
- this.video.volume = w(t, 0, 1), t > 0 && (this.video.muted = !1);
1760
+ this.video.volume = x(t, 0, 1), t > 0 && (this.video.muted = !1);
1682
1761
  }
1683
1762
  setMuted(t) {
1684
1763
  this.video.muted = t;
@@ -1697,6 +1776,12 @@ class Rt {
1697
1776
  return null;
1698
1777
  }
1699
1778
  }
1779
+ /** Debounced persistState — for high-frequency triggers (volume drag). */
1780
+ schedulePersist() {
1781
+ this.persistTimer && clearTimeout(this.persistTimer), this.persistTimer = setTimeout(() => {
1782
+ this.persistTimer = null, this.destroyed || this.persistState();
1783
+ }, 300);
1784
+ }
1700
1785
  /** Write the enabled prefs to localStorage. No-op when persistence is off. */
1701
1786
  persistState() {
1702
1787
  if (this.persistKey)
@@ -1727,19 +1812,29 @@ class Rt {
1727
1812
  setQuality(t) {
1728
1813
  if (this.sourceController?.kind === "hls") {
1729
1814
  this.sourceController.setLevel(t);
1730
- const n = t === -1 ? this.labels.qualityAuto : this.sourceController.levels.find((r) => r.index === t)?.label ?? String(t);
1731
- this.emitter.emit("qualitychange", { label: n });
1815
+ const r = t === -1 ? this.labels.qualityAuto : this.sourceController.levels.find((a) => a.index === t)?.label ?? String(t);
1816
+ this.emitter.emit("qualitychange", { label: r });
1732
1817
  return;
1733
1818
  }
1734
1819
  const e = this.source?.qualities;
1735
1820
  if (!e || !e[t] || t === this.progressiveQuality) return;
1736
1821
  const i = this.video.currentTime, s = !this.video.paused && !this.video.ended;
1737
- this.progressiveQuality = t, this.video.src = e[t].src, this.video.currentTime = i, s && this.video.play().catch(() => {
1738
- }), this.emitter.emit("qualitychange", { label: e[t].label ?? String(e[t].quality ?? t) });
1822
+ this.progressiveQuality = t, this.video.src = e[t].src;
1823
+ const n = this.loadToken;
1824
+ this.video.addEventListener("loadedmetadata", () => {
1825
+ if (n === this.loadToken) {
1826
+ try {
1827
+ this.video.currentTime = i;
1828
+ } catch {
1829
+ }
1830
+ s && this.video.play().catch(() => {
1831
+ });
1832
+ }
1833
+ }, { once: !0, signal: this.abort.signal }), this.emitter.emit("qualitychange", { label: e[t].label ?? String(e[t].quality ?? t) });
1739
1834
  }
1740
1835
  // === subtitles ========================================================
1741
1836
  get subtitleTracks() {
1742
- return Q(this.source?.subtitles);
1837
+ return U(this.source?.subtitles);
1743
1838
  }
1744
1839
  get activeSubtitle() {
1745
1840
  const t = this.video.textTracks;
@@ -1773,13 +1868,13 @@ class Rt {
1773
1868
  return t < this.sources.length ? this.sources[t] : this.playlistOptions.loop ? this.sources[0] ?? null : null;
1774
1869
  }
1775
1870
  get hasPlaylist() {
1776
- return this.sources.length > 1;
1871
+ return this.sources.length > 1 || this.externalAdvance;
1777
1872
  }
1778
1873
  get hasNext() {
1779
- return this.shuffleMode || this.playlistOptions.loop ? this.sources.length > 1 : this.currentIndex < this.sources.length - 1;
1874
+ return this.externalAdvance ? !0 : this.shuffleMode || this.playlistOptions.loop ? this.sources.length > 1 : this.currentIndex < this.sources.length - 1;
1780
1875
  }
1781
1876
  get hasPrevious() {
1782
- return this.playlistOptions.loop ? this.sources.length > 1 : this.currentIndex > 0;
1877
+ return this.externalAdvance ? !0 : this.playlistOptions.loop ? this.sources.length > 1 : this.currentIndex > 0;
1783
1878
  }
1784
1879
  /** Shuffle mode: `next()` and auto-advance pick a random item. */
1785
1880
  get shuffle() {
@@ -1795,8 +1890,18 @@ class Rt {
1795
1890
  setRepeat(t) {
1796
1891
  this.playlistOptions.loop = t;
1797
1892
  }
1893
+ /** External mode: emit the intent instead of switching. Returns true when handled. */
1894
+ emitAdvanceRequest(t, e) {
1895
+ if (!this.externalAdvance) return !1;
1896
+ const i = e !== null && e >= 0 && e < this.sources.length;
1897
+ return this.emitter.emit("advancerequest", {
1898
+ direction: t,
1899
+ index: i ? e : null,
1900
+ source: i ? this.sources[e] : null
1901
+ }), !0;
1902
+ }
1798
1903
  next() {
1799
- if (this.hasNext) {
1904
+ if (this.hasNext && !this.emitAdvanceRequest("next", this.sources.length > 1 ? (this.currentIndex + 1) % this.sources.length : null)) {
1800
1905
  if (this.shuffleMode && this.sources.length > 1) {
1801
1906
  let t = this.currentIndex;
1802
1907
  for (; t === this.currentIndex; ) t = Math.floor(Math.random() * this.sources.length);
@@ -1807,11 +1912,11 @@ class Rt {
1807
1912
  }
1808
1913
  }
1809
1914
  previous() {
1810
- this.hasPrevious && this.playItem((this.currentIndex - 1 + this.sources.length) % this.sources.length);
1915
+ this.hasPrevious && (this.emitAdvanceRequest("previous", this.sources.length > 1 ? (this.currentIndex - 1 + this.sources.length) % this.sources.length : null) || this.playItem((this.currentIndex - 1 + this.sources.length) % this.sources.length));
1811
1916
  }
1812
- /** Jump to a playlist item and start playback. */
1917
+ /** Jump to a playlist item and start playback (external mode: emits the intent instead). */
1813
1918
  playItem(t) {
1814
- t < 0 || t >= this.sources.length || this.loadItem(t, !0).then(() => {
1919
+ t < 0 || t >= this.sources.length || t !== this.currentIndex && this.emitAdvanceRequest("select", t) || this.loadItem(t, !0).then(() => {
1815
1920
  this.emitter.emit("playlistitemchange", { source: this.sources[t], index: t });
1816
1921
  });
1817
1922
  }
@@ -1830,17 +1935,23 @@ class Rt {
1830
1935
  * to one item; an array installs a new playlist.
1831
1936
  */
1832
1937
  load(t, e = 0) {
1833
- this.sources = Array.isArray(t) ? [...t] : [t], this.playlistPanel.rebuild(), this.loadItem(w(e, 0, this.sources.length - 1), !1);
1938
+ this.sources = Array.isArray(t) ? [...t] : [t], this.playlistPanel.rebuild(), this.loadItem(x(e, 0, this.sources.length - 1), !1);
1834
1939
  }
1835
1940
  // === fullscreen / pip =================================================
1836
1941
  get isFullscreen() {
1837
1942
  return document.fullscreenElement === this.container;
1838
1943
  }
1839
1944
  async toggleFullscreen() {
1840
- this.isFullscreen ? await document.exitFullscreen() : this.container.requestFullscreen ? await this.container.requestFullscreen() : this.video.webkitEnterFullscreen?.();
1945
+ try {
1946
+ this.isFullscreen ? await document.exitFullscreen() : this.container.requestFullscreen ? await this.container.requestFullscreen() : this.video.webkitEnterFullscreen?.();
1947
+ } catch {
1948
+ }
1841
1949
  }
1842
1950
  async togglePip() {
1843
- document.pictureInPictureElement === this.video ? await document.exitPictureInPicture() : await this.video.requestPictureInPicture();
1951
+ try {
1952
+ document.pictureInPictureElement === this.video ? await document.exitPictureInPicture() : await this.video.requestPictureInPicture();
1953
+ } catch {
1954
+ }
1844
1955
  }
1845
1956
  // === chapters =========================================================
1846
1957
  /** Normalized chapters of the current source (after metadata is known). */
@@ -1865,7 +1976,7 @@ class Rt {
1865
1976
  }
1866
1977
  /** Normalize the active group's scenes into `chapters` and refresh the UI. */
1867
1978
  applyActiveSceneGroup() {
1868
- this.chapters = z(this.activeSceneType?.scenes ?? [], this.video.duration), this.currentChapter = null, this.controls.progress.setChapters(this.chapters), this.controls.syncFeatureButtons(), this.scenesPanel.visible && this.scenesPanel.rebuild();
1979
+ this.chapters = Q(this.activeSceneType?.scenes ?? [], this.video.duration), this.currentChapter = null, this.controls.progress.setChapters(this.chapters), this.controls.syncFeatureButtons(), this.scenesPanel.visible && this.scenesPanel.rebuild();
1869
1980
  }
1870
1981
  // === actions ==========================================================
1871
1982
  /**
@@ -1902,70 +2013,68 @@ class Rt {
1902
2013
  }
1903
2014
  // === teardown =========================================================
1904
2015
  destroy() {
1905
- this.destroyed || (this.destroyed = !0, this.loadToken++, this.adManager?.destroy(), this.controls.destroy(), this.sourceController?.destroy(), this.abort.abort(), this.idleTimer && clearTimeout(this.idleTimer), this.peekTimer && clearTimeout(this.peekTimer), this.container.remove(), this.emitter.emit("destroy", void 0), this.emitter.removeAll());
2016
+ this.destroyed || (this.destroyed = !0, this.loadToken++, this.adManager?.destroy(), this.controls.destroy(), this.sourceController?.destroy(), this.abort.abort(), this.idleTimer && clearTimeout(this.idleTimer), this.peekTimer && clearTimeout(this.peekTimer), this.retryTimer && clearTimeout(this.retryTimer), this.persistTimer && (clearTimeout(this.persistTimer), this.persistTimer = null, this.persistState()), this.container.remove(), At(), this.emitter.emit("destroy", void 0), this.emitter.removeAll());
1906
2017
  }
1907
2018
  // === internals ========================================================
1908
- async loadItem(t, e) {
1909
- const i = ++this.loadToken, s = this.sources[t];
1910
- if (!s) return;
1911
- this.currentIndex = t, this.sourceController?.destroy(), this.sourceController = null, this.chapters = [], this.currentChapter = null, this.sceneGroupList = [], this.activeSceneGroupId = "", this.progressiveQuality = -1, this.playedOnce = !1, this.endPeek();
1912
- for (const u of [...this.video.querySelectorAll("track")]) u.remove();
1913
- this.adManager?.resetForNewSource(), this.related.hide(), this.upNext.hide(), this.pauseScreen.hide(), this.scenesPanel.hide(), this.thumbTrack = null, this.errorBox.hidden = !0, this.decodeRecoveries = 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();
1914
- for (const u of Q(s.subtitles)) {
1915
- const m = l("track", "", {
2019
+ async loadItem(t, e, i = !1) {
2020
+ const s = ++this.loadToken, n = this.sources[t];
2021
+ if (!n) return;
2022
+ this.currentIndex = t, this.sourceController?.destroy(), this.sourceController = null, this.chapters = [], this.currentChapter = null, this.sceneGroupList = [], this.activeSceneGroupId = "", this.progressiveQuality = -1, this.playedOnce = !1, this.lastPlayheadTime = 0, this.errorResumeTime = 0, this.endPeek();
2023
+ for (const p of [...this.video.querySelectorAll("track")]) p.remove();
2024
+ this.adManager?.resetForNewSource(), this.related.hide(), this.upNext.hide(), this.pauseScreen.hide(), this.scenesPanel.hide(), this.thumbTrack = null, this.decodeRecoveries = 0, this.video.poster = n.poster ?? "", this.poster.setSource(n), this.pauseScreen.setSource(n), this.controls.progress.setChapters([]), this.controls.progress.setThumbnails(null), this.controls.progress.setHeatmap([]), e ? this.poster.hide() : this.poster.show(), this.playlistPanel.rebuild();
2025
+ for (const p of U(n.subtitles)) {
2026
+ const v = l("track", "", {
1916
2027
  kind: "subtitles",
1917
- src: u.src,
1918
- label: u.label,
1919
- ...u.srclang ? { srclang: u.srclang } : {}
2028
+ src: p.src,
2029
+ label: p.label,
2030
+ ...p.srclang ? { srclang: p.srclang } : {}
1920
2031
  });
1921
- u.default && m.setAttribute("default", ""), this.video.append(m);
2032
+ p.default && v.setAttribute("default", ""), this.video.append(v);
1922
2033
  }
1923
- let n = s.src, r = s.type;
1924
- if (s.qualities && s.qualities.length > 0) {
1925
- const u = Math.max(0, s.qualities.findIndex((m) => m.src === s.src));
1926
- this.progressiveQuality = u, n = s.qualities[u].src, r = s.qualities[u].type ?? r;
2034
+ let r = n.src, a = n.type;
2035
+ if (n.qualities && n.qualities.length > 0) {
2036
+ const p = Math.max(0, n.qualities.findIndex((v) => v.src === n.src));
2037
+ this.progressiveQuality = p, r = n.qualities[p].src, a = n.qualities[p].type ?? a;
1927
2038
  }
1928
2039
  this.video.preload = this.adManager?.hasPendingPreRoll ? "auto" : "metadata";
1929
- const a = await ft(this.video, n, r, {
2040
+ const h = await bt(this.video, r, a, {
1930
2041
  onLevels: () => {
1931
- i === this.loadToken && this.controls.syncFeatureButtons();
2042
+ s === this.loadToken && this.controls.syncFeatureButtons();
1932
2043
  },
1933
- onLevelSwitch: (u) => this.emitter.emit("qualitychange", { label: u }),
1934
- onError: (u, m) => this.emitter.emit("error", { message: u, cause: m })
2044
+ onLevelSwitch: (p) => this.emitter.emit("qualitychange", { label: p }),
2045
+ onError: (p, v) => this.emitter.emit("error", { message: p, cause: v, fatal: !0 })
1935
2046
  });
1936
- if (i !== this.loadToken) {
1937
- a.destroy();
2047
+ if (s !== this.loadToken) {
2048
+ h.destroy();
1938
2049
  return;
1939
2050
  }
1940
- if (this.sourceController = a, this.emitter.emit("sourcechange", { source: s, index: t }), s.thumbnails && Z.load(s.thumbnails).then((u) => {
1941
- i === this.loadToken && (this.thumbTrack = u, this.controls.progress.setThumbnails(u), this.scenesPanel.visible && this.scenesPanel.rebuild());
1942
- }).catch((u) => this.emitter.emit("error", { message: "Failed to load thumbnails track", cause: u })), s.sceneGroups && s.sceneGroups.length > 0) {
1943
- this.sceneGroupList = s.sceneGroups, this.activeSceneGroupId = s.sceneGroups[0].id;
1944
- const u = () => {
1945
- i === this.loadToken && this.applyActiveSceneGroup();
2051
+ if (this.sourceController = h, this.emitter.emit("sourcechange", { source: n, index: t }), n.thumbnails && D.load(n.thumbnails).then((p) => {
2052
+ s === this.loadToken && (this.thumbTrack = p, this.controls.progress.setThumbnails(p), this.scenesPanel.visible && this.scenesPanel.rebuild());
2053
+ }).catch((p) => this.emitter.emit("error", { message: "Failed to load thumbnails track", cause: p })), n.sceneGroups && n.sceneGroups.length > 0) {
2054
+ this.sceneGroupList = n.sceneGroups, this.activeSceneGroupId = n.sceneGroups[0].id;
2055
+ const p = () => {
2056
+ s === this.loadToken && this.applyActiveSceneGroup();
1946
2057
  };
1947
- Number.isFinite(this.video.duration) && this.video.duration > 0 ? u() : this.video.addEventListener("loadedmetadata", u, { once: !0, signal: this.abort.signal });
1948
- } else if (s.chapters) {
1949
- const u = (m) => {
1950
- const v = () => {
1951
- i === this.loadToken && (this.chapters = z(m, this.video.duration), this.controls.progress.setChapters(this.chapters), this.controls.syncFeatureButtons(), this.scenesPanel.visible && this.scenesPanel.rebuild());
2058
+ Number.isFinite(this.video.duration) && this.video.duration > 0 ? p() : this.video.addEventListener("loadedmetadata", p, { once: !0, signal: this.abort.signal });
2059
+ } else if (n.chapters) {
2060
+ const p = (v) => {
2061
+ const f = () => {
2062
+ s === this.loadToken && (this.chapters = Q(v, this.video.duration), this.controls.progress.setChapters(this.chapters), this.controls.syncFeatureButtons(), this.scenesPanel.visible && this.scenesPanel.rebuild());
1952
2063
  };
1953
- Number.isFinite(this.video.duration) && this.video.duration > 0 ? v() : this.video.addEventListener("loadedmetadata", v, { once: !0, signal: this.abort.signal });
2064
+ Number.isFinite(this.video.duration) && this.video.duration > 0 ? f() : this.video.addEventListener("loadedmetadata", f, { once: !0, signal: this.abort.signal });
1954
2065
  };
1955
- typeof s.chapters == "string" ? pt(s.chapters).then((m) => u(m)).catch((m) => this.emitter.emit("error", { message: "Failed to load chapters track", cause: m })) : u(s.chapters);
2066
+ typeof n.chapters == "string" ? ft(n.chapters).then((v) => p(v)).catch((v) => this.emitter.emit("error", { message: "Failed to load chapters track", cause: v })) : p(n.chapters);
1956
2067
  }
1957
- const h = s.heatmap, c = h && !Array.isArray(h), p = c ? h.values.length > 0 : !!(h && h.length > 0);
1958
- if (h && p && this.controlsOptions.heatmap) {
1959
- const u = () => {
1960
- if (i !== this.loadToken) return;
1961
- const m = c ? ot(h.values, h.mode) : rt(h, this.video.duration);
1962
- this.controls.progress.setHeatmap(m, c ? h.smoothing ?? 1 : 1);
2068
+ const c = n.heatmap, u = c && !Array.isArray(c), m = u ? c.values.length > 0 : !!(c && c.length > 0);
2069
+ if (c && m && this.controlsOptions.heatmap) {
2070
+ const p = () => {
2071
+ if (s !== this.loadToken) return;
2072
+ const v = u ? ht(c.values, c.mode) : at(c, this.video.duration);
2073
+ this.controls.progress.setHeatmap(v, u ? c.smoothing ?? 1 : 1);
1963
2074
  };
1964
- c || Number.isFinite(this.video.duration) && this.video.duration > 0 ? u() : this.video.addEventListener("loadedmetadata", u, { once: !0, signal: this.abort.signal });
2075
+ u || Number.isFinite(this.video.duration) && this.video.duration > 0 ? p() : this.video.addEventListener("loadedmetadata", p, { once: !0, signal: this.abort.signal });
1965
2076
  }
1966
- e && this.play().catch(() => {
1967
- i === this.loadToken && this.poster.show();
1968
- });
2077
+ e && this.play(i);
1969
2078
  }
1970
2079
  bindVideoEvents() {
1971
2080
  const { signal: t } = this.abort, e = this.video;
@@ -1976,19 +2085,19 @@ class Rt {
1976
2085
  }, { signal: t }), e.addEventListener("ended", () => {
1977
2086
  this.handleEnded();
1978
2087
  }, { signal: t }), e.addEventListener("timeupdate", () => {
1979
- this.emitter.emit("timeupdate", { currentTime: e.currentTime, duration: e.duration || 0 }), this.adManager?.checkMidRolls(e.currentTime);
1980
- const i = J(this.chapters, e.currentTime);
2088
+ !this.adPlaying && e.currentTime > 0 && (this.lastPlayheadTime = e.currentTime), this.emitter.emit("timeupdate", { currentTime: e.currentTime, duration: e.duration || 0 }), this.adManager?.checkMidRolls(e.currentTime);
2089
+ const i = Y(this.chapters, e.currentTime);
1981
2090
  i !== this.currentChapter && (this.currentChapter = i, this.emitter.emit("chapterchange", { chapter: i }));
1982
2091
  }, { signal: t }), e.addEventListener("progress", () => {
1983
2092
  this.emitter.emit("progress", { buffered: this.bufferedEnd });
1984
2093
  }, { signal: t }), e.addEventListener("volumechange", () => {
1985
- this.emitter.emit("volumechange", { volume: e.volume, muted: e.muted }), this.persistVolume && this.persistState();
2094
+ this.emitter.emit("volumechange", { volume: e.volume, muted: e.muted }), this.persistVolume && this.schedulePersist();
1986
2095
  }, { 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", () => {
1987
2096
  this.spinner.hidden = !1;
1988
2097
  }, { signal: t });
1989
2098
  for (const i of ["playing", "canplay", "seeked"])
1990
2099
  e.addEventListener(i, () => {
1991
- this.spinner.hidden = !0, this.errorBox.hidden = !0, this.decodeRecoveries = 0;
2100
+ this.spinner.hidden = !0, this.decodeRecoveries = 0, i === "playing" && this.clearError();
1992
2101
  }, { signal: t });
1993
2102
  e.addEventListener("error", () => {
1994
2103
  const i = e.error;
@@ -2008,14 +2117,19 @@ class Rt {
2008
2117
  e.readyState >= 1 ? a() : e.addEventListener("loadedmetadata", a, { once: !0, signal: this.abort.signal });
2009
2118
  return;
2010
2119
  }
2011
- this.emitter.emit("error", { message: i.message || `Media error (code ${i.code})`, cause: i });
2120
+ this.emitter.emit("error", { message: i.message || `Media error (code ${i.code})`, cause: i, fatal: !0 });
2012
2121
  }, { 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", () => {
2013
2122
  this.emitter.emit("fullscreenchange", { active: this.isFullscreen }), this.container.classList.toggle("imp-player--fullscreen", this.isFullscreen);
2123
+ }, { signal: t }), e.addEventListener("webkitbeginfullscreen", () => {
2124
+ this.emitter.emit("fullscreenchange", { active: !0 }), this.container.classList.add("imp-player--fullscreen");
2125
+ }, { signal: t }), e.addEventListener("webkitendfullscreen", () => {
2126
+ this.emitter.emit("fullscreenchange", { active: !1 }), this.container.classList.remove("imp-player--fullscreen");
2014
2127
  }, { signal: t });
2015
2128
  }
2016
2129
  async handleEnded() {
2017
2130
  if (this.emitter.emit("ended", void 0), this.showControlsNow(), !(this.adManager && (await this.adManager.playPostRoll(), this.destroyed))) {
2018
2131
  if (this.autoAdvanceEnabled && this.hasNext) {
2132
+ if (this.emitAdvanceRequest("ended", this.sources.length > 1 ? (this.currentIndex + 1) % this.sources.length : null)) return;
2019
2133
  this.next();
2020
2134
  return;
2021
2135
  }
@@ -2118,22 +2232,22 @@ class Rt {
2118
2232
  }
2119
2233
  }
2120
2234
  export {
2121
- tt as Emitter,
2122
- Rt as Player,
2123
- Z as ThumbnailTrack,
2124
- rt as buildHeatmapValues,
2125
- J as chapterAt,
2126
- et as defaultIcons,
2127
- H as defaultLabels,
2128
- x as formatTime,
2129
- it as getLocale,
2130
- lt as heatmapPath,
2131
- mt as isHlsSource,
2132
- pt as loadChaptersVtt,
2133
- z as normalizeChapters,
2134
- Et as registerLocale,
2135
- Pt as registerLocales,
2136
- At as registeredLanguages,
2137
- at as resolveVast
2235
+ st as Emitter,
2236
+ Ft as Player,
2237
+ D as ThumbnailTrack,
2238
+ at as buildHeatmapValues,
2239
+ Y as chapterAt,
2240
+ nt as defaultIcons,
2241
+ Z as defaultLabels,
2242
+ _ as formatTime,
2243
+ rt as getLocale,
2244
+ ct as heatmapPath,
2245
+ yt as isHlsSource,
2246
+ ft as loadChaptersVtt,
2247
+ Q as normalizeChapters,
2248
+ It as registerLocale,
2249
+ $t as registerLocales,
2250
+ qt as registeredLanguages,
2251
+ dt as resolveVast
2138
2252
  };
2139
2253
  //# sourceMappingURL=core.js.map