itube-modern-player 0.2.3 → 0.3.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,56 +1,56 @@
1
- import { d as I } from "./labels-C3gAZEm-.js";
2
- function l(r, t, e) {
3
- const i = document.createElement(r);
1
+ import { d as V } from "./labels-C3gAZEm-.js";
2
+ function a(o, t, e) {
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 m(r, t, e) {
9
- const i = l("button", `imp-btn ${r}`, { type: "button", "aria-label": t, title: t });
8
+ function f(o, t, e) {
9
+ const i = a("button", `imp-btn ${o}`, { type: "button", "aria-label": t, title: t });
10
10
  return i.innerHTML = e, i;
11
11
  }
12
- function E(r, t, e) {
13
- r.innerHTML = t, e !== void 0 && (r.setAttribute("aria-label", e), r.setAttribute("title", e));
12
+ function M(o, t, e) {
13
+ o.innerHTML = t, e !== void 0 && (o.setAttribute("aria-label", e), o.setAttribute("title", e));
14
14
  }
15
- function y(r, t, e) {
16
- return Math.min(e, Math.max(t, r));
15
+ function w(o, t, e) {
16
+ return Math.min(e, Math.max(t, o));
17
17
  }
18
- function w(r) {
19
- if (!Number.isFinite(r) || r < 0) return "0:00";
20
- const t = Math.floor(r % 60), e = Math.floor(r / 60 % 60), i = Math.floor(r / 3600), s = i > 0 ? String(e).padStart(2, "0") : String(e), n = String(t).padStart(2, "0");
18
+ function x(o) {
19
+ if (!Number.isFinite(o) || o < 0) return "0:00";
20
+ 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");
21
21
  return i > 0 ? `${i}:${s}:${n}` : `${s}:${n}`;
22
22
  }
23
- function R(r) {
24
- const t = r.trim().match(/^(?:(\d+):)?(\d{1,2}):(\d{2})(?:[.,](\d{1,3}))?$/);
23
+ function $(o) {
24
+ const t = o.trim().match(/^(?:(\d+):)?(\d{1,2}):(\d{2})(?:[.,](\d{1,3}))?$/);
25
25
  if (!t) return null;
26
26
  const e = t[1] ? Number(t[1]) : 0, i = Number(t[2]), s = Number(t[3]), n = t[4] ? Number(t[4].padEnd(3, "0")) : 0;
27
27
  return e * 3600 + i * 60 + s + n / 1e3;
28
28
  }
29
- function U(r) {
30
- const t = [], e = r.replace(/\r\n?/g, `
29
+ function Q(o) {
30
+ const t = [], e = o.replace(/\r\n?/g, `
31
31
  `).split(/\n\n+/);
32
32
  for (const i of e) {
33
33
  const s = i.split(`
34
- `).filter((f) => f.trim() !== "");
34
+ `).filter((p) => p.trim() !== "");
35
35
  if (s.length === 0) continue;
36
- let n = s.findIndex((f) => f.includes("-->"));
36
+ let n = s.findIndex((p) => p.includes("-->"));
37
37
  if (n === -1) continue;
38
- const [o, a] = s[n].split("-->"), c = R(o), h = R((a ?? "").split(" ")[1] ?? a ?? "") ?? R(a ?? "");
39
- if (c === null || h === null) continue;
38
+ const [r, l] = s[n].split("-->"), h = $(r), c = $((l ?? "").split(" ")[1] ?? l ?? "") ?? $(l ?? "");
39
+ if (h === null || c === null) continue;
40
40
  const u = s.slice(n + 1).join(`
41
41
  `).trim();
42
- u && t.push({ start: c, end: h, text: u });
42
+ u && t.push({ start: h, end: c, text: u });
43
43
  }
44
44
  return t;
45
45
  }
46
- function G(r, t) {
46
+ function G(o, t) {
47
47
  try {
48
- return new URL(r, new URL(t, window.location.href)).toString();
48
+ return new URL(o, new URL(t, window.location.href)).toString();
49
49
  } catch {
50
- return r;
50
+ return o;
51
51
  }
52
52
  }
53
- class Y {
53
+ class X {
54
54
  constructor() {
55
55
  this.listeners = /* @__PURE__ */ new Map();
56
56
  }
@@ -82,184 +82,186 @@ class Y {
82
82
  this.listeners.clear();
83
83
  }
84
84
  }
85
- const p = (r, t = "0 0 24 24") => `<svg viewBox="${t}" fill="currentColor" aria-hidden="true" focusable="false">${r}</svg>`, J = {
86
- play: p('<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"/>'),
87
- pause: p('<rect x="6" y="5" width="4" height="14" rx="1"/><rect x="14" y="5" width="4" height="14" rx="1"/>'),
88
- replay: p('<path d="M12 5V2.5L7.5 6 12 9.5V7a5 5 0 1 1-5 5H5a7 7 0 1 0 7-7Z"/>'),
89
- bigPlay: p('<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"/>'),
90
- volumeHigh: p('<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"/>'),
91
- volumeLow: p('<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"/>'),
92
- volumeMute: p('<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"/>'),
93
- fullscreen: p('<path d="M5 5h5v2H7v3H5V5Zm9 0h5v5h-2V7h-3V5ZM5 14h2v3h3v2H5v-5Zm12 0h2v5h-5v-2h3v-3Z"/>'),
94
- fullscreenExit: p('<path d="M10 10H5V8h3V5h2v5Zm4 0V5h2v3h3v2h-5Zm-4 4v5H8v-3H5v-2h5Zm4 0h5v2h-3v3h-2v-5Z"/>'),
95
- pip: p('<path d="M3 5h18v14H3V5Zm2 2v10h14V7H5Z"/><rect x="12" y="11" width="6" height="4"/>'),
96
- settings: p('<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"/>'),
97
- speed: p('<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"/>'),
98
- scenes: p('<path d="M3 5h18v14H3V5Zm2 2v10h3V7H5Zm5 0v10h9V7h-9Zm-5 3h3v1H5v-1Zm0 3h3v1H5v-1Z"/>'),
99
- shuffle: p('<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)"/>'),
100
- repeat: p('<path d="M7 7h10v2.5L21 6l-4-3.5V5H5v6h2V7Zm10 10H7v-2.5L3 18l4 3.5V19h12v-6h-2v4Z"/>'),
101
- subtitles: p('<path d="M3 5h18v14H3V5Zm2 2v10h14V7H5Zm2 3h6v2H7v-2Zm8 0h2v2h-2v-2ZM7 14h2v2H7v-2Zm4 0h6v2h-6v-2Z"/>'),
102
- list: p('<path d="M4 6h2v2H4V6Zm4 0h12v2H8V6ZM4 11h2v2H4v-2Zm4 0h12v2H8v-2ZM4 16h2v2H4v-2Zm4 0h12v2H8v-2Z"/>'),
103
- next: p('<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"/>'),
104
- previous: p('<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"/>'),
105
- seekForward: p('<path d="M12 4V1.5L17 5.5 12 9.5V7a5.5 5.5 0 1 0 5.5 5.5H20A8 8 0 1 1 12 4Z"/>'),
106
- seekBack: p('<path d="M12 4V1.5L7 5.5 12 9.5V7a5.5 5.5 0 1 1-5.5 5.5H4A8 8 0 1 0 12 4Z"/>'),
107
- like: p('<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"/>'),
108
- dislike: p('<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"/>'),
109
- addTo: p('<path d="M4 6h12v2H4V6Zm0 4h12v2H4v-2Zm0 4h8v2H4v-2Zm14 0v-4h2v4h4v2h-4v4h-2v-4h-4v-2h4Z"/>'),
110
- share: p('<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"/>'),
111
- report: p('<path d="M5 3h2v18H5V3Zm4 1h10l-2.5 4L19 12H9V4Z"/>'),
112
- more: p('<circle cx="12" cy="5" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="12" cy="19" r="2"/>'),
113
- close: p('<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"/>')
114
- }, T = { en: I };
115
- function Lt(r, t) {
116
- T[r] = t;
85
+ const v = (o, t = "0 0 24 24") => `<svg viewBox="${t}" fill="currentColor" aria-hidden="true" focusable="false">${o}</svg>`, K = {
86
+ play: v('<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"/>'),
87
+ pause: v('<rect x="6" y="5" width="4" height="14" rx="1"/><rect x="14" y="5" width="4" height="14" rx="1"/>'),
88
+ replay: v('<path d="M12 5V2.5L7.5 6 12 9.5V7a5 5 0 1 1-5 5H5a7 7 0 1 0 7-7Z"/>'),
89
+ bigPlay: v('<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"/>'),
90
+ volumeHigh: v('<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"/>'),
91
+ volumeLow: v('<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"/>'),
92
+ volumeMute: v('<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"/>'),
93
+ fullscreen: v('<path d="M5 5h5v2H7v3H5V5Zm9 0h5v5h-2V7h-3V5ZM5 14h2v3h3v2H5v-5Zm12 0h2v5h-5v-2h3v-3Z"/>'),
94
+ fullscreenExit: v('<path d="M10 10H5V8h3V5h2v5Zm4 0V5h2v3h3v2h-5Zm-4 4v5H8v-3H5v-2h5Zm4 0h5v2h-3v3h-2v-5Z"/>'),
95
+ pip: v('<path d="M3 5h18v14H3V5Zm2 2v10h14V7H5Z"/><rect x="12" y="11" width="6" height="4"/>'),
96
+ settings: v('<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"/>'),
97
+ speed: v('<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"/>'),
98
+ scenes: v('<path d="M3 5h18v14H3V5Zm2 2v10h3V7H5Zm5 0v10h9V7h-9Zm-5 3h3v1H5v-1Zm0 3h3v1H5v-1Z"/>'),
99
+ shuffle: v('<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)"/>'),
100
+ repeat: v('<path d="M7 7h10v2.5L21 6l-4-3.5V5H5v6h2V7Zm10 10H7v-2.5L3 18l4 3.5V19h12v-6h-2v4Z"/>'),
101
+ subtitles: v('<path d="M3 5h18v14H3V5Zm2 2v10h14V7H5Zm2 3h6v2H7v-2Zm8 0h2v2h-2v-2ZM7 14h2v2H7v-2Zm4 0h6v2h-6v-2Z"/>'),
102
+ list: v('<path d="M4 6h2v2H4V6Zm4 0h12v2H8V6ZM4 11h2v2H4v-2Zm4 0h12v2H8v-2ZM4 16h2v2H4v-2Zm4 0h12v2H8v-2Z"/>'),
103
+ next: v('<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"/>'),
104
+ previous: v('<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"/>'),
105
+ // Thin circular-arrow ("rotate") icons open center so the step number reads
106
+ // clearly inside the ring (matches the reference skip ±N look).
107
+ 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>',
108
+ 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>',
109
+ like: v('<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"/>'),
110
+ dislike: v('<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"/>'),
111
+ addTo: v('<path d="M4 6h12v2H4V6Zm0 4h12v2H4v-2Zm0 4h8v2H4v-2Zm14 0v-4h2v4h4v2h-4v4h-2v-4h-4v-2h4Z"/>'),
112
+ share: v('<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"/>'),
113
+ report: v('<path d="M5 3h2v18H5V3Zm4 1h10l-2.5 4L19 12H9V4Z"/>'),
114
+ more: v('<circle cx="12" cy="5" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="12" cy="19" r="2"/>'),
115
+ close: v('<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"/>')
116
+ }, P = { en: V };
117
+ function Lt(o, t) {
118
+ P[o] = t;
117
119
  }
118
- function St(r) {
119
- for (const [t, e] of Object.entries(r))
120
- e && (T[t] = e);
120
+ function St(o) {
121
+ for (const [t, e] of Object.entries(o))
122
+ e && (P[t] = e);
121
123
  }
122
- function tt(r) {
123
- return r && T[r] || I;
124
+ function J(o) {
125
+ return o && P[o] || V;
124
126
  }
125
- function xt() {
126
- return Object.keys(T);
127
+ function _t() {
128
+ return Object.keys(P);
127
129
  }
128
- function et(r, t, e = 100) {
129
- if (r.length === 0 || !Number.isFinite(t) || t <= 0) return [];
130
+ function Y(o, t, e = 100) {
131
+ if (o.length === 0 || !Number.isFinite(t) || t <= 0) return [];
130
132
  const i = new Array(e).fill(0);
131
133
  let s = !1;
132
- for (const h of r) {
133
- if (!Number.isFinite(h.time) || h.time < 0 || h.time > t) continue;
134
- const u = Math.max(0, h.value);
134
+ for (const c of o) {
135
+ if (!Number.isFinite(c.time) || c.time < 0 || c.time > t) continue;
136
+ const u = Math.max(0, c.value);
135
137
  if (u === 0) continue;
136
- const f = Math.min(e - 1, Math.floor(h.time / t * e));
137
- i[f] += u, s = !0;
138
+ const p = Math.min(e - 1, Math.floor(c.time / t * e));
139
+ i[p] += u, s = !0;
138
140
  }
139
141
  if (!s) return [];
140
- const n = [0.06, 0.24, 0.4, 0.24, 0.06], o = i.map(
141
- (h, u) => n.reduce((f, d, b) => f + d * (i[u + b - 2] ?? 0), 0)
142
- ), a = Math.max(...o);
143
- if (a <= 0) return [];
144
- const c = 0.08;
145
- return o.map((h) => c + (1 - c) * (h / a));
142
+ const n = [0.06, 0.24, 0.4, 0.24, 0.06], r = i.map(
143
+ (c, u) => n.reduce((p, m, b) => p + m * (i[u + b - 2] ?? 0), 0)
144
+ ), l = Math.max(...r);
145
+ if (l <= 0) return [];
146
+ const h = 0.08;
147
+ return r.map((c) => h + (1 - h) * (c / l));
146
148
  }
147
- function it(r, t = 1e3, e = 100) {
148
- if (r.length === 0) return "";
149
- const i = t / (r.length - 1 || 1);
149
+ function tt(o, t = 1e3, e = 100) {
150
+ if (o.length === 0) return "";
151
+ const i = t / (o.length - 1 || 1);
150
152
  let s = `M 0 ${e}`;
151
- return r.forEach((n, o) => {
152
- s += ` L ${(o * i).toFixed(1)} ${(e - n * e).toFixed(1)}`;
153
+ return o.forEach((n, r) => {
154
+ s += ` L ${(r * i).toFixed(1)} ${(e - n * e).toFixed(1)}`;
153
155
  }), s += ` L ${t} ${e} Z`, s;
154
156
  }
155
- async function st(r, t) {
156
- if (r.src)
157
+ async function et(o, t) {
158
+ if (o.src)
157
159
  return {
158
- roll: r.roll,
159
- mediaUrl: r.src,
160
- clickThrough: r.clickUrl,
160
+ roll: o.roll,
161
+ mediaUrl: o.src,
162
+ clickThrough: o.clickUrl,
161
163
  impressions: [],
162
164
  tracking: {}
163
165
  };
164
- if (!r.vastTag) throw new Error('Ad roll has neither "vastTag" nor "src"');
165
- return j(r, r.vastTag, t, 0, { impressions: [], tracking: {} });
166
+ if (!o.vastTag) throw new Error('Ad roll has neither "vastTag" nor "src"');
167
+ return z(o, o.vastTag, t, 0, { impressions: [], tracking: {} });
166
168
  }
167
- async function j(r, t, e, i, s) {
169
+ async function z(o, t, e, i, s) {
168
170
  if (i > e.maxWrapperDepth) throw new Error("VAST wrapper depth limit exceeded");
169
- const n = new AbortController(), o = setTimeout(() => n.abort(), e.requestTimeout);
170
- let a;
171
+ const n = new AbortController(), r = setTimeout(() => n.abort(), e.requestTimeout);
172
+ let l;
171
173
  try {
172
- const v = await fetch(t, { signal: n.signal, credentials: "omit" });
173
- if (!v.ok) throw new Error(`VAST request failed (${v.status})`);
174
- a = await v.text();
174
+ const g = await fetch(t, { signal: n.signal, credentials: "omit" });
175
+ if (!g.ok) throw new Error(`VAST request failed (${g.status})`);
176
+ l = await g.text();
175
177
  } finally {
176
- clearTimeout(o);
177
- }
178
- const c = new DOMParser().parseFromString(a, "text/xml");
179
- if (c.querySelector("parsererror")) throw new Error("VAST response is not valid XML");
180
- const h = c.querySelector("VAST > Ad");
181
- if (!h) throw new Error("VAST response contains no ads");
182
- nt(h, s);
183
- const u = h.querySelector(":scope > Wrapper");
178
+ clearTimeout(r);
179
+ }
180
+ const h = new DOMParser().parseFromString(l, "text/xml");
181
+ if (h.querySelector("parsererror")) throw new Error("VAST response is not valid XML");
182
+ const c = h.querySelector("VAST > Ad");
183
+ if (!c) throw new Error("VAST response contains no ads");
184
+ it(c, s);
185
+ const u = c.querySelector(":scope > Wrapper");
184
186
  if (u) {
185
- const v = k(u.querySelector("VASTAdTagURI"));
186
- if (!v) throw new Error("VAST wrapper without VASTAdTagURI");
187
- return j(r, v, e, i + 1, s);
188
- }
189
- const f = h.querySelector(":scope > InLine");
190
- if (!f) throw new Error("VAST ad has neither InLine nor Wrapper");
191
- const d = f.querySelector("Creatives > Creative > Linear");
192
- if (!d) throw new Error("VAST ad has no Linear creative");
193
- const b = rt(d);
187
+ const g = L(u.querySelector("VASTAdTagURI"));
188
+ if (!g) throw new Error("VAST wrapper without VASTAdTagURI");
189
+ return z(o, g, e, i + 1, s);
190
+ }
191
+ const p = c.querySelector(":scope > InLine");
192
+ if (!p) throw new Error("VAST ad has neither InLine nor Wrapper");
193
+ const m = p.querySelector("Creatives > Creative > Linear");
194
+ if (!m) throw new Error("VAST ad has no Linear creative");
195
+ const b = st(m);
194
196
  if (!b) throw new Error("VAST ad has no playable MediaFile");
195
197
  return {
196
- roll: r.roll,
198
+ roll: o.roll,
197
199
  mediaUrl: b.url,
198
200
  mediaType: b.type,
199
- clickThrough: k(d.querySelector("VideoClicks > ClickThrough")) ?? r.clickUrl,
200
- duration: V(k(d.querySelector(":scope > Duration"))),
201
- skipOffset: ot(
202
- d.getAttribute("skipoffset"),
203
- V(k(d.querySelector(":scope > Duration")))
201
+ clickThrough: L(m.querySelector("VideoClicks > ClickThrough")) ?? o.clickUrl,
202
+ duration: N(L(m.querySelector(":scope > Duration"))),
203
+ skipOffset: nt(
204
+ m.getAttribute("skipoffset"),
205
+ N(L(m.querySelector(":scope > Duration")))
204
206
  ),
205
207
  impressions: s.impressions,
206
208
  tracking: s.tracking,
207
- adTitle: k(f.querySelector(":scope > AdTitle")) ?? void 0
209
+ adTitle: L(p.querySelector(":scope > AdTitle")) ?? void 0
208
210
  };
209
211
  }
210
- function nt(r, t) {
212
+ function it(o, t) {
211
213
  var e, i;
212
- for (const s of r.querySelectorAll("Impression")) {
213
- const n = k(s);
214
+ for (const s of o.querySelectorAll("Impression")) {
215
+ const n = L(s);
214
216
  n && t.impressions.push(n);
215
217
  }
216
- for (const s of r.querySelectorAll("Linear > TrackingEvents > Tracking")) {
217
- const n = s.getAttribute("event"), o = k(s);
218
- !n || !o || ["start", "firstQuartile", "midpoint", "thirdQuartile", "complete", "skip", "pause", "resume"].includes(n) && ((e = t.tracking)[n] ?? (e[n] = [])).push(o);
218
+ for (const s of o.querySelectorAll("Linear > TrackingEvents > Tracking")) {
219
+ const n = s.getAttribute("event"), r = L(s);
220
+ !n || !r || ["start", "firstQuartile", "midpoint", "thirdQuartile", "complete", "skip", "pause", "resume"].includes(n) && ((e = t.tracking)[n] ?? (e[n] = [])).push(r);
219
221
  }
220
- for (const s of r.querySelectorAll("Linear > VideoClicks > ClickTracking")) {
221
- const n = k(s);
222
+ for (const s of o.querySelectorAll("Linear > VideoClicks > ClickTracking")) {
223
+ const n = L(s);
222
224
  n && ((i = t.tracking).click ?? (i.click = [])).push(n);
223
225
  }
224
226
  }
225
- function rt(r) {
226
- const e = [...r.querySelectorAll("MediaFiles > MediaFile")].map((o) => ({
227
- url: k(o) ?? "",
228
- type: o.getAttribute("type") ?? void 0,
229
- delivery: o.getAttribute("delivery") ?? "",
230
- bitrate: Number(o.getAttribute("bitrate") ?? 0),
231
- apiFramework: o.getAttribute("apiFramework") ?? ""
232
- })).filter((o) => o.url && o.apiFramework.toUpperCase() !== "VPAID").filter(
233
- (o) => !o.type || /(video\/(mp4|webm|ogg)|application\/(x-mpegurl|vnd\.apple\.mpegurl))/i.test(o.type)
227
+ function st(o) {
228
+ const e = [...o.querySelectorAll("MediaFiles > MediaFile")].map((r) => ({
229
+ url: L(r) ?? "",
230
+ type: r.getAttribute("type") ?? void 0,
231
+ delivery: r.getAttribute("delivery") ?? "",
232
+ bitrate: Number(r.getAttribute("bitrate") ?? 0),
233
+ apiFramework: r.getAttribute("apiFramework") ?? ""
234
+ })).filter((r) => r.url && r.apiFramework.toUpperCase() !== "VPAID").filter(
235
+ (r) => !r.type || /(video\/(mp4|webm|ogg)|application\/(x-mpegurl|vnd\.apple\.mpegurl))/i.test(r.type)
234
236
  );
235
237
  if (e.length === 0) return null;
236
- e.sort((o, a) => o.bitrate - a.bitrate);
237
- const i = e.filter((o) => o.delivery !== "streaming"), s = i.length > 0 ? i : e, n = s[Math.floor(s.length / 2)];
238
+ e.sort((r, l) => r.bitrate - l.bitrate);
239
+ const i = e.filter((r) => r.delivery !== "streaming"), s = i.length > 0 ? i : e, n = s[Math.floor(s.length / 2)];
238
240
  return { url: n.url, type: n.type };
239
241
  }
240
- function V(r) {
241
- if (!r) return;
242
- const t = r.trim().match(/^(?:(\d+):)?(\d{1,2}):(\d{2})(?:\.(\d{1,3}))?$/);
242
+ function N(o) {
243
+ if (!o) return;
244
+ const t = o.trim().match(/^(?:(\d+):)?(\d{1,2}):(\d{2})(?:\.(\d{1,3}))?$/);
243
245
  if (t)
244
246
  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);
245
247
  }
246
- function ot(r, t) {
247
- if (!r) return;
248
- const e = r.trim().match(/^(\d+(?:\.\d+)?)%$/);
249
- return e ? t !== void 0 ? Number(e[1]) / 100 * t : void 0 : V(r);
248
+ function nt(o, t) {
249
+ if (!o) return;
250
+ const e = o.trim().match(/^(\d+(?:\.\d+)?)%$/);
251
+ return e ? t !== void 0 ? Number(e[1]) / 100 * t : void 0 : N(o);
250
252
  }
251
- function C(r) {
252
- if (r)
253
- for (const t of r)
253
+ function T(o) {
254
+ if (o)
255
+ for (const t of o)
254
256
  try {
255
257
  new Image().src = t;
256
258
  } catch {
257
259
  }
258
260
  }
259
- function k(r) {
260
- return r?.textContent?.trim().replace(/^<!\[CDATA\[|\]\]>$/g, "").trim() || null;
261
+ function L(o) {
262
+ return o?.textContent?.trim().replace(/^<!\[CDATA\[|\]\]>$/g, "").trim() || null;
261
263
  }
262
- class lt {
264
+ class rt {
263
265
  constructor(t, e) {
264
266
  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 = {
265
267
  skipDelay: 5,
@@ -278,7 +280,7 @@ class lt {
278
280
  */
279
281
  ensureAdVideo() {
280
282
  if (!this.adVideo) {
281
- this.adVideo = l("video", "imp-ad__video", { playsinline: "" });
283
+ this.adVideo = a("video", "imp-ad__video", { playsinline: "" });
282
284
  try {
283
285
  this.adVideo.load();
284
286
  } catch {
@@ -326,11 +328,11 @@ class lt {
326
328
  for (const n of t) {
327
329
  this.playedRolls.add(n);
328
330
  try {
329
- const o = await st(n, this.opts);
330
- await this.playAd(o);
331
- } catch (o) {
332
- const a = o instanceof Error ? o : new Error(String(o));
333
- this.host.emitter.emit("aderror", { roll: n, error: a });
331
+ const r = await et(n, this.opts);
332
+ await this.playAd(r);
333
+ } catch (r) {
334
+ const l = r instanceof Error ? r : new Error(String(r));
335
+ this.host.emitter.emit("aderror", { roll: n, error: l });
334
336
  }
335
337
  if (this.destroyed) return;
336
338
  }
@@ -343,70 +345,70 @@ class lt {
343
345
  }
344
346
  playAd(t) {
345
347
  return new Promise((e) => {
346
- const { labels: i } = this.host, s = l("div", "imp-ad"), n = this.ensureAdVideo(), o = new AbortController(), a = o.signal;
348
+ const { labels: i } = this.host, s = a("div", "imp-ad"), n = this.ensureAdVideo(), r = new AbortController(), l = r.signal;
347
349
  n.src = t.mediaUrl, n.muted = this.host.contentVideo.muted, n.volume = this.host.contentVideo.volume;
348
- const c = l("div", "imp-spinner imp-ad__spinner"), h = l("div", "imp-ad__hud"), u = l("span", "imp-ad__badge");
350
+ const h = a("div", "imp-spinner imp-ad__spinner"), c = a("div", "imp-ad__hud"), u = a("span", "imp-ad__badge");
349
351
  u.textContent = t.adTitle ? `${i.adLabel} · ${t.adTitle}` : i.adLabel;
350
- const f = l("span", "imp-ad__countdown");
351
- h.append(u, f);
352
- const d = l("div", "imp-ad__actions");
352
+ const p = a("span", "imp-ad__countdown");
353
+ c.append(u, p);
354
+ const m = a("div", "imp-ad__actions");
353
355
  let b = null;
354
- t.clickThrough && (b = l("button", "imp-ad__visit", { type: "button" }), b.textContent = i.visitAdvertiser, d.append(b));
355
- const v = l("button", "imp-ad__skip", { type: "button" });
356
- v.hidden = !0, d.append(v), s.append(n, c, h, d), this.host.container.append(s), this.layer = s;
357
- const H = t.skipOffset ?? this.opts.skipDelay, N = /* @__PURE__ */ new Set(), L = (g) => {
358
- N.has(g) || (N.add(g), C(t.tracking[g]));
356
+ t.clickThrough && (b = a("button", "imp-ad__visit", { type: "button" }), b.textContent = i.visitAdvertiser, m.append(b));
357
+ const g = a("button", "imp-ad__skip", { type: "button" });
358
+ g.hidden = !0, m.append(g), s.append(n, h, c, m), this.host.container.append(s), this.layer = s;
359
+ const B = t.skipOffset ?? this.opts.skipDelay, d = /* @__PURE__ */ new Set(), y = (k) => {
360
+ d.has(k) || (d.add(k), T(t.tracking[k]));
359
361
  };
360
- let P = Date.now(), Z = -1;
361
- const X = setInterval(() => {
362
+ let A = Date.now(), F = -1;
363
+ const j = setInterval(() => {
362
364
  if (n.paused) {
363
- P = Date.now();
365
+ A = Date.now();
364
366
  return;
365
367
  }
366
- if (n.currentTime !== Z) {
367
- Z = n.currentTime, P = Date.now();
368
+ if (n.currentTime !== F) {
369
+ F = n.currentTime, A = Date.now();
368
370
  return;
369
371
  }
370
- Date.now() - P >= this.opts.mediaTimeout && (this.host.emitter.emit("aderror", {
372
+ Date.now() - A >= this.opts.mediaTimeout && (this.host.emitter.emit("aderror", {
371
373
  roll: { roll: t.roll },
372
374
  error: new Error(`Ad media stalled for ${this.opts.mediaTimeout} ms — skipping`)
373
- }), A());
374
- }, 500), A = () => {
375
- clearInterval(X), o.abort(), n.pause(), n.removeAttribute("src"), n.load(), s.remove(), this.layer = null, e();
376
- }, O = (g) => {
377
- g ? (L("skip"), this.host.emitter.emit("adskip", { ad: t })) : L("complete"), this.host.emitter.emit("adend", { ad: t }), A();
375
+ }), R());
376
+ }, 500), R = () => {
377
+ clearInterval(j), r.abort(), n.pause(), n.removeAttribute("src"), n.load(), s.remove(), this.layer = null, e();
378
+ }, H = (k) => {
379
+ k ? (y("skip"), this.host.emitter.emit("adskip", { ad: t })) : y("complete"), this.host.emitter.emit("adend", { ad: t }), R();
378
380
  };
379
381
  n.addEventListener("playing", () => {
380
- C(t.impressions), L("start"), this.host.emitter.emit("adstart", { ad: t });
381
- }, { once: !0, signal: a }), n.addEventListener("playing", () => {
382
- c.hidden = !0;
383
- }, { signal: a }), n.addEventListener("waiting", () => {
384
- c.hidden = !1;
385
- }, { signal: a }), n.addEventListener("timeupdate", () => {
386
- const g = n.currentTime, x = n.duration;
387
- if (Number.isFinite(x) && x > 0 && (f.textContent = w(Math.max(0, x - g)), g / x >= 0.25 && L("firstQuartile"), g / x >= 0.5 && L("midpoint"), g / x >= 0.75 && L("thirdQuartile")), H >= 0) {
388
- const z = Math.ceil(H - g);
389
- z > 0 ? (v.hidden = !1, v.disabled = !0, v.textContent = `${i.skipAdIn} ${z}`) : (v.hidden = !1, v.disabled = !1, v.textContent = i.skipAd);
382
+ T(t.impressions), y("start"), this.host.emitter.emit("adstart", { ad: t });
383
+ }, { once: !0, signal: l }), n.addEventListener("playing", () => {
384
+ h.hidden = !0;
385
+ }, { signal: l }), n.addEventListener("waiting", () => {
386
+ h.hidden = !1;
387
+ }, { signal: l }), n.addEventListener("timeupdate", () => {
388
+ const k = n.currentTime, _ = n.duration;
389
+ if (Number.isFinite(_) && _ > 0 && (p.textContent = x(Math.max(0, _ - k)), k / _ >= 0.25 && y("firstQuartile"), k / _ >= 0.5 && y("midpoint"), k / _ >= 0.75 && y("thirdQuartile")), B >= 0) {
390
+ const D = Math.ceil(B - k);
391
+ D > 0 ? (g.hidden = !1, g.disabled = !0, g.textContent = `${i.skipAdIn} ${D}`) : (g.hidden = !1, g.disabled = !1, g.textContent = i.skipAd);
390
392
  }
391
- }, { signal: a }), n.addEventListener("ended", () => O(!1), { signal: a }), n.addEventListener("error", () => {
393
+ }, { signal: l }), n.addEventListener("ended", () => H(!1), { signal: l }), n.addEventListener("error", () => {
392
394
  this.host.emitter.emit("aderror", {
393
395
  roll: { roll: t.roll },
394
396
  error: new Error("Ad media failed to play")
395
- }), A();
396
- }, { signal: a }), v.addEventListener("click", () => O(!0));
397
- const D = () => {
398
- t.clickThrough && (L("click"), this.host.emitter.emit("adclick", { ad: t }), window.open(t.clickThrough, "_blank", "noopener"), n.pause());
397
+ }), R();
398
+ }, { signal: l }), g.addEventListener("click", () => H(!0));
399
+ const O = () => {
400
+ t.clickThrough && (y("click"), this.host.emitter.emit("adclick", { ad: t }), window.open(t.clickThrough, "_blank", "noopener"), n.pause());
399
401
  };
400
- n.addEventListener("click", D, { signal: a }), b?.addEventListener("click", D);
401
- let W = !1, B = !1;
402
+ n.addEventListener("click", O, { signal: l }), b?.addEventListener("click", O);
403
+ let Z = !1, C = !1;
402
404
  n.addEventListener("playing", () => {
403
- W = !0;
404
- }, { once: !0, signal: a }), n.addEventListener("pause", () => {
405
- n.ended || !s.isConnected || (s.classList.add("imp-ad--paused"), W && !B && (B = !0, C(t.tracking.pause), this.host.emitter.emit("adpause", { ad: t })));
406
- }, { signal: a }), n.addEventListener("play", () => {
407
- s.classList.remove("imp-ad--paused"), B && (B = !1, C(t.tracking.resume), this.host.emitter.emit("adresume", { ad: t }));
408
- }, { signal: a }), s.addEventListener("click", (g) => {
409
- (g.target === s || s.classList.contains("imp-ad--paused")) && n.paused && n.play().catch(() => {
405
+ Z = !0;
406
+ }, { once: !0, signal: l }), n.addEventListener("pause", () => {
407
+ n.ended || !s.isConnected || (s.classList.add("imp-ad--paused"), Z && !C && (C = !0, T(t.tracking.pause), this.host.emitter.emit("adpause", { ad: t })));
408
+ }, { signal: l }), n.addEventListener("play", () => {
409
+ s.classList.remove("imp-ad--paused"), C && (C = !1, T(t.tracking.resume), this.host.emitter.emit("adresume", { ad: t }));
410
+ }, { signal: l }), s.addEventListener("click", (k) => {
411
+ (k.target === s || s.classList.contains("imp-ad--paused")) && n.paused && n.play().catch(() => {
410
412
  });
411
413
  }), n.play().catch(() => {
412
414
  s.classList.add("imp-ad--paused");
@@ -421,36 +423,36 @@ class lt {
421
423
  this.destroyed = !0, this.adVideo?.pause(), this.layer?.remove(), this.layer = null, this.adVideo = null;
422
424
  }
423
425
  }
424
- function at(r, t) {
425
- const e = [...r].sort((s, n) => s.start - n.start), i = [];
426
+ function ot(o, t) {
427
+ const e = [...o].sort((s, n) => s.start - n.start), i = [];
426
428
  for (let s = 0; s < e.length; s++) {
427
429
  const n = Math.max(0, e[s].start);
428
430
  if (Number.isFinite(t) && n >= t) continue;
429
- let o = e[s].end ?? e[s + 1]?.start ?? t;
430
- Number.isFinite(t) && (o = Math.min(o, t)), !(o <= n) && i.push({ start: n, end: o, title: e[s].title });
431
+ let r = e[s].end ?? e[s + 1]?.start ?? t;
432
+ Number.isFinite(t) && (r = Math.min(r, t)), !(r <= n) && i.push({ start: n, end: r, title: e[s].title });
431
433
  }
432
434
  return i;
433
435
  }
434
- async function ht(r) {
435
- const t = await fetch(r);
436
+ async function lt(o) {
437
+ const t = await fetch(o);
436
438
  if (!t.ok) throw new Error(`Failed to load chapters VTT (${t.status})`);
437
439
  const e = await t.text();
438
- return U(e).map((i) => ({ start: i.start, end: i.end, title: i.text }));
440
+ return Q(e).map((i) => ({ start: i.start, end: i.end, title: i.text }));
439
441
  }
440
- function K(r, t) {
441
- for (const e of r)
442
+ function U(o, t) {
443
+ for (const e of o)
442
444
  if (t >= e.start && t < e.end) return e;
443
445
  return null;
444
446
  }
445
- function ct(r, t) {
446
- return t ? /application\/(x-mpegurl|vnd\.apple\.mpegurl)/i.test(t) : /\.m3u8(\?|#|$)/i.test(r);
447
+ function at(o, t) {
448
+ return t ? /application\/(x-mpegurl|vnd\.apple\.mpegurl)/i.test(t) : /\.m3u8(\?|#|$)/i.test(o);
447
449
  }
448
450
  let S;
449
- async function dt() {
451
+ async function ht() {
450
452
  if (S !== void 0) return S;
451
- const r = globalThis.Hls;
452
- if (r)
453
- return S = r, S;
453
+ const o = globalThis.Hls;
454
+ if (o)
455
+ return S = o, S;
454
456
  try {
455
457
  S = (await import("hls.js/light")).default;
456
458
  } catch {
@@ -458,14 +460,14 @@ async function dt() {
458
460
  }
459
461
  return S;
460
462
  }
461
- async function ut(r, t, e, i) {
462
- if (ct(t, e)) {
463
- const s = r.canPlayType("application/vnd.apple.mpegurl"), n = s ? null : await dt();
464
- return n && n.isSupported() ? pt(n, r, t, i) : s ? (r.src = t, $(r)) : (i.onError("HLS is not supported in this browser and hls.js could not be loaded."), $(r));
463
+ async function ct(o, t, e, i) {
464
+ if (at(t, e)) {
465
+ const s = o.canPlayType("application/vnd.apple.mpegurl"), n = s ? null : await ht();
466
+ return n && n.isSupported() ? dt(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));
465
467
  }
466
- return r.src = t, $(r);
468
+ return o.src = t, q(o);
467
469
  }
468
- function $(r) {
470
+ function q(o) {
469
471
  return {
470
472
  kind: "native",
471
473
  levels: [],
@@ -473,56 +475,56 @@ function $(r) {
473
475
  setLevel() {
474
476
  },
475
477
  destroy() {
476
- r.removeAttribute("src"), r.load();
478
+ o.removeAttribute("src"), o.load();
477
479
  }
478
480
  };
479
481
  }
480
- function pt(r, t, e, i) {
481
- const s = new r({ enableWorker: !0 }), n = {
482
+ function dt(o, t, e, i) {
483
+ const s = new o({ enableWorker: !0 }), n = {
482
484
  kind: "hls",
483
485
  levels: [],
484
486
  selected: -1,
485
- setLevel(c) {
486
- n.selected = c, s.currentLevel = c;
487
+ setLevel(h) {
488
+ n.selected = h, s.currentLevel = h;
487
489
  },
488
490
  destroy() {
489
491
  s.destroy(), t.removeAttribute("src"), t.load();
490
492
  }
491
493
  };
492
- s.on(r.Events.MANIFEST_PARSED, () => {
493
- n.levels = s.levels.map((c, h) => ({
494
- index: h,
495
- label: c.height ? `${c.height}p` : `${Math.round(c.bitrate / 1e3)} kbps`
494
+ s.on(o.Events.MANIFEST_PARSED, () => {
495
+ n.levels = s.levels.map((h, c) => ({
496
+ index: c,
497
+ label: h.height ? `${h.height}p` : `${Math.round(h.bitrate / 1e3)} kbps`
496
498
  })).reverse(), i.onLevels(n.levels);
497
- }), s.on(r.Events.LEVEL_SWITCHED, (c, h) => {
498
- const u = s.levels[h.level];
499
+ }), s.on(o.Events.LEVEL_SWITCHED, (h, c) => {
500
+ const u = s.levels[c.level];
499
501
  u && i.onLevelSwitch(u.height ? `${u.height}p` : `${Math.round(u.bitrate / 1e3)} kbps`);
500
502
  });
501
- let o = 0, a = !1;
502
- return s.on(r.Events.ERROR, (c, h) => {
503
- if (h.fatal)
504
- switch (h.type) {
505
- case r.ErrorTypes.NETWORK_ERROR:
503
+ let r = 0, l = !1;
504
+ return s.on(o.Events.ERROR, (h, c) => {
505
+ if (c.fatal)
506
+ switch (c.type) {
507
+ case o.ErrorTypes.NETWORK_ERROR:
506
508
  s.startLoad();
507
509
  break;
508
- case r.ErrorTypes.MEDIA_ERROR:
509
- o < 3 ? (o++, s.recoverMediaError()) : (i.onError(`HLS media error: ${h.details}`, h), s.destroy());
510
+ case o.ErrorTypes.MEDIA_ERROR:
511
+ r < 3 ? (r++, s.recoverMediaError()) : (i.onError(`HLS media error: ${c.details}`, c), s.destroy());
510
512
  break;
511
513
  default:
512
- if (a)
513
- i.onError(`HLS fatal error: ${h.details}`, h), s.destroy();
514
+ if (l)
515
+ i.onError(`HLS fatal error: ${c.details}`, c), s.destroy();
514
516
  else {
515
- a = !0;
517
+ l = !0;
516
518
  try {
517
519
  s.loadSource(e), s.startLoad();
518
520
  } catch {
519
- i.onError(`HLS fatal error: ${h.details}`, h), s.destroy();
521
+ i.onError(`HLS fatal error: ${c.details}`, c), s.destroy();
520
522
  }
521
523
  }
522
524
  }
523
525
  }), s.loadSource(e), s.attachMedia(t), n;
524
526
  }
525
- class q {
527
+ class I {
526
528
  constructor(t) {
527
529
  this.cues = t;
528
530
  }
@@ -530,17 +532,17 @@ class q {
530
532
  const e = await fetch(t);
531
533
  if (!e.ok) throw new Error(`Failed to load thumbnails VTT (${e.status})`);
532
534
  const i = await e.text(), s = [];
533
- for (const n of U(i)) {
534
- const [o, a] = n.text.trim().split("#");
535
- if (!o) continue;
536
- const c = {
535
+ for (const n of Q(i)) {
536
+ const [r, l] = n.text.trim().split("#");
537
+ if (!r) continue;
538
+ const h = {
537
539
  start: n.start,
538
540
  end: n.end,
539
- src: G(o, t)
540
- }, h = a?.match(/xywh=(\d+),(\d+),(\d+),(\d+)/);
541
- h && (c.xywh = { x: Number(h[1]), y: Number(h[2]), w: Number(h[3]), h: Number(h[4]) }), s.push(c);
541
+ src: G(r, t)
542
+ }, c = l?.match(/xywh=(\d+),(\d+),(\d+),(\d+)/);
543
+ c && (h.xywh = { x: Number(c[1]), y: Number(c[2]), w: Number(c[3]), h: Number(c[4]) }), s.push(h);
542
544
  }
543
- return s.sort((n, o) => n.start - o.start), new q(s);
545
+ return s.sort((n, r) => n.start - r.start), new I(s);
544
546
  }
545
547
  cueAt(t) {
546
548
  let e = 0, i = this.cues.length - 1;
@@ -553,9 +555,10 @@ class q {
553
555
  return null;
554
556
  }
555
557
  }
556
- class M {
558
+ const ut = '<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>', pt = '<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>';
559
+ class E {
557
560
  constructor(t) {
558
- 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) => {
561
+ this.anchor = t, this.outsideListener = null, this.root = a("div", "imp-menu"), this.root.hidden = !0, this.backdrop = a("div", "imp-menu__backdrop"), this.backdrop.hidden = !0, this.backdrop.addEventListener("pointerdown", (e) => {
559
562
  e.preventDefault(), this.close();
560
563
  }), t.append(this.backdrop);
561
564
  }
@@ -567,35 +570,68 @@ class M {
567
570
  }
568
571
  show(t) {
569
572
  this.root.textContent = "";
570
- for (const e of t) {
571
- if (e.items.length === 0) continue;
572
- const i = l("div", "imp-menu__section");
573
- if (e.title) {
574
- const s = l("div", "imp-menu__title");
575
- s.textContent = e.title, i.append(s);
576
- }
577
- for (const s of e.items) {
578
- const n = l("button", "imp-menu__item", { type: "button", role: "menuitemradio" });
579
- if (n.setAttribute("aria-checked", String(s.active)), s.active && n.classList.add("imp-menu__item--active"), s.icon) {
580
- const a = l("span", "imp-menu__icon");
581
- s.icon.trimStart().startsWith("<svg") ? a.innerHTML = s.icon : a.append(l("img", "", { src: s.icon, alt: "" })), n.append(a);
582
- }
583
- const o = l("span", "imp-menu__label");
584
- o.textContent = s.label, n.append(o), n.addEventListener("click", () => {
585
- e.onSelect(s.value), this.close();
586
- }), i.append(n);
573
+ for (const e of t)
574
+ e.items.length !== 0 && this.root.append(this.renderSection(e));
575
+ this.reveal();
576
+ }
577
+ /** Settings (gear) drill-down: a root list of rows, each opening its options. */
578
+ toggleSettings(t, e) {
579
+ this.open ? this.close() : this.showSettings(t, e);
580
+ }
581
+ showSettings(t, e) {
582
+ this.root.classList.add("imp-menu--wide"), this.renderSettingsRoot(e), this.reveal();
583
+ }
584
+ renderSettingsRoot(t) {
585
+ this.root.textContent = "";
586
+ const e = a("div", "imp-menu__section");
587
+ for (const i of t) {
588
+ const s = a("button", "imp-menu__item imp-menu__row", { type: "button" }), n = a("span", "imp-menu__label");
589
+ n.textContent = i.label;
590
+ const r = a("span", "imp-menu__value");
591
+ r.textContent = i.value;
592
+ const l = a("span", "imp-menu__chevron");
593
+ l.innerHTML = ut, s.append(n, r, l), s.addEventListener("click", () => this.renderSettingsDetail(t, i)), e.append(s);
594
+ }
595
+ this.root.append(e);
596
+ }
597
+ renderSettingsDetail(t, e) {
598
+ this.root.textContent = "";
599
+ const i = a("button", "imp-menu__item imp-menu__back", { type: "button" }), s = a("span", "imp-menu__chevron");
600
+ s.innerHTML = pt;
601
+ const n = a("span", "imp-menu__label");
602
+ 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;
603
+ }
604
+ /** Build one option block (radio items) from a section. */
605
+ renderSection(t) {
606
+ const e = a("div", "imp-menu__section");
607
+ if (t.title) {
608
+ const i = a("div", "imp-menu__title");
609
+ i.textContent = t.title, e.append(i);
610
+ }
611
+ for (const i of t.items) {
612
+ const s = a("button", "imp-menu__item", { type: "button", role: "menuitemradio" });
613
+ if (s.setAttribute("aria-checked", String(i.active)), i.active && s.classList.add("imp-menu__item--active"), i.icon) {
614
+ const r = a("span", "imp-menu__icon");
615
+ i.icon.trimStart().startsWith("<svg") ? r.innerHTML = i.icon : r.append(a("img", "", { src: i.icon, alt: "" })), s.append(r);
587
616
  }
588
- this.root.append(i);
617
+ const n = a("span", "imp-menu__label");
618
+ n.textContent = i.label, s.append(n), s.addEventListener("click", () => {
619
+ t.onSelect(i.value), this.close();
620
+ }), e.append(s);
589
621
  }
590
- this.root.hidden = !1, this.backdrop.hidden = !1, this.outsideListener = (e) => {
591
- const i = e.target;
592
- !this.root.contains(i) && !this.anchor.contains(i) && this.close();
622
+ return e;
623
+ }
624
+ /** Reveal the populated menu + backdrop and arm the outside-click listener. */
625
+ reveal() {
626
+ this.root.hidden = !1, this.backdrop.hidden = !1, this.outsideListener = (t) => {
627
+ const e = t.target;
628
+ !this.root.contains(e) && !this.anchor.contains(e) && this.close();
593
629
  }, setTimeout(() => {
594
630
  this.outsideListener && document.addEventListener("pointerdown", this.outsideListener);
595
631
  }, 0);
596
632
  }
597
633
  close() {
598
- this.root.hidden = !0, this.backdrop.hidden = !0, this.outsideListener && (document.removeEventListener("pointerdown", this.outsideListener), this.outsideListener = null);
634
+ 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);
599
635
  }
600
636
  destroy() {
601
637
  this.close(), this.root.remove();
@@ -603,7 +639,7 @@ class M {
603
639
  }
604
640
  class mt {
605
641
  constructor(t) {
606
- 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.tooltip = l("div", "imp-progress__tooltip"), this.tooltip.append(this.tooltipThumb, this.tooltipChapter, this.tooltipTime), 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();
642
+ this.cb = t, this.segments = [], this.duration = 0, this.chapters = [], this.thumbnails = null, this.scrubbing = !1, this.root = a("div", "imp-progress", { role: "slider", "aria-label": "Seek", tabindex: "-1" }), this.buffered = a("div", "imp-progress__buffered"), this.track = a("div", "imp-progress__track"), this.handle = a("div", "imp-progress__handle"), this.tooltipThumb = a("div", "imp-progress__thumb"), this.tooltipChapter = a("div", "imp-progress__tooltip-chapter"), this.tooltipTime = a("div", "imp-progress__tooltip-time"), this.tooltip = a("div", "imp-progress__tooltip"), this.tooltip.append(this.tooltipThumb, this.tooltipChapter, this.tooltipTime), this.heatmap = a("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();
607
643
  }
608
644
  /** Render the popularity curve (empty array hides it). */
609
645
  setHeatmap(t) {
@@ -611,7 +647,7 @@ class mt {
611
647
  this.heatmap.hidden = !0, this.heatmap.textContent = "";
612
648
  return;
613
649
  }
614
- this.heatmap.innerHTML = `<svg viewBox="0 0 1000 100" preserveAspectRatio="none" aria-hidden="true"><path d="${it(t)}"/></svg>`, this.heatmap.hidden = !1;
650
+ this.heatmap.innerHTML = `<svg viewBox="0 0 1000 100" preserveAspectRatio="none" aria-hidden="true"><path d="${tt(t)}"/></svg>`, this.heatmap.hidden = !1;
615
651
  }
616
652
  setDuration(t) {
617
653
  this.duration = Number.isFinite(t) ? t : 0, this.root.classList.toggle("imp-progress--live", !Number.isFinite(t)), this.chapters.length === 0 && this.setChapters([]);
@@ -624,10 +660,10 @@ class mt {
624
660
  n.start > s && i.push({ start: s, end: n.start, title: "" }), i.push(n), s = n.end;
625
661
  this.duration > 0 && s < this.duration && i.push({ start: s, end: this.duration, title: "" });
626
662
  for (const n of i) {
627
- const o = l("div", "imp-progress__segment");
628
- o.style.flexGrow = String(Math.max(n.end - n.start, 0.01));
629
- const a = l("div", "imp-progress__fill");
630
- o.append(a), this.track.append(o), this.segments.push({ chapter: n, root: o, fill: a });
663
+ const r = a("div", "imp-progress__segment");
664
+ r.style.flexGrow = String(Math.max(n.end - n.start, 0.01));
665
+ const l = a("div", "imp-progress__fill");
666
+ r.append(l), this.track.append(r), this.segments.push({ chapter: n, root: r, fill: l });
631
667
  }
632
668
  }
633
669
  setThumbnails(t) {
@@ -636,20 +672,20 @@ class mt {
636
672
  update(t, e, i) {
637
673
  if (e !== this.duration && Number.isFinite(e) && this.setDuration(e), this.scrubbing) return;
638
674
  this.render(t);
639
- const s = this.duration > 0 ? y(i / this.duration, 0, 1) : 0;
640
- this.buffered.style.width = `${s * 100}%`, this.root.setAttribute("aria-valuemin", "0"), this.root.setAttribute("aria-valuemax", String(Math.round(this.duration))), this.root.setAttribute("aria-valuenow", String(Math.round(t))), this.root.setAttribute("aria-valuetext", `${w(t)} / ${w(this.duration)}`);
675
+ const s = this.duration > 0 ? w(i / this.duration, 0, 1) : 0;
676
+ 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)}`);
641
677
  }
642
678
  render(t) {
643
679
  for (const { chapter: i, fill: s } of this.segments) {
644
- const n = i.end - i.start, o = n > 0 ? y((t - i.start) / n, 0, 1) : 0;
645
- s.style.transform = `scaleX(${o})`;
680
+ const n = i.end - i.start, r = n > 0 ? w((t - i.start) / n, 0, 1) : 0;
681
+ s.style.transform = `scaleX(${r})`;
646
682
  }
647
- const e = this.duration > 0 ? y(t / this.duration, 0, 1) : 0;
683
+ const e = this.duration > 0 ? w(t / this.duration, 0, 1) : 0;
648
684
  this.handle.style.left = `${e * 100}%`;
649
685
  }
650
686
  timeFromEvent(t) {
651
687
  const e = this.root.getBoundingClientRect();
652
- return (e.width > 0 ? y((t.clientX - e.left) / e.width, 0, 1) : 0) * this.duration;
688
+ return (e.width > 0 ? w((t.clientX - e.left) / e.width, 0, 1) : 0) * this.duration;
653
689
  }
654
690
  bindPointer() {
655
691
  this.root.addEventListener("pointerdown", (t) => {
@@ -664,23 +700,23 @@ class mt {
664
700
  }
665
701
  showTooltip(t) {
666
702
  const e = this.timeFromEvent(t);
667
- this.tooltipTime.textContent = w(e);
668
- const i = K(this.chapters, e);
703
+ this.tooltipTime.textContent = x(e);
704
+ const i = U(this.chapters, e);
669
705
  this.tooltipChapter.textContent = i?.title ?? "", this.tooltipChapter.hidden = !i?.title;
670
706
  const s = this.thumbnails?.cueAt(e) ?? null;
671
707
  s ? (this.tooltipThumb.hidden = !1, this.tooltipThumb.style.backgroundImage = `url("${s.src}")`, s.xywh ? (this.tooltipThumb.style.width = `${s.xywh.w}px`, this.tooltipThumb.style.height = `${s.xywh.h}px`, this.tooltipThumb.style.backgroundPosition = `-${s.xywh.x}px -${s.xywh.y}px`, this.tooltipThumb.style.backgroundSize = "auto") : (this.tooltipThumb.style.width = "160px", this.tooltipThumb.style.height = "90px", this.tooltipThumb.style.backgroundPosition = "center", this.tooltipThumb.style.backgroundSize = "cover")) : this.tooltipThumb.hidden = !0, this.tooltip.classList.add("imp-progress__tooltip--visible");
672
- const n = this.root.getBoundingClientRect(), o = y(t.clientX - n.left, 0, n.width), a = this.tooltip.offsetWidth / 2;
673
- this.tooltip.style.left = `${y(o, a, Math.max(a, n.width - a))}px`;
708
+ const n = this.root.getBoundingClientRect(), r = w(t.clientX - n.left, 0, n.width), l = this.tooltip.offsetWidth / 2;
709
+ this.tooltip.style.left = `${w(r, l, Math.max(l, n.width - l))}px`;
674
710
  }
675
711
  hideTooltip() {
676
712
  this.tooltip.classList.remove("imp-progress__tooltip--visible");
677
713
  }
678
714
  }
679
- const _ = class _ {
715
+ class vt {
680
716
  constructor(t) {
681
- this.player = t, this.subtitlesBtn = null, this.settingsBtn = null, this.settingsMenu = null, this.subtitlesMenu = null, this.moreMenu = null, this.moreWrap = null, this.qualityBtn = null, this.qualityMenu = null, this.scenesBtn = null, this.likeBtn = null, this.dislikeBtn = null, this.likeCountEl = null, this.dislikeCountEl = null, this.prevBtn = null, this.nextBtn = null, this.seekBackBtn = null, this.seekFwdBtn = null, this.centerPlayBtn = null, this.centerPrevBtn = null, this.centerNextBtn = null, this.collapsibles = [], this.overflowed = /* @__PURE__ */ new Set(), this.resizeObserver = null, this.reflowScheduled = !1, this.actionItems = [], this.wasPlayingBeforeScrub = !1, this.disposers = [], this.onWindowResize = null;
717
+ this.player = t, this.subtitlesBtn = null, this.settingsBtn = null, this.settingsMenu = null, this.subtitlesMenu = null, this.moreMenu = null, this.moreWrap = null, this.qualityBtn = null, this.qualityMenu = null, this.gearBtn = null, this.gearMenu = null, this.gear = { speed: !1, quality: !1, subtitles: !1 }, this.nextPreviewEl = null, this.nextPreviewOpts = null, this.scenesBtn = null, this.likeBtn = null, this.dislikeBtn = null, this.likeCountEl = null, this.dislikeCountEl = null, this.prevBtn = null, this.nextBtn = null, this.seekBackBtn = null, this.seekFwdBtn = null, this.centerPlayBtn = null, this.centerPrevBtn = null, this.centerNextBtn = null, this.collapsibles = [], this.overflowed = /* @__PURE__ */ new Set(), this.resizeObserver = null, this.reflowScheduled = !1, this.actionItems = [], this.wasPlayingBeforeScrub = !1, this.disposers = [], this.onWindowResize = null;
682
718
  const { labels: e, icons: i } = t, s = t.controlsOptions;
683
- this.root = l("div", "imp-controls"), this.progress = new mt({
719
+ this.root = a("div", "imp-controls"), this.progress = new mt({
684
720
  onSeek: (d) => t.seek(d),
685
721
  onScrubStart: () => {
686
722
  this.wasPlayingBeforeScrub = !t.paused, t.pause();
@@ -689,16 +725,16 @@ const _ = class _ {
689
725
  this.wasPlayingBeforeScrub && t.play();
690
726
  }
691
727
  }), s.progress && this.root.append(this.progress.root);
692
- const n = l("div", "imp-controls__row");
728
+ const n = a("div", "imp-controls__row");
693
729
  this.row = n, this.root.append(n);
694
- const o = l("div", "imp-controls__group"), a = l("div", "imp-controls__group");
695
- this.rightGroup = a;
696
- const c = l("div", "imp-controls__spacer");
697
- this.chapterLabel = l("div", "imp-controls__chapter"), n.append(o, c, a), c.append(this.chapterLabel);
698
- const h = typeof s.seekButtons == "object" ? s.seekButtons : {}, u = h.back ?? t.seekStep, f = h.forward ?? t.seekStep;
699
- if (s.playlist && t.hasPlaylist && (this.prevBtn = m("imp-btn--prev", e.previous, i.previous), this.prevBtn.addEventListener("click", () => t.previous()), o.append(this.prevBtn)), s.seekButtons && (this.seekBackBtn = m("imp-btn--seek-back", `${e.seekBack} ${u}s`, i.seekBack), this.seekBackBtn.addEventListener("click", () => t.skip(-u)), o.append(this.seekBackBtn)), s.play && (this.playBtn = m("imp-btn--play", e.play, i.play), this.playBtn.addEventListener("click", () => t.togglePlay()), o.append(this.playBtn)), s.seekButtons && (this.seekFwdBtn = m("imp-btn--seek-forward", `${e.seekForward} ${f}s`, i.seekForward), this.seekFwdBtn.addEventListener("click", () => t.skip(f)), o.append(this.seekFwdBtn)), s.playlist && t.hasPlaylist && (this.nextBtn = m("imp-btn--next", e.next, i.next), this.nextBtn.addEventListener("click", () => t.next()), o.append(this.nextBtn)), s.volume) {
700
- const d = l("div", "imp-volume");
701
- this.muteBtn = m("imp-btn--mute", e.mute, i.volumeHigh), this.muteBtn.addEventListener("click", () => t.toggleMute()), this.volumeSlider = l("input", "imp-volume__slider", {
730
+ const r = a("div", "imp-controls__group"), l = a("div", "imp-controls__group");
731
+ this.rightGroup = l;
732
+ const h = a("div", "imp-controls__spacer");
733
+ this.chapterLabel = a("div", "imp-controls__chapter"), n.append(r, h, l), h.append(this.chapterLabel);
734
+ const c = typeof s.seekButtons == "object" ? s.seekButtons : {}, u = c.back ?? t.seekStep, p = c.forward ?? t.seekStep;
735
+ if (s.playlist && t.hasPlaylist && !s.hidePrev && (this.prevBtn = f("imp-btn--prev", e.previous, i.previous), this.prevBtn.addEventListener("click", () => t.previous()), r.append(this.prevBtn)), s.seekButtons && (this.seekBackBtn = f("imp-btn--seek-back", `${e.seekBack} ${u}s`, i.seekBack), this.addStepBadge(this.seekBackBtn, u), this.seekBackBtn.addEventListener("click", () => t.skip(-u)), r.append(this.seekBackBtn)), s.play && (this.playBtn = f("imp-btn--play", e.play, i.play), this.playBtn.addEventListener("click", () => t.togglePlay()), r.append(this.playBtn)), s.seekButtons && (this.seekFwdBtn = f("imp-btn--seek-forward", `${e.seekForward} ${p}s`, i.seekForward), this.addStepBadge(this.seekFwdBtn, p), this.seekFwdBtn.addEventListener("click", () => t.skip(p)), r.append(this.seekFwdBtn)), s.playlist && t.hasPlaylist && (this.nextBtn = f("imp-btn--next", e.next, i.next), this.nextBtn.addEventListener("click", () => t.next()), r.append(this.nextBtn)), s.volume) {
736
+ const d = a("div", "imp-volume");
737
+ this.muteBtn = f("imp-btn--mute", e.mute, i.volumeHigh), this.muteBtn.addEventListener("click", () => t.toggleMute()), this.volumeSlider = a("input", "imp-volume__slider", {
702
738
  type: "range",
703
739
  min: "0",
704
740
  max: "1",
@@ -706,12 +742,24 @@ const _ = class _ {
706
742
  "aria-label": "Volume"
707
743
  }), this.volumeSlider.addEventListener("input", () => {
708
744
  t.setVolume(Number(this.volumeSlider.value));
709
- }), d.append(this.muteBtn, this.volumeSlider), o.append(d);
745
+ }), d.append(this.muteBtn, this.volumeSlider), r.append(d);
710
746
  }
711
- if (s.time && (this.timeLabel = l("div", "imp-controls__time"), this.liveBadge = l("span", "imp-controls__live"), this.liveBadge.textContent = e.live, this.liveBadge.hidden = !0, o.append(this.timeLabel, this.liveBadge)), this.buildLikeDislike(a), s.subtitles) {
712
- this.subtitlesBtn = m("imp-btn--subtitles", e.subtitles, i.subtitles), this.subtitlesMenu = new M(this.subtitlesBtn);
713
- const d = l("div", "imp-controls__menu-anchor");
714
- d.append(this.subtitlesBtn, this.subtitlesMenu.root), this.subtitlesBtn.addEventListener("click", () => this.toggleSubtitlesMenu()), a.append(d), this.registerCollapsible({
747
+ s.time && (this.timeLabel = a("div", "imp-controls__time"), this.liveBadge = a("span", "imp-controls__live"), this.liveBadge.textContent = e.live, this.liveBadge.hidden = !0, r.append(this.timeLabel, this.liveBadge)), this.buildLikeDislike(l);
748
+ for (const d of (t.actionsOptions.custom ?? []).filter((y) => y.placement === "bar")) {
749
+ const y = f(`imp-btn--custom imp-btn--custom-${d.id}`, d.title, d.icon ?? i.more);
750
+ y.addEventListener("click", () => t.emit("customaction", { id: d.id })), l.append(y), this.registerCollapsible({
751
+ key: `custom:${d.id}`,
752
+ el: y,
753
+ priority: 55,
754
+ available: () => !0,
755
+ section: () => this.simpleSection(`custom:${d.id}`, d.title, d.icon ?? i.more, () => t.emit("customaction", { id: d.id }))
756
+ });
757
+ }
758
+ const m = (d) => d === !1 ? "off" : d === "bar" ? "bar" : "gear", b = m(s.subtitles), g = m(s.quality), B = m(s.speed);
759
+ if (this.gear = { speed: B === "gear", quality: g === "gear", subtitles: b === "gear" }, b === "bar") {
760
+ this.subtitlesBtn = f("imp-btn--subtitles", e.subtitles, i.subtitles), this.subtitlesMenu = new E(this.subtitlesBtn);
761
+ const d = a("div", "imp-controls__menu-anchor");
762
+ d.append(this.subtitlesBtn, this.subtitlesMenu.root), this.subtitlesBtn.addEventListener("click", () => this.toggleSubtitlesMenu()), l.append(d), this.registerCollapsible({
715
763
  key: "subtitles",
716
764
  el: d,
717
765
  priority: 30,
@@ -719,21 +767,10 @@ const _ = class _ {
719
767
  section: () => this.subtitlesSection()
720
768
  });
721
769
  }
722
- if (s.settings) {
723
- this.settingsBtn = m("imp-btn--settings", e.settings, i.speed), this.settingsMenu = new M(this.settingsBtn);
724
- const d = l("div", "imp-controls__menu-anchor");
725
- d.append(this.settingsBtn, this.settingsMenu.root), this.settingsBtn.addEventListener("click", () => this.toggleSettingsMenu()), a.append(d), this.registerCollapsible({
726
- key: "settings",
727
- el: d,
728
- priority: 40,
729
- available: () => !0,
730
- section: () => this.speedSection()
731
- });
732
- }
733
- if (s.quality) {
734
- this.qualityBtn = m("imp-btn--quality", e.quality, i.settings), this.qualityMenu = new M(this.qualityBtn);
735
- const d = l("div", "imp-controls__menu-anchor");
736
- d.append(this.qualityBtn, this.qualityMenu.root), this.qualityBtn.addEventListener("click", () => this.toggleQualityMenu()), a.append(d), this.registerCollapsible({
770
+ if (g === "bar") {
771
+ this.qualityBtn = f("imp-btn--quality", e.quality, i.settings), this.qualityMenu = new E(this.qualityBtn);
772
+ const d = a("div", "imp-controls__menu-anchor");
773
+ d.append(this.qualityBtn, this.qualityMenu.root), this.qualityBtn.addEventListener("click", () => this.toggleQualityMenu()), l.append(d), this.registerCollapsible({
737
774
  key: "quality",
738
775
  el: d,
739
776
  priority: 10,
@@ -741,15 +778,26 @@ const _ = class _ {
741
778
  section: () => this.qualitySection()
742
779
  });
743
780
  }
744
- if (s.scenes && (this.scenesBtn = m("imp-btn--scenes", e.scenes, i.scenes), this.scenesBtn.addEventListener("click", () => t.toggleScenesPanel()), a.append(this.scenesBtn), this.registerCollapsible({
781
+ if (B === "bar") {
782
+ this.settingsBtn = f("imp-btn--speed", e.speed, i.speed), this.settingsMenu = new E(this.settingsBtn);
783
+ const d = a("div", "imp-controls__menu-anchor");
784
+ d.append(this.settingsBtn, this.settingsMenu.root), this.settingsBtn.addEventListener("click", () => this.toggleSettingsMenu()), l.append(d), this.registerCollapsible({
785
+ key: "speed",
786
+ el: d,
787
+ priority: 40,
788
+ available: () => !0,
789
+ section: () => this.speedSection()
790
+ });
791
+ }
792
+ if (s.scenes && (this.scenesBtn = f("imp-btn--scenes", e.scenes, i.scenes), this.scenesBtn.addEventListener("click", () => t.toggleScenesPanel()), l.append(this.scenesBtn), this.registerCollapsible({
745
793
  key: "scenes",
746
794
  el: this.scenesBtn,
747
795
  priority: 25,
748
796
  available: () => t.chapterList.length > 0,
749
797
  section: () => this.simpleSection("scenes", e.scenes, i.scenes, () => t.toggleScenesPanel())
750
798
  })), s.playlist && t.hasPlaylist) {
751
- const d = m("imp-btn--list", e.playlist, i.list);
752
- d.addEventListener("click", () => t.togglePlaylistPanel()), a.append(d), this.registerCollapsible({
799
+ const d = f("imp-btn--list", e.playlist, i.list);
800
+ d.addEventListener("click", () => t.togglePlaylistPanel()), l.append(d), this.registerCollapsible({
753
801
  key: "list",
754
802
  el: d,
755
803
  priority: 50,
@@ -758,8 +806,8 @@ const _ = class _ {
758
806
  });
759
807
  }
760
808
  if (s.pip && "requestPictureInPicture" in HTMLVideoElement.prototype) {
761
- const d = m("imp-btn--pip", e.pip, i.pip);
762
- d.addEventListener("click", () => void t.togglePip()), a.append(d), this.registerCollapsible({
809
+ const d = f("imp-btn--pip", e.pip, i.pip);
810
+ d.addEventListener("click", () => void t.togglePip()), l.append(d), this.registerCollapsible({
763
811
  key: "pip",
764
812
  el: d,
765
813
  priority: 20,
@@ -767,7 +815,7 @@ const _ = class _ {
767
815
  section: () => this.simpleSection("pip", e.pip, i.pip, () => void t.togglePip())
768
816
  });
769
817
  }
770
- if (s.fullscreen && (this.fullscreenBtn = m("imp-btn--fullscreen", e.fullscreen, i.fullscreen), this.fullscreenBtn.addEventListener("click", () => void t.toggleFullscreen()), a.append(this.fullscreenBtn)), this.prevBtn && this.registerCollapsible({
818
+ if (s.fullscreen && (this.fullscreenBtn = f("imp-btn--fullscreen", e.fullscreen, i.fullscreen), this.fullscreenBtn.addEventListener("click", () => void t.toggleFullscreen()), l.append(this.fullscreenBtn)), this.prevBtn && this.registerCollapsible({
771
819
  key: "prev",
772
820
  el: this.prevBtn,
773
821
  priority: 70,
@@ -796,47 +844,138 @@ const _ = class _ {
796
844
  el: d,
797
845
  priority: 82,
798
846
  available: () => Number.isFinite(t.duration) && t.duration > 0,
799
- section: () => this.simpleSection("seekFwd", `${e.seekForward} ${f}s`, i.seekForward, () => t.skip(f))
847
+ section: () => this.simpleSection("seekFwd", `${e.seekForward} ${p}s`, i.seekForward, () => t.skip(p))
800
848
  });
801
849
  }
802
- if (this.center = l("div", "imp-center-controls"), s.playlist && t.hasPlaylist && (this.centerPrevBtn = this.makeCenterButton("prev", e.previous, i.previous), this.centerPrevBtn.addEventListener("click", () => t.previous()), this.center.append(this.centerPrevBtn)), s.seekButtons) {
850
+ if (this.center = a("div", "imp-center-controls"), s.playlist && t.hasPlaylist && (this.centerPrevBtn = this.makeCenterButton("prev", e.previous, i.previous), this.centerPrevBtn.addEventListener("click", () => t.previous()), this.center.append(this.centerPrevBtn)), s.seekButtons) {
803
851
  const d = this.makeCenterButton("seek-back", `${e.seekBack} ${u}s`, i.seekBack);
804
- d.addEventListener("click", () => t.skip(-u)), this.center.append(d);
852
+ this.addStepBadge(d, u), d.addEventListener("click", () => t.skip(-u)), this.center.append(d);
805
853
  }
806
854
  if (s.play && (this.centerPlayBtn = this.makeCenterButton("play", e.play, i.play), this.centerPlayBtn.addEventListener("click", () => t.togglePlay()), this.center.append(this.centerPlayBtn)), s.seekButtons) {
807
- const d = this.makeCenterButton("seek-forward", `${e.seekForward} ${f}s`, i.seekForward);
808
- d.addEventListener("click", () => t.skip(f)), this.center.append(d);
855
+ const d = this.makeCenterButton("seek-forward", `${e.seekForward} ${p}s`, i.seekForward);
856
+ this.addStepBadge(d, p), d.addEventListener("click", () => t.skip(p)), this.center.append(d);
809
857
  }
810
- s.playlist && t.hasPlaylist && (this.centerNextBtn = this.makeCenterButton("next", e.next, i.next), this.centerNextBtn.addEventListener("click", () => t.next()), this.center.append(this.centerNextBtn)), this.center.style.display = "none", this.buildMoreDropdown(a), this.bind(), this.syncVolume(), this.syncPlayState(), this.setLikeState(t.actionsOptions.likeState ?? null), typeof ResizeObserver < "u" && (this.resizeObserver = new ResizeObserver(() => this.scheduleReflow()), this.resizeObserver.observe(t.container)), this.onWindowResize = () => this.scheduleReflow(), window.addEventListener("resize", this.onWindowResize);
858
+ 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) {
859
+ this.gearBtn = f("imp-btn--settings", e.settings, i.settings), this.gearMenu = new E(this.gearBtn);
860
+ const d = a("div", "imp-controls__menu-anchor");
861
+ d.append(this.gearBtn, this.gearMenu.root), this.gearBtn.addEventListener("click", () => this.toggleGearMenu()), l.append(d), this.registerCollapsible({
862
+ key: "gear",
863
+ el: d,
864
+ priority: 40,
865
+ available: () => this.gearSections().length > 0,
866
+ section: () => this.gearSections()
867
+ });
868
+ }
869
+ this.buildMoreDropdown(l), this.bind(), this.syncVolume(), this.syncPlayState(), this.setLikeState(t.actionsOptions.likeState ?? null), typeof ResizeObserver < "u" && (this.resizeObserver = new ResizeObserver(() => this.scheduleReflow()), this.resizeObserver.observe(t.container)), this.onWindowResize = () => this.scheduleReflow(), window.addEventListener("resize", this.onWindowResize);
811
870
  }
812
871
  registerCollapsible(t) {
813
872
  this.collapsibles.push(t);
814
873
  }
815
874
  /** Center-cluster button — deliberately NOT `.imp-btn` (own sizing/look). */
816
875
  makeCenterButton(t, e, i) {
817
- const s = l("button", `imp-center-btn imp-center-btn--${t}`, { type: "button", "aria-label": e, title: e });
876
+ const s = a("button", `imp-center-btn imp-center-btn--${t}`, { type: "button", "aria-label": e, title: e });
818
877
  return s.innerHTML = i, s;
819
878
  }
879
+ /** Overlay the seek step value (e.g. "15") inside the circular-arrow icon. */
880
+ addStepBadge(t, e) {
881
+ const i = a("span", "imp-seek-num");
882
+ i.textContent = String(e), t.append(i);
883
+ }
884
+ // === gear (unified settings) ==========================================
885
+ /** Sections for the gear when overflowed into ⋯ (expanded, no drill-down). */
886
+ gearSections() {
887
+ const t = this.player, e = [];
888
+ return this.gear.quality && t.qualityLevels.length > 0 && e.push(this.qualitySection()), this.gear.speed && e.push(this.speedSection()), this.gear.subtitles && t.subtitleTracks.length > 0 && e.push(this.subtitlesSection()), e;
889
+ }
890
+ /** Gear drill-down rows: one per setting, each showing its current value. */
891
+ gearEntries() {
892
+ const t = this.player, e = [];
893
+ if (this.gear.quality && t.qualityLevels.length > 0) {
894
+ const i = t.currentQuality === -1 ? t.labels.qualityAuto : t.qualityLevels.find((s) => s.index === t.currentQuality)?.label ?? t.labels.qualityAuto;
895
+ e.push({ key: "quality", label: t.labels.quality, value: i, section: () => this.qualitySection() });
896
+ }
897
+ if (this.gear.speed) {
898
+ const i = t.playbackRate;
899
+ e.push({ key: "speed", label: t.labels.speed, value: i === 1 ? "1×" : `${i}×`, section: () => this.speedSection() });
900
+ }
901
+ if (this.gear.subtitles && t.subtitleTracks.length > 0) {
902
+ const i = t.activeSubtitle === -1 ? t.labels.subtitlesOff : t.subtitleTracks[t.activeSubtitle]?.label ?? t.labels.subtitlesOff;
903
+ e.push({ key: "subtitles", label: t.labels.subtitles, value: i, section: () => this.subtitlesSection() });
904
+ }
905
+ return e;
906
+ }
907
+ toggleGearMenu() {
908
+ if (!this.gearMenu) return;
909
+ const t = this.gearEntries();
910
+ t.length !== 0 && (this.closeMenus(this.gearMenu), this.gearMenu.toggleSettings(this.player.labels.settings, t));
911
+ }
912
+ // === next-up hover preview ============================================
913
+ setupNextPreview() {
914
+ const t = this.player, e = t.controlsOptions;
915
+ if (e.nextPreview === !1 || !e.playlist || !t.hasPlaylist) return;
916
+ const i = typeof e.nextPreview == "object" ? e.nextPreview : {};
917
+ this.nextPreviewOpts = {
918
+ thumbnail: i.thumbnail ?? !0,
919
+ title: i.title ?? !0,
920
+ duration: i.duration ?? !0,
921
+ meta: i.meta ?? !0
922
+ }, this.nextPreviewEl = a("div", "imp-next-preview"), this.nextPreviewEl.hidden = !0, t.container.append(this.nextPreviewEl), this.nextBtn && this.bindNextPreview(this.nextBtn), this.centerNextBtn && this.bindNextPreview(this.centerNextBtn);
923
+ }
924
+ bindNextPreview(t) {
925
+ t.addEventListener("pointerenter", (e) => {
926
+ e.pointerType === "mouse" && this.showNextPreview(t);
927
+ }), t.addEventListener("pointerleave", () => this.hideNextPreview()), t.addEventListener("click", () => this.hideNextPreview());
928
+ }
929
+ showNextPreview(t) {
930
+ const e = this.nextPreviewEl, i = this.nextPreviewOpts;
931
+ if (!e || !i) return;
932
+ const s = this.player.nextSource;
933
+ if (!s) return;
934
+ e.textContent = "";
935
+ const n = a("div", "imp-next-preview__kicker");
936
+ if (n.textContent = this.player.labels.next, e.append(n), i.thumbnail && s.poster) {
937
+ const m = a("div", "imp-next-preview__thumb");
938
+ if (m.style.backgroundImage = `url("${s.poster}")`, i.duration && s.duration) {
939
+ const b = a("span", "imp-next-preview__duration");
940
+ b.textContent = x(s.duration), m.append(b);
941
+ }
942
+ e.append(m);
943
+ }
944
+ if (i.title && s.title) {
945
+ const m = a("div", "imp-next-preview__title");
946
+ m.textContent = s.title, e.append(m);
947
+ }
948
+ if (i.meta && s.previewMeta?.length) {
949
+ const m = a("div", "imp-next-preview__meta");
950
+ m.textContent = s.previewMeta.join(" · "), e.append(m);
951
+ }
952
+ e.hidden = !1;
953
+ const r = this.player.container.getBoundingClientRect(), l = t.getBoundingClientRect(), h = 8, c = e.offsetWidth, u = l.left - r.left + l.width / 2 - c / 2, p = Math.max(h, Math.min(u, r.width - c - h));
954
+ e.style.left = `${p}px`, e.style.bottom = `${r.height - (l.top - r.top) + 10}px`;
955
+ }
956
+ hideNextPreview() {
957
+ this.nextPreviewEl && (this.nextPreviewEl.hidden = !0);
958
+ }
820
959
  /** like/dislike — visible buttons (collapsible), highlightable via `setLikeState`. */
821
960
  buildLikeDislike(t) {
822
961
  const e = this.player, i = e.actionsOptions, { labels: s, icons: n } = e;
823
962
  if (i.like) {
824
- this.likeBtn = m("imp-btn--like", s.like, n.like), this.likeBtn.addEventListener("click", () => e.emit("action", { id: "like" })), this.likeCountEl = this.attachCountTooltip(this.likeBtn, i.likeCount);
825
- const o = this.wrapWithTooltip(this.likeBtn, this.likeCountEl);
826
- t.append(o), this.registerCollapsible({
963
+ this.likeBtn = f("imp-btn--like", s.like, n.like), this.likeBtn.addEventListener("click", () => e.emit("action", { id: "like" })), this.likeCountEl = this.attachCountTooltip(this.likeBtn, i.likeCount);
964
+ const r = this.wrapWithTooltip(this.likeBtn, this.likeCountEl);
965
+ t.append(r), this.registerCollapsible({
827
966
  key: "like",
828
- el: o,
967
+ el: r,
829
968
  priority: 62,
830
969
  available: () => !0,
831
970
  section: () => this.simpleSection("like", s.like, n.like, () => e.emit("action", { id: "like" }))
832
971
  });
833
972
  }
834
973
  if (i.dislike) {
835
- this.dislikeBtn = m("imp-btn--dislike", s.dislike, n.dislike), this.dislikeBtn.addEventListener("click", () => e.emit("action", { id: "dislike" })), this.dislikeCountEl = this.attachCountTooltip(this.dislikeBtn, i.dislikeCount);
836
- const o = this.wrapWithTooltip(this.dislikeBtn, this.dislikeCountEl);
837
- t.append(o), this.registerCollapsible({
974
+ this.dislikeBtn = f("imp-btn--dislike", s.dislike, n.dislike), this.dislikeBtn.addEventListener("click", () => e.emit("action", { id: "dislike" })), this.dislikeCountEl = this.attachCountTooltip(this.dislikeBtn, i.dislikeCount);
975
+ const r = this.wrapWithTooltip(this.dislikeBtn, this.dislikeCountEl);
976
+ t.append(r), this.registerCollapsible({
838
977
  key: "dislike",
839
- el: o,
978
+ el: r,
840
979
  priority: 60,
841
980
  available: () => !0,
842
981
  section: () => this.simpleSection("dislike", s.dislike, n.dislike, () => e.emit("action", { id: "dislike" }))
@@ -844,11 +983,11 @@ const _ = class _ {
844
983
  }
845
984
  }
846
985
  attachCountTooltip(t, e) {
847
- const i = l("span", "imp-count-tooltip");
986
+ const i = a("span", "imp-count-tooltip");
848
987
  return this.setCountText(i, e), i;
849
988
  }
850
989
  wrapWithTooltip(t, e) {
851
- const i = l("div", "imp-action");
990
+ const i = a("div", "imp-action");
852
991
  return i.append(t, e), i;
853
992
  }
854
993
  setCountText(t, e) {
@@ -865,33 +1004,37 @@ const _ = class _ {
865
1004
  buildMoreDropdown(t) {
866
1005
  const e = this.player, i = e.actionsOptions, { labels: s, icons: n } = e;
867
1006
  i.addTo && this.actionItems.push({ value: "addTo", label: s.addTo, icon: n.addTo, run: () => e.emit("action", { id: "addTo" }) }), i.share && this.actionItems.push({ value: "share", label: s.share, icon: n.share, run: () => void e.share() }), i.report && this.actionItems.push({ value: "report", label: s.report, icon: n.report, run: () => e.emit("action", { id: "report" }) });
868
- for (const c of i.custom ?? [])
869
- this.actionItems.push({ value: `custom:${c.id}`, label: c.title, icon: c.icon, run: () => e.emit("customaction", { id: c.id }) });
870
- const o = m("imp-btn--more", s.more, n.more);
871
- this.moreMenu = new M(o);
872
- const a = l("div", "imp-controls__menu-anchor imp-controls__more");
873
- a.append(o, this.moreMenu.root), o.addEventListener("click", () => {
1007
+ for (const h of (i.custom ?? []).filter((c) => c.placement !== "bar"))
1008
+ this.actionItems.push({ value: `custom:${h.id}`, label: h.title, icon: h.icon, run: () => e.emit("customaction", { id: h.id }) });
1009
+ const r = f("imp-btn--more", s.more, n.more);
1010
+ this.moreMenu = new E(r);
1011
+ const l = a("div", "imp-controls__menu-anchor imp-controls__more");
1012
+ l.append(r, this.moreMenu.root), r.addEventListener("click", () => {
874
1013
  this.closeMenus(this.moreMenu), this.moreMenu?.toggle(this.buildMoreSections());
875
- }), t.append(a), this.moreWrap = a;
1014
+ }), t.append(l), this.moreWrap = l;
876
1015
  }
877
1016
  /** ⋯ menu = overflowed controls (in display order) + consumer actions. */
878
1017
  buildMoreSections() {
879
- const t = [], e = /* @__PURE__ */ new Map(), i = [], s = ["prev", "next", "seekBack", "seekFwd", "like", "dislike", "scenes", "pip", "list", "subtitles", "settings", "quality"], n = this.collapsibles.filter((o) => this.overflowed.has(o.key) && o.available()).sort((o, a) => s.indexOf(o.key) - s.indexOf(a.key));
880
- for (const o of n) {
881
- const a = o.section();
882
- if (a)
883
- if (!a.title && a.items.length === 1) {
884
- const c = a.items[0];
885
- i.push(c), e.set(c.value, () => a.onSelect(c.value));
886
- } else
887
- t.push(a);
1018
+ const t = [], e = /* @__PURE__ */ new Map(), i = [], s = ["prev", "next", "seekBack", "seekFwd", "like", "dislike", "scenes", "pip", "list", "subtitles", "speed", "quality", "gear"], n = (l) => {
1019
+ const h = s.indexOf(l);
1020
+ return h === -1 ? s.length : h;
1021
+ }, r = this.collapsibles.filter((l) => this.overflowed.has(l.key) && l.available()).sort((l, h) => n(l.key) - n(h.key));
1022
+ for (const l of r) {
1023
+ const h = l.section();
1024
+ if (h)
1025
+ for (const c of Array.isArray(h) ? h : [h])
1026
+ if (!c.title && c.items.length === 1) {
1027
+ const u = c.items[0];
1028
+ i.push(u), e.set(u.value, () => c.onSelect(u.value));
1029
+ } else
1030
+ t.push(c);
888
1031
  }
889
- if (i.length > 0 && t.unshift({ title: "", items: i, onSelect: (o) => e.get(o)?.() }), this.actionItems.length > 0) {
890
- const o = new Map(this.actionItems.map((a) => [a.value, a.run]));
1032
+ if (i.length > 0 && t.unshift({ title: "", items: i, onSelect: (l) => e.get(l)?.() }), this.actionItems.length > 0) {
1033
+ const l = new Map(this.actionItems.map((h) => [h.value, h.run]));
891
1034
  t.push({
892
1035
  title: "",
893
- items: this.actionItems.map(({ value: a, label: c, icon: h }) => ({ value: a, label: c, icon: h, active: !1 })),
894
- onSelect: (a) => o.get(a)?.()
1036
+ items: this.actionItems.map(({ value: h, label: c, icon: u }) => ({ value: h, label: c, icon: u, active: !1 })),
1037
+ onSelect: (h) => l.get(h)?.()
895
1038
  });
896
1039
  }
897
1040
  return t;
@@ -944,26 +1087,28 @@ const _ = class _ {
944
1087
  * the ⋯ menu can offer them. Unavailable controls are hidden outright.
945
1088
  */
946
1089
  reflow() {
947
- const t = window.innerWidth <= 767;
948
- this.center.style.display = t ? "flex" : "none", this.playBtn && (this.playBtn.style.display = t ? "none" : ""), this.overflowed.clear();
949
- for (const s of this.collapsibles) {
950
- if (t && _.CENTER_KEYS.has(s.key)) {
951
- s.el.style.display = "none";
1090
+ const t = window.innerWidth <= 767, i = this.player.controlsOptions.seekPlacement !== "bar" || t;
1091
+ this.center.style.display = i ? "flex" : "none", this.centerPrevBtn && (this.centerPrevBtn.style.display = t ? "" : "none"), this.centerNextBtn && (this.centerNextBtn.style.display = t ? "" : "none"), this.playBtn && (this.playBtn.style.display = t ? "none" : "");
1092
+ const s = (l) => l === "seekBack" || l === "seekFwd" ? i : l === "prev" || l === "next" ? t : !1;
1093
+ this.overflowed.clear();
1094
+ for (const l of this.collapsibles) {
1095
+ if (s(l.key)) {
1096
+ l.el.style.display = "none";
952
1097
  continue;
953
1098
  }
954
- const n = s.available();
955
- s.el.style.display = n ? "" : "none", s.el.classList.remove("imp-collapsed");
1099
+ const h = l.available();
1100
+ l.el.style.display = h ? "" : "none", l.el.classList.remove("imp-collapsed");
956
1101
  }
957
- const e = this.collapsibles.filter((s) => s.available() && !(t && _.CENTER_KEYS.has(s.key))).sort((s, n) => s.priority - n.priority);
958
- let i = e.length;
959
- for (; i-- > 0 && this.overflowsRow(); ) {
960
- const s = e.find((n) => !this.overflowed.has(n.key));
961
- if (!s) break;
962
- s.el.style.display = "none", s.el.classList.add("imp-collapsed"), this.overflowed.add(s.key);
1102
+ const n = this.collapsibles.filter((l) => l.available() && !s(l.key)).sort((l, h) => l.priority - h.priority);
1103
+ let r = n.length;
1104
+ for (; r-- > 0 && this.overflowsRow(); ) {
1105
+ const l = n.find((h) => !this.overflowed.has(h.key));
1106
+ if (!l) break;
1107
+ l.el.style.display = "none", l.el.classList.add("imp-collapsed"), this.overflowed.add(l.key);
963
1108
  }
964
1109
  if (this.moreWrap) {
965
- const s = this.actionItems.length > 0 || this.overflowed.size > 0;
966
- this.moreWrap.style.display = s ? "" : "none";
1110
+ const l = this.actionItems.length > 0 || this.overflowed.size > 0;
1111
+ this.moreWrap.style.display = l ? "" : "none";
967
1112
  }
968
1113
  }
969
1114
  overflowsRow() {
@@ -974,7 +1119,7 @@ const _ = class _ {
974
1119
  const t = this.player;
975
1120
  this.disposers.push(
976
1121
  t.on("timeupdate", ({ currentTime: e, duration: i }) => {
977
- this.progress.update(e, i, t.bufferedEnd), this.timeLabel && (t.live ? (this.timeLabel.hidden = !0, this.liveBadge.hidden = !1) : (this.timeLabel.hidden = !1, this.liveBadge.hidden = !0, this.timeLabel.textContent = `${w(e)} / ${w(i)}`));
1122
+ this.progress.update(e, i, t.bufferedEnd), this.timeLabel && (t.live ? (this.timeLabel.hidden = !0, this.liveBadge.hidden = !1) : (this.timeLabel.hidden = !1, this.liveBadge.hidden = !0, this.timeLabel.textContent = `${x(e)} / ${x(i)}`));
978
1123
  }),
979
1124
  t.on("play", () => this.syncPlayState()),
980
1125
  t.on("pause", () => this.syncPlayState()),
@@ -984,7 +1129,7 @@ const _ = class _ {
984
1129
  this.chapterLabel.textContent = e?.title ?? "";
985
1130
  }),
986
1131
  t.on("fullscreenchange", ({ active: e }) => {
987
- this.fullscreenBtn && E(this.fullscreenBtn, e ? t.icons.fullscreenExit : t.icons.fullscreen, e ? t.labels.exitFullscreen : t.labels.fullscreen), this.scheduleReflow();
1132
+ this.fullscreenBtn && M(this.fullscreenBtn, e ? t.icons.fullscreenExit : t.icons.fullscreen, e ? t.labels.exitFullscreen : t.labels.fullscreen), this.scheduleReflow();
988
1133
  }),
989
1134
  t.on("playlistitemchange", () => {
990
1135
  this.syncPlaylistButtons(), this.scheduleReflow();
@@ -996,12 +1141,12 @@ const _ = class _ {
996
1141
  }
997
1142
  syncPlayState() {
998
1143
  const t = this.player, [e, i] = t.ended ? [t.icons.replay, t.labels.replay] : t.paused ? [t.icons.play, t.labels.play] : [t.icons.pause, t.labels.pause];
999
- this.playBtn && E(this.playBtn, e, i), this.centerPlayBtn && E(this.centerPlayBtn, e, i);
1144
+ this.playBtn && M(this.playBtn, e, i), this.centerPlayBtn && M(this.centerPlayBtn, e, i);
1000
1145
  }
1001
1146
  syncVolume() {
1002
1147
  if (!this.muteBtn) return;
1003
1148
  const t = this.player, e = t.muted ? 0 : t.volume, i = e === 0 ? t.icons.volumeMute : e < 0.5 ? t.icons.volumeLow : t.icons.volumeHigh;
1004
- E(this.muteBtn, i, t.muted ? t.labels.unmute : t.labels.mute), this.volumeSlider.value = String(e), this.volumeSlider.style.setProperty("--imp-volume-fill", `${e * 100}%`);
1149
+ M(this.muteBtn, i, t.muted ? t.labels.unmute : t.labels.mute), this.volumeSlider.value = String(e), this.volumeSlider.style.setProperty("--imp-volume-fill", `${e * 100}%`);
1005
1150
  }
1006
1151
  /** Called by the player when per-source data (chapters/quality/subtitles) changes. */
1007
1152
  syncFeatureButtons() {
@@ -1012,7 +1157,7 @@ const _ = class _ {
1012
1157
  this.prevBtn && (this.prevBtn.disabled = !t.hasPrevious), this.nextBtn && (this.nextBtn.disabled = !t.hasNext), this.centerPrevBtn && (this.centerPrevBtn.disabled = !t.hasPrevious), this.centerNextBtn && (this.centerNextBtn.disabled = !t.hasNext);
1013
1158
  }
1014
1159
  closeMenus(t) {
1015
- for (const e of [this.settingsMenu, this.subtitlesMenu, this.qualityMenu, this.moreMenu])
1160
+ for (const e of [this.gearMenu, this.settingsMenu, this.subtitlesMenu, this.qualityMenu, this.moreMenu])
1016
1161
  e && e !== t && e.close();
1017
1162
  }
1018
1163
  toggleSettingsMenu() {
@@ -1026,15 +1171,13 @@ const _ = class _ {
1026
1171
  }
1027
1172
  destroy() {
1028
1173
  for (const t of this.disposers) t();
1029
- this.disposers = [], this.resizeObserver?.disconnect(), this.onWindowResize && window.removeEventListener("resize", this.onWindowResize), this.settingsMenu?.destroy(), this.subtitlesMenu?.destroy(), this.qualityMenu?.destroy(), this.moreMenu?.destroy(), this.root.remove();
1174
+ this.disposers = [], this.resizeObserver?.disconnect(), this.onWindowResize && window.removeEventListener("resize", this.onWindowResize), this.gearMenu?.destroy(), this.settingsMenu?.destroy(), this.subtitlesMenu?.destroy(), this.qualityMenu?.destroy(), this.moreMenu?.destroy(), this.nextPreviewEl?.remove(), this.root.remove();
1030
1175
  }
1031
- };
1032
- _.CENTER_KEYS = /* @__PURE__ */ new Set(["seekBack", "seekFwd", "prev", "next"]);
1033
- let F = _;
1176
+ }
1034
1177
  class ft {
1035
1178
  constructor(t) {
1036
- this.root = l("div", "imp-poster"), this.image = l("img", "imp-poster__image", { alt: "", decoding: "async" }), this.image.hidden = !0;
1037
- const e = m("imp-poster__play", t.labels.play, t.icons.bigPlay);
1179
+ this.root = a("div", "imp-poster"), this.image = a("img", "imp-poster__image", { alt: "", decoding: "async" }), this.image.hidden = !0;
1180
+ const e = f("imp-poster__play", t.labels.play, t.icons.bigPlay);
1038
1181
  e.addEventListener("click", () => void t.play()), this.root.append(this.image, e), this.root.addEventListener("click", (i) => {
1039
1182
  (i.target === this.root || i.target === this.image) && t.play();
1040
1183
  });
@@ -1049,13 +1192,13 @@ class ft {
1049
1192
  this.root.hidden = !0;
1050
1193
  }
1051
1194
  }
1052
- class vt {
1195
+ class gt {
1053
1196
  constructor(t) {
1054
- this.labels = t, this.channelUrl = null, this.custom = null, 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", () => {
1197
+ this.labels = t, this.channelUrl = null, this.custom = null, this.visible = { title: !0, description: !0, sponsor: !0 }, this.root = a("div", "imp-pause-screen"), this.root.hidden = !0, this.defaultContent = a("div", "imp-pause-screen__default"), this.channel = a("button", "imp-channel", { type: "button" }), this.channel.hidden = !0, this.channelAvatar = a("div", "imp-channel__avatar"), this.channelName = a("div", "imp-channel__name"), this.channel.append(this.channelName, this.channelAvatar), this.channel.addEventListener("click", () => {
1055
1198
  this.channelUrl && window.open(this.channelUrl, "_blank", "noopener");
1056
1199
  });
1057
- const e = l("div", "imp-pause-screen__heading");
1058
- this.title = l("div", "imp-pause-screen__title"), this.description = l("div", "imp-pause-screen__description"), this.sponsor = l("a", "imp-sponsor", { target: "_blank", rel: "nofollow noopener" }), this.sponsor.hidden = !0, this.sponsorLabel = l("span", "imp-sponsor__label"), this.sponsorText = l("span", "imp-sponsor__text"), this.sponsor.append(this.sponsorLabel, this.sponsorText), this.sponsor.addEventListener("click", (i) => i.stopPropagation()), e.append(this.title, this.description, this.sponsor), this.defaultContent.append(e, this.channel), this.root.append(this.defaultContent);
1200
+ const e = a("div", "imp-pause-screen__heading");
1201
+ this.title = a("div", "imp-pause-screen__title"), this.description = a("div", "imp-pause-screen__description"), this.sponsor = a("a", "imp-sponsor", { target: "_blank", rel: "nofollow noopener" }), this.sponsor.hidden = !0, this.sponsorLabel = a("span", "imp-sponsor__label"), this.sponsorText = a("span", "imp-sponsor__text"), this.sponsor.append(this.sponsorLabel, this.sponsorText), this.sponsor.addEventListener("click", (i) => i.stopPropagation()), e.append(this.sponsor, this.title, this.description), this.defaultContent.append(e, this.channel), this.root.append(this.defaultContent);
1059
1202
  }
1060
1203
  setCustomContent(t) {
1061
1204
  this.custom?.remove(), this.custom = t, t && (t.classList.add("imp-pause-screen__custom"), this.root.append(t)), this.defaultContent.hidden = t !== null, this.root.classList.toggle("imp-pause-screen--custom", t !== null);
@@ -1064,9 +1207,17 @@ class vt {
1064
1207
  get hasCustom() {
1065
1208
  return this.custom !== null;
1066
1209
  }
1210
+ /** Hide specific parts of the default overlay (consumer renders them itself). */
1211
+ setVisibility(t) {
1212
+ this.visible = {
1213
+ title: t.title ?? this.visible.title,
1214
+ description: t.description ?? this.visible.description,
1215
+ sponsor: t.sponsor ?? this.visible.sponsor
1216
+ };
1217
+ }
1067
1218
  setSource(t) {
1068
- this.title.textContent = t?.title ?? "", this.description.textContent = t?.description ?? "";
1069
- const e = t?.sponsor;
1219
+ this.title.textContent = t?.title ?? "", this.description.textContent = t?.description ?? "", this.title.hidden = !this.visible.title || !t?.title, this.description.hidden = !this.visible.description || !t?.description;
1220
+ const e = this.visible.sponsor ? t?.sponsor : void 0;
1070
1221
  this.sponsor.hidden = !e, e && (this.sponsor.href = e.url, this.sponsorText.textContent = e.text, this.sponsorLabel.textContent = e.label ?? this.labels.sponsored);
1071
1222
  const i = t?.channel;
1072
1223
  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()));
@@ -1078,10 +1229,10 @@ class vt {
1078
1229
  this.root.hidden = !0;
1079
1230
  }
1080
1231
  }
1081
- class gt {
1232
+ class bt {
1082
1233
  constructor(t) {
1083
- this.player = t, this.clickBehavior = "player", this.root = l("div", "imp-related"), this.root.hidden = !0, this.heading = l("div", "imp-related__title"), this.grid = l("div", "imp-related__grid");
1084
- const e = m("imp-related__close", "Close", t.icons.close);
1234
+ this.player = t, this.clickBehavior = "player", this.root = a("div", "imp-related"), this.root.hidden = !0, this.heading = a("div", "imp-related__title"), this.grid = a("div", "imp-related__grid");
1235
+ const e = f("imp-related__close", "Close", t.icons.close);
1085
1236
  e.addEventListener("click", () => this.hide()), this.root.append(e, this.heading, this.grid);
1086
1237
  }
1087
1238
  setOptions(t) {
@@ -1092,12 +1243,12 @@ class gt {
1092
1243
  }
1093
1244
  }
1094
1245
  buildCard(t) {
1095
- const e = l("button", "imp-related__card", { type: "button" }), i = l("div", "imp-related__thumb");
1246
+ const e = a("button", "imp-related__card", { type: "button" }), i = a("div", "imp-related__thumb");
1096
1247
  if (t.poster && (i.style.backgroundImage = `url("${t.poster}")`), t.duration) {
1097
- const n = l("span", "imp-related__duration");
1248
+ const n = a("span", "imp-related__duration");
1098
1249
  n.textContent = t.duration, i.append(n);
1099
1250
  }
1100
- const s = l("div", "imp-related__card-title");
1251
+ const s = a("div", "imp-related__card-title");
1101
1252
  return s.textContent = t.title, e.append(i, s), e.addEventListener("click", () => {
1102
1253
  this.player.emit("relatedclick", { item: t }), this.hide(), this.activate(t);
1103
1254
  }), e;
@@ -1129,37 +1280,37 @@ class gt {
1129
1280
  }
1130
1281
  class yt {
1131
1282
  constructor(t, e = "sidebar", i) {
1132
- this.player = t, this.root = l("div", `imp-playlist imp-playlist--${e}`), this.root.hidden = !0;
1133
- const s = l("div", "imp-playlist__header"), n = l("div", "imp-playlist__heading");
1283
+ this.player = t, this.root = a("div", `imp-playlist imp-playlist--${e}`), this.root.hidden = !0;
1284
+ const s = a("div", "imp-playlist__header"), n = a("div", "imp-playlist__heading");
1134
1285
  if (i) {
1135
- const c = l("div", "imp-playlist__kicker");
1136
- c.textContent = t.labels.playlist;
1137
- const h = l("div", "imp-playlist__name");
1138
- h.textContent = i, n.append(c, h);
1286
+ const h = a("div", "imp-playlist__kicker");
1287
+ h.textContent = t.labels.playlist;
1288
+ const c = a("div", "imp-playlist__name");
1289
+ c.textContent = i, n.append(h, c);
1139
1290
  } else
1140
1291
  n.textContent = t.labels.playlist;
1141
- const o = l("div", "imp-playlist__tools");
1142
- this.shuffleBtn = m("imp-playlist__shuffle", t.labels.shuffle, t.icons.shuffle), this.shuffleBtn.addEventListener("click", () => {
1292
+ const r = a("div", "imp-playlist__tools");
1293
+ this.shuffleBtn = f("imp-playlist__shuffle", t.labels.shuffle, t.icons.shuffle), this.shuffleBtn.addEventListener("click", () => {
1143
1294
  t.setShuffle(!t.shuffle), this.syncModes();
1144
- }), this.repeatBtn = m("imp-playlist__repeat", t.labels.repeat, t.icons.repeat), this.repeatBtn.addEventListener("click", () => {
1295
+ }), this.repeatBtn = f("imp-playlist__repeat", t.labels.repeat, t.icons.repeat), this.repeatBtn.addEventListener("click", () => {
1145
1296
  t.setRepeat(!t.repeat), this.syncModes();
1146
1297
  });
1147
- const a = m("imp-playlist__close", "Close", t.icons.close);
1148
- a.addEventListener("click", () => this.hide()), o.append(this.shuffleBtn, this.repeatBtn, a), s.append(n, o), this.list = l("div", "imp-playlist__list"), this.root.append(s, this.list), this.rebuild(), this.syncModes();
1298
+ const l = f("imp-playlist__close", "Close", t.icons.close);
1299
+ l.addEventListener("click", () => this.hide()), r.append(this.shuffleBtn, this.repeatBtn, l), s.append(n, r), this.list = a("div", "imp-playlist__list"), this.root.append(s, this.list), this.rebuild(), this.syncModes();
1149
1300
  }
1150
1301
  syncModes() {
1151
1302
  this.shuffleBtn.classList.toggle("imp-btn--active", this.player.shuffle), this.repeatBtn.classList.toggle("imp-btn--active", this.player.repeat);
1152
1303
  }
1153
1304
  rebuild() {
1154
1305
  this.list.textContent = "", this.player.playlist.forEach((t, e) => {
1155
- const i = l("button", "imp-playlist__item", { type: "button" });
1306
+ const i = a("button", "imp-playlist__item", { type: "button" });
1156
1307
  e === this.player.index && i.classList.add("imp-playlist__item--active");
1157
- const s = l("div", "imp-playlist__thumb");
1308
+ const s = a("div", "imp-playlist__thumb");
1158
1309
  t.poster && (s.style.backgroundImage = `url("${t.poster}")`);
1159
- const n = l("div", "imp-playlist__meta"), o = l("div", "imp-playlist__title");
1160
- if (o.textContent = t.title ?? `#${e + 1}`, n.append(o), t.duration) {
1161
- const a = l("div", "imp-playlist__duration");
1162
- a.textContent = w(t.duration), n.append(a);
1310
+ const n = a("div", "imp-playlist__meta"), r = a("div", "imp-playlist__title");
1311
+ if (r.textContent = t.title ?? `#${e + 1}`, n.append(r), t.duration) {
1312
+ const l = a("div", "imp-playlist__duration");
1313
+ l.textContent = x(t.duration), n.append(l);
1163
1314
  }
1164
1315
  i.append(s, n), i.addEventListener("click", () => {
1165
1316
  this.player.playItem(e), window.innerWidth <= 767 && this.hide();
@@ -1179,28 +1330,28 @@ class yt {
1179
1330
  this.visible ? this.hide() : this.show();
1180
1331
  }
1181
1332
  }
1182
- class bt {
1333
+ class kt {
1183
1334
  constructor(t, e = "bottom") {
1184
- this.player = t, this.items = [], this.root = l("div", `imp-playlist imp-scenes imp-playlist--${e}`), this.root.hidden = !0;
1185
- const i = l("div", "imp-playlist__header"), s = l("span");
1335
+ this.player = t, this.items = [], this.root = a("div", `imp-playlist imp-scenes imp-playlist--${e}`), this.root.hidden = !0;
1336
+ const i = a("div", "imp-playlist__header"), s = a("span");
1186
1337
  s.textContent = t.labels.scenes;
1187
- const n = m("imp-playlist__close", "Close", t.icons.close);
1188
- 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());
1338
+ const n = f("imp-playlist__close", "Close", t.icons.close);
1339
+ n.addEventListener("click", () => this.hide()), i.append(s, n), this.list = a("div", "imp-playlist__list"), this.root.append(i, this.list), t.on("chapterchange", () => this.syncActive());
1189
1340
  }
1190
1341
  /** Re-render from the player's current chapters + thumbnail track. */
1191
1342
  rebuild() {
1192
1343
  this.list.textContent = "", this.items = [];
1193
1344
  const t = this.player.thumbnails;
1194
1345
  for (const e of this.player.chapterList) {
1195
- const i = l("button", "imp-playlist__item", { type: "button" }), s = l("div", "imp-playlist__thumb"), n = t?.cueAt(e.start + 0.01) ?? null;
1346
+ const i = a("button", "imp-playlist__item", { type: "button" }), s = a("div", "imp-playlist__thumb"), n = t?.cueAt(e.start + 0.01) ?? null;
1196
1347
  if (n?.xywh) {
1197
- const h = l("div", "imp-scenes__sprite");
1198
- h.style.width = `${n.xywh.w}px`, h.style.height = `${n.xywh.h}px`, h.style.backgroundImage = `url("${n.src}")`, h.style.backgroundPosition = `-${n.xywh.x}px -${n.xywh.y}px`, h.style.setProperty("--imp-sprite-w", String(n.xywh.w)), s.append(h);
1348
+ const c = a("div", "imp-scenes__sprite");
1349
+ 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);
1199
1350
  } else n && (s.style.backgroundImage = `url("${n.src}")`);
1200
- const o = l("div", "imp-playlist__meta"), a = l("div", "imp-playlist__title");
1201
- a.textContent = e.title || w(e.start);
1202
- const c = l("div", "imp-playlist__duration");
1203
- c.textContent = w(e.start), o.append(a, c), i.append(s, o), i.addEventListener("click", () => {
1351
+ const r = a("div", "imp-playlist__meta"), l = a("div", "imp-playlist__title");
1352
+ l.textContent = e.title || x(e.start);
1353
+ const h = a("div", "imp-playlist__duration");
1354
+ h.textContent = x(e.start), r.append(l, h), i.append(s, r), i.addEventListener("click", () => {
1204
1355
  this.player.seek(e.start), this.player.play(), window.innerWidth <= 767 && this.hide();
1205
1356
  }), this.list.append(i), this.items.push(i);
1206
1357
  }
@@ -1225,60 +1376,69 @@ class bt {
1225
1376
  this.visible ? this.hide() : this.show();
1226
1377
  }
1227
1378
  }
1228
- function Q(r) {
1229
- return r ? typeof r == "string" ? [{ src: r, label: "Subtitles" }] : Array.isArray(r) ? r : [r] : [];
1379
+ function W(o) {
1380
+ return o ? typeof o == "string" ? [{ src: o, label: "Subtitles" }] : Array.isArray(o) ? o : [o] : [];
1230
1381
  }
1231
- const kt = {
1382
+ const wt = {
1232
1383
  play: !0,
1233
1384
  progress: !0,
1234
1385
  time: !0,
1235
1386
  volume: !0,
1236
1387
  fullscreen: !0,
1237
1388
  pip: !0,
1238
- settings: !0,
1239
- quality: !1,
1389
+ // Settings-type controls default into the unified ⚙ dropdown.
1390
+ speed: "gear",
1391
+ settings: "gear",
1392
+ // legacy alias for `speed`; resolved in the constructor
1393
+ quality: "gear",
1240
1394
  scenes: !0,
1241
1395
  heatmap: !0,
1242
- subtitles: !0,
1396
+ subtitles: "gear",
1243
1397
  seekButtons: !0,
1398
+ // Prev/seek/play/next as a centered overlay on every viewport.
1399
+ seekPlacement: "overlay",
1244
1400
  playlist: !0,
1401
+ hidePrev: !0,
1402
+ nextPreview: !0,
1245
1403
  hideDelay: 2500
1246
1404
  };
1247
- class _t {
1405
+ class Bt {
1248
1406
  constructor(t, e = {}) {
1249
- this.scrubbing = !1, this.emitter = new Y(), this.abort = new AbortController(), this.sources = [], this.currentIndex = -1, this.sourceController = null, this.loadToken = 0, this.chapters = [], this.currentChapter = null, this.progressiveQuality = -1, this.thumbTrack = null, this.shuffleMode = !1, this.decodeRecoveries = 0, this.adManager = null, this.playedOnce = !1, this.idleTimer = null, this.destroyed = !1;
1407
+ this.scrubbing = !1, this.emitter = new X(), this.abort = new AbortController(), this.sources = [], this.currentIndex = -1, this.sourceController = null, this.loadToken = 0, this.chapters = [], this.currentChapter = null, this.progressiveQuality = -1, this.thumbTrack = null, this.shuffleMode = !1, this.decodeRecoveries = 0, this.adManager = null, this.playedOnce = !1, this.idleTimer = null, this.destroyed = !1;
1250
1408
  const i = typeof t == "string" ? document.querySelector(t) : t;
1251
1409
  if (!i) throw new Error(`[itube-player] mount target not found: ${String(t)}`);
1252
- this.mount = i, this.options = e, this.labels = { ...I, ...tt(e.language), ...e.labels }, this.icons = { ...J, ...e.icons }, this.controlsOptions = { ...kt, ...e.controls }, this.actionsOptions = e.actions ?? {}, this.playbackRates = e.playbackRates ?? [0.5, 0.75, 1, 1.25, 1.5, 2], this.seekStep = e.seekStep ?? 10, this.playlistOptions = { title: "", autoAdvance: !0, loop: !1, shuffle: !1, startIndex: 0, layout: "sidebar", ...e.playlist }, this.shuffleMode = this.playlistOptions.shuffle, this.sources = e.source ? Array.isArray(e.source) ? [...e.source] : [e.source] : [], this.container = l("div", "imp-player", { tabindex: "0" }), e.className && this.container.classList.add(e.className);
1253
- const s = e.styling;
1254
- if (s?.themeColor && this.container.style.setProperty("--imp-accent", s.themeColor), s?.likeColor && this.container.style.setProperty("--imp-like", s.likeColor), s?.dislikeColor && this.container.style.setProperty("--imp-dislike", s.dislikeColor), s?.borderRadius !== void 0) {
1255
- const h = typeof s.borderRadius == "number" ? `${s.borderRadius}px` : s.borderRadius;
1256
- this.container.style.setProperty("--imp-radius", h);
1410
+ this.mount = i, this.options = e, this.labels = { ...V, ...J(e.language), ...e.labels }, this.icons = { ...K, ...e.icons };
1411
+ const s = e.controls ?? {}, n = s.speed ?? s.settings ?? "gear";
1412
+ this.controlsOptions = { ...wt, ...s, speed: n, settings: n }, this.actionsOptions = e.actions ?? {}, this.playbackRates = e.playbackRates ?? [0.5, 0.75, 1, 1.25, 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, this.sources = e.source ? Array.isArray(e.source) ? [...e.source] : [e.source] : [], this.container = a("div", "imp-player", { tabindex: "0" }), e.className && this.container.classList.add(e.className);
1413
+ const r = e.styling;
1414
+ if (r?.themeColor && this.container.style.setProperty("--imp-accent", r.themeColor), r?.likeColor && this.container.style.setProperty("--imp-like", r.likeColor), r?.dislikeColor && this.container.style.setProperty("--imp-dislike", r.dislikeColor), r?.borderRadius !== void 0) {
1415
+ const p = typeof r.borderRadius == "number" ? `${r.borderRadius}px` : r.borderRadius;
1416
+ this.container.style.setProperty("--imp-radius", p);
1257
1417
  }
1258
- s?.playButtonStyle === "inverted" && this.container.classList.add("imp-player--play-inverted"), this.video = l("video", "imp-video"), e.playsInline !== !1 && this.video.setAttribute("playsinline", ""), e.crossOrigin !== void 0 && (this.video.crossOrigin = e.crossOrigin), this.video.preload = "metadata", e.loop && (this.video.loop = !0), e.muted && (this.video.muted = !0), this.video.volume = y(e.volume ?? 1, 0, 1);
1259
- const n = l("div", "imp-layer");
1260
- this.spinner = l("div", "imp-spinner"), this.spinner.hidden = !0, this.errorBox = l("div", "imp-error"), this.errorBox.hidden = !0, this.pauseScreen = new vt(this.labels), this.poster = new ft(this), this.related = new gt(this), this.related.setOptions(e.related), this.controls = new F(this), this.playlistPanel = new yt(this, this.playlistOptions.layout, this.playlistOptions.title || void 0), this.scenesPanel = new bt(this, e.scenes?.layout ?? "bottom");
1261
- const o = l("div", "imp-layer__middle");
1262
- o.append(this.spinner, this.errorBox, this.controls.center);
1263
- const a = l("div", "imp-layer__bottom");
1264
- a.append(this.controls.root), n.append(this.pauseScreen.root, this.related.root, o, a), this.container.append(this.video, n, this.poster.root, this.playlistPanel.root, this.scenesPanel.root), this.mount.append(this.container), e.pauseScreen instanceof HTMLElement ? this.pauseScreen.setCustomContent(e.pauseScreen) : typeof e.pauseScreen == "function" && this.pauseScreen.setCustomContent(e.pauseScreen(this));
1265
- const c = e.adConfig ?? e.ads;
1266
- c && c.adList.length > 0 && (this.adManager = new lt(
1418
+ r?.playButtonStyle === "inverted" && this.container.classList.add("imp-player--play-inverted"), this.video = a("video", "imp-video"), e.playsInline !== !1 && this.video.setAttribute("playsinline", ""), e.crossOrigin !== void 0 && (this.video.crossOrigin = e.crossOrigin), this.video.preload = "metadata", e.loop && (this.video.loop = !0), e.muted && (this.video.muted = !0), this.video.volume = w(e.volume ?? 1, 0, 1);
1419
+ const l = a("div", "imp-layer");
1420
+ this.spinner = a("div", "imp-spinner"), this.spinner.hidden = !0, this.errorBox = a("div", "imp-error"), this.errorBox.hidden = !0, this.pauseScreen = new gt(this.labels), this.poster = new ft(this), this.related = new bt(this), this.related.setOptions(e.related), this.controls = new vt(this), this.playlistPanel = new yt(this, this.playlistOptions.layout, this.playlistOptions.title || void 0), this.scenesPanel = new kt(this, e.scenes?.layout ?? "bottom");
1421
+ const h = a("div", "imp-layer__middle");
1422
+ h.append(this.spinner, this.errorBox, this.controls.center);
1423
+ const c = a("div", "imp-layer__bottom");
1424
+ c.append(this.controls.root), l.append(this.pauseScreen.root, this.related.root, h, c), this.container.append(this.video, l, 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);
1425
+ const u = e.adConfig ?? e.ads;
1426
+ u && u.adList.length > 0 && (this.adManager = new rt(
1267
1427
  { container: this.container, contentVideo: this.video, emitter: this.emitter, labels: this.labels, closeIcon: this.icons.close },
1268
- c
1269
- )), this.emitter.on("error", ({ message: h }) => {
1270
- this.errorBox.textContent = h, this.errorBox.hidden = !1, this.spinner.hidden = !0, this.poster.hide();
1271
- }), this.bindVideoEvents(), this.bindIdleHide(), e.keyboard !== !1 && this.bindKeyboard(), this.video.addEventListener("pointerup", (h) => {
1428
+ u
1429
+ )), this.emitter.on("error", ({ message: p }) => {
1430
+ this.errorBox.textContent = p, this.errorBox.hidden = !1, this.spinner.hidden = !0, this.poster.hide();
1431
+ }), this.bindVideoEvents(), this.bindIdleHide(), e.keyboard !== !1 && this.bindKeyboard(), this.video.addEventListener("pointerup", (p) => {
1272
1432
  if (!(this.adPlaying || !this.playedOnce)) {
1273
- if (h.pointerType === "mouse") {
1433
+ if (p.pointerType === "mouse") {
1274
1434
  this.togglePlay();
1275
1435
  return;
1276
1436
  }
1277
1437
  this.container.classList.contains("imp-player--idle") ? (this.showControlsNow(), this.scheduleIdle()) : this.video.paused || this.container.classList.add("imp-player--idle");
1278
1438
  }
1279
- }, { signal: this.abort.signal }), this.pauseScreen.root.addEventListener("click", (h) => {
1280
- this.pauseScreen.hasCustom || h.target === this.pauseScreen.root && this.togglePlay();
1281
- }, { signal: this.abort.signal }), this.sources.length > 0 && this.loadItem(y(this.playlistOptions.startIndex, 0, this.sources.length - 1), !!e.autoplay), this.emitter.emit("ready", { player: this });
1439
+ }, { signal: this.abort.signal }), this.pauseScreen.root.addEventListener("click", (p) => {
1440
+ this.pauseScreen.hasCustom || p.target === this.pauseScreen.root && this.togglePlay();
1441
+ }, { 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 });
1282
1442
  }
1283
1443
  // === events ===========================================================
1284
1444
  on(t, e) {
@@ -1327,7 +1487,7 @@ class _t {
1327
1487
  this.video.paused || this.video.ended ? this.play() : this.pause();
1328
1488
  }
1329
1489
  seek(t) {
1330
- Number.isFinite(this.video.duration) && (this.video.currentTime = y(t, 0, this.video.duration));
1490
+ Number.isFinite(this.video.duration) && (this.video.currentTime = w(t, 0, this.video.duration));
1331
1491
  }
1332
1492
  /** Relative seek, e.g. `skip(-10)`. */
1333
1493
  skip(t) {
@@ -1341,7 +1501,7 @@ class _t {
1341
1501
  return this.video.muted;
1342
1502
  }
1343
1503
  setVolume(t) {
1344
- this.video.volume = y(t, 0, 1), t > 0 && (this.video.muted = !1);
1504
+ this.video.volume = w(t, 0, 1), t > 0 && (this.video.muted = !1);
1345
1505
  }
1346
1506
  setMuted(t) {
1347
1507
  this.video.muted = t;
@@ -1370,7 +1530,7 @@ class _t {
1370
1530
  setQuality(t) {
1371
1531
  if (this.sourceController?.kind === "hls") {
1372
1532
  this.sourceController.setLevel(t);
1373
- const n = t === -1 ? this.labels.qualityAuto : this.sourceController.levels.find((o) => o.index === t)?.label ?? String(t);
1533
+ const n = t === -1 ? this.labels.qualityAuto : this.sourceController.levels.find((r) => r.index === t)?.label ?? String(t);
1374
1534
  this.emitter.emit("qualitychange", { label: n });
1375
1535
  return;
1376
1536
  }
@@ -1382,7 +1542,7 @@ class _t {
1382
1542
  }
1383
1543
  // === subtitles ========================================================
1384
1544
  get subtitleTracks() {
1385
- return Q(this.source?.subtitles);
1545
+ return W(this.source?.subtitles);
1386
1546
  }
1387
1547
  get activeSubtitle() {
1388
1548
  const t = this.video.textTracks;
@@ -1406,6 +1566,15 @@ class _t {
1406
1566
  get source() {
1407
1567
  return this.sources[this.currentIndex] ?? null;
1408
1568
  }
1569
+ /**
1570
+ * The item that `next()` would play in linear order (for the next-up preview).
1571
+ * `null` in shuffle mode (the pick is random) or when there is no next item.
1572
+ */
1573
+ get nextSource() {
1574
+ if (this.shuffleMode || this.sources.length < 2) return null;
1575
+ const t = this.currentIndex + 1;
1576
+ return t < this.sources.length ? this.sources[t] : this.playlistOptions.loop ? this.sources[0] ?? null : null;
1577
+ }
1409
1578
  get hasPlaylist() {
1410
1579
  return this.sources.length > 1;
1411
1580
  }
@@ -1464,7 +1633,7 @@ class _t {
1464
1633
  * to one item; an array installs a new playlist.
1465
1634
  */
1466
1635
  load(t, e = 0) {
1467
- this.sources = Array.isArray(t) ? [...t] : [t], this.playlistPanel.rebuild(), this.loadItem(y(e, 0, this.sources.length - 1), !1);
1636
+ this.sources = Array.isArray(t) ? [...t] : [t], this.playlistPanel.rebuild(), this.loadItem(w(e, 0, this.sources.length - 1), !1);
1468
1637
  }
1469
1638
  // === fullscreen / pip =================================================
1470
1639
  get isFullscreen() {
@@ -1526,50 +1695,50 @@ class _t {
1526
1695
  const i = ++this.loadToken, s = this.sources[t];
1527
1696
  if (!s) return;
1528
1697
  this.currentIndex = t, this.sourceController?.destroy(), this.sourceController = null, this.chapters = [], this.currentChapter = null, this.progressiveQuality = -1, this.playedOnce = !1;
1529
- for (const c of [...this.video.querySelectorAll("track")]) c.remove();
1698
+ for (const h of [...this.video.querySelectorAll("track")]) h.remove();
1530
1699
  this.adManager?.resetForNewSource(), this.related.hide(), this.pauseScreen.hide(), this.scenesPanel.hide(), this.thumbTrack = null, this.errorBox.hidden = !0, this.decodeRecoveries = 0, this.video.poster = 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();
1531
- for (const c of Q(s.subtitles)) {
1532
- const h = l("track", "", {
1700
+ for (const h of W(s.subtitles)) {
1701
+ const c = a("track", "", {
1533
1702
  kind: "subtitles",
1534
- src: c.src,
1535
- label: c.label,
1536
- ...c.srclang ? { srclang: c.srclang } : {}
1703
+ src: h.src,
1704
+ label: h.label,
1705
+ ...h.srclang ? { srclang: h.srclang } : {}
1537
1706
  });
1538
- c.default && h.setAttribute("default", ""), this.video.append(h);
1707
+ h.default && c.setAttribute("default", ""), this.video.append(c);
1539
1708
  }
1540
- let n = s.src, o = s.type;
1709
+ let n = s.src, r = s.type;
1541
1710
  if (s.qualities && s.qualities.length > 0) {
1542
- const c = Math.max(0, s.qualities.findIndex((h) => h.src === s.src));
1543
- this.progressiveQuality = c, n = s.qualities[c].src, o = s.qualities[c].type ?? o;
1711
+ const h = Math.max(0, s.qualities.findIndex((c) => c.src === s.src));
1712
+ this.progressiveQuality = h, n = s.qualities[h].src, r = s.qualities[h].type ?? r;
1544
1713
  }
1545
1714
  this.video.preload = this.adManager?.hasPendingPreRoll ? "auto" : "metadata";
1546
- const a = await ut(this.video, n, o, {
1715
+ const l = await ct(this.video, n, r, {
1547
1716
  onLevels: () => {
1548
1717
  i === this.loadToken && this.controls.syncFeatureButtons();
1549
1718
  },
1550
- onLevelSwitch: (c) => this.emitter.emit("qualitychange", { label: c }),
1551
- onError: (c, h) => this.emitter.emit("error", { message: c, cause: h })
1719
+ onLevelSwitch: (h) => this.emitter.emit("qualitychange", { label: h }),
1720
+ onError: (h, c) => this.emitter.emit("error", { message: h, cause: c })
1552
1721
  });
1553
1722
  if (i !== this.loadToken) {
1554
- a.destroy();
1723
+ l.destroy();
1555
1724
  return;
1556
1725
  }
1557
- if (this.sourceController = a, this.emitter.emit("sourcechange", { source: s, index: t }), s.thumbnails && q.load(s.thumbnails).then((c) => {
1558
- i === this.loadToken && (this.thumbTrack = c, this.controls.progress.setThumbnails(c), this.scenesPanel.visible && this.scenesPanel.rebuild());
1559
- }).catch((c) => this.emitter.emit("error", { message: "Failed to load thumbnails track", cause: c })), s.chapters) {
1560
- const c = (h) => {
1726
+ if (this.sourceController = l, this.emitter.emit("sourcechange", { source: s, index: t }), s.thumbnails && I.load(s.thumbnails).then((h) => {
1727
+ i === this.loadToken && (this.thumbTrack = h, this.controls.progress.setThumbnails(h), this.scenesPanel.visible && this.scenesPanel.rebuild());
1728
+ }).catch((h) => this.emitter.emit("error", { message: "Failed to load thumbnails track", cause: h })), s.chapters) {
1729
+ const h = (c) => {
1561
1730
  const u = () => {
1562
- i === this.loadToken && (this.chapters = at(h, this.video.duration), this.controls.progress.setChapters(this.chapters), this.controls.syncFeatureButtons(), this.scenesPanel.visible && this.scenesPanel.rebuild());
1731
+ i === this.loadToken && (this.chapters = ot(c, this.video.duration), this.controls.progress.setChapters(this.chapters), this.controls.syncFeatureButtons(), this.scenesPanel.visible && this.scenesPanel.rebuild());
1563
1732
  };
1564
1733
  Number.isFinite(this.video.duration) && this.video.duration > 0 ? u() : this.video.addEventListener("loadedmetadata", u, { once: !0, signal: this.abort.signal });
1565
1734
  };
1566
- typeof s.chapters == "string" ? ht(s.chapters).then((h) => c(h)).catch((h) => this.emitter.emit("error", { message: "Failed to load chapters track", cause: h })) : c(s.chapters);
1735
+ typeof s.chapters == "string" ? lt(s.chapters).then((c) => h(c)).catch((c) => this.emitter.emit("error", { message: "Failed to load chapters track", cause: c })) : h(s.chapters);
1567
1736
  }
1568
1737
  if (s.heatmap && s.heatmap.length > 0 && this.controlsOptions.heatmap) {
1569
- const c = s.heatmap, h = () => {
1570
- i === this.loadToken && this.controls.progress.setHeatmap(et(c, this.video.duration));
1738
+ const h = s.heatmap, c = () => {
1739
+ i === this.loadToken && this.controls.progress.setHeatmap(Y(h, this.video.duration));
1571
1740
  };
1572
- Number.isFinite(this.video.duration) && this.video.duration > 0 ? h() : this.video.addEventListener("loadedmetadata", h, { once: !0, signal: this.abort.signal });
1741
+ Number.isFinite(this.video.duration) && this.video.duration > 0 ? c() : this.video.addEventListener("loadedmetadata", c, { once: !0, signal: this.abort.signal });
1573
1742
  }
1574
1743
  e && this.play().catch(() => {
1575
1744
  i === this.loadToken && this.poster.show();
@@ -1585,7 +1754,7 @@ class _t {
1585
1754
  this.handleEnded();
1586
1755
  }, { signal: t }), e.addEventListener("timeupdate", () => {
1587
1756
  this.emitter.emit("timeupdate", { currentTime: e.currentTime, duration: e.duration || 0 }), this.adManager?.checkMidRolls(e.currentTime);
1588
- const i = K(this.chapters, e.currentTime);
1757
+ const i = U(this.chapters, e.currentTime);
1589
1758
  i !== this.currentChapter && (this.currentChapter = i, this.emitter.emit("chapterchange", { chapter: i }));
1590
1759
  }, { signal: t }), e.addEventListener("progress", () => {
1591
1760
  this.emitter.emit("progress", { buffered: this.bufferedEnd });
@@ -1603,17 +1772,17 @@ class _t {
1603
1772
  if (!i || this.sourceController?.kind === "hls" || e.getAttribute("src") === null && !e.currentSrc) return;
1604
1773
  if ((i.code === MediaError.MEDIA_ERR_DECODE || /DEMUXER|PARSE|DECODE/i.test(i.message || "")) && this.decodeRecoveries < 2 && Number.isFinite(e.duration)) {
1605
1774
  this.decodeRecoveries++;
1606
- const n = e.currentTime, o = !e.paused;
1775
+ const n = e.currentTime, r = !e.paused;
1607
1776
  e.load();
1608
- const a = () => {
1777
+ const l = () => {
1609
1778
  try {
1610
1779
  e.currentTime = n;
1611
1780
  } catch {
1612
1781
  }
1613
- o && e.play().catch(() => {
1782
+ r && e.play().catch(() => {
1614
1783
  });
1615
1784
  };
1616
- e.readyState >= 1 ? a() : e.addEventListener("loadedmetadata", a, { once: !0, signal: this.abort.signal });
1785
+ e.readyState >= 1 ? l() : e.addEventListener("loadedmetadata", l, { once: !0, signal: this.abort.signal });
1617
1786
  return;
1618
1787
  }
1619
1788
  this.emitter.emit("error", { message: i.message || `Media error (code ${i.code})`, cause: i });
@@ -1694,22 +1863,22 @@ class _t {
1694
1863
  }
1695
1864
  }
1696
1865
  export {
1697
- Y as Emitter,
1698
- _t as Player,
1699
- q as ThumbnailTrack,
1700
- et as buildHeatmapValues,
1701
- K as chapterAt,
1702
- J as defaultIcons,
1703
- I as defaultLabels,
1704
- w as formatTime,
1705
- tt as getLocale,
1706
- it as heatmapPath,
1707
- ct as isHlsSource,
1708
- ht as loadChaptersVtt,
1709
- at as normalizeChapters,
1866
+ X as Emitter,
1867
+ Bt as Player,
1868
+ I as ThumbnailTrack,
1869
+ Y as buildHeatmapValues,
1870
+ U as chapterAt,
1871
+ K as defaultIcons,
1872
+ V as defaultLabels,
1873
+ x as formatTime,
1874
+ J as getLocale,
1875
+ tt as heatmapPath,
1876
+ at as isHlsSource,
1877
+ lt as loadChaptersVtt,
1878
+ ot as normalizeChapters,
1710
1879
  Lt as registerLocale,
1711
1880
  St as registerLocales,
1712
- xt as registeredLanguages,
1713
- st as resolveVast
1881
+ _t as registeredLanguages,
1882
+ et as resolveVast
1714
1883
  };
1715
1884
  //# sourceMappingURL=core.js.map