itube-modern-player 0.4.1 → 0.4.2
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 +11 -0
- package/dist/core.cjs +3 -3
- package/dist/core.cjs.map +1 -1
- package/dist/core.js +328 -301
- 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 +8 -0
- package/dist/types.d.ts +19 -0
- package/package.json +1 -1
package/dist/core.js
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
import { d as
|
|
2
|
-
function o(
|
|
3
|
-
const i = document.createElement(
|
|
1
|
+
import { d as V } from "./labels-DRuCG6N8.js";
|
|
2
|
+
function o(a, t, e) {
|
|
3
|
+
const i = document.createElement(a);
|
|
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 = o("button", `imp-btn ${
|
|
8
|
+
function g(a, t, e) {
|
|
9
|
+
const i = o("button", `imp-btn ${a}`, { type: "button", "aria-label": t, title: t });
|
|
10
10
|
return i.innerHTML = e, i;
|
|
11
11
|
}
|
|
12
|
-
function E(
|
|
13
|
-
|
|
12
|
+
function E(a, t, e) {
|
|
13
|
+
a.innerHTML = t, e !== void 0 && (a.setAttribute("aria-label", e), a.setAttribute("title", e));
|
|
14
14
|
}
|
|
15
|
-
function w(
|
|
16
|
-
return Math.min(e, Math.max(t,
|
|
15
|
+
function w(a, t, e) {
|
|
16
|
+
return Math.min(e, Math.max(t, a));
|
|
17
17
|
}
|
|
18
|
-
function x(
|
|
19
|
-
if (!Number.isFinite(
|
|
20
|
-
const t = Math.floor(
|
|
18
|
+
function x(a) {
|
|
19
|
+
if (!Number.isFinite(a) || a < 0) return "0:00";
|
|
20
|
+
const t = Math.floor(a % 60), e = Math.floor(a / 60 % 60), i = Math.floor(a / 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 I(
|
|
24
|
-
const t =
|
|
23
|
+
function I(a) {
|
|
24
|
+
const t = a.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 Q(
|
|
30
|
-
const t = [], e =
|
|
29
|
+
function Q(a) {
|
|
30
|
+
const t = [], e = a.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((m) => m.trim() !== "");
|
|
35
35
|
if (s.length === 0) continue;
|
|
36
|
-
let n = s.findIndex((
|
|
36
|
+
let n = s.findIndex((m) => m.includes("-->"));
|
|
37
37
|
if (n === -1) continue;
|
|
38
|
-
const [r,
|
|
38
|
+
const [r, l] = s[n].split("-->"), h = I(r), c = I((l ?? "").split(" ")[1] ?? l ?? "") ?? I(l ?? "");
|
|
39
39
|
if (h === null || c === null) continue;
|
|
40
40
|
const u = s.slice(n + 1).join(`
|
|
41
41
|
`).trim();
|
|
@@ -43,14 +43,14 @@ function Q(l) {
|
|
|
43
43
|
}
|
|
44
44
|
return t;
|
|
45
45
|
}
|
|
46
|
-
function
|
|
46
|
+
function K(a, t) {
|
|
47
47
|
try {
|
|
48
|
-
return new URL(
|
|
48
|
+
return new URL(a, new URL(t, window.location.href)).toString();
|
|
49
49
|
} catch {
|
|
50
|
-
return
|
|
50
|
+
return a;
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
-
class
|
|
53
|
+
class X {
|
|
54
54
|
constructor() {
|
|
55
55
|
this.listeners = /* @__PURE__ */ new Map();
|
|
56
56
|
}
|
|
@@ -82,155 +82,155 @@ class K {
|
|
|
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:
|
|
85
|
+
const f = (a, t = "0 0 24 24") => `<svg viewBox="${t}" fill="currentColor" aria-hidden="true" focusable="false">${a}</svg>`, J = {
|
|
86
|
+
play: f('<path d="M8 5.14v13.72c0 .8.87 1.3 1.56.88l10.54-6.86a1.05 1.05 0 0 0 0-1.76L9.56 4.26C8.87 3.84 8 4.34 8 5.14Z"/>'),
|
|
87
|
+
pause: f('<rect x="6" y="5" width="4" height="14" rx="1"/><rect x="14" y="5" width="4" height="14" rx="1"/>'),
|
|
88
|
+
replay: f('<path d="M12 5V2.5L7.5 6 12 9.5V7a5 5 0 1 1-5 5H5a7 7 0 1 0 7-7Z"/>'),
|
|
89
|
+
bigPlay: f('<path d="M8 5.14v13.72c0 .8.87 1.3 1.56.88l10.54-6.86a1.05 1.05 0 0 0 0-1.76L9.56 4.26C8.87 3.84 8 4.34 8 5.14Z"/>'),
|
|
90
|
+
volumeHigh: f('<path d="M4 9v6h3.5L12 19.5v-15L7.5 9H4Z"/><path d="M14.5 8.6a4.5 4.5 0 0 1 0 6.8v-1.9a2.5 2.5 0 0 0 0-3v-1.9Z"/><path d="M14.5 5.2a8 8 0 0 1 0 13.6v-2a6 6 0 0 0 0-9.6v-2Z"/>'),
|
|
91
|
+
volumeLow: f('<path d="M4 9v6h3.5L12 19.5v-15L7.5 9H4Z"/><path d="M14.5 8.6a4.5 4.5 0 0 1 0 6.8v-1.9a2.5 2.5 0 0 0 0-3v-1.9Z"/>'),
|
|
92
|
+
volumeMute: f('<path d="M4 9v6h3.5L12 19.5v-15L7.5 9H4Z"/><path d="m15.3 9.3 1.4 1.4 1.4-1.4 1.4 1.4-1.4 1.4 1.4 1.4-1.4 1.4-1.4-1.4-1.4 1.4-1.4-1.4 1.4-1.4-1.4-1.4 1.4-1.4Z"/>'),
|
|
93
|
+
fullscreen: f('<path d="M5 5h5v2H7v3H5V5Zm9 0h5v5h-2V7h-3V5ZM5 14h2v3h3v2H5v-5Zm12 0h2v5h-5v-2h3v-3Z"/>'),
|
|
94
|
+
fullscreenExit: f('<path d="M10 10H5V8h3V5h2v5Zm4 0V5h2v3h3v2h-5Zm-4 4v5H8v-3H5v-2h5Zm4 0h5v2h-3v3h-2v-5Z"/>'),
|
|
95
|
+
pip: f('<path d="M3 5h18v14H3V5Zm2 2v10h14V7H5Z"/><rect x="12" y="11" width="6" height="4"/>'),
|
|
96
|
+
settings: f('<path d="M12 8.5A3.5 3.5 0 1 0 12 15.5 3.5 3.5 0 0 0 12 8.5Zm0 2a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3Z"/><path d="M10.3 2.8 9.9 5.1a7 7 0 0 0-1.5.86l-2.2-.8-1.7 3 1.8 1.5a7 7 0 0 0 0 1.7l-1.8 1.5 1.7 3 2.2-.8c.46.36.97.65 1.5.86l.4 2.3h3.4l.4-2.3a7 7 0 0 0 1.5-.86l2.2.8 1.7-3-1.8-1.5a7 7 0 0 0 0-1.7l1.8-1.5-1.7-3-2.2.8a7 7 0 0 0-1.5-.86l-.4-2.3h-3.4Zm1.7 5.7a3.5 3.5 0 1 1 0 7 3.5 3.5 0 0 1 0-7Z"/>'),
|
|
97
|
+
speed: f('<path d="M12 4a9 9 0 0 0-9 9 8.96 8.96 0 0 0 1.62 5.16l1.64-1.15A7 7 0 0 1 5 13a7 7 0 1 1 12.74 4.01l1.64 1.15A8.96 8.96 0 0 0 21 13a9 9 0 0 0-9-9Z"/><path d="m15.6 8.3-3.95 3.13a1.5 1.5 0 1 0 1.92 1.92L16.7 9.4a.78.78 0 0 0-1.1-1.1Z"/>'),
|
|
98
|
+
scenes: f('<path d="M3 5h18v14H3V5Zm2 2v10h3V7H5Zm5 0v10h9V7h-9Zm-5 3h3v1H5v-1Zm0 3h3v1H5v-1Z"/>'),
|
|
99
|
+
shuffle: f('<path d="M4 6h2.6c1.5 0 2.9.7 3.8 1.9l4.1 5.4a2.75 2.75 0 0 0 2.2 1.1H19l-1.8-1.8 1.4-1.4 4.2 4.2-4.2 4.2-1.4-1.4L19 16.4h-2.3a4.75 4.75 0 0 1-3.8-1.9L8.8 9.1A2.75 2.75 0 0 0 6.6 8H4V6Z"/><path d="M19 7.6h-2.3c-.86 0-1.67.41-2.18 1.1l-.93 1.23-1.25-1.65.58-.77A4.75 4.75 0 0 1 16.7 5.6H19L17.2 3.8l1.4-1.4 4.2 4.2-4.2 4.2-1.4-1.4L19 7.6Z" transform="translate(0 1.2)"/>'),
|
|
100
|
+
repeat: f('<path d="M7 7h10v2.5L21 6l-4-3.5V5H5v6h2V7Zm10 10H7v-2.5L3 18l4 3.5V19h12v-6h-2v4Z"/>'),
|
|
101
|
+
subtitles: f('<path d="M3 5h18v14H3V5Zm2 2v10h14V7H5Zm2 3h6v2H7v-2Zm8 0h2v2h-2v-2ZM7 14h2v2H7v-2Zm4 0h6v2h-6v-2Z"/>'),
|
|
102
|
+
list: f('<path d="M4 6h2v2H4V6Zm4 0h12v2H8V6ZM4 11h2v2H4v-2Zm4 0h12v2H8v-2ZM4 16h2v2H4v-2Zm4 0h12v2H8v-2Z"/>'),
|
|
103
|
+
next: f('<path d="M6 5.5v13c0 .77.84 1.25 1.5.85l9-6.5a1 1 0 0 0 0-1.7l-9-6.5c-.66-.4-1.5.08-1.5.85Z"/><rect x="17" y="5" width="2.5" height="14" rx="1"/>'),
|
|
104
|
+
previous: f('<path d="M18 5.5v13c0 .77-.84 1.25-1.5.85l-9-6.5a1 1 0 0 1 0-1.7l9-6.5c.66-.4 1.5.08 1.5.85Z"/><rect x="4.5" y="5" width="2.5" height="14" rx="1"/>'),
|
|
105
105
|
// Thin circular-arrow ("rotate") icons — open center so the step number reads
|
|
106
106
|
// clearly inside the ring (matches the reference skip ±N look).
|
|
107
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
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:
|
|
110
|
-
dislike:
|
|
111
|
-
addTo:
|
|
112
|
-
share:
|
|
113
|
-
report:
|
|
114
|
-
more:
|
|
115
|
-
close:
|
|
109
|
+
like: f('<path d="M9 21H5a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h4v11Zm2 0h7.1a2 2 0 0 0 2-1.6l1.3-7a2 2 0 0 0-2-2.4H14V5.5A2.5 2.5 0 0 0 11.5 3l-.5.1V10h-.9L11 21Z"/>'),
|
|
110
|
+
dislike: f('<path d="M15 3h4a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2h-4V3Zm-2 0H5.9a2 2 0 0 0-2 1.6l-1.3 7a2 2 0 0 0 2 2.4H10v4.5A2.5 2.5 0 0 0 12.5 21l.5-.1V14h.9L13 3Z"/>'),
|
|
111
|
+
addTo: f('<path d="M4 6h12v2H4V6Zm0 4h12v2H4v-2Zm0 4h8v2H4v-2Zm14 0v-4h2v4h4v2h-4v4h-2v-4h-4v-2h4Z"/>'),
|
|
112
|
+
share: f('<path d="M18 8a3 3 0 1 0-2.83-4H15a3 3 0 0 0 .14 1.06L8.4 8.94a3 3 0 1 0 0 6.12l6.74 3.88A3 3 0 1 0 16 16.6l-6.74-3.88a3.03 3.03 0 0 0 0-1.44L16 7.4c.55.38 1.24.6 2 .6Z"/>'),
|
|
113
|
+
report: f('<path d="M5 3h2v18H5V3Zm4 1h10l-2.5 4L19 12H9V4Z"/>'),
|
|
114
|
+
more: f('<circle cx="12" cy="5" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="12" cy="19" r="2"/>'),
|
|
115
|
+
close: f('<path d="m6.4 5 5.6 5.6L17.6 5 19 6.4 13.4 12l5.6 5.6-1.4 1.4-5.6-5.6L6.4 19 5 17.6 10.6 12 5 6.4 6.4 5Z"/>'),
|
|
116
116
|
// Generic "uploaded by a user" glyph (head + shoulders) for preview meta.
|
|
117
|
-
user:
|
|
117
|
+
user: f('<path d="M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm0 2c-3.6 0-8 1.8-8 4.4V21h16v-2.6c0-2.6-4.4-4.4-8-4.4Z"/>'),
|
|
118
118
|
// Generic "channel" glyph (play badge) for preview meta when a channel is set.
|
|
119
|
-
channel:
|
|
120
|
-
}, P = { en:
|
|
121
|
-
function
|
|
122
|
-
P[
|
|
119
|
+
channel: f('<path d="M3 5h18a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1Zm7 3.5v7l6-3.5-6-3.5Z"/>')
|
|
120
|
+
}, P = { en: V };
|
|
121
|
+
function _t(a, t) {
|
|
122
|
+
P[a] = t;
|
|
123
123
|
}
|
|
124
|
-
function Lt(
|
|
125
|
-
for (const [t, e] of Object.entries(
|
|
124
|
+
function Lt(a) {
|
|
125
|
+
for (const [t, e] of Object.entries(a))
|
|
126
126
|
e && (P[t] = e);
|
|
127
127
|
}
|
|
128
|
-
function Y(
|
|
129
|
-
return
|
|
128
|
+
function Y(a) {
|
|
129
|
+
return a && P[a] || V;
|
|
130
130
|
}
|
|
131
131
|
function Bt() {
|
|
132
132
|
return Object.keys(P);
|
|
133
133
|
}
|
|
134
|
-
function tt(
|
|
135
|
-
if (
|
|
134
|
+
function tt(a, t, e = 100) {
|
|
135
|
+
if (a.length === 0 || !Number.isFinite(t) || t <= 0) return [];
|
|
136
136
|
const i = new Array(e).fill(0);
|
|
137
137
|
let s = !1;
|
|
138
|
-
for (const c of
|
|
138
|
+
for (const c of a) {
|
|
139
139
|
if (!Number.isFinite(c.time) || c.time < 0 || c.time > t) continue;
|
|
140
140
|
const u = Math.max(0, c.value);
|
|
141
141
|
if (u === 0) continue;
|
|
142
|
-
const
|
|
143
|
-
i[
|
|
142
|
+
const m = Math.min(e - 1, Math.floor(c.time / t * e));
|
|
143
|
+
i[m] += u, s = !0;
|
|
144
144
|
}
|
|
145
145
|
if (!s) return [];
|
|
146
146
|
const n = [0.06, 0.24, 0.4, 0.24, 0.06], r = i.map(
|
|
147
|
-
(c, u) => n.reduce((p, v
|
|
148
|
-
),
|
|
149
|
-
if (
|
|
147
|
+
(c, u) => n.reduce((m, p, v) => m + p * (i[u + v - 2] ?? 0), 0)
|
|
148
|
+
), l = Math.max(...r);
|
|
149
|
+
if (l <= 0) return [];
|
|
150
150
|
const h = 0.08;
|
|
151
|
-
return r.map((c) => h + (1 - h) * (c /
|
|
151
|
+
return r.map((c) => h + (1 - h) * (c / l));
|
|
152
152
|
}
|
|
153
|
-
function et(
|
|
154
|
-
if (
|
|
155
|
-
const i = t / (
|
|
153
|
+
function et(a, t = 1e3, e = 100) {
|
|
154
|
+
if (a.length === 0) return "";
|
|
155
|
+
const i = t / (a.length - 1 || 1);
|
|
156
156
|
let s = `M 0 ${e}`;
|
|
157
|
-
return
|
|
157
|
+
return a.forEach((n, r) => {
|
|
158
158
|
s += ` L ${(r * i).toFixed(1)} ${(e - n * e).toFixed(1)}`;
|
|
159
159
|
}), s += ` L ${t} ${e} Z`, s;
|
|
160
160
|
}
|
|
161
|
-
async function it(
|
|
162
|
-
if (
|
|
161
|
+
async function it(a, t) {
|
|
162
|
+
if (a.src)
|
|
163
163
|
return {
|
|
164
|
-
roll:
|
|
165
|
-
mediaUrl:
|
|
166
|
-
clickThrough:
|
|
164
|
+
roll: a.roll,
|
|
165
|
+
mediaUrl: a.src,
|
|
166
|
+
clickThrough: a.clickUrl,
|
|
167
167
|
impressions: [],
|
|
168
168
|
tracking: {}
|
|
169
169
|
};
|
|
170
|
-
if (!
|
|
171
|
-
return z(
|
|
170
|
+
if (!a.vastTag) throw new Error('Ad roll has neither "vastTag" nor "src"');
|
|
171
|
+
return z(a, a.vastTag, t, 0, { impressions: [], tracking: {} });
|
|
172
172
|
}
|
|
173
|
-
async function z(
|
|
173
|
+
async function z(a, t, e, i, s) {
|
|
174
174
|
if (i > e.maxWrapperDepth) throw new Error("VAST wrapper depth limit exceeded");
|
|
175
175
|
const n = new AbortController(), r = setTimeout(() => n.abort(), e.requestTimeout);
|
|
176
|
-
let
|
|
176
|
+
let l;
|
|
177
177
|
try {
|
|
178
|
-
const
|
|
179
|
-
if (!
|
|
180
|
-
|
|
178
|
+
const y = await fetch(t, { signal: n.signal, credentials: "omit" });
|
|
179
|
+
if (!y.ok) throw new Error(`VAST request failed (${y.status})`);
|
|
180
|
+
l = await y.text();
|
|
181
181
|
} finally {
|
|
182
182
|
clearTimeout(r);
|
|
183
183
|
}
|
|
184
|
-
const h = new DOMParser().parseFromString(
|
|
184
|
+
const h = new DOMParser().parseFromString(l, "text/xml");
|
|
185
185
|
if (h.querySelector("parsererror")) throw new Error("VAST response is not valid XML");
|
|
186
186
|
const c = h.querySelector("VAST > Ad");
|
|
187
187
|
if (!c) throw new Error("VAST response contains no ads");
|
|
188
188
|
st(c, s);
|
|
189
189
|
const u = c.querySelector(":scope > Wrapper");
|
|
190
190
|
if (u) {
|
|
191
|
-
const
|
|
192
|
-
if (!
|
|
193
|
-
return z(
|
|
194
|
-
}
|
|
195
|
-
const
|
|
196
|
-
if (!
|
|
197
|
-
const
|
|
198
|
-
if (!
|
|
199
|
-
const
|
|
200
|
-
if (!
|
|
191
|
+
const y = S(u.querySelector("VASTAdTagURI"));
|
|
192
|
+
if (!y) throw new Error("VAST wrapper without VASTAdTagURI");
|
|
193
|
+
return z(a, y, e, i + 1, s);
|
|
194
|
+
}
|
|
195
|
+
const m = c.querySelector(":scope > InLine");
|
|
196
|
+
if (!m) throw new Error("VAST ad has neither InLine nor Wrapper");
|
|
197
|
+
const p = m.querySelector("Creatives > Creative > Linear");
|
|
198
|
+
if (!p) throw new Error("VAST ad has no Linear creative");
|
|
199
|
+
const v = nt(p);
|
|
200
|
+
if (!v) throw new Error("VAST ad has no playable MediaFile");
|
|
201
201
|
return {
|
|
202
|
-
roll:
|
|
203
|
-
mediaUrl:
|
|
204
|
-
mediaType:
|
|
205
|
-
clickThrough:
|
|
206
|
-
duration: N(
|
|
202
|
+
roll: a.roll,
|
|
203
|
+
mediaUrl: v.url,
|
|
204
|
+
mediaType: v.type,
|
|
205
|
+
clickThrough: S(p.querySelector("VideoClicks > ClickThrough")) ?? a.clickUrl,
|
|
206
|
+
duration: N(S(p.querySelector(":scope > Duration"))),
|
|
207
207
|
skipOffset: rt(
|
|
208
|
-
|
|
209
|
-
N(
|
|
208
|
+
p.getAttribute("skipoffset"),
|
|
209
|
+
N(S(p.querySelector(":scope > Duration")))
|
|
210
210
|
),
|
|
211
211
|
impressions: s.impressions,
|
|
212
212
|
tracking: s.tracking,
|
|
213
|
-
adTitle:
|
|
213
|
+
adTitle: S(m.querySelector(":scope > AdTitle")) ?? void 0
|
|
214
214
|
};
|
|
215
215
|
}
|
|
216
|
-
function st(
|
|
216
|
+
function st(a, t) {
|
|
217
217
|
var e, i;
|
|
218
|
-
for (const s of
|
|
219
|
-
const n =
|
|
218
|
+
for (const s of a.querySelectorAll("Impression")) {
|
|
219
|
+
const n = S(s);
|
|
220
220
|
n && t.impressions.push(n);
|
|
221
221
|
}
|
|
222
|
-
for (const s of
|
|
223
|
-
const n = s.getAttribute("event"), r =
|
|
222
|
+
for (const s of a.querySelectorAll("Linear > TrackingEvents > Tracking")) {
|
|
223
|
+
const n = s.getAttribute("event"), r = S(s);
|
|
224
224
|
!n || !r || ["start", "firstQuartile", "midpoint", "thirdQuartile", "complete", "skip", "pause", "resume"].includes(n) && ((e = t.tracking)[n] ?? (e[n] = [])).push(r);
|
|
225
225
|
}
|
|
226
|
-
for (const s of
|
|
227
|
-
const n =
|
|
226
|
+
for (const s of a.querySelectorAll("Linear > VideoClicks > ClickTracking")) {
|
|
227
|
+
const n = S(s);
|
|
228
228
|
n && ((i = t.tracking).click ?? (i.click = [])).push(n);
|
|
229
229
|
}
|
|
230
230
|
}
|
|
231
|
-
function nt(
|
|
232
|
-
const e = [...
|
|
233
|
-
url:
|
|
231
|
+
function nt(a) {
|
|
232
|
+
const e = [...a.querySelectorAll("MediaFiles > MediaFile")].map((r) => ({
|
|
233
|
+
url: S(r) ?? "",
|
|
234
234
|
type: r.getAttribute("type") ?? void 0,
|
|
235
235
|
delivery: r.getAttribute("delivery") ?? "",
|
|
236
236
|
bitrate: Number(r.getAttribute("bitrate") ?? 0),
|
|
@@ -239,31 +239,31 @@ function nt(l) {
|
|
|
239
239
|
(r) => !r.type || /(video\/(mp4|webm|ogg)|application\/(x-mpegurl|vnd\.apple\.mpegurl))/i.test(r.type)
|
|
240
240
|
);
|
|
241
241
|
if (e.length === 0) return null;
|
|
242
|
-
e.sort((r,
|
|
242
|
+
e.sort((r, l) => r.bitrate - l.bitrate);
|
|
243
243
|
const i = e.filter((r) => r.delivery !== "streaming"), s = i.length > 0 ? i : e, n = s[Math.floor(s.length / 2)];
|
|
244
244
|
return { url: n.url, type: n.type };
|
|
245
245
|
}
|
|
246
|
-
function N(
|
|
247
|
-
if (!
|
|
248
|
-
const t =
|
|
246
|
+
function N(a) {
|
|
247
|
+
if (!a) return;
|
|
248
|
+
const t = a.trim().match(/^(?:(\d+):)?(\d{1,2}):(\d{2})(?:\.(\d{1,3}))?$/);
|
|
249
249
|
if (t)
|
|
250
250
|
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);
|
|
251
251
|
}
|
|
252
|
-
function rt(
|
|
253
|
-
if (!
|
|
254
|
-
const e =
|
|
255
|
-
return e ? t !== void 0 ? Number(e[1]) / 100 * t : void 0 : N(
|
|
252
|
+
function rt(a, t) {
|
|
253
|
+
if (!a) return;
|
|
254
|
+
const e = a.trim().match(/^(\d+(?:\.\d+)?)%$/);
|
|
255
|
+
return e ? t !== void 0 ? Number(e[1]) / 100 * t : void 0 : N(a);
|
|
256
256
|
}
|
|
257
|
-
function M(
|
|
258
|
-
if (
|
|
259
|
-
for (const t of
|
|
257
|
+
function M(a) {
|
|
258
|
+
if (a)
|
|
259
|
+
for (const t of a)
|
|
260
260
|
try {
|
|
261
261
|
new Image().src = t;
|
|
262
262
|
} catch {
|
|
263
263
|
}
|
|
264
264
|
}
|
|
265
|
-
function
|
|
266
|
-
return
|
|
265
|
+
function S(a) {
|
|
266
|
+
return a?.textContent?.trim().replace(/^<!\[CDATA\[|\]\]>$/g, "").trim() || null;
|
|
267
267
|
}
|
|
268
268
|
class ot {
|
|
269
269
|
constructor(t, e) {
|
|
@@ -335,8 +335,8 @@ class ot {
|
|
|
335
335
|
const r = await it(n, this.opts);
|
|
336
336
|
await this.playAd(r);
|
|
337
337
|
} catch (r) {
|
|
338
|
-
const
|
|
339
|
-
this.host.emitter.emit("aderror", { roll: n, error:
|
|
338
|
+
const l = r instanceof Error ? r : new Error(String(r));
|
|
339
|
+
this.host.emitter.emit("aderror", { roll: n, error: l });
|
|
340
340
|
}
|
|
341
341
|
if (this.destroyed) return;
|
|
342
342
|
}
|
|
@@ -349,17 +349,17 @@ class ot {
|
|
|
349
349
|
}
|
|
350
350
|
playAd(t) {
|
|
351
351
|
return new Promise((e) => {
|
|
352
|
-
const { labels: i } = this.host, s = o("div", "imp-ad"), n = this.ensureAdVideo(), r = new AbortController(),
|
|
352
|
+
const { labels: i } = this.host, s = o("div", "imp-ad"), n = this.ensureAdVideo(), r = new AbortController(), l = r.signal;
|
|
353
353
|
n.src = t.mediaUrl, n.muted = this.host.contentVideo.muted, n.volume = this.host.contentVideo.volume;
|
|
354
354
|
const h = o("div", "imp-spinner imp-ad__spinner"), c = o("div", "imp-ad__hud"), u = o("span", "imp-ad__badge");
|
|
355
355
|
u.textContent = t.adTitle ? `${i.adLabel} · ${t.adTitle}` : i.adLabel;
|
|
356
|
-
const
|
|
357
|
-
c.append(u,
|
|
358
|
-
const
|
|
359
|
-
let
|
|
360
|
-
t.clickThrough && (
|
|
361
|
-
const
|
|
362
|
-
|
|
356
|
+
const m = o("span", "imp-ad__countdown");
|
|
357
|
+
c.append(u, m);
|
|
358
|
+
const p = o("div", "imp-ad__actions");
|
|
359
|
+
let v = null;
|
|
360
|
+
t.clickThrough && (v = o("button", "imp-ad__visit", { type: "button" }), v.textContent = i.visitAdvertiser, p.append(v));
|
|
361
|
+
const y = o("button", "imp-ad__skip", { type: "button" });
|
|
362
|
+
y.hidden = !0, p.append(y), s.append(n, h, c, p), this.host.container.append(s), this.layer = s;
|
|
363
363
|
const T = t.skipOffset ?? this.opts.skipDelay, d = /* @__PURE__ */ new Set(), b = (k) => {
|
|
364
364
|
d.has(k) || (d.add(k), M(t.tracking[k]));
|
|
365
365
|
};
|
|
@@ -384,34 +384,34 @@ class ot {
|
|
|
384
384
|
};
|
|
385
385
|
n.addEventListener("playing", () => {
|
|
386
386
|
M(t.impressions), b("start"), this.host.emitter.emit("adstart", { ad: t });
|
|
387
|
-
}, { once: !0, signal:
|
|
387
|
+
}, { once: !0, signal: l }), n.addEventListener("playing", () => {
|
|
388
388
|
h.hidden = !0;
|
|
389
|
-
}, { signal:
|
|
389
|
+
}, { signal: l }), n.addEventListener("waiting", () => {
|
|
390
390
|
h.hidden = !1;
|
|
391
|
-
}, { signal:
|
|
391
|
+
}, { signal: l }), n.addEventListener("timeupdate", () => {
|
|
392
392
|
const k = n.currentTime, L = n.duration;
|
|
393
|
-
if (Number.isFinite(L) && L > 0 && (
|
|
393
|
+
if (Number.isFinite(L) && L > 0 && (m.textContent = x(Math.max(0, L - k)), k / L >= 0.25 && b("firstQuartile"), k / L >= 0.5 && b("midpoint"), k / L >= 0.75 && b("thirdQuartile")), T >= 0) {
|
|
394
394
|
const D = Math.ceil(T - k);
|
|
395
|
-
D > 0 ? (
|
|
395
|
+
D > 0 ? (y.hidden = !1, y.disabled = !0, y.textContent = `${i.skipAdIn} ${D}`) : (y.hidden = !1, y.disabled = !1, y.textContent = i.skipAd);
|
|
396
396
|
}
|
|
397
|
-
}, { signal:
|
|
397
|
+
}, { signal: l }), n.addEventListener("ended", () => H(!1), { signal: l }), n.addEventListener("error", () => {
|
|
398
398
|
this.host.emitter.emit("aderror", {
|
|
399
399
|
roll: { roll: t.roll },
|
|
400
400
|
error: new Error("Ad media failed to play")
|
|
401
401
|
}), R();
|
|
402
|
-
}, { signal:
|
|
402
|
+
}, { signal: l }), y.addEventListener("click", () => H(!0));
|
|
403
403
|
const O = () => {
|
|
404
404
|
t.clickThrough && (b("click"), this.host.emitter.emit("adclick", { ad: t }), window.open(t.clickThrough, "_blank", "noopener"), n.pause());
|
|
405
405
|
};
|
|
406
|
-
n.addEventListener("click", O, { signal:
|
|
406
|
+
n.addEventListener("click", O, { signal: l }), v?.addEventListener("click", O);
|
|
407
407
|
let Z = !1, C = !1;
|
|
408
408
|
n.addEventListener("playing", () => {
|
|
409
409
|
Z = !0;
|
|
410
|
-
}, { once: !0, signal:
|
|
410
|
+
}, { once: !0, signal: l }), n.addEventListener("pause", () => {
|
|
411
411
|
n.ended || !s.isConnected || (s.classList.add("imp-ad--paused"), Z && !C && (C = !0, M(t.tracking.pause), this.host.emitter.emit("adpause", { ad: t })));
|
|
412
|
-
}, { signal:
|
|
412
|
+
}, { signal: l }), n.addEventListener("play", () => {
|
|
413
413
|
s.classList.remove("imp-ad--paused"), C && (C = !1, M(t.tracking.resume), this.host.emitter.emit("adresume", { ad: t }));
|
|
414
|
-
}, { signal:
|
|
414
|
+
}, { signal: l }), s.addEventListener("click", (k) => {
|
|
415
415
|
(k.target === s || s.classList.contains("imp-ad--paused")) && n.paused && n.play().catch(() => {
|
|
416
416
|
});
|
|
417
417
|
}), n.play().catch(() => {
|
|
@@ -427,8 +427,8 @@ class ot {
|
|
|
427
427
|
this.destroyed = !0, this.adVideo?.pause(), this.layer?.remove(), this.layer = null, this.adVideo = null;
|
|
428
428
|
}
|
|
429
429
|
}
|
|
430
|
-
function W(
|
|
431
|
-
const e = [...
|
|
430
|
+
function W(a, t) {
|
|
431
|
+
const e = [...a].sort((s, n) => s.start - n.start), i = [];
|
|
432
432
|
for (let s = 0; s < e.length; s++) {
|
|
433
433
|
const n = Math.max(0, e[s].start);
|
|
434
434
|
if (Number.isFinite(t) && n >= t) continue;
|
|
@@ -437,41 +437,41 @@ function W(l, t) {
|
|
|
437
437
|
}
|
|
438
438
|
return i;
|
|
439
439
|
}
|
|
440
|
-
async function lt(
|
|
441
|
-
const t = await fetch(
|
|
440
|
+
async function lt(a) {
|
|
441
|
+
const t = await fetch(a);
|
|
442
442
|
if (!t.ok) throw new Error(`Failed to load chapters VTT (${t.status})`);
|
|
443
443
|
const e = await t.text();
|
|
444
444
|
return Q(e).map((i) => ({ start: i.start, end: i.end, title: i.text }));
|
|
445
445
|
}
|
|
446
|
-
function U(
|
|
447
|
-
for (const e of
|
|
446
|
+
function U(a, t) {
|
|
447
|
+
for (const e of a)
|
|
448
448
|
if (t >= e.start && t < e.end) return e;
|
|
449
449
|
return null;
|
|
450
450
|
}
|
|
451
|
-
function at(
|
|
452
|
-
return t ? /application\/(x-mpegurl|vnd\.apple\.mpegurl)/i.test(t) : /\.m3u8(\?|#|$)/i.test(
|
|
451
|
+
function at(a, t) {
|
|
452
|
+
return t ? /application\/(x-mpegurl|vnd\.apple\.mpegurl)/i.test(t) : /\.m3u8(\?|#|$)/i.test(a);
|
|
453
453
|
}
|
|
454
|
-
let
|
|
454
|
+
let _;
|
|
455
455
|
async function ht() {
|
|
456
|
-
if (
|
|
457
|
-
const
|
|
458
|
-
if (
|
|
459
|
-
return
|
|
456
|
+
if (_ !== void 0) return _;
|
|
457
|
+
const a = globalThis.Hls;
|
|
458
|
+
if (a)
|
|
459
|
+
return _ = a, _;
|
|
460
460
|
try {
|
|
461
|
-
|
|
461
|
+
_ = (await import("hls.js/light")).default;
|
|
462
462
|
} catch {
|
|
463
|
-
|
|
463
|
+
_ = null;
|
|
464
464
|
}
|
|
465
|
-
return
|
|
465
|
+
return _;
|
|
466
466
|
}
|
|
467
|
-
async function ct(
|
|
467
|
+
async function ct(a, t, e, i) {
|
|
468
468
|
if (at(t, e)) {
|
|
469
|
-
const s =
|
|
470
|
-
return n && n.isSupported() ? dt(n,
|
|
469
|
+
const s = a.canPlayType("application/vnd.apple.mpegurl"), n = s ? null : await ht();
|
|
470
|
+
return n && n.isSupported() ? dt(n, a, t, i) : s ? (a.src = t, $(a)) : (i.onError("HLS is not supported in this browser and hls.js could not be loaded."), $(a));
|
|
471
471
|
}
|
|
472
|
-
return
|
|
472
|
+
return a.src = t, $(a);
|
|
473
473
|
}
|
|
474
|
-
function $(
|
|
474
|
+
function $(a) {
|
|
475
475
|
return {
|
|
476
476
|
kind: "native",
|
|
477
477
|
levels: [],
|
|
@@ -479,12 +479,12 @@ function $(l) {
|
|
|
479
479
|
setLevel() {
|
|
480
480
|
},
|
|
481
481
|
destroy() {
|
|
482
|
-
|
|
482
|
+
a.removeAttribute("src"), a.load();
|
|
483
483
|
}
|
|
484
484
|
};
|
|
485
485
|
}
|
|
486
|
-
function dt(
|
|
487
|
-
const s = new
|
|
486
|
+
function dt(a, t, e, i) {
|
|
487
|
+
const s = new a({ enableWorker: !0 }), n = {
|
|
488
488
|
kind: "hls",
|
|
489
489
|
levels: [],
|
|
490
490
|
selected: -1,
|
|
@@ -495,30 +495,30 @@ function dt(l, t, e, i) {
|
|
|
495
495
|
s.destroy(), t.removeAttribute("src"), t.load();
|
|
496
496
|
}
|
|
497
497
|
};
|
|
498
|
-
s.on(
|
|
498
|
+
s.on(a.Events.MANIFEST_PARSED, () => {
|
|
499
499
|
n.levels = s.levels.map((h, c) => ({
|
|
500
500
|
index: c,
|
|
501
501
|
label: h.height ? `${h.height}p` : `${Math.round(h.bitrate / 1e3)} kbps`
|
|
502
502
|
})).reverse(), i.onLevels(n.levels);
|
|
503
|
-
}), s.on(
|
|
503
|
+
}), s.on(a.Events.LEVEL_SWITCHED, (h, c) => {
|
|
504
504
|
const u = s.levels[c.level];
|
|
505
505
|
u && i.onLevelSwitch(u.height ? `${u.height}p` : `${Math.round(u.bitrate / 1e3)} kbps`);
|
|
506
506
|
});
|
|
507
|
-
let r = 0,
|
|
508
|
-
return s.on(
|
|
507
|
+
let r = 0, l = !1;
|
|
508
|
+
return s.on(a.Events.ERROR, (h, c) => {
|
|
509
509
|
if (c.fatal)
|
|
510
510
|
switch (c.type) {
|
|
511
|
-
case
|
|
511
|
+
case a.ErrorTypes.NETWORK_ERROR:
|
|
512
512
|
s.startLoad();
|
|
513
513
|
break;
|
|
514
|
-
case
|
|
514
|
+
case a.ErrorTypes.MEDIA_ERROR:
|
|
515
515
|
r < 3 ? (r++, s.recoverMediaError()) : (i.onError(`HLS media error: ${c.details}`, c), s.destroy());
|
|
516
516
|
break;
|
|
517
517
|
default:
|
|
518
|
-
if (
|
|
518
|
+
if (l)
|
|
519
519
|
i.onError(`HLS fatal error: ${c.details}`, c), s.destroy();
|
|
520
520
|
else {
|
|
521
|
-
|
|
521
|
+
l = !0;
|
|
522
522
|
try {
|
|
523
523
|
s.loadSource(e), s.startLoad();
|
|
524
524
|
} catch {
|
|
@@ -528,7 +528,7 @@ function dt(l, t, e, i) {
|
|
|
528
528
|
}
|
|
529
529
|
}), s.loadSource(e), s.attachMedia(t), n;
|
|
530
530
|
}
|
|
531
|
-
class
|
|
531
|
+
class q {
|
|
532
532
|
constructor(t) {
|
|
533
533
|
this.cues = t;
|
|
534
534
|
}
|
|
@@ -537,16 +537,16 @@ class V {
|
|
|
537
537
|
if (!e.ok) throw new Error(`Failed to load thumbnails VTT (${e.status})`);
|
|
538
538
|
const i = await e.text(), s = [];
|
|
539
539
|
for (const n of Q(i)) {
|
|
540
|
-
const [r,
|
|
540
|
+
const [r, l] = n.text.trim().split("#");
|
|
541
541
|
if (!r) continue;
|
|
542
542
|
const h = {
|
|
543
543
|
start: n.start,
|
|
544
544
|
end: n.end,
|
|
545
|
-
src:
|
|
546
|
-
}, c =
|
|
545
|
+
src: K(r, t)
|
|
546
|
+
}, c = l?.match(/xywh=(\d+),(\d+),(\d+),(\d+)/);
|
|
547
547
|
c && (h.xywh = { x: Number(c[1]), y: Number(c[2]), w: Number(c[3]), h: Number(c[4]) }), s.push(h);
|
|
548
548
|
}
|
|
549
|
-
return s.sort((n, r) => n.start - r.start), new
|
|
549
|
+
return s.sort((n, r) => n.start - r.start), new q(s);
|
|
550
550
|
}
|
|
551
551
|
cueAt(t) {
|
|
552
552
|
let e = 0, i = this.cues.length - 1;
|
|
@@ -597,8 +597,8 @@ class B {
|
|
|
597
597
|
n.textContent = i.label;
|
|
598
598
|
const r = o("span", "imp-menu__value");
|
|
599
599
|
r.textContent = i.value ?? "";
|
|
600
|
-
const
|
|
601
|
-
|
|
600
|
+
const l = o("span", "imp-menu__chevron");
|
|
601
|
+
l.innerHTML = ut, s.append(n, r, l), s.addEventListener("click", () => this.renderSettingsDetail(t, i)), e.append(s);
|
|
602
602
|
}
|
|
603
603
|
this.root.append(e);
|
|
604
604
|
}
|
|
@@ -685,8 +685,8 @@ class mt {
|
|
|
685
685
|
for (const n of i) {
|
|
686
686
|
const r = o("div", "imp-progress__segment");
|
|
687
687
|
r.style.flexGrow = String(Math.max(n.end - n.start, 0.01));
|
|
688
|
-
const
|
|
689
|
-
r.append(
|
|
688
|
+
const l = o("div", "imp-progress__fill");
|
|
689
|
+
r.append(l), this.track.append(r), this.segments.push({ chapter: n, root: r, fill: l });
|
|
690
690
|
}
|
|
691
691
|
}
|
|
692
692
|
setThumbnails(t) {
|
|
@@ -728,8 +728,8 @@ class mt {
|
|
|
728
728
|
this.tooltipChapter.textContent = i?.title ?? "", this.tooltipChapter.hidden = !i?.title;
|
|
729
729
|
const s = this.thumbnails?.cueAt(e) ?? null;
|
|
730
730
|
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");
|
|
731
|
-
const n = this.root.getBoundingClientRect(), r = w(t.clientX - n.left, 0, n.width),
|
|
732
|
-
this.tooltip.style.left = `${w(r,
|
|
731
|
+
const n = this.root.getBoundingClientRect(), r = w(t.clientX - n.left, 0, n.width), l = this.tooltip.offsetWidth / 2;
|
|
732
|
+
this.tooltip.style.left = `${w(r, l, Math.max(l, n.width - l))}px`;
|
|
733
733
|
}
|
|
734
734
|
hideTooltip() {
|
|
735
735
|
this.tooltip.classList.remove("imp-progress__tooltip--visible");
|
|
@@ -750,14 +750,14 @@ class vt {
|
|
|
750
750
|
}), s.progress && this.root.append(this.progress.root);
|
|
751
751
|
const n = o("div", "imp-controls__row");
|
|
752
752
|
this.row = n, this.root.append(n);
|
|
753
|
-
const r = o("div", "imp-controls__group"),
|
|
754
|
-
this.rightGroup =
|
|
753
|
+
const r = o("div", "imp-controls__group"), l = o("div", "imp-controls__group");
|
|
754
|
+
this.rightGroup = l;
|
|
755
755
|
const h = o("div", "imp-controls__spacer");
|
|
756
|
-
this.chapterLabel = o("div", "imp-controls__chapter"), n.append(r, h,
|
|
757
|
-
const c = typeof s.seekButtons == "object" ? s.seekButtons : {}, u = c.back ?? t.seekStep,
|
|
758
|
-
if (this.seekLabelFn = c.label, s.playlist && t.hasPlaylist && !s.hidePrev && (this.prevBtn =
|
|
756
|
+
this.chapterLabel = o("div", "imp-controls__chapter"), n.append(r, h, l), h.append(this.chapterLabel);
|
|
757
|
+
const c = typeof s.seekButtons == "object" ? s.seekButtons : {}, u = c.back ?? t.seekStep, m = c.forward ?? t.seekStep;
|
|
758
|
+
if (this.seekLabelFn = c.label, s.playlist && t.hasPlaylist && !s.hidePrev && (this.prevBtn = g("imp-btn--prev", e.previous, i.previous), this.prevBtn.addEventListener("click", () => t.previous()), r.append(this.prevBtn)), s.seekButtons && (this.seekBackBtn = g("imp-btn--seek-back", `${e.seekBack} ${u}s`, i.seekBack), this.addStepBadge(this.seekBackBtn, u, "back"), this.seekBackBtn.addEventListener("click", () => t.skip(-u)), r.append(this.seekBackBtn)), s.play && (this.playBtn = g("imp-btn--play", e.play, i.play), this.playBtn.addEventListener("click", () => t.togglePlay()), r.append(this.playBtn)), s.seekButtons && (this.seekFwdBtn = g("imp-btn--seek-forward", `${e.seekForward} ${m}s`, i.seekForward), this.addStepBadge(this.seekFwdBtn, m, "forward"), this.seekFwdBtn.addEventListener("click", () => t.skip(m)), r.append(this.seekFwdBtn)), s.playlist && t.hasPlaylist && (this.nextBtn = g("imp-btn--next", e.next, i.next), this.nextBtn.addEventListener("click", () => t.next()), r.append(this.nextBtn)), s.volume) {
|
|
759
759
|
const d = o("div", "imp-volume");
|
|
760
|
-
this.muteBtn =
|
|
760
|
+
this.muteBtn = g("imp-btn--mute", e.mute, i.volumeHigh), this.muteBtn.addEventListener("click", () => t.toggleMute()), this.volumeSlider = o("input", "imp-volume__slider", {
|
|
761
761
|
type: "range",
|
|
762
762
|
min: "0",
|
|
763
763
|
max: "1",
|
|
@@ -769,7 +769,7 @@ class vt {
|
|
|
769
769
|
}
|
|
770
770
|
s.time && (this.timeLabel = o("div", "imp-controls__time"), this.liveBadge = o("span", "imp-controls__live"), this.liveBadge.textContent = e.live, this.liveBadge.hidden = !0, r.append(this.timeLabel, this.liveBadge)), this.buildLikeDislike();
|
|
771
771
|
for (const d of (t.actionsOptions.custom ?? []).filter((b) => b.placement === "bar")) {
|
|
772
|
-
const b =
|
|
772
|
+
const b = g(`imp-btn--custom imp-btn--custom-${d.id}`, d.title, d.icon ?? i.more);
|
|
773
773
|
b.addEventListener("click", () => t.emit("customaction", { id: d.id })), this.rightItems.set(`custom:${d.id}`, b), this.registerCollapsible({
|
|
774
774
|
key: `custom:${d.id}`,
|
|
775
775
|
el: b,
|
|
@@ -778,9 +778,9 @@ class vt {
|
|
|
778
778
|
section: () => this.simpleSection(`custom:${d.id}`, d.title, d.icon ?? i.more, () => t.emit("customaction", { id: d.id }))
|
|
779
779
|
});
|
|
780
780
|
}
|
|
781
|
-
const
|
|
782
|
-
if (this.gear = { speed: T === "gear", quality:
|
|
783
|
-
this.subtitlesBtn =
|
|
781
|
+
const p = (d) => d === !1 ? "off" : d === "bar" ? "bar" : "gear", v = p(s.subtitles), y = p(s.quality), T = p(s.speed);
|
|
782
|
+
if (this.gear = { speed: T === "gear", quality: y === "gear", subtitles: v === "gear" }, v === "bar") {
|
|
783
|
+
this.subtitlesBtn = g("imp-btn--subtitles", e.subtitles, i.subtitles), this.subtitlesMenu = new B(this.subtitlesBtn);
|
|
784
784
|
const d = o("div", "imp-controls__menu-anchor");
|
|
785
785
|
d.append(this.subtitlesBtn, this.subtitlesMenu.root), this.subtitlesBtn.addEventListener("click", () => this.toggleSubtitlesMenu()), this.rightItems.set("subtitles", d), this.registerCollapsible({
|
|
786
786
|
key: "subtitles",
|
|
@@ -790,8 +790,8 @@ class vt {
|
|
|
790
790
|
section: () => this.subtitlesSection()
|
|
791
791
|
});
|
|
792
792
|
}
|
|
793
|
-
if (
|
|
794
|
-
this.qualityBtn =
|
|
793
|
+
if (y === "bar") {
|
|
794
|
+
this.qualityBtn = g("imp-btn--quality", e.quality, i.settings), this.qualityMenu = new B(this.qualityBtn);
|
|
795
795
|
const d = o("div", "imp-controls__menu-anchor");
|
|
796
796
|
d.append(this.qualityBtn, this.qualityMenu.root), this.qualityBtn.addEventListener("click", () => this.toggleQualityMenu()), this.rightItems.set("quality", d), this.registerCollapsible({
|
|
797
797
|
key: "quality",
|
|
@@ -802,7 +802,7 @@ class vt {
|
|
|
802
802
|
});
|
|
803
803
|
}
|
|
804
804
|
if (T === "bar") {
|
|
805
|
-
this.settingsBtn =
|
|
805
|
+
this.settingsBtn = g("imp-btn--speed", e.speed, i.speed), this.settingsMenu = new B(this.settingsBtn);
|
|
806
806
|
const d = o("div", "imp-controls__menu-anchor");
|
|
807
807
|
d.append(this.settingsBtn, this.settingsMenu.root), this.settingsBtn.addEventListener("click", () => this.toggleSettingsMenu()), this.rightItems.set("speed", d), this.registerCollapsible({
|
|
808
808
|
key: "speed",
|
|
@@ -812,7 +812,7 @@ class vt {
|
|
|
812
812
|
section: () => this.speedSection()
|
|
813
813
|
});
|
|
814
814
|
}
|
|
815
|
-
if (s.scenes && (this.scenesBtn =
|
|
815
|
+
if (s.scenes && (this.scenesBtn = g("imp-btn--scenes", e.scenes, i.scenes), this.scenesBtn.addEventListener("click", () => t.toggleScenesPanel()), this.rightItems.set("scenes", this.scenesBtn), this.registerCollapsible({
|
|
816
816
|
key: "scenes",
|
|
817
817
|
el: this.scenesBtn,
|
|
818
818
|
priority: 25,
|
|
@@ -830,7 +830,7 @@ class vt {
|
|
|
830
830
|
});
|
|
831
831
|
}
|
|
832
832
|
if (s.playlist && t.hasPlaylist) {
|
|
833
|
-
const d =
|
|
833
|
+
const d = g("imp-btn--list", e.playlist, i.list);
|
|
834
834
|
d.addEventListener("click", () => t.togglePlaylistPanel()), this.rightItems.set("playlist", d), this.registerCollapsible({
|
|
835
835
|
key: "list",
|
|
836
836
|
el: d,
|
|
@@ -840,7 +840,7 @@ class vt {
|
|
|
840
840
|
});
|
|
841
841
|
}
|
|
842
842
|
if (s.pip && "requestPictureInPicture" in HTMLVideoElement.prototype) {
|
|
843
|
-
const d =
|
|
843
|
+
const d = g("imp-btn--pip", e.pip, i.pip);
|
|
844
844
|
d.addEventListener("click", () => void t.togglePip()), this.rightItems.set("pip", d), this.registerCollapsible({
|
|
845
845
|
key: "pip",
|
|
846
846
|
el: d,
|
|
@@ -849,7 +849,7 @@ class vt {
|
|
|
849
849
|
section: () => this.simpleSection("pip", e.pip, i.pip, () => void t.togglePip())
|
|
850
850
|
});
|
|
851
851
|
}
|
|
852
|
-
if (s.fullscreen && (this.fullscreenBtn =
|
|
852
|
+
if (s.fullscreen && (this.fullscreenBtn = g("imp-btn--fullscreen", e.fullscreen, i.fullscreen), this.fullscreenBtn.addEventListener("click", () => void t.toggleFullscreen()), this.rightItems.set("fullscreen", this.fullscreenBtn)), this.prevBtn && this.registerCollapsible({
|
|
853
853
|
key: "prev",
|
|
854
854
|
el: this.prevBtn,
|
|
855
855
|
priority: 70,
|
|
@@ -878,7 +878,7 @@ class vt {
|
|
|
878
878
|
el: d,
|
|
879
879
|
priority: 82,
|
|
880
880
|
available: () => Number.isFinite(t.duration) && t.duration > 0,
|
|
881
|
-
section: () => this.simpleSection("seekFwd", `${e.seekForward} ${
|
|
881
|
+
section: () => this.simpleSection("seekFwd", `${e.seekForward} ${m}s`, i.seekForward, () => t.skip(m))
|
|
882
882
|
});
|
|
883
883
|
}
|
|
884
884
|
if (this.center = o("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) {
|
|
@@ -886,11 +886,11 @@ class vt {
|
|
|
886
886
|
this.addStepBadge(d, u, "back"), d.addEventListener("click", () => t.skip(-u)), this.center.append(d);
|
|
887
887
|
}
|
|
888
888
|
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) {
|
|
889
|
-
const d = this.makeCenterButton("seek-forward", `${e.seekForward} ${
|
|
890
|
-
this.addStepBadge(d,
|
|
889
|
+
const d = this.makeCenterButton("seek-forward", `${e.seekForward} ${m}s`, i.seekForward);
|
|
890
|
+
this.addStepBadge(d, m, "forward"), d.addEventListener("click", () => t.skip(m)), this.center.append(d);
|
|
891
891
|
}
|
|
892
892
|
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) {
|
|
893
|
-
this.gearBtn =
|
|
893
|
+
this.gearBtn = g("imp-btn--settings", e.settings, i.settings), this.gearMenu = new B(this.gearBtn);
|
|
894
894
|
const d = o("div", "imp-controls__menu-anchor");
|
|
895
895
|
d.append(this.gearBtn, this.gearMenu.root), this.gearBtn.addEventListener("click", () => this.toggleGearMenu()), this.rightItems.set("gear", d), this.registerCollapsible({
|
|
896
896
|
key: "gear",
|
|
@@ -900,7 +900,7 @@ class vt {
|
|
|
900
900
|
section: () => this.gearSections()
|
|
901
901
|
});
|
|
902
902
|
}
|
|
903
|
-
this.layoutRightCluster(
|
|
903
|
+
this.layoutRightCluster(l), 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);
|
|
904
904
|
}
|
|
905
905
|
registerCollapsible(t) {
|
|
906
906
|
this.collapsibles.push(t);
|
|
@@ -1024,24 +1024,24 @@ class vt {
|
|
|
1024
1024
|
e.textContent = "";
|
|
1025
1025
|
const n = o("div", "imp-next-preview__kicker");
|
|
1026
1026
|
if (n.textContent = this.player.labels.next, e.append(n), i.thumbnail && s.poster) {
|
|
1027
|
-
const
|
|
1028
|
-
if (
|
|
1029
|
-
const
|
|
1030
|
-
|
|
1027
|
+
const p = o("div", "imp-next-preview__thumb");
|
|
1028
|
+
if (p.style.backgroundImage = `url("${s.poster}")`, i.duration && s.duration) {
|
|
1029
|
+
const v = o("span", "imp-next-preview__duration");
|
|
1030
|
+
v.textContent = x(s.duration), p.append(v);
|
|
1031
1031
|
}
|
|
1032
|
-
e.append(
|
|
1032
|
+
e.append(p);
|
|
1033
1033
|
}
|
|
1034
1034
|
if (i.title && s.title) {
|
|
1035
|
-
const
|
|
1036
|
-
|
|
1035
|
+
const p = o("div", "imp-next-preview__title");
|
|
1036
|
+
p.textContent = s.title, e.append(p);
|
|
1037
1037
|
}
|
|
1038
1038
|
if (i.meta && s.previewMeta?.length) {
|
|
1039
|
-
const
|
|
1040
|
-
|
|
1039
|
+
const p = o("div", "imp-next-preview__meta");
|
|
1040
|
+
p.textContent = s.previewMeta.join(" · "), e.append(p);
|
|
1041
1041
|
}
|
|
1042
1042
|
e.hidden = !1;
|
|
1043
|
-
const r = this.player.container.getBoundingClientRect(),
|
|
1044
|
-
e.style.left = `${
|
|
1043
|
+
const r = this.player.container.getBoundingClientRect(), l = t.getBoundingClientRect(), h = 8, c = e.offsetWidth, u = l.left - r.left + l.width / 2 - c / 2, m = Math.max(h, Math.min(u, r.width - c - h));
|
|
1044
|
+
e.style.left = `${m}px`, e.style.bottom = `${r.height - (l.top - r.top) + 10}px`;
|
|
1045
1045
|
}
|
|
1046
1046
|
hideNextPreview() {
|
|
1047
1047
|
this.nextPreviewEl && (this.nextPreviewEl.hidden = !0);
|
|
@@ -1050,7 +1050,7 @@ class vt {
|
|
|
1050
1050
|
buildLikeDislike() {
|
|
1051
1051
|
const t = this.player, e = t.actionsOptions, { labels: i, icons: s } = t;
|
|
1052
1052
|
if (e.like) {
|
|
1053
|
-
this.likeBtn =
|
|
1053
|
+
this.likeBtn = g("imp-btn--like", i.like, s.like), this.likeBtn.addEventListener("click", () => t.emit("action", { id: "like" })), this.likeCountEl = this.attachCountTooltip(this.likeBtn, e.likeCount);
|
|
1054
1054
|
const n = this.wrapWithTooltip(this.likeBtn, this.likeCountEl);
|
|
1055
1055
|
this.rightItems.set("like", n), this.registerCollapsible({
|
|
1056
1056
|
key: "like",
|
|
@@ -1061,7 +1061,7 @@ class vt {
|
|
|
1061
1061
|
});
|
|
1062
1062
|
}
|
|
1063
1063
|
if (e.dislike) {
|
|
1064
|
-
this.dislikeBtn =
|
|
1064
|
+
this.dislikeBtn = g("imp-btn--dislike", i.dislike, s.dislike), this.dislikeBtn.addEventListener("click", () => t.emit("action", { id: "dislike" })), this.dislikeCountEl = this.attachCountTooltip(this.dislikeBtn, e.dislikeCount);
|
|
1065
1065
|
const n = this.wrapWithTooltip(this.dislikeBtn, this.dislikeCountEl);
|
|
1066
1066
|
this.rightItems.set("dislike", n), this.registerCollapsible({
|
|
1067
1067
|
key: "dislike",
|
|
@@ -1096,21 +1096,21 @@ class vt {
|
|
|
1096
1096
|
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" }) });
|
|
1097
1097
|
for (const h of (i.custom ?? []).filter((c) => c.placement !== "bar"))
|
|
1098
1098
|
this.actionItems.push({ value: `custom:${h.id}`, label: h.title, icon: h.icon, run: () => e.emit("customaction", { id: h.id }) });
|
|
1099
|
-
const r =
|
|
1099
|
+
const r = g("imp-btn--more", s.more, n.more);
|
|
1100
1100
|
this.moreMenu = new B(r);
|
|
1101
|
-
const
|
|
1102
|
-
|
|
1101
|
+
const l = o("div", "imp-controls__menu-anchor imp-controls__more");
|
|
1102
|
+
l.append(r, this.moreMenu.root), r.addEventListener("click", () => {
|
|
1103
1103
|
this.closeMenus(this.moreMenu), this.moreMenu?.toggle(this.buildMoreSections());
|
|
1104
|
-
}), t.append(
|
|
1104
|
+
}), t.append(l), this.moreWrap = l;
|
|
1105
1105
|
}
|
|
1106
1106
|
/** ⋯ menu = overflowed controls (in display order) + consumer actions. */
|
|
1107
1107
|
buildMoreSections() {
|
|
1108
|
-
const t = [], e = /* @__PURE__ */ new Map(), i = [], s = ["prev", "next", "seekBack", "seekFwd", "like", "dislike", "scenes", "sceneTypes", "pip", "list", "subtitles", "speed", "quality", "gear"], n = (
|
|
1109
|
-
const h = s.indexOf(
|
|
1108
|
+
const t = [], e = /* @__PURE__ */ new Map(), i = [], s = ["prev", "next", "seekBack", "seekFwd", "like", "dislike", "scenes", "sceneTypes", "pip", "list", "subtitles", "speed", "quality", "gear"], n = (l) => {
|
|
1109
|
+
const h = s.indexOf(l);
|
|
1110
1110
|
return h === -1 ? s.length : h;
|
|
1111
|
-
}, r = this.collapsibles.filter((
|
|
1112
|
-
for (const
|
|
1113
|
-
const h =
|
|
1111
|
+
}, r = this.collapsibles.filter((l) => this.overflowed.has(l.key) && l.available()).sort((l, h) => n(l.key) - n(h.key));
|
|
1112
|
+
for (const l of r) {
|
|
1113
|
+
const h = l.section();
|
|
1114
1114
|
if (h)
|
|
1115
1115
|
for (const c of Array.isArray(h) ? h : [h])
|
|
1116
1116
|
if (!c.title && c.items.length === 1) {
|
|
@@ -1119,12 +1119,12 @@ class vt {
|
|
|
1119
1119
|
} else
|
|
1120
1120
|
t.push(c);
|
|
1121
1121
|
}
|
|
1122
|
-
if (i.length > 0 && t.unshift({ title: "", items: i, onSelect: (
|
|
1123
|
-
const
|
|
1122
|
+
if (i.length > 0 && t.unshift({ title: "", items: i, onSelect: (l) => e.get(l)?.() }), this.actionItems.length > 0) {
|
|
1123
|
+
const l = new Map(this.actionItems.map((h) => [h.value, h.run]));
|
|
1124
1124
|
t.push({
|
|
1125
1125
|
title: "",
|
|
1126
1126
|
items: this.actionItems.map(({ value: h, label: c, icon: u }) => ({ value: h, label: c, icon: u, active: !1 })),
|
|
1127
|
-
onSelect: (h) =>
|
|
1127
|
+
onSelect: (h) => l.get(h)?.()
|
|
1128
1128
|
});
|
|
1129
1129
|
}
|
|
1130
1130
|
return t;
|
|
@@ -1179,26 +1179,26 @@ class vt {
|
|
|
1179
1179
|
reflow() {
|
|
1180
1180
|
const t = window.innerWidth <= 767, i = this.player.controlsOptions.seekPlacement !== "bar" || t;
|
|
1181
1181
|
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" : "");
|
|
1182
|
-
const s = (
|
|
1182
|
+
const s = (l) => l === "seekBack" || l === "seekFwd" ? i : l === "prev" || l === "next" ? t : !1;
|
|
1183
1183
|
this.overflowed.clear();
|
|
1184
|
-
for (const
|
|
1185
|
-
if (s(
|
|
1186
|
-
|
|
1184
|
+
for (const l of this.collapsibles) {
|
|
1185
|
+
if (s(l.key)) {
|
|
1186
|
+
l.el.style.display = "none";
|
|
1187
1187
|
continue;
|
|
1188
1188
|
}
|
|
1189
|
-
const h =
|
|
1190
|
-
|
|
1189
|
+
const h = l.available();
|
|
1190
|
+
l.el.style.display = h ? "" : "none", l.el.classList.remove("imp-collapsed");
|
|
1191
1191
|
}
|
|
1192
|
-
const n = this.collapsibles.filter((
|
|
1192
|
+
const n = this.collapsibles.filter((l) => l.available() && !s(l.key)).sort((l, h) => l.priority - h.priority);
|
|
1193
1193
|
let r = n.length;
|
|
1194
1194
|
for (; r-- > 0 && this.overflowsRow(); ) {
|
|
1195
|
-
const
|
|
1196
|
-
if (!
|
|
1197
|
-
|
|
1195
|
+
const l = n.find((h) => !this.overflowed.has(h.key));
|
|
1196
|
+
if (!l) break;
|
|
1197
|
+
l.el.style.display = "none", l.el.classList.add("imp-collapsed"), this.overflowed.add(l.key);
|
|
1198
1198
|
}
|
|
1199
1199
|
if (this.moreWrap) {
|
|
1200
|
-
const
|
|
1201
|
-
this.moreWrap.style.display =
|
|
1200
|
+
const l = this.actionItems.length > 0 || this.overflowed.size > 0;
|
|
1201
|
+
this.moreWrap.style.display = l ? "" : "none";
|
|
1202
1202
|
}
|
|
1203
1203
|
}
|
|
1204
1204
|
overflowsRow() {
|
|
@@ -1267,7 +1267,7 @@ class vt {
|
|
|
1267
1267
|
class ft {
|
|
1268
1268
|
constructor(t) {
|
|
1269
1269
|
this.root = o("div", "imp-poster"), this.image = o("img", "imp-poster__image", { alt: "", decoding: "async" }), this.image.hidden = !0;
|
|
1270
|
-
const e =
|
|
1270
|
+
const e = g("imp-poster__play", t.labels.play, t.icons.bigPlay);
|
|
1271
1271
|
e.addEventListener("click", () => void t.play()), this.root.append(this.image, e), this.root.addEventListener("click", (i) => {
|
|
1272
1272
|
(i.target === this.root || i.target === this.image) && t.play();
|
|
1273
1273
|
});
|
|
@@ -1322,7 +1322,7 @@ class gt {
|
|
|
1322
1322
|
class yt {
|
|
1323
1323
|
constructor(t) {
|
|
1324
1324
|
this.player = t, this.clickBehavior = "player", this.root = o("div", "imp-related"), this.root.hidden = !0, this.heading = o("div", "imp-related__title"), this.grid = o("div", "imp-related__grid");
|
|
1325
|
-
const e =
|
|
1325
|
+
const e = g("imp-related__close", "Close", t.icons.close);
|
|
1326
1326
|
e.addEventListener("click", () => this.hide()), this.root.append(e, this.heading, this.grid);
|
|
1327
1327
|
}
|
|
1328
1328
|
setOptions(t) {
|
|
@@ -1387,18 +1387,18 @@ class bt {
|
|
|
1387
1387
|
const h = o("span", "imp-upnext__duration");
|
|
1388
1388
|
h.textContent = x(t.duration), r.append(h);
|
|
1389
1389
|
}
|
|
1390
|
-
const
|
|
1391
|
-
|
|
1390
|
+
const l = o("span", "imp-upnext__thumb-play");
|
|
1391
|
+
l.innerHTML = this.player.icons.bigPlay, r.append(l), r.addEventListener("click", () => this.player.next()), i.append(r);
|
|
1392
1392
|
}
|
|
1393
1393
|
if (t.title) {
|
|
1394
1394
|
const r = o("div", "imp-upnext__title");
|
|
1395
1395
|
r.textContent = t.title, i.append(r);
|
|
1396
1396
|
}
|
|
1397
1397
|
if (t.previewMeta?.length) {
|
|
1398
|
-
const r = o("div", "imp-upnext__meta"),
|
|
1399
|
-
|
|
1398
|
+
const r = o("div", "imp-upnext__meta"), l = o("span", "imp-upnext__meta-icon");
|
|
1399
|
+
l.innerHTML = t.metaIcon ?? (t.channel ? this.player.icons.channel : this.player.icons.user);
|
|
1400
1400
|
const h = o("span", "imp-upnext__meta-text");
|
|
1401
|
-
h.textContent = t.previewMeta.join(" · "), r.append(
|
|
1401
|
+
h.textContent = t.previewMeta.join(" · "), r.append(l, h), i.append(r);
|
|
1402
1402
|
}
|
|
1403
1403
|
const n = o("button", "imp-upnext__btn", { type: "button" });
|
|
1404
1404
|
n.textContent = e.playNext, n.addEventListener("click", () => this.player.next()), i.append(n), this.root.append(i), this.root.hidden = !1;
|
|
@@ -1419,13 +1419,13 @@ class kt {
|
|
|
1419
1419
|
} else
|
|
1420
1420
|
n.textContent = t.labels.playlist;
|
|
1421
1421
|
const r = o("div", "imp-playlist__tools");
|
|
1422
|
-
this.shuffleBtn =
|
|
1422
|
+
this.shuffleBtn = g("imp-playlist__shuffle", t.labels.shuffle, t.icons.shuffle), this.shuffleBtn.addEventListener("click", () => {
|
|
1423
1423
|
t.setShuffle(!t.shuffle), this.syncModes();
|
|
1424
|
-
}), this.repeatBtn =
|
|
1424
|
+
}), this.repeatBtn = g("imp-playlist__repeat", t.labels.repeat, t.icons.repeat), this.repeatBtn.addEventListener("click", () => {
|
|
1425
1425
|
t.setRepeat(!t.repeat), this.syncModes();
|
|
1426
1426
|
});
|
|
1427
|
-
const
|
|
1428
|
-
|
|
1427
|
+
const l = g("imp-playlist__close", "Close", t.icons.close);
|
|
1428
|
+
l.addEventListener("click", () => this.hide()), r.append(this.shuffleBtn, this.repeatBtn, l), s.append(n, r), this.list = o("div", "imp-playlist__list"), this.root.append(s, this.list), this.rebuild(), this.syncModes();
|
|
1429
1429
|
}
|
|
1430
1430
|
syncModes() {
|
|
1431
1431
|
this.shuffleBtn.classList.toggle("imp-btn--active", this.player.shuffle), this.repeatBtn.classList.toggle("imp-btn--active", this.player.repeat);
|
|
@@ -1438,8 +1438,8 @@ class kt {
|
|
|
1438
1438
|
t.poster && (s.style.backgroundImage = `url("${t.poster}")`);
|
|
1439
1439
|
const n = o("div", "imp-playlist__meta"), r = o("div", "imp-playlist__title");
|
|
1440
1440
|
if (r.textContent = t.title ?? `#${e + 1}`, n.append(r), t.duration) {
|
|
1441
|
-
const
|
|
1442
|
-
|
|
1441
|
+
const l = o("div", "imp-playlist__duration");
|
|
1442
|
+
l.textContent = x(t.duration), n.append(l);
|
|
1443
1443
|
}
|
|
1444
1444
|
i.append(s, n), i.addEventListener("click", () => {
|
|
1445
1445
|
this.player.playItem(e), window.innerWidth <= 767 && this.hide();
|
|
@@ -1464,7 +1464,7 @@ class wt {
|
|
|
1464
1464
|
this.player = t, this.items = [], this.root = o("div", `imp-playlist imp-scenes imp-playlist--${e}`), this.root.hidden = !0;
|
|
1465
1465
|
const i = o("div", "imp-playlist__header"), s = o("span");
|
|
1466
1466
|
s.textContent = t.labels.scenes;
|
|
1467
|
-
const n =
|
|
1467
|
+
const n = g("imp-playlist__close", "Close", t.icons.close);
|
|
1468
1468
|
n.addEventListener("click", () => this.hide()), i.append(s, n), this.list = o("div", "imp-playlist__list"), this.root.append(i, this.list), t.on("chapterchange", () => this.syncActive());
|
|
1469
1469
|
}
|
|
1470
1470
|
/** Re-render from the player's current chapters + thumbnail track. */
|
|
@@ -1477,10 +1477,10 @@ class wt {
|
|
|
1477
1477
|
const c = o("div", "imp-scenes__sprite");
|
|
1478
1478
|
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);
|
|
1479
1479
|
} else n && (s.style.backgroundImage = `url("${n.src}")`);
|
|
1480
|
-
const r = o("div", "imp-playlist__meta"),
|
|
1481
|
-
|
|
1480
|
+
const r = o("div", "imp-playlist__meta"), l = o("div", "imp-playlist__title");
|
|
1481
|
+
l.textContent = e.title || x(e.start);
|
|
1482
1482
|
const h = o("div", "imp-playlist__duration");
|
|
1483
|
-
h.textContent = x(e.start), r.append(
|
|
1483
|
+
h.textContent = x(e.start), r.append(l, h), i.append(s, r), i.addEventListener("click", () => {
|
|
1484
1484
|
this.player.seek(e.start), this.player.play(), window.innerWidth <= 767 && this.hide();
|
|
1485
1485
|
}), this.list.append(i), this.items.push(i);
|
|
1486
1486
|
}
|
|
@@ -1505,8 +1505,8 @@ class wt {
|
|
|
1505
1505
|
this.visible ? this.hide() : this.show();
|
|
1506
1506
|
}
|
|
1507
1507
|
}
|
|
1508
|
-
function G(
|
|
1509
|
-
return
|
|
1508
|
+
function G(a) {
|
|
1509
|
+
return a ? typeof a == "string" ? [{ src: a, label: "Subtitles" }] : Array.isArray(a) ? a : [a] : [];
|
|
1510
1510
|
}
|
|
1511
1511
|
const xt = {
|
|
1512
1512
|
play: !0,
|
|
@@ -1536,40 +1536,47 @@ const xt = {
|
|
|
1536
1536
|
};
|
|
1537
1537
|
class Tt {
|
|
1538
1538
|
constructor(t, e = {}) {
|
|
1539
|
-
this.scrubbing = !1, this.emitter = new
|
|
1539
|
+
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.sceneGroupList = [], this.activeSceneGroupId = "", this.progressiveQuality = -1, this.thumbTrack = null, this.shuffleMode = !1, this.autoAdvanceEnabled = !0, this.persistKey = null, this.persistVolume = !1, this.persistAutoAdvance = !1, this.decodeRecoveries = 0, this.adManager = null, this.playedOnce = !1, this.idleTimer = null, this.destroyed = !1;
|
|
1540
1540
|
const i = typeof t == "string" ? document.querySelector(t) : t;
|
|
1541
1541
|
if (!i) throw new Error(`[itube-player] mount target not found: ${String(t)}`);
|
|
1542
|
-
this.mount = i, this.options = e, this.labels = { ...
|
|
1542
|
+
this.mount = i, this.options = e, this.labels = { ...V, ...Y(e.language), ...e.labels }, this.icons = { ...J, ...e.icons };
|
|
1543
1543
|
const s = e.controls ?? {}, n = s.speed ?? s.settings ?? "gear";
|
|
1544
|
-
this.controlsOptions = { ...xt, ...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,
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
const p = typeof r.borderRadius == "number" ? `${r.borderRadius}px` : r.borderRadius;
|
|
1548
|
-
this.container.style.setProperty("--imp-radius", p);
|
|
1544
|
+
if (this.controlsOptions = { ...xt, ...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, e.persist) {
|
|
1545
|
+
const v = e.persist === !0 ? {} : e.persist;
|
|
1546
|
+
this.persistKey = v.key ?? "itube-player", this.persistVolume = v.volume !== !1, this.persistAutoAdvance = v.autoAdvance !== !1;
|
|
1549
1547
|
}
|
|
1550
|
-
r
|
|
1551
|
-
|
|
1548
|
+
const r = this.readPersisted();
|
|
1549
|
+
this.autoAdvanceEnabled = this.persistAutoAdvance && typeof r?.autoAdvance == "boolean" ? r.autoAdvance : this.playlistOptions.autoAdvance, this.sources = e.source ? Array.isArray(e.source) ? [...e.source] : [e.source] : [], this.container = o("div", "imp-player", { tabindex: "0" }), e.className && this.container.classList.add(e.className);
|
|
1550
|
+
const l = e.styling;
|
|
1551
|
+
if (l?.themeColor && this.container.style.setProperty("--imp-accent", l.themeColor), l?.likeColor && this.container.style.setProperty("--imp-like", l.likeColor), l?.dislikeColor && this.container.style.setProperty("--imp-dislike", l.dislikeColor), l?.borderRadius !== void 0) {
|
|
1552
|
+
const v = typeof l.borderRadius == "number" ? `${l.borderRadius}px` : l.borderRadius;
|
|
1553
|
+
this.container.style.setProperty("--imp-radius", v);
|
|
1554
|
+
}
|
|
1555
|
+
l?.playButtonStyle === "inverted" && this.container.classList.add("imp-player--play-inverted"), this.video = o("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);
|
|
1556
|
+
const h = this.persistVolume ? r : null;
|
|
1557
|
+
this.video.volume = w(h?.volume ?? e.volume ?? 1, 0, 1), (h?.muted ?? e.muted) && (this.video.muted = !0);
|
|
1558
|
+
const c = o("div", "imp-layer");
|
|
1552
1559
|
this.spinner = o("div", "imp-spinner"), this.spinner.hidden = !0, this.errorBox = o("div", "imp-error"), this.errorBox.hidden = !0, this.pauseScreen = new gt(this.labels), this.poster = new ft(this), this.related = new yt(this), this.related.setOptions(e.related), this.upNext = new bt(this), this.controls = new vt(this), this.playlistPanel = new kt(this, this.playlistOptions.layout, this.playlistOptions.title || void 0), this.scenesPanel = new wt(this, e.scenes?.layout ?? "bottom");
|
|
1553
|
-
const
|
|
1554
|
-
|
|
1555
|
-
const
|
|
1556
|
-
|
|
1557
|
-
const
|
|
1558
|
-
|
|
1560
|
+
const u = o("div", "imp-layer__middle");
|
|
1561
|
+
u.append(this.spinner, this.errorBox, this.controls.center);
|
|
1562
|
+
const m = o("div", "imp-layer__bottom");
|
|
1563
|
+
m.append(this.controls.root), c.append(this.pauseScreen.root, this.related.root, this.upNext.root, u, m), this.container.append(this.video, c, this.poster.root, this.playlistPanel.root, this.scenesPanel.root), this.mount.append(this.container), e.pauseScreen instanceof HTMLElement ? this.pauseScreen.setCustomContent(e.pauseScreen) : typeof e.pauseScreen == "function" ? this.pauseScreen.setCustomContent(e.pauseScreen(this)) : e.pauseScreen && typeof e.pauseScreen == "object" && this.pauseScreen.setVisibility(e.pauseScreen);
|
|
1564
|
+
const p = e.adConfig ?? e.ads;
|
|
1565
|
+
p && p.adList.length > 0 && (this.adManager = new ot(
|
|
1559
1566
|
{ container: this.container, contentVideo: this.video, emitter: this.emitter, labels: this.labels, closeIcon: this.icons.close },
|
|
1560
|
-
|
|
1561
|
-
)), this.emitter.on("error", ({ message:
|
|
1562
|
-
this.errorBox.textContent =
|
|
1563
|
-
}), this.bindVideoEvents(), this.bindIdleHide(), e.keyboard !== !1 && this.bindKeyboard(), this.video.addEventListener("pointerup", (
|
|
1567
|
+
p
|
|
1568
|
+
)), this.emitter.on("error", ({ message: v }) => {
|
|
1569
|
+
this.errorBox.textContent = v, this.errorBox.hidden = !1, this.spinner.hidden = !0, this.poster.hide();
|
|
1570
|
+
}), this.bindVideoEvents(), this.bindIdleHide(), e.keyboard !== !1 && this.bindKeyboard(), this.video.addEventListener("pointerup", (v) => {
|
|
1564
1571
|
if (!(this.adPlaying || !this.playedOnce)) {
|
|
1565
|
-
if (
|
|
1572
|
+
if (v.pointerType === "mouse") {
|
|
1566
1573
|
this.togglePlay();
|
|
1567
1574
|
return;
|
|
1568
1575
|
}
|
|
1569
1576
|
this.container.classList.contains("imp-player--idle") ? (this.showControlsNow(), this.scheduleIdle()) : this.video.paused || this.container.classList.add("imp-player--idle");
|
|
1570
1577
|
}
|
|
1571
|
-
}, { signal: this.abort.signal }), this.pauseScreen.root.addEventListener("click", (
|
|
1572
|
-
this.pauseScreen.hasCustom ||
|
|
1578
|
+
}, { signal: this.abort.signal }), this.pauseScreen.root.addEventListener("click", (v) => {
|
|
1579
|
+
this.pauseScreen.hasCustom || v.target === this.pauseScreen.root && this.togglePlay();
|
|
1573
1580
|
}, { 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 });
|
|
1574
1581
|
}
|
|
1575
1582
|
// === events ===========================================================
|
|
@@ -1641,6 +1648,26 @@ class Tt {
|
|
|
1641
1648
|
toggleMute() {
|
|
1642
1649
|
this.video.muted = !this.video.muted;
|
|
1643
1650
|
}
|
|
1651
|
+
// === persistence ======================================================
|
|
1652
|
+
/** Read persisted prefs (safe against private mode / SSR / bad JSON). */
|
|
1653
|
+
readPersisted() {
|
|
1654
|
+
if (!this.persistKey) return null;
|
|
1655
|
+
try {
|
|
1656
|
+
const t = localStorage.getItem(this.persistKey), e = t ? JSON.parse(t) : null;
|
|
1657
|
+
return e && typeof e == "object" ? e : null;
|
|
1658
|
+
} catch {
|
|
1659
|
+
return null;
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
/** Write the enabled prefs to localStorage. No-op when persistence is off. */
|
|
1663
|
+
persistState() {
|
|
1664
|
+
if (this.persistKey)
|
|
1665
|
+
try {
|
|
1666
|
+
const t = {};
|
|
1667
|
+
this.persistVolume && (t.volume = this.video.volume, t.muted = this.video.muted), this.persistAutoAdvance && (t.autoAdvance = this.autoAdvanceEnabled), localStorage.setItem(this.persistKey, JSON.stringify(t));
|
|
1668
|
+
} catch {
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1644
1671
|
// === rate / quality ===================================================
|
|
1645
1672
|
get playbackRate() {
|
|
1646
1673
|
return this.video.playbackRate;
|
|
@@ -1861,7 +1888,7 @@ class Tt {
|
|
|
1861
1888
|
this.progressiveQuality = h, n = s.qualities[h].src, r = s.qualities[h].type ?? r;
|
|
1862
1889
|
}
|
|
1863
1890
|
this.video.preload = this.adManager?.hasPendingPreRoll ? "auto" : "metadata";
|
|
1864
|
-
const
|
|
1891
|
+
const l = await ct(this.video, n, r, {
|
|
1865
1892
|
onLevels: () => {
|
|
1866
1893
|
i === this.loadToken && this.controls.syncFeatureButtons();
|
|
1867
1894
|
},
|
|
@@ -1869,10 +1896,10 @@ class Tt {
|
|
|
1869
1896
|
onError: (h, c) => this.emitter.emit("error", { message: h, cause: c })
|
|
1870
1897
|
});
|
|
1871
1898
|
if (i !== this.loadToken) {
|
|
1872
|
-
|
|
1899
|
+
l.destroy();
|
|
1873
1900
|
return;
|
|
1874
1901
|
}
|
|
1875
|
-
if (this.sourceController =
|
|
1902
|
+
if (this.sourceController = l, this.emitter.emit("sourcechange", { source: s, index: t }), s.thumbnails && q.load(s.thumbnails).then((h) => {
|
|
1876
1903
|
i === this.loadToken && (this.thumbTrack = h, this.controls.progress.setThumbnails(h), this.scenesPanel.visible && this.scenesPanel.rebuild());
|
|
1877
1904
|
}).catch((h) => this.emitter.emit("error", { message: "Failed to load thumbnails track", cause: h })), s.sceneGroups && s.sceneGroups.length > 0) {
|
|
1878
1905
|
this.sceneGroupList = s.sceneGroups, this.activeSceneGroupId = s.sceneGroups[0].id;
|
|
@@ -1914,7 +1941,7 @@ class Tt {
|
|
|
1914
1941
|
}, { signal: t }), e.addEventListener("progress", () => {
|
|
1915
1942
|
this.emitter.emit("progress", { buffered: this.bufferedEnd });
|
|
1916
1943
|
}, { signal: t }), e.addEventListener("volumechange", () => {
|
|
1917
|
-
this.emitter.emit("volumechange", { volume: e.volume, muted: e.muted });
|
|
1944
|
+
this.emitter.emit("volumechange", { volume: e.volume, muted: e.muted }), this.persistVolume && this.persistState();
|
|
1918
1945
|
}, { signal: t }), e.addEventListener("seeking", () => this.emitter.emit("seeking", { currentTime: e.currentTime }), { signal: t }), e.addEventListener("seeked", () => this.emitter.emit("seeked", { currentTime: e.currentTime }), { signal: t }), e.addEventListener("waiting", () => {
|
|
1919
1946
|
this.spinner.hidden = !1;
|
|
1920
1947
|
}, { signal: t });
|
|
@@ -1929,7 +1956,7 @@ class Tt {
|
|
|
1929
1956
|
this.decodeRecoveries++;
|
|
1930
1957
|
const n = e.currentTime, r = !e.paused;
|
|
1931
1958
|
e.load();
|
|
1932
|
-
const
|
|
1959
|
+
const l = () => {
|
|
1933
1960
|
try {
|
|
1934
1961
|
e.currentTime = n;
|
|
1935
1962
|
} catch {
|
|
@@ -1937,7 +1964,7 @@ class Tt {
|
|
|
1937
1964
|
r && e.play().catch(() => {
|
|
1938
1965
|
});
|
|
1939
1966
|
};
|
|
1940
|
-
e.readyState >= 1 ?
|
|
1967
|
+
e.readyState >= 1 ? l() : e.addEventListener("loadedmetadata", l, { once: !0, signal: this.abort.signal });
|
|
1941
1968
|
return;
|
|
1942
1969
|
}
|
|
1943
1970
|
this.emitter.emit("error", { message: i.message || `Media error (code ${i.code})`, cause: i });
|
|
@@ -1963,7 +1990,7 @@ class Tt {
|
|
|
1963
1990
|
return this.autoAdvanceEnabled;
|
|
1964
1991
|
}
|
|
1965
1992
|
setAutoAdvance(t) {
|
|
1966
|
-
this.autoAdvanceEnabled = t, t && this.upNext.hide();
|
|
1993
|
+
this.autoAdvanceEnabled = t, t && this.upNext.hide(), this.persistAutoAdvance && this.persistState();
|
|
1967
1994
|
}
|
|
1968
1995
|
// === controls visibility ==============================================
|
|
1969
1996
|
bindIdleHide() {
|
|
@@ -2029,20 +2056,20 @@ class Tt {
|
|
|
2029
2056
|
}
|
|
2030
2057
|
}
|
|
2031
2058
|
export {
|
|
2032
|
-
|
|
2059
|
+
X as Emitter,
|
|
2033
2060
|
Tt as Player,
|
|
2034
|
-
|
|
2061
|
+
q as ThumbnailTrack,
|
|
2035
2062
|
tt as buildHeatmapValues,
|
|
2036
2063
|
U as chapterAt,
|
|
2037
2064
|
J as defaultIcons,
|
|
2038
|
-
|
|
2065
|
+
V as defaultLabels,
|
|
2039
2066
|
x as formatTime,
|
|
2040
2067
|
Y as getLocale,
|
|
2041
2068
|
et as heatmapPath,
|
|
2042
2069
|
at as isHlsSource,
|
|
2043
2070
|
lt as loadChaptersVtt,
|
|
2044
2071
|
W as normalizeChapters,
|
|
2045
|
-
|
|
2072
|
+
_t as registerLocale,
|
|
2046
2073
|
Lt as registerLocales,
|
|
2047
2074
|
Bt as registeredLanguages,
|
|
2048
2075
|
it as resolveVast
|