itube-modern-player 0.2.2 → 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/README.md +41 -8
- package/dist/core.cjs +3 -3
- package/dist/core.cjs.map +1 -1
- package/dist/core.js +685 -516
- package/dist/core.js.map +1 -1
- package/dist/itube-modern-player.iife.js +3 -3
- package/dist/itube-modern-player.iife.js.map +1 -1
- package/dist/player.d.ts +5 -0
- package/dist/style.css +1 -1
- package/dist/types.d.ts +72 -10
- package/dist/ui/controls.d.ts +19 -2
- package/dist/ui/menu.d.ts +18 -0
- package/dist/ui/overlays.d.ts +8 -0
- package/package.json +1 -1
package/dist/core.js
CHANGED
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
import { d as
|
|
2
|
-
function
|
|
3
|
-
const i = document.createElement(
|
|
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
|
|
9
|
-
const i =
|
|
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
|
|
13
|
-
|
|
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
|
|
16
|
-
return Math.min(e, Math.max(t,
|
|
15
|
+
function w(o, t, e) {
|
|
16
|
+
return Math.min(e, Math.max(t, o));
|
|
17
17
|
}
|
|
18
|
-
function
|
|
19
|
-
if (!Number.isFinite(
|
|
20
|
-
const t = Math.floor(
|
|
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
|
|
24
|
-
const t =
|
|
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
|
|
30
|
-
const t = [], e =
|
|
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((
|
|
34
|
+
`).filter((p) => p.trim() !== "");
|
|
35
35
|
if (s.length === 0) continue;
|
|
36
|
-
let n = s.findIndex((
|
|
36
|
+
let n = s.findIndex((p) => p.includes("-->"));
|
|
37
37
|
if (n === -1) continue;
|
|
38
|
-
const [
|
|
39
|
-
if (
|
|
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:
|
|
42
|
+
u && t.push({ start: h, end: c, text: u });
|
|
43
43
|
}
|
|
44
44
|
return t;
|
|
45
45
|
}
|
|
46
|
-
function G(
|
|
46
|
+
function G(o, t) {
|
|
47
47
|
try {
|
|
48
|
-
return new URL(
|
|
48
|
+
return new URL(o, new URL(t, window.location.href)).toString();
|
|
49
49
|
} catch {
|
|
50
|
-
return
|
|
50
|
+
return o;
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
-
class
|
|
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
|
|
86
|
-
play:
|
|
87
|
-
pause:
|
|
88
|
-
replay:
|
|
89
|
-
bigPlay:
|
|
90
|
-
volumeHigh:
|
|
91
|
-
volumeLow:
|
|
92
|
-
volumeMute:
|
|
93
|
-
fullscreen:
|
|
94
|
-
fullscreenExit:
|
|
95
|
-
pip:
|
|
96
|
-
settings:
|
|
97
|
-
speed:
|
|
98
|
-
scenes:
|
|
99
|
-
shuffle:
|
|
100
|
-
repeat:
|
|
101
|
-
subtitles:
|
|
102
|
-
list:
|
|
103
|
-
next:
|
|
104
|
-
previous:
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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(
|
|
119
|
-
for (const [t, e] of Object.entries(
|
|
120
|
-
e && (
|
|
120
|
+
function St(o) {
|
|
121
|
+
for (const [t, e] of Object.entries(o))
|
|
122
|
+
e && (P[t] = e);
|
|
121
123
|
}
|
|
122
|
-
function
|
|
123
|
-
return
|
|
124
|
+
function J(o) {
|
|
125
|
+
return o && P[o] || V;
|
|
124
126
|
}
|
|
125
|
-
function
|
|
126
|
-
return Object.keys(
|
|
127
|
+
function _t() {
|
|
128
|
+
return Object.keys(P);
|
|
127
129
|
}
|
|
128
|
-
function
|
|
129
|
-
if (
|
|
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
|
|
133
|
-
if (!Number.isFinite(
|
|
134
|
-
const u = Math.max(0,
|
|
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
|
|
137
|
-
i[
|
|
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],
|
|
141
|
-
(
|
|
142
|
-
),
|
|
143
|
-
if (
|
|
144
|
-
const
|
|
145
|
-
return
|
|
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
|
|
148
|
-
if (
|
|
149
|
-
const i = t / (
|
|
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
|
|
152
|
-
s += ` L ${(
|
|
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
|
|
156
|
-
if (
|
|
157
|
+
async function et(o, t) {
|
|
158
|
+
if (o.src)
|
|
157
159
|
return {
|
|
158
|
-
roll:
|
|
159
|
-
mediaUrl:
|
|
160
|
-
clickThrough:
|
|
160
|
+
roll: o.roll,
|
|
161
|
+
mediaUrl: o.src,
|
|
162
|
+
clickThrough: o.clickUrl,
|
|
161
163
|
impressions: [],
|
|
162
164
|
tracking: {}
|
|
163
165
|
};
|
|
164
|
-
if (!
|
|
165
|
-
return
|
|
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
|
|
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(),
|
|
170
|
-
let
|
|
171
|
+
const n = new AbortController(), r = setTimeout(() => n.abort(), e.requestTimeout);
|
|
172
|
+
let l;
|
|
171
173
|
try {
|
|
172
|
-
const
|
|
173
|
-
if (!
|
|
174
|
-
|
|
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(
|
|
177
|
-
}
|
|
178
|
-
const
|
|
179
|
-
if (
|
|
180
|
-
const
|
|
181
|
-
if (!
|
|
182
|
-
|
|
183
|
-
const u =
|
|
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
|
|
186
|
-
if (!
|
|
187
|
-
return
|
|
188
|
-
}
|
|
189
|
-
const
|
|
190
|
-
if (!
|
|
191
|
-
const
|
|
192
|
-
if (!
|
|
193
|
-
const b =
|
|
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:
|
|
198
|
+
roll: o.roll,
|
|
197
199
|
mediaUrl: b.url,
|
|
198
200
|
mediaType: b.type,
|
|
199
|
-
clickThrough:
|
|
200
|
-
duration:
|
|
201
|
-
skipOffset:
|
|
202
|
-
|
|
203
|
-
|
|
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:
|
|
209
|
+
adTitle: L(p.querySelector(":scope > AdTitle")) ?? void 0
|
|
208
210
|
};
|
|
209
211
|
}
|
|
210
|
-
function
|
|
212
|
+
function it(o, t) {
|
|
211
213
|
var e, i;
|
|
212
|
-
for (const s of
|
|
213
|
-
const n =
|
|
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
|
|
217
|
-
const n = s.getAttribute("event"),
|
|
218
|
-
!n || !
|
|
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
|
|
221
|
-
const n =
|
|
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
|
|
226
|
-
const e = [...
|
|
227
|
-
url:
|
|
228
|
-
type:
|
|
229
|
-
delivery:
|
|
230
|
-
bitrate: Number(
|
|
231
|
-
apiFramework:
|
|
232
|
-
})).filter((
|
|
233
|
-
(
|
|
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((
|
|
237
|
-
const i = e.filter((
|
|
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
|
|
241
|
-
if (!
|
|
242
|
-
const t =
|
|
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
|
|
247
|
-
if (!
|
|
248
|
-
const e =
|
|
249
|
-
return e ? t !== void 0 ? Number(e[1]) / 100 * t : void 0 :
|
|
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
|
|
252
|
-
if (
|
|
253
|
-
for (const t of
|
|
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
|
|
260
|
-
return
|
|
261
|
+
function L(o) {
|
|
262
|
+
return o?.textContent?.trim().replace(/^<!\[CDATA\[|\]\]>$/g, "").trim() || null;
|
|
261
263
|
}
|
|
262
|
-
class
|
|
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 =
|
|
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
|
|
330
|
-
await this.playAd(
|
|
331
|
-
} catch (
|
|
332
|
-
const
|
|
333
|
-
this.host.emitter.emit("aderror", { roll: n, error:
|
|
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 =
|
|
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
|
|
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
|
|
351
|
-
|
|
352
|
-
const
|
|
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 =
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
const
|
|
358
|
-
|
|
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
|
|
361
|
-
const
|
|
362
|
+
let A = Date.now(), F = -1;
|
|
363
|
+
const j = setInterval(() => {
|
|
362
364
|
if (n.paused) {
|
|
363
|
-
|
|
365
|
+
A = Date.now();
|
|
364
366
|
return;
|
|
365
367
|
}
|
|
366
|
-
if (n.currentTime !==
|
|
367
|
-
|
|
368
|
+
if (n.currentTime !== F) {
|
|
369
|
+
F = n.currentTime, A = Date.now();
|
|
368
370
|
return;
|
|
369
371
|
}
|
|
370
|
-
Date.now() -
|
|
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
|
-
}),
|
|
374
|
-
}, 500),
|
|
375
|
-
clearInterval(
|
|
376
|
-
},
|
|
377
|
-
|
|
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
|
-
|
|
381
|
-
}, { once: !0, signal:
|
|
382
|
-
|
|
383
|
-
}, { signal:
|
|
384
|
-
|
|
385
|
-
}, { signal:
|
|
386
|
-
const
|
|
387
|
-
if (Number.isFinite(
|
|
388
|
-
const
|
|
389
|
-
|
|
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:
|
|
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
|
-
}),
|
|
396
|
-
}, { signal:
|
|
397
|
-
const
|
|
398
|
-
t.clickThrough && (
|
|
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",
|
|
401
|
-
let
|
|
402
|
+
n.addEventListener("click", O, { signal: l }), b?.addEventListener("click", O);
|
|
403
|
+
let Z = !1, C = !1;
|
|
402
404
|
n.addEventListener("playing", () => {
|
|
403
|
-
|
|
404
|
-
}, { once: !0, signal:
|
|
405
|
-
n.ended || !s.isConnected || (s.classList.add("imp-ad--paused"),
|
|
406
|
-
}, { signal:
|
|
407
|
-
s.classList.remove("imp-ad--paused"),
|
|
408
|
-
}, { signal:
|
|
409
|
-
(
|
|
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
|
|
425
|
-
const e = [...
|
|
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
|
|
430
|
-
Number.isFinite(t) && (
|
|
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
|
|
435
|
-
const t = await fetch(
|
|
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
|
|
440
|
+
return Q(e).map((i) => ({ start: i.start, end: i.end, title: i.text }));
|
|
439
441
|
}
|
|
440
|
-
function
|
|
441
|
-
for (const e of
|
|
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
|
|
446
|
-
return t ? /application\/(x-mpegurl|vnd\.apple\.mpegurl)/i.test(t) : /\.m3u8(\?|#|$)/i.test(
|
|
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
|
|
451
|
+
async function ht() {
|
|
450
452
|
if (S !== void 0) return S;
|
|
451
|
-
const
|
|
452
|
-
if (
|
|
453
|
-
return 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
|
|
462
|
-
if (
|
|
463
|
-
const s =
|
|
464
|
-
return n && n.isSupported() ?
|
|
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
|
|
468
|
+
return o.src = t, q(o);
|
|
467
469
|
}
|
|
468
|
-
function
|
|
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
|
-
|
|
478
|
+
o.removeAttribute("src"), o.load();
|
|
477
479
|
}
|
|
478
480
|
};
|
|
479
481
|
}
|
|
480
|
-
function
|
|
481
|
-
const s = new
|
|
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(
|
|
486
|
-
n.selected =
|
|
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(
|
|
493
|
-
n.levels = s.levels.map((
|
|
494
|
-
index:
|
|
495
|
-
label:
|
|
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(
|
|
498
|
-
const u = s.levels[
|
|
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
|
|
502
|
-
return s.on(
|
|
503
|
-
if (
|
|
504
|
-
switch (
|
|
505
|
-
case
|
|
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
|
|
509
|
-
|
|
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 (
|
|
513
|
-
i.onError(`HLS fatal error: ${
|
|
514
|
+
if (l)
|
|
515
|
+
i.onError(`HLS fatal error: ${c.details}`, c), s.destroy();
|
|
514
516
|
else {
|
|
515
|
-
|
|
517
|
+
l = !0;
|
|
516
518
|
try {
|
|
517
519
|
s.loadSource(e), s.startLoad();
|
|
518
520
|
} catch {
|
|
519
|
-
i.onError(`HLS fatal error: ${
|
|
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
|
|
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
|
|
534
|
-
const [
|
|
535
|
-
if (!
|
|
536
|
-
const
|
|
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(
|
|
540
|
-
},
|
|
541
|
-
|
|
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,
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
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
|
-
|
|
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
|
-
|
|
591
|
-
|
|
592
|
-
|
|
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 =
|
|
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="${
|
|
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
|
|
628
|
-
|
|
629
|
-
const
|
|
630
|
-
|
|
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 ?
|
|
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", `${
|
|
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,
|
|
645
|
-
s.style.transform = `scaleX(${
|
|
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 ?
|
|
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 ?
|
|
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 =
|
|
668
|
-
const i =
|
|
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(),
|
|
673
|
-
this.tooltip.style.left = `${
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
728
|
+
const n = a("div", "imp-controls__row");
|
|
693
729
|
this.row = n, this.root.append(n);
|
|
694
|
-
const
|
|
695
|
-
this.rightGroup =
|
|
696
|
-
const
|
|
697
|
-
this.chapterLabel =
|
|
698
|
-
const
|
|
699
|
-
if (s.playlist && t.hasPlaylist && (this.prevBtn =
|
|
700
|
-
const d =
|
|
701
|
-
this.muteBtn =
|
|
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),
|
|
745
|
+
}), d.append(this.muteBtn, this.volumeSlider), r.append(d);
|
|
710
746
|
}
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
const
|
|
714
|
-
|
|
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 (
|
|
723
|
-
this.
|
|
724
|
-
const d =
|
|
725
|
-
d.append(this.
|
|
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 (
|
|
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 =
|
|
752
|
-
d.addEventListener("click", () => t.togglePlaylistPanel()),
|
|
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 =
|
|
762
|
-
d.addEventListener("click", () => void t.togglePip()),
|
|
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 =
|
|
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} ${
|
|
847
|
+
section: () => this.simpleSection("seekFwd", `${e.seekForward} ${p}s`, i.seekForward, () => t.skip(p))
|
|
800
848
|
});
|
|
801
849
|
}
|
|
802
|
-
if (this.center =
|
|
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} ${
|
|
808
|
-
d.addEventListener("click", () => t.skip(
|
|
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.
|
|
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 =
|
|
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 =
|
|
825
|
-
const
|
|
826
|
-
t.append(
|
|
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:
|
|
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 =
|
|
836
|
-
const
|
|
837
|
-
t.append(
|
|
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:
|
|
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 =
|
|
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 =
|
|
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
|
|
869
|
-
this.actionItems.push({ value: `custom:${
|
|
870
|
-
const
|
|
871
|
-
this.moreMenu = new
|
|
872
|
-
const
|
|
873
|
-
|
|
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(
|
|
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", "
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
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: (
|
|
890
|
-
const
|
|
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:
|
|
894
|
-
onSelect: (
|
|
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 =
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
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
|
|
955
|
-
|
|
1099
|
+
const h = l.available();
|
|
1100
|
+
l.el.style.display = h ? "" : "none", l.el.classList.remove("imp-collapsed");
|
|
956
1101
|
}
|
|
957
|
-
const
|
|
958
|
-
let
|
|
959
|
-
for (;
|
|
960
|
-
const
|
|
961
|
-
if (!
|
|
962
|
-
|
|
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
|
|
966
|
-
this.moreWrap.style.display =
|
|
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 = `${
|
|
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 &&
|
|
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 &&
|
|
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
|
-
|
|
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 =
|
|
1037
|
-
const e =
|
|
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
|
|
1195
|
+
class gt {
|
|
1053
1196
|
constructor(t) {
|
|
1054
|
-
this.labels = t, this.channelUrl = null, this.custom = null, this.root =
|
|
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 =
|
|
1058
|
-
this.title =
|
|
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
|
|
1232
|
+
class bt {
|
|
1082
1233
|
constructor(t) {
|
|
1083
|
-
this.player = t, this.clickBehavior = "player", this.root =
|
|
1084
|
-
const e =
|
|
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 =
|
|
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 =
|
|
1248
|
+
const n = a("span", "imp-related__duration");
|
|
1098
1249
|
n.textContent = t.duration, i.append(n);
|
|
1099
1250
|
}
|
|
1100
|
-
const s =
|
|
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,40 +1280,40 @@ class gt {
|
|
|
1129
1280
|
}
|
|
1130
1281
|
class yt {
|
|
1131
1282
|
constructor(t, e = "sidebar", i) {
|
|
1132
|
-
this.player = t, this.root =
|
|
1133
|
-
const s =
|
|
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
|
|
1136
|
-
|
|
1137
|
-
const
|
|
1138
|
-
|
|
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
|
|
1142
|
-
this.shuffleBtn =
|
|
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 =
|
|
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
|
|
1148
|
-
|
|
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 =
|
|
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 =
|
|
1308
|
+
const s = a("div", "imp-playlist__thumb");
|
|
1158
1309
|
t.poster && (s.style.backgroundImage = `url("${t.poster}")`);
|
|
1159
|
-
const n =
|
|
1160
|
-
if (
|
|
1161
|
-
const
|
|
1162
|
-
|
|
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
|
-
this.player.playItem(e);
|
|
1316
|
+
this.player.playItem(e), window.innerWidth <= 767 && this.hide();
|
|
1166
1317
|
}), this.list.append(i);
|
|
1167
1318
|
});
|
|
1168
1319
|
}
|
|
@@ -1179,29 +1330,29 @@ class yt {
|
|
|
1179
1330
|
this.visible ? this.hide() : this.show();
|
|
1180
1331
|
}
|
|
1181
1332
|
}
|
|
1182
|
-
class
|
|
1333
|
+
class kt {
|
|
1183
1334
|
constructor(t, e = "bottom") {
|
|
1184
|
-
this.player = t, this.items = [], this.root =
|
|
1185
|
-
const i =
|
|
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 =
|
|
1188
|
-
n.addEventListener("click", () => this.hide()), i.append(s, n), this.list =
|
|
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 =
|
|
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
|
|
1198
|
-
|
|
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
|
|
1201
|
-
|
|
1202
|
-
const
|
|
1203
|
-
|
|
1204
|
-
this.player.seek(e.start), this.player.play();
|
|
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", () => {
|
|
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
|
}
|
|
1207
1358
|
this.syncActive();
|
|
@@ -1225,60 +1376,69 @@ class bt {
|
|
|
1225
1376
|
this.visible ? this.hide() : this.show();
|
|
1226
1377
|
}
|
|
1227
1378
|
}
|
|
1228
|
-
function
|
|
1229
|
-
return
|
|
1379
|
+
function W(o) {
|
|
1380
|
+
return o ? typeof o == "string" ? [{ src: o, label: "Subtitles" }] : Array.isArray(o) ? o : [o] : [];
|
|
1230
1381
|
}
|
|
1231
|
-
const
|
|
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
|
-
|
|
1239
|
-
|
|
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:
|
|
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
|
|
1405
|
+
class Bt {
|
|
1248
1406
|
constructor(t, e = {}) {
|
|
1249
|
-
this.scrubbing = !1, this.emitter = new
|
|
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 = { ...
|
|
1253
|
-
const s = e.
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
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
|
-
|
|
1259
|
-
const
|
|
1260
|
-
this.spinner =
|
|
1261
|
-
const
|
|
1262
|
-
|
|
1263
|
-
const
|
|
1264
|
-
|
|
1265
|
-
const
|
|
1266
|
-
|
|
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
|
-
|
|
1269
|
-
)), this.emitter.on("error", ({ message:
|
|
1270
|
-
this.errorBox.textContent =
|
|
1271
|
-
}), this.bindVideoEvents(), this.bindIdleHide(), e.keyboard !== !1 && this.bindKeyboard(), this.video.addEventListener("pointerup", (
|
|
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 (
|
|
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", (
|
|
1280
|
-
this.pauseScreen.hasCustom ||
|
|
1281
|
-
}, { signal: this.abort.signal }), this.sources.length > 0 && this.loadItem(
|
|
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 =
|
|
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 =
|
|
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((
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
1532
|
-
const
|
|
1700
|
+
for (const h of W(s.subtitles)) {
|
|
1701
|
+
const c = a("track", "", {
|
|
1533
1702
|
kind: "subtitles",
|
|
1534
|
-
src:
|
|
1535
|
-
label:
|
|
1536
|
-
...
|
|
1703
|
+
src: h.src,
|
|
1704
|
+
label: h.label,
|
|
1705
|
+
...h.srclang ? { srclang: h.srclang } : {}
|
|
1537
1706
|
});
|
|
1538
|
-
|
|
1707
|
+
h.default && c.setAttribute("default", ""), this.video.append(c);
|
|
1539
1708
|
}
|
|
1540
|
-
let n = s.src,
|
|
1709
|
+
let n = s.src, r = s.type;
|
|
1541
1710
|
if (s.qualities && s.qualities.length > 0) {
|
|
1542
|
-
const
|
|
1543
|
-
this.progressiveQuality =
|
|
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
|
|
1715
|
+
const l = await ct(this.video, n, r, {
|
|
1547
1716
|
onLevels: () => {
|
|
1548
1717
|
i === this.loadToken && this.controls.syncFeatureButtons();
|
|
1549
1718
|
},
|
|
1550
|
-
onLevelSwitch: (
|
|
1551
|
-
onError: (
|
|
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
|
-
|
|
1723
|
+
l.destroy();
|
|
1555
1724
|
return;
|
|
1556
1725
|
}
|
|
1557
|
-
if (this.sourceController =
|
|
1558
|
-
i === this.loadToken && (this.thumbTrack =
|
|
1559
|
-
}).catch((
|
|
1560
|
-
const
|
|
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 =
|
|
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" ?
|
|
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
|
|
1570
|
-
i === this.loadToken && this.controls.progress.setHeatmap(
|
|
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 ?
|
|
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 =
|
|
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,
|
|
1775
|
+
const n = e.currentTime, r = !e.paused;
|
|
1607
1776
|
e.load();
|
|
1608
|
-
const
|
|
1777
|
+
const l = () => {
|
|
1609
1778
|
try {
|
|
1610
1779
|
e.currentTime = n;
|
|
1611
1780
|
} catch {
|
|
1612
1781
|
}
|
|
1613
|
-
|
|
1782
|
+
r && e.play().catch(() => {
|
|
1614
1783
|
});
|
|
1615
1784
|
};
|
|
1616
|
-
e.readyState >= 1 ?
|
|
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
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
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
|
-
|
|
1713
|
-
|
|
1881
|
+
_t as registeredLanguages,
|
|
1882
|
+
et as resolveVast
|
|
1714
1883
|
};
|
|
1715
1884
|
//# sourceMappingURL=core.js.map
|