@oddin-gg/havik-player 2.10.0 → 2.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/havik-player.global.js +18 -18
- package/dist/havik-player.global.js.map +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +43 -1
- package/dist/index.d.ts +43 -1
- package/dist/index.js +654 -325
- package/dist/index.js.map +1 -1
- package/docs/API.md +43 -16
- package/embed/index.html +1 -1
- package/examples/vanilla.html +1 -1
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -46,9 +46,32 @@ async function s(e) {
|
|
|
46
46
|
function c(e) {
|
|
47
47
|
return e === "live" || e === "ended" || e === "upcoming" || e === "pending" ? e : "upcoming";
|
|
48
48
|
}
|
|
49
|
+
function l(e) {
|
|
50
|
+
if (!Array.isArray(e)) return;
|
|
51
|
+
let t = [];
|
|
52
|
+
for (let n of e) {
|
|
53
|
+
if (!n || typeof n != "object") continue;
|
|
54
|
+
let e = typeof n.urn == "string" ? n.urn : "", r = typeof n.name == "string" ? n.name : "";
|
|
55
|
+
if (!e && !r) continue;
|
|
56
|
+
let i = {
|
|
57
|
+
urn: e,
|
|
58
|
+
name: r,
|
|
59
|
+
isHome: n.isHome === !0
|
|
60
|
+
};
|
|
61
|
+
typeof n.logoUrl == "string" && u(n.logoUrl) && (i.logoUrl = n.logoUrl), t.push(i);
|
|
62
|
+
}
|
|
63
|
+
return t.length > 0 ? t : void 0;
|
|
64
|
+
}
|
|
65
|
+
function u(e) {
|
|
66
|
+
try {
|
|
67
|
+
return new URL(e).protocol === "https:";
|
|
68
|
+
} catch {
|
|
69
|
+
return !1;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
49
72
|
//#endregion
|
|
50
73
|
//#region src/core/http.ts
|
|
51
|
-
function
|
|
74
|
+
function d(e, t) {
|
|
52
75
|
let r = e.replace(/\/+$/, ""), i;
|
|
53
76
|
try {
|
|
54
77
|
i = new URL(r + t);
|
|
@@ -58,14 +81,14 @@ function l(e, t) {
|
|
|
58
81
|
if (i.protocol !== "https:" && i.protocol !== "http:") throw new n("INTERNAL", 0, `baseUrl must be http(s), got: ${JSON.stringify(e)}`);
|
|
59
82
|
return i.toString();
|
|
60
83
|
}
|
|
61
|
-
function
|
|
84
|
+
function f(e) {
|
|
62
85
|
if (!e) return;
|
|
63
86
|
let t = Number(e);
|
|
64
87
|
if (Number.isFinite(t)) return Math.max(0, Math.round(t * 1e3));
|
|
65
88
|
let n = Date.parse(e);
|
|
66
89
|
if (!Number.isNaN(n)) return Math.max(0, n - Date.now());
|
|
67
90
|
}
|
|
68
|
-
async function
|
|
91
|
+
async function p(e, t) {
|
|
69
92
|
let r = await s(t.credential), i = t.headers ?? new Headers();
|
|
70
93
|
if (t.apiHeaders) for (let [e, n] of Object.entries(t.apiHeaders)) i.has(e) || i.set(e, n);
|
|
71
94
|
i.set("x-api-key", r.apiKey);
|
|
@@ -80,49 +103,49 @@ async function d(e, t) {
|
|
|
80
103
|
mode: "cors"
|
|
81
104
|
});
|
|
82
105
|
} catch (e) {
|
|
83
|
-
throw t.signal?.aborted ? new n("ABORTED", 0, "request aborted", { cause: e }) : new n("NETWORK", 0, `network request failed: ${
|
|
106
|
+
throw t.signal?.aborted ? new n("ABORTED", 0, "request aborted", { cause: e }) : new n("NETWORK", 0, `network request failed: ${m(e)}`, { cause: e });
|
|
84
107
|
}
|
|
85
108
|
}
|
|
86
|
-
function
|
|
109
|
+
function m(e) {
|
|
87
110
|
return e instanceof Error ? e.message : String(e);
|
|
88
111
|
}
|
|
89
112
|
//#endregion
|
|
90
113
|
//#region src/core/waitForLive.ts
|
|
91
|
-
var
|
|
114
|
+
var h = 1e3, g = 3e4, _ = 6e5, ee = 3e5, te = 1e3, ne = {
|
|
92
115
|
TOO_EARLY: "tooEarly",
|
|
93
116
|
UNAVAILABLE: "unavailable",
|
|
94
117
|
RATE_LIMITED: "rateLimited",
|
|
95
118
|
NETWORK: "network"
|
|
96
119
|
};
|
|
97
|
-
function
|
|
98
|
-
let t = e === !0 || e === !1 ? {} : e, n = Math.max(
|
|
120
|
+
function re(e) {
|
|
121
|
+
let t = e === !0 || e === !1 ? {} : e, n = Math.max(te, t.floorMs ?? h), r = Math.max(n, t.ceilMs ?? g), i = Math.max(0, t.imminentMs ?? _), a = Math.max(r, t.sanityFloorMs ?? ee);
|
|
99
122
|
return {
|
|
100
123
|
timeoutMs: t.timeoutMs,
|
|
101
124
|
floorMs: n,
|
|
102
125
|
ceilMs: r,
|
|
103
126
|
imminentMs: i,
|
|
104
127
|
sanityFloorMs: a,
|
|
105
|
-
kickoffMs:
|
|
128
|
+
kickoffMs: ie(t.kickoffAt),
|
|
106
129
|
jitter: t.jitter ?? !0,
|
|
107
130
|
onState: t.onState
|
|
108
131
|
};
|
|
109
132
|
}
|
|
110
|
-
function
|
|
133
|
+
function ie(e) {
|
|
111
134
|
if (e == null) return;
|
|
112
135
|
if (typeof e == "number") return Number.isFinite(e) ? e : void 0;
|
|
113
136
|
let t = Date.parse(e);
|
|
114
137
|
return Number.isFinite(t) ? t : void 0;
|
|
115
138
|
}
|
|
116
|
-
function
|
|
139
|
+
function ae(e, t, n) {
|
|
117
140
|
return Math.min(n, Math.max(t, e));
|
|
118
141
|
}
|
|
119
|
-
function
|
|
142
|
+
function oe(e) {
|
|
120
143
|
return Math.round(e * (1 + .15 * Math.random()));
|
|
121
144
|
}
|
|
122
|
-
function
|
|
145
|
+
function se(e, t, n, r) {
|
|
123
146
|
let i = r ?? n.kickoffMs, a = i == null ? void 0 : Math.max(0, i - t), o = Math.max(n.floorMs, e ?? 0);
|
|
124
147
|
if (a == null || a <= n.imminentMs) return {
|
|
125
|
-
delay:
|
|
148
|
+
delay: ae(e ?? n.floorMs, o, n.ceilMs),
|
|
126
149
|
ttkMs: a
|
|
127
150
|
};
|
|
128
151
|
let s = Math.min(Math.floor(a / 10), n.sanityFloorMs, a);
|
|
@@ -131,7 +154,7 @@ function ae(e, t, n, r) {
|
|
|
131
154
|
ttkMs: a
|
|
132
155
|
};
|
|
133
156
|
}
|
|
134
|
-
function
|
|
157
|
+
function ce(e, t) {
|
|
135
158
|
return new Promise((r, i) => {
|
|
136
159
|
if (t?.aborted) {
|
|
137
160
|
i(new n("ABORTED", 0, "wait-for-live aborted"));
|
|
@@ -146,7 +169,7 @@ function oe(e, t) {
|
|
|
146
169
|
});
|
|
147
170
|
}
|
|
148
171
|
async function v(e, t, r) {
|
|
149
|
-
let i =
|
|
172
|
+
let i = re(t), a = Date.now(), s = i.timeoutMs == null ? Infinity : a + i.timeoutMs, c = 0, l;
|
|
150
173
|
for (;;) {
|
|
151
174
|
if (r?.aborted) throw new n("ABORTED", 0, "wait-for-live aborted");
|
|
152
175
|
try {
|
|
@@ -154,18 +177,18 @@ async function v(e, t, r) {
|
|
|
154
177
|
} catch (e) {
|
|
155
178
|
if (!(e instanceof n) || !o(e.code)) throw e;
|
|
156
179
|
c += 1, e.liveStartsAtMs != null && Number.isFinite(e.liveStartsAtMs) && (l = e.liveStartsAtMs);
|
|
157
|
-
let t = Date.now(), u =
|
|
158
|
-
if (i.jitter && (f =
|
|
180
|
+
let t = Date.now(), u = se(e.retryAfterMs, t, i, l), d = u.ttkMs, f = u.delay;
|
|
181
|
+
if (i.jitter && (f = oe(f)), t + f > s) throw new n("TIMEOUT", e.httpStatus, `timed out after ${i.timeoutMs}ms waiting for the stream to go live`, {
|
|
159
182
|
retryAfterMs: e.retryAfterMs,
|
|
160
183
|
cause: e
|
|
161
184
|
});
|
|
162
185
|
i.onState?.({
|
|
163
|
-
phase:
|
|
186
|
+
phase: ne[e.code] ?? "unavailable",
|
|
164
187
|
retryInMs: f,
|
|
165
188
|
attempt: c,
|
|
166
189
|
elapsedMs: t - a,
|
|
167
190
|
ttkMs: d
|
|
168
|
-
}), await
|
|
191
|
+
}), await ce(f, r);
|
|
169
192
|
}
|
|
170
193
|
}
|
|
171
194
|
}
|
|
@@ -173,20 +196,20 @@ async function v(e, t, r) {
|
|
|
173
196
|
//#region src/core/resolve.ts
|
|
174
197
|
async function y(e) {
|
|
175
198
|
if (!e.matchUrn || typeof e.matchUrn != "string") throw new n("INVALID_URN", 0, "resolveStream: a non-empty matchUrn is required");
|
|
176
|
-
let t = await d(
|
|
199
|
+
let t = await p(d(e.baseUrl, `/v1/playback/${encodeURIComponent(e.matchUrn)}`), {
|
|
177
200
|
credential: e.credential,
|
|
178
201
|
signal: e.signal,
|
|
179
202
|
apiHeaders: e.apiHeaders
|
|
180
203
|
});
|
|
181
|
-
if (!t.ok) throw await
|
|
182
|
-
return
|
|
204
|
+
if (!t.ok) throw await le(t);
|
|
205
|
+
return de(await t.json(), e.matchUrn);
|
|
183
206
|
}
|
|
184
207
|
function b(e) {
|
|
185
208
|
let t = () => y(e);
|
|
186
209
|
return e.waitForLive ? v(t, e.waitForLive, e.signal) : t();
|
|
187
210
|
}
|
|
188
|
-
async function
|
|
189
|
-
let t =
|
|
211
|
+
async function le(e) {
|
|
212
|
+
let t = f(e.headers.get("retry-after")), i = e.headers.get("x-request-id") ?? e.headers.get("x-amzn-requestid") ?? void 0, a = e.statusText || `HTTP ${e.status}`, o, s;
|
|
190
213
|
try {
|
|
191
214
|
let t = await e.json();
|
|
192
215
|
if (t?.error?.message && (a = t.error.message), t?.error?.code && (o = t.error.code), typeof t?.liveStartsAt == "string") {
|
|
@@ -201,7 +224,7 @@ async function se(e) {
|
|
|
201
224
|
liveStartsAtMs: s
|
|
202
225
|
});
|
|
203
226
|
}
|
|
204
|
-
var
|
|
227
|
+
var ue = /* @__PURE__ */ new Set([
|
|
205
228
|
"matchUrn",
|
|
206
229
|
"protocol",
|
|
207
230
|
"drmEnabled",
|
|
@@ -222,7 +245,7 @@ function x(e, t) {
|
|
|
222
245
|
if (r.protocol !== "https:" && r.protocol !== "http:") throw new n("INTERNAL", 0, `playback ${e} has a disallowed scheme: ${r.protocol}`);
|
|
223
246
|
return t;
|
|
224
247
|
}
|
|
225
|
-
function
|
|
248
|
+
function de(e, t) {
|
|
226
249
|
if (!e.manifestUrl) throw new n("INTERNAL", 0, "playback response is missing manifestUrl");
|
|
227
250
|
let r = e.drmEnabled ?? !!e.drm, i = {
|
|
228
251
|
matchUrn: e.matchUrn ?? t,
|
|
@@ -239,7 +262,7 @@ function le(e, t) {
|
|
|
239
262
|
}), (t.widevine || t.fairplay) && (i.drm = t);
|
|
240
263
|
}
|
|
241
264
|
let a = {};
|
|
242
|
-
for (let [t, n] of Object.entries(e))
|
|
265
|
+
for (let [t, n] of Object.entries(e)) ue.has(t) || (a[t] = n);
|
|
243
266
|
return Object.keys(a).length > 0 && (i.extensions = a), i;
|
|
244
267
|
}
|
|
245
268
|
//#endregion
|
|
@@ -247,37 +270,37 @@ function le(e, t) {
|
|
|
247
270
|
function S(e) {
|
|
248
271
|
return e.ownerDocument ?? document;
|
|
249
272
|
}
|
|
250
|
-
function
|
|
273
|
+
function C(e) {
|
|
251
274
|
return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
|
|
252
275
|
}
|
|
253
|
-
function
|
|
254
|
-
let n =
|
|
276
|
+
function w(e, t) {
|
|
277
|
+
let n = C(S(e));
|
|
255
278
|
return n != null && (n === e || t != null && n === t) || e.webkitDisplayingFullscreen === !0;
|
|
256
279
|
}
|
|
257
|
-
async function
|
|
280
|
+
async function T(e, t) {
|
|
258
281
|
let n = t ?? e;
|
|
259
282
|
if (typeof n.requestFullscreen == "function") return await n.requestFullscreen(), !0;
|
|
260
283
|
if (typeof n.webkitRequestFullscreen == "function") return n.webkitRequestFullscreen(), !0;
|
|
261
284
|
let r = e;
|
|
262
285
|
return r.webkitSupportsFullscreen && typeof r.webkitEnterFullscreen == "function" ? (r.webkitEnterFullscreen(), !0) : !1;
|
|
263
286
|
}
|
|
264
|
-
async function
|
|
287
|
+
async function E(e, t) {
|
|
265
288
|
let n = e;
|
|
266
289
|
if (n.webkitDisplayingFullscreen) {
|
|
267
290
|
n.webkitExitFullscreen?.();
|
|
268
291
|
return;
|
|
269
292
|
}
|
|
270
|
-
let r = S(e), i =
|
|
293
|
+
let r = S(e), i = C(r);
|
|
271
294
|
i != null && (i === e || t != null && i === t) && (typeof r.exitFullscreen == "function" ? await r.exitFullscreen() : r.webkitExitFullscreen?.());
|
|
272
295
|
}
|
|
273
296
|
//#endregion
|
|
274
297
|
//#region src/core/catalog.ts
|
|
275
|
-
async function
|
|
298
|
+
async function fe(e) {
|
|
276
299
|
let t = new URLSearchParams();
|
|
277
300
|
e.status && t.set("status", Array.isArray(e.status) ? e.status.join(",") : e.status), e.sport && t.set("sport", e.sport);
|
|
278
|
-
let i = t.toString(), a =
|
|
301
|
+
let i = t.toString(), a = d(e.baseUrl, "/v1/catalog" + (i ? `?${i}` : "")), o = new Headers();
|
|
279
302
|
e.etag && o.set("If-None-Match", e.etag);
|
|
280
|
-
let s = await
|
|
303
|
+
let s = await p(a, {
|
|
281
304
|
credential: e.credential,
|
|
282
305
|
signal: e.signal,
|
|
283
306
|
headers: o,
|
|
@@ -290,12 +313,12 @@ async function de(e) {
|
|
|
290
313
|
};
|
|
291
314
|
if (!s.ok) throw new n(r(s.status), s.status, `catalog request failed (HTTP ${s.status})`);
|
|
292
315
|
return {
|
|
293
|
-
tournaments:
|
|
316
|
+
tournaments: pe(await s.json()),
|
|
294
317
|
etag: s.headers.get("etag") ?? void 0,
|
|
295
318
|
notModified: !1
|
|
296
319
|
};
|
|
297
320
|
}
|
|
298
|
-
function
|
|
321
|
+
function pe(e) {
|
|
299
322
|
return (e.tournaments ?? []).map((e) => {
|
|
300
323
|
let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
|
|
301
324
|
return {
|
|
@@ -311,15 +334,16 @@ function fe(e) {
|
|
|
311
334
|
datePlannedStart: e.datePlannedStart,
|
|
312
335
|
tournamentUrn: t,
|
|
313
336
|
tournamentName: n,
|
|
314
|
-
sport: r
|
|
337
|
+
sport: r,
|
|
338
|
+
teams: l(e.teams)
|
|
315
339
|
}))
|
|
316
340
|
};
|
|
317
341
|
});
|
|
318
342
|
}
|
|
319
|
-
async function
|
|
320
|
-
let t =
|
|
343
|
+
async function me(e) {
|
|
344
|
+
let t = d(e.baseUrl, `/v1/tournaments/${encodeURIComponent(e.urn)}`), i = new Headers();
|
|
321
345
|
e.etag && i.set("If-None-Match", e.etag);
|
|
322
|
-
let a = await
|
|
346
|
+
let a = await p(t, {
|
|
323
347
|
credential: e.credential,
|
|
324
348
|
signal: e.signal,
|
|
325
349
|
headers: i,
|
|
@@ -336,13 +360,13 @@ async function pe(e) {
|
|
|
336
360
|
};
|
|
337
361
|
if (!a.ok) throw new n(r(a.status), a.status, `tournament request failed (HTTP ${a.status})`);
|
|
338
362
|
return {
|
|
339
|
-
tournament:
|
|
363
|
+
tournament: he(await a.json()),
|
|
340
364
|
etag: a.headers.get("etag") ?? void 0,
|
|
341
365
|
notModified: !1,
|
|
342
366
|
notFound: !1
|
|
343
367
|
};
|
|
344
368
|
}
|
|
345
|
-
function
|
|
369
|
+
function he(e) {
|
|
346
370
|
let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
|
|
347
371
|
return {
|
|
348
372
|
urn: t,
|
|
@@ -357,23 +381,24 @@ function me(e) {
|
|
|
357
381
|
datePlannedStart: e.datePlannedStart,
|
|
358
382
|
tournamentUrn: t,
|
|
359
383
|
tournamentName: n,
|
|
360
|
-
sport: r
|
|
384
|
+
sport: r,
|
|
385
|
+
teams: l(e.teams)
|
|
361
386
|
}))
|
|
362
387
|
};
|
|
363
388
|
}
|
|
364
|
-
function
|
|
389
|
+
function ge(e) {
|
|
365
390
|
return e.tournaments.flatMap((e) => e.matches);
|
|
366
391
|
}
|
|
367
392
|
//#endregion
|
|
368
393
|
//#region src/core/poll.ts
|
|
369
|
-
function
|
|
394
|
+
function _e(e) {
|
|
370
395
|
let t = Math.max(2e3, e.intervalMs ?? 1e4), i = new AbortController(), a, o, s, u = !1, f = () => {
|
|
371
|
-
u || (a = setTimeout(
|
|
372
|
-
},
|
|
396
|
+
u || (a = setTimeout(m, t));
|
|
397
|
+
}, m = async () => {
|
|
373
398
|
try {
|
|
374
|
-
let t =
|
|
399
|
+
let t = d(e.baseUrl, `/v1/matches/${encodeURIComponent(e.matchUrn)}`), a = new Headers();
|
|
375
400
|
o && a.set("If-None-Match", o);
|
|
376
|
-
let u = await
|
|
401
|
+
let u = await p(t, {
|
|
377
402
|
credential: e.credential,
|
|
378
403
|
signal: i.signal,
|
|
379
404
|
headers: a,
|
|
@@ -382,13 +407,18 @@ function ge(e) {
|
|
|
382
407
|
if (u.status !== 304) {
|
|
383
408
|
if (!u.ok) throw new n(r(u.status), u.status, `match status request failed (HTTP ${u.status})`);
|
|
384
409
|
o = u.headers.get("etag") ?? o;
|
|
385
|
-
let t = await u.json(), i = c(t.status), a = typeof t.status == "string" ? t.status : i
|
|
386
|
-
|
|
410
|
+
let t = await u.json(), i = c(t.status), a = typeof t.status == "string" ? t.status : i, d = l(t.teams), f = JSON.stringify([
|
|
411
|
+
a,
|
|
412
|
+
t.datePlannedStart ?? null,
|
|
413
|
+
d ?? null
|
|
414
|
+
]);
|
|
415
|
+
f !== s && (s = f, e.onChange({
|
|
387
416
|
matchUrn: t.matchUrn ?? e.matchUrn,
|
|
388
417
|
matchName: t.matchName,
|
|
389
418
|
status: i,
|
|
390
419
|
statusRaw: t.status,
|
|
391
|
-
datePlannedStart: t.datePlannedStart
|
|
420
|
+
datePlannedStart: t.datePlannedStart,
|
|
421
|
+
teams: d
|
|
392
422
|
}));
|
|
393
423
|
}
|
|
394
424
|
} catch (t) {
|
|
@@ -397,21 +427,21 @@ function ge(e) {
|
|
|
397
427
|
f();
|
|
398
428
|
}
|
|
399
429
|
};
|
|
400
|
-
return
|
|
430
|
+
return m(), { stop() {
|
|
401
431
|
u = !0, i.abort(), a && clearTimeout(a);
|
|
402
432
|
} };
|
|
403
433
|
}
|
|
404
434
|
//#endregion
|
|
405
435
|
//#region src/core/events.ts
|
|
406
|
-
var
|
|
407
|
-
function
|
|
408
|
-
let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = e.idleTimeoutMs ??
|
|
436
|
+
var ve = 45e3;
|
|
437
|
+
function D(e) {
|
|
438
|
+
let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = e.idleTimeoutMs ?? ve, i = Number.isFinite(r) && r > 0 ? r : 0, a = new AbortController(), o = !1, c = (e) => new Promise((t) => {
|
|
409
439
|
if (a.signal.aborted) return t();
|
|
410
440
|
let n = setTimeout(t, e);
|
|
411
441
|
a.signal.addEventListener("abort", () => {
|
|
412
442
|
clearTimeout(n), t();
|
|
413
443
|
}, { once: !0 });
|
|
414
|
-
}),
|
|
444
|
+
}), l = (t) => {
|
|
415
445
|
e.onAlive?.();
|
|
416
446
|
let n = "message", r = [];
|
|
417
447
|
for (let e of t.split("\n")) {
|
|
@@ -424,9 +454,9 @@ function E(e) {
|
|
|
424
454
|
let t = JSON.parse(r.join("\n"));
|
|
425
455
|
t && typeof t.state == "string" && e.onState(t);
|
|
426
456
|
} catch {}
|
|
427
|
-
},
|
|
428
|
-
let r = e.getReader(), a = new TextDecoder(), s = "", c = !1,
|
|
429
|
-
i && (clearTimeout(
|
|
457
|
+
}, u = /\r\n\r\n|\n\n|\r\r/, f = async (e, t, n) => {
|
|
458
|
+
let r = e.getReader(), a = new TextDecoder(), s = "", c = !1, d, f = () => {
|
|
459
|
+
i && (clearTimeout(d), d = setTimeout(() => {
|
|
430
460
|
n(), r.cancel().catch(() => {});
|
|
431
461
|
}, i));
|
|
432
462
|
};
|
|
@@ -436,27 +466,27 @@ function E(e) {
|
|
|
436
466
|
if (n) return;
|
|
437
467
|
e && e.length > 0 && (f(), c || (c = !0, t())), s += a.decode(e, { stream: !0 });
|
|
438
468
|
let i;
|
|
439
|
-
for (; (i =
|
|
469
|
+
for (; (i = u.exec(s)) !== null;) l(s.slice(0, i.index)), s = s.slice(i.index + i[0].length);
|
|
440
470
|
if (o) return;
|
|
441
471
|
}
|
|
442
472
|
} finally {
|
|
443
|
-
clearTimeout(
|
|
473
|
+
clearTimeout(d), await r.cancel().catch(() => {});
|
|
444
474
|
}
|
|
445
475
|
};
|
|
446
476
|
return (async () => {
|
|
447
477
|
let r = t;
|
|
448
478
|
for (; !o;) {
|
|
449
|
-
let
|
|
450
|
-
a.signal.addEventListener("abort",
|
|
479
|
+
let l = new AbortController(), u = () => l.abort();
|
|
480
|
+
a.signal.addEventListener("abort", u, { once: !0 });
|
|
451
481
|
let p = null, m, h = () => {
|
|
452
|
-
p = `no data for ${i}ms`,
|
|
482
|
+
p = `no data for ${i}ms`, l.abort();
|
|
453
483
|
};
|
|
454
484
|
try {
|
|
455
485
|
let n = await s(e.credential);
|
|
456
486
|
if (o) return;
|
|
457
|
-
let a =
|
|
487
|
+
let a = d(e.eventsBaseUrl, `/v1/events/${encodeURIComponent(e.matchUrn)}`);
|
|
458
488
|
i && (m = setTimeout(() => {
|
|
459
|
-
p = `no response headers within ${i}ms`,
|
|
489
|
+
p = `no response headers within ${i}ms`, l.abort();
|
|
460
490
|
}, i));
|
|
461
491
|
let c = await fetch(a, {
|
|
462
492
|
method: "GET",
|
|
@@ -464,7 +494,7 @@ function E(e) {
|
|
|
464
494
|
"x-api-key": n.apiKey,
|
|
465
495
|
accept: "text/event-stream"
|
|
466
496
|
},
|
|
467
|
-
signal:
|
|
497
|
+
signal: l.signal,
|
|
468
498
|
cache: "no-store",
|
|
469
499
|
credentials: "omit",
|
|
470
500
|
mode: "cors"
|
|
@@ -477,7 +507,7 @@ function E(e) {
|
|
|
477
507
|
if (o || a.signal.aborted) return;
|
|
478
508
|
p || e.onError?.(t);
|
|
479
509
|
} finally {
|
|
480
|
-
clearTimeout(m), a.signal.removeEventListener("abort",
|
|
510
|
+
clearTimeout(m), a.signal.removeEventListener("abort", u), l.abort();
|
|
481
511
|
}
|
|
482
512
|
if (o) return;
|
|
483
513
|
p && e.onError?.(/* @__PURE__ */ Error(`live-state subscribe idle: ${p} — reconnecting`)), await c(r), r = Math.min(n, r * 2);
|
|
@@ -486,7 +516,7 @@ function E(e) {
|
|
|
486
516
|
o || (o = !0, a.abort());
|
|
487
517
|
} };
|
|
488
518
|
}
|
|
489
|
-
function
|
|
519
|
+
function O(e) {
|
|
490
520
|
try {
|
|
491
521
|
let t = new URL(e);
|
|
492
522
|
return t.hostname = `events.${t.hostname}`, t.pathname = "", t.search = "", t.origin;
|
|
@@ -496,27 +526,27 @@ function D(e) {
|
|
|
496
526
|
}
|
|
497
527
|
//#endregion
|
|
498
528
|
//#region src/core/drm/deviceId.ts
|
|
499
|
-
var
|
|
500
|
-
function
|
|
501
|
-
if (
|
|
529
|
+
var k = "havik.player.deviceId", A;
|
|
530
|
+
function j() {
|
|
531
|
+
if (A) return A;
|
|
502
532
|
try {
|
|
503
|
-
let e = globalThis.localStorage?.getItem(
|
|
504
|
-
if (e) return
|
|
533
|
+
let e = globalThis.localStorage?.getItem(k);
|
|
534
|
+
if (e) return A = e, e;
|
|
505
535
|
} catch {}
|
|
506
|
-
let e =
|
|
507
|
-
|
|
536
|
+
let e = be();
|
|
537
|
+
A = e;
|
|
508
538
|
try {
|
|
509
|
-
globalThis.localStorage?.setItem(
|
|
539
|
+
globalThis.localStorage?.setItem(k, e);
|
|
510
540
|
} catch {}
|
|
511
541
|
return e;
|
|
512
542
|
}
|
|
513
|
-
function
|
|
514
|
-
|
|
543
|
+
function ye() {
|
|
544
|
+
A = void 0;
|
|
515
545
|
try {
|
|
516
|
-
globalThis.localStorage?.removeItem(
|
|
546
|
+
globalThis.localStorage?.removeItem(k);
|
|
517
547
|
} catch {}
|
|
518
548
|
}
|
|
519
|
-
function
|
|
549
|
+
function be() {
|
|
520
550
|
let e = globalThis.crypto;
|
|
521
551
|
if (e && typeof e.randomUUID == "function") return e.randomUUID();
|
|
522
552
|
let t = /* @__PURE__ */ new Uint8Array(16);
|
|
@@ -528,21 +558,21 @@ function ye() {
|
|
|
528
558
|
}
|
|
529
559
|
//#endregion
|
|
530
560
|
//#region src/core/drm/headers.ts
|
|
531
|
-
function
|
|
561
|
+
function xe(e, t, n = {}) {
|
|
532
562
|
let r = {
|
|
533
563
|
"x-api-key": t.apiKey,
|
|
534
564
|
"X-Match-Urn": e.matchUrn,
|
|
535
|
-
"X-Device-Id": n.deviceId ??
|
|
565
|
+
"X-Device-Id": n.deviceId ?? j(),
|
|
536
566
|
"Content-Type": "application/octet-stream"
|
|
537
567
|
};
|
|
538
568
|
return n.userId && (r["X-User-Id"] = n.userId), r;
|
|
539
569
|
}
|
|
540
570
|
//#endregion
|
|
541
571
|
//#region src/core/drm/cdm.ts
|
|
542
|
-
var
|
|
543
|
-
function
|
|
544
|
-
let n =
|
|
545
|
-
n || (n = /* @__PURE__ */ new Map(),
|
|
572
|
+
var M = /* @__PURE__ */ new WeakMap();
|
|
573
|
+
function Se(e, t) {
|
|
574
|
+
let n = M.get(e);
|
|
575
|
+
n || (n = /* @__PURE__ */ new Map(), M.set(e, n));
|
|
546
576
|
let r = n.get(t.keySystem);
|
|
547
577
|
if (r) return r;
|
|
548
578
|
let i = t.createMediaKeys().catch((e) => {
|
|
@@ -550,22 +580,22 @@ function xe(e, t) {
|
|
|
550
580
|
});
|
|
551
581
|
return n.set(t.keySystem, i), i;
|
|
552
582
|
}
|
|
553
|
-
function
|
|
583
|
+
function N() {
|
|
554
584
|
return typeof navigator < "u" && typeof navigator.requestMediaKeySystemAccess == "function";
|
|
555
585
|
}
|
|
556
|
-
var
|
|
557
|
-
function
|
|
586
|
+
var P = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
|
|
587
|
+
function Ce(e) {
|
|
558
588
|
return e.startsWith("com.widevine");
|
|
559
589
|
}
|
|
560
|
-
function
|
|
561
|
-
if (!
|
|
590
|
+
function F(e, t) {
|
|
591
|
+
if (!Ce(e)) return t;
|
|
562
592
|
let n = (e, t) => {
|
|
563
593
|
let n = e.videoCapabilities;
|
|
564
594
|
return !n?.length || !n.some((e) => e.robustness) ? !1 : n.every((e) => {
|
|
565
|
-
let n =
|
|
566
|
-
return n === -1 ||
|
|
595
|
+
let n = P.indexOf(e.robustness);
|
|
596
|
+
return n === -1 || P.indexOf(t) > n;
|
|
567
597
|
});
|
|
568
|
-
}, r =
|
|
598
|
+
}, r = P.flatMap((e) => t.filter((t) => n(t, e)).map((t) => ({
|
|
569
599
|
...t,
|
|
570
600
|
videoCapabilities: t.videoCapabilities?.map((t) => ({
|
|
571
601
|
...t,
|
|
@@ -575,19 +605,86 @@ function Ce(e, t) {
|
|
|
575
605
|
return [...t, ...r];
|
|
576
606
|
}
|
|
577
607
|
function we(e) {
|
|
578
|
-
return (t, n) =>
|
|
608
|
+
return (t, n) => N() ? navigator.requestMediaKeySystemAccess(t, F(t, n)).then((t) => ({
|
|
579
609
|
keySystem: t.keySystem,
|
|
580
610
|
getConfiguration: () => t.getConfiguration(),
|
|
581
|
-
createMediaKeys: () =>
|
|
611
|
+
createMediaKeys: () => Se(e, t)
|
|
582
612
|
})) : Promise.reject(/* @__PURE__ */ Error("navigator.requestMediaKeySystemAccess is unavailable — EME needs a secure context (https, or localhost)"));
|
|
583
613
|
}
|
|
614
|
+
var I = {
|
|
615
|
+
video: "SW_SECURE_DECODE",
|
|
616
|
+
audio: "SW_SECURE_CRYPTO",
|
|
617
|
+
scheme: "cbcs"
|
|
618
|
+
};
|
|
619
|
+
function Te(e) {
|
|
620
|
+
if (!N()) return;
|
|
621
|
+
let t = (e, t) => ({
|
|
622
|
+
contentType: e,
|
|
623
|
+
robustness: t,
|
|
624
|
+
encryptionScheme: I.scheme
|
|
625
|
+
});
|
|
626
|
+
we(e)("com.widevine.alpha", [{
|
|
627
|
+
initDataTypes: ["cenc"],
|
|
628
|
+
distinctiveIdentifier: "optional",
|
|
629
|
+
persistentState: "optional",
|
|
630
|
+
sessionTypes: ["temporary"],
|
|
631
|
+
audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"", I.audio)],
|
|
632
|
+
videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"", I.video)]
|
|
633
|
+
}]).then((e) => e.createMediaKeys()).catch(() => {});
|
|
634
|
+
}
|
|
635
|
+
function L(e) {
|
|
636
|
+
let t = R(e);
|
|
637
|
+
if (/^avc[13]/.test(t)) return "avc";
|
|
638
|
+
if (/^(hvc1|hev1)/.test(t)) return "hevc";
|
|
639
|
+
if (/^(dvh1|dvhe)/.test(t)) return "dv";
|
|
640
|
+
if (t.startsWith("av01")) return "av1";
|
|
641
|
+
if (/^vp0?9/.test(t)) return "vp9";
|
|
642
|
+
}
|
|
643
|
+
function R(e) {
|
|
644
|
+
return (e ?? "").trim().toLowerCase();
|
|
645
|
+
}
|
|
646
|
+
var Ee = {
|
|
647
|
+
hevc: "hvc1.1.6.L93.90",
|
|
648
|
+
dv: "dvh1.05.06",
|
|
649
|
+
av1: "av01.0.05M.08",
|
|
650
|
+
vp9: "vp09.00.10.08"
|
|
651
|
+
}, De = /* @__PURE__ */ new Map(), z = /* @__PURE__ */ new Map();
|
|
652
|
+
function Oe(e) {
|
|
653
|
+
let t = R(e), n = De.get(t);
|
|
654
|
+
if (n) return n;
|
|
655
|
+
let r = {
|
|
656
|
+
initDataTypes: ["cenc"],
|
|
657
|
+
distinctiveIdentifier: "optional",
|
|
658
|
+
persistentState: "optional",
|
|
659
|
+
sessionTypes: ["temporary"],
|
|
660
|
+
videoCapabilities: [{
|
|
661
|
+
contentType: `video/mp4; codecs="${e.trim()}"`,
|
|
662
|
+
robustness: I.video,
|
|
663
|
+
encryptionScheme: I.scheme
|
|
664
|
+
}]
|
|
665
|
+
}, i = (async () => {
|
|
666
|
+
try {
|
|
667
|
+
return await navigator.requestMediaKeySystemAccess("com.widevine.alpha", F("com.widevine.alpha", [r])), !0;
|
|
668
|
+
} catch {
|
|
669
|
+
return !1;
|
|
670
|
+
}
|
|
671
|
+
})().then((e) => (z.set(t, e), e));
|
|
672
|
+
return De.set(t, i), i;
|
|
673
|
+
}
|
|
674
|
+
function ke() {
|
|
675
|
+
if (N()) for (let e of Object.values(Ee)) Oe(e);
|
|
676
|
+
}
|
|
677
|
+
function Ae(e) {
|
|
678
|
+
let t = L(e);
|
|
679
|
+
if (t) return t === "avc" ? !0 : z.get(R(e)) ?? z.get(R(Ee[t]));
|
|
680
|
+
}
|
|
584
681
|
//#endregion
|
|
585
682
|
//#region src/core/drm/support.ts
|
|
586
|
-
var
|
|
683
|
+
var je = 5e3, Me = "video/mp4; codecs=\"avc1.42E01E\"", B = "audio/mp4; codecs=\"mp4a.40.2\"", Ne = {
|
|
587
684
|
widevine: ["com.widevine.alpha"],
|
|
588
685
|
fairplay: ["com.apple.fps"]
|
|
589
686
|
};
|
|
590
|
-
function
|
|
687
|
+
function Pe(e) {
|
|
591
688
|
return e === "fairplay" ? [{
|
|
592
689
|
initDataTypes: [
|
|
593
690
|
"sinf",
|
|
@@ -595,30 +692,30 @@ function ke(e) {
|
|
|
595
692
|
"cenc"
|
|
596
693
|
],
|
|
597
694
|
videoCapabilities: [{
|
|
598
|
-
contentType:
|
|
695
|
+
contentType: Me,
|
|
599
696
|
robustness: "",
|
|
600
697
|
encryptionScheme: "cbcs"
|
|
601
698
|
}],
|
|
602
699
|
audioCapabilities: [{
|
|
603
|
-
contentType:
|
|
700
|
+
contentType: B,
|
|
604
701
|
robustness: "",
|
|
605
702
|
encryptionScheme: "cbcs"
|
|
606
703
|
}]
|
|
607
|
-
}] :
|
|
704
|
+
}] : F("com.widevine.alpha", [{
|
|
608
705
|
initDataTypes: ["cenc"],
|
|
609
706
|
videoCapabilities: [{
|
|
610
|
-
contentType:
|
|
611
|
-
robustness:
|
|
612
|
-
encryptionScheme:
|
|
707
|
+
contentType: Me,
|
|
708
|
+
robustness: I.video,
|
|
709
|
+
encryptionScheme: I.scheme
|
|
613
710
|
}],
|
|
614
711
|
audioCapabilities: [{
|
|
615
|
-
contentType:
|
|
616
|
-
robustness:
|
|
617
|
-
encryptionScheme:
|
|
712
|
+
contentType: B,
|
|
713
|
+
robustness: I.audio,
|
|
714
|
+
encryptionScheme: I.scheme
|
|
618
715
|
}]
|
|
619
716
|
}]);
|
|
620
717
|
}
|
|
621
|
-
function
|
|
718
|
+
function V(e, t) {
|
|
622
719
|
return new Promise((n, r) => {
|
|
623
720
|
let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
|
|
624
721
|
e.then((e) => {
|
|
@@ -628,8 +725,8 @@ function P(e, t) {
|
|
|
628
725
|
});
|
|
629
726
|
});
|
|
630
727
|
}
|
|
631
|
-
async function
|
|
632
|
-
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ??
|
|
728
|
+
async function Fe(e = {}) {
|
|
729
|
+
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? je, r = {};
|
|
633
730
|
if (typeof window < "u" && window.isSecureContext === !1) return {
|
|
634
731
|
verdict: "insecure-context",
|
|
635
732
|
detail: r
|
|
@@ -641,7 +738,7 @@ async function Ae(e = {}) {
|
|
|
641
738
|
};
|
|
642
739
|
let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
|
|
643
740
|
for (let e of t) {
|
|
644
|
-
let t =
|
|
741
|
+
let t = Ne[e];
|
|
645
742
|
if (!t) {
|
|
646
743
|
r[e] = "unknown system";
|
|
647
744
|
continue;
|
|
@@ -652,7 +749,7 @@ async function Ae(e = {}) {
|
|
|
652
749
|
break;
|
|
653
750
|
}
|
|
654
751
|
try {
|
|
655
|
-
return await
|
|
752
|
+
return await V((await V(i(n, Pe(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
|
|
656
753
|
verdict: "supported",
|
|
657
754
|
system: e,
|
|
658
755
|
detail: r
|
|
@@ -676,49 +773,49 @@ async function Ae(e = {}) {
|
|
|
676
773
|
}
|
|
677
774
|
//#endregion
|
|
678
775
|
//#region src/core/manifest.ts
|
|
679
|
-
var
|
|
680
|
-
function
|
|
681
|
-
return
|
|
776
|
+
var Ie = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
|
|
777
|
+
function Le(e) {
|
|
778
|
+
return Ie.test(e);
|
|
682
779
|
}
|
|
683
780
|
//#endregion
|
|
684
781
|
//#region src/core/env.ts
|
|
685
|
-
var
|
|
782
|
+
var H = {
|
|
686
783
|
integration: "https://feed-dev.oddin-video.gg",
|
|
687
784
|
production: "https://feed.oddin-video.gg"
|
|
688
785
|
};
|
|
689
|
-
function
|
|
690
|
-
let t = Object.prototype.hasOwnProperty.call(
|
|
786
|
+
function U(e) {
|
|
787
|
+
let t = Object.prototype.hasOwnProperty.call(H, e) ? H[e] : void 0;
|
|
691
788
|
if (!t) throw new n("INTERNAL", 0, `unknown env ${JSON.stringify(e)} — expected 'integration' or 'production'`);
|
|
692
789
|
return t;
|
|
693
790
|
}
|
|
694
791
|
//#endregion
|
|
695
792
|
//#region src/core/stats.ts
|
|
696
|
-
var
|
|
697
|
-
function
|
|
793
|
+
var W = { droppedFrames: 0 };
|
|
794
|
+
function G(e) {
|
|
698
795
|
try {
|
|
699
796
|
return new URL(e).host;
|
|
700
797
|
} catch {
|
|
701
798
|
return "";
|
|
702
799
|
}
|
|
703
800
|
}
|
|
704
|
-
var
|
|
705
|
-
function
|
|
801
|
+
var Re = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
|
|
802
|
+
function ze(e) {
|
|
706
803
|
if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
|
|
707
804
|
let t = "", n = -1, r = performance.getEntriesByType("resource");
|
|
708
|
-
for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" ||
|
|
709
|
-
let e =
|
|
805
|
+
for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || Re.test(i.name)) && i.startTime >= n) {
|
|
806
|
+
let e = G(i.name);
|
|
710
807
|
e && (t = e, n = i.startTime);
|
|
711
808
|
}
|
|
712
809
|
return t;
|
|
713
810
|
}
|
|
714
|
-
function
|
|
811
|
+
function K(e) {
|
|
715
812
|
let t = e.getVideoPlaybackQuality?.();
|
|
716
813
|
return {
|
|
717
814
|
dropped: t?.droppedVideoFrames ?? 0,
|
|
718
815
|
totalFrames: t?.totalVideoFrames ?? 0
|
|
719
816
|
};
|
|
720
817
|
}
|
|
721
|
-
function
|
|
818
|
+
function Be(e, t) {
|
|
722
819
|
let n = [
|
|
723
820
|
["playing", () => t("playing")],
|
|
724
821
|
["waiting", () => t("buffering")],
|
|
@@ -735,7 +832,7 @@ function Fe(e, t) {
|
|
|
735
832
|
}
|
|
736
833
|
//#endregion
|
|
737
834
|
//#region src/core/engine/native.ts
|
|
738
|
-
function
|
|
835
|
+
function Ve(e) {
|
|
739
836
|
try {
|
|
740
837
|
let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
|
|
741
838
|
return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
|
|
@@ -743,15 +840,15 @@ function Ie(e) {
|
|
|
743
840
|
return;
|
|
744
841
|
}
|
|
745
842
|
}
|
|
746
|
-
function
|
|
843
|
+
function q(e) {
|
|
747
844
|
return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
|
|
748
845
|
}
|
|
749
|
-
function
|
|
846
|
+
function J() {
|
|
750
847
|
if (typeof window > "u") return !1;
|
|
751
848
|
let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
|
|
752
849
|
return e || t;
|
|
753
850
|
}
|
|
754
|
-
var
|
|
851
|
+
var Y = class {
|
|
755
852
|
name = "native";
|
|
756
853
|
deps;
|
|
757
854
|
onLoaded;
|
|
@@ -787,7 +884,7 @@ var H = class {
|
|
|
787
884
|
type: "error",
|
|
788
885
|
error: new n("INTERNAL", 0, "native HLS playback error"),
|
|
789
886
|
fatal: !0
|
|
790
|
-
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src =
|
|
887
|
+
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = He(t.manifestUrl, t.analytics?.sid), e.load();
|
|
791
888
|
}
|
|
792
889
|
startLoad() {
|
|
793
890
|
this.loadStarted || (this.loadStarted = !0, this.restorePreload());
|
|
@@ -809,7 +906,7 @@ var H = class {
|
|
|
809
906
|
});
|
|
810
907
|
this.onEncrypted = (n) => {
|
|
811
908
|
let i = n;
|
|
812
|
-
i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV =
|
|
909
|
+
i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = Ve(i.initData), (async () => {
|
|
813
910
|
try {
|
|
814
911
|
let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
|
|
815
912
|
initDataTypes: [i.initDataType],
|
|
@@ -904,11 +1001,11 @@ var H = class {
|
|
|
904
1001
|
e.seekable.length > 0 && (e.currentTime = e.seekable.end(e.seekable.length - 1));
|
|
905
1002
|
}
|
|
906
1003
|
getStats() {
|
|
907
|
-
let e = this.deps.video, t =
|
|
1004
|
+
let e = this.deps.video, t = K(e), n = {
|
|
908
1005
|
droppedFrames: t.dropped,
|
|
909
1006
|
decodedFrames: t.totalFrames
|
|
910
1007
|
};
|
|
911
|
-
return this.cdnHost ||=
|
|
1008
|
+
return this.cdnHost ||= ze(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity ? (n.isLive = !0, e.seekable.length > 0 && (n.atLiveEdge = e.currentTime >= e.seekable.end(e.seekable.length - 1) - 2)) : Number.isFinite(e.duration) && e.duration > 0 && (n.isLive = !1), n;
|
|
912
1009
|
}
|
|
913
1010
|
stop() {
|
|
914
1011
|
try {
|
|
@@ -927,35 +1024,198 @@ var H = class {
|
|
|
927
1024
|
} catch {}
|
|
928
1025
|
}
|
|
929
1026
|
};
|
|
930
|
-
function
|
|
1027
|
+
function He(e, t) {
|
|
931
1028
|
return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
|
|
932
1029
|
}
|
|
933
1030
|
//#endregion
|
|
1031
|
+
//#region src/core/engine/prefetch.ts
|
|
1032
|
+
var Ue = 15e3, We = 5e3, Ge = 6;
|
|
1033
|
+
function Ke(e) {
|
|
1034
|
+
try {
|
|
1035
|
+
let t = new URL(e);
|
|
1036
|
+
return t.searchParams.delete("CMCD"), t.toString();
|
|
1037
|
+
} catch {
|
|
1038
|
+
return e;
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
var qe = class {
|
|
1042
|
+
cmcd;
|
|
1043
|
+
entries = /* @__PURE__ */ new Map();
|
|
1044
|
+
keyed = /* @__PURE__ */ new Set();
|
|
1045
|
+
perTrack = /* @__PURE__ */ new Map();
|
|
1046
|
+
stats = {
|
|
1047
|
+
started: 0,
|
|
1048
|
+
served: 0,
|
|
1049
|
+
missed: 0,
|
|
1050
|
+
failed: 0,
|
|
1051
|
+
expired: 0
|
|
1052
|
+
};
|
|
1053
|
+
constructor(e = {}) {
|
|
1054
|
+
this.cmcd = e;
|
|
1055
|
+
}
|
|
1056
|
+
keyUsable(e) {
|
|
1057
|
+
this.keyed.add(e);
|
|
1058
|
+
}
|
|
1059
|
+
isActive(e) {
|
|
1060
|
+
return !this.keyed.has(e);
|
|
1061
|
+
}
|
|
1062
|
+
prefetch(e, t, n) {
|
|
1063
|
+
if (!this.isActive(t)) return;
|
|
1064
|
+
let r = Ke(e);
|
|
1065
|
+
if (this.entries.has(r)) return;
|
|
1066
|
+
let i = this.perTrack.get(t) ?? 0;
|
|
1067
|
+
if (i >= Ge) return;
|
|
1068
|
+
this.perTrack.set(t, i + 1);
|
|
1069
|
+
let a = new AbortController(), o = {
|
|
1070
|
+
started: performance.now(),
|
|
1071
|
+
first: 0,
|
|
1072
|
+
bytes: Promise.resolve(null),
|
|
1073
|
+
abort: a
|
|
1074
|
+
};
|
|
1075
|
+
o.bytes = fetch(this.withCmcd(e, t, n), {
|
|
1076
|
+
credentials: "omit",
|
|
1077
|
+
mode: "cors",
|
|
1078
|
+
signal: a.signal
|
|
1079
|
+
}).then(async (e) => (o.first = performance.now(), e.ok ? e.arrayBuffer() : null)).catch(() => null), this.entries.set(r, o), this.stats.started += 1, setTimeout(() => {
|
|
1080
|
+
this.entries.get(r) === o && (this.entries.delete(r), a.abort(), this.stats.expired += 1);
|
|
1081
|
+
}, Ue);
|
|
1082
|
+
}
|
|
1083
|
+
take(e) {
|
|
1084
|
+
let t = Ke(e), n = this.entries.get(t);
|
|
1085
|
+
return n && this.entries.delete(t), n;
|
|
1086
|
+
}
|
|
1087
|
+
destroy() {
|
|
1088
|
+
for (let e of this.entries.values()) e.abort.abort();
|
|
1089
|
+
this.entries.clear();
|
|
1090
|
+
}
|
|
1091
|
+
withCmcd(e, t, n) {
|
|
1092
|
+
let { sessionId: r, contentId: i } = this.cmcd;
|
|
1093
|
+
if (!r && !i) return e;
|
|
1094
|
+
let a = [];
|
|
1095
|
+
i && a.push(`cid="${i}"`), a.push(`ot=${n === "init" ? "i" : t === "audio" ? "a" : "v"}`), a.push("sf=h"), r && a.push(`sid="${r}"`), a.push("st=ll");
|
|
1096
|
+
try {
|
|
1097
|
+
let t = new URL(e);
|
|
1098
|
+
return t.searchParams.set("CMCD", a.join(",")), t.toString();
|
|
1099
|
+
} catch {
|
|
1100
|
+
return e;
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
};
|
|
1104
|
+
function Je(t) {
|
|
1105
|
+
let n = e.DefaultConfig?.loader;
|
|
1106
|
+
if (typeof n != "function") return;
|
|
1107
|
+
class r extends n {
|
|
1108
|
+
served = !1;
|
|
1109
|
+
cancelled = !1;
|
|
1110
|
+
stats = Ye();
|
|
1111
|
+
load(e, n, r) {
|
|
1112
|
+
let i = e.rangeEnd ? void 0 : t.take(e.url);
|
|
1113
|
+
if (!i) {
|
|
1114
|
+
super.load(e, n, r);
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
this.served = !0;
|
|
1118
|
+
let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || We, s = setTimeout(() => {
|
|
1119
|
+
!this.cancelled && this.served && (i.abort.abort(), t.stats.failed += 1, this.served = !1, super.load(e, n, r));
|
|
1120
|
+
}, o);
|
|
1121
|
+
i.bytes.then((o) => {
|
|
1122
|
+
if (clearTimeout(s), this.cancelled || !this.served) return;
|
|
1123
|
+
if (!o) {
|
|
1124
|
+
t.stats.failed += 1, this.served = !1, super.load(e, n, r);
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
t.stats.served += 1;
|
|
1128
|
+
let c = this.stats;
|
|
1129
|
+
c.loading.start = a, c.loading.first = Math.max(a, i.first || a), c.loading.end = performance.now(), c.loaded = c.total = o.byteLength, r.onSuccess({
|
|
1130
|
+
url: e.url,
|
|
1131
|
+
data: o
|
|
1132
|
+
}, c, e, null);
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
abort() {
|
|
1136
|
+
if (this.served) {
|
|
1137
|
+
this.cancelled = !0, this.stats.aborted = !0;
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1140
|
+
super.abort();
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
return r;
|
|
1144
|
+
}
|
|
1145
|
+
function Ye() {
|
|
1146
|
+
return {
|
|
1147
|
+
aborted: !1,
|
|
1148
|
+
loaded: 0,
|
|
1149
|
+
retry: 0,
|
|
1150
|
+
total: 0,
|
|
1151
|
+
chunkCount: 0,
|
|
1152
|
+
bwEstimate: 0,
|
|
1153
|
+
loading: {
|
|
1154
|
+
start: 0,
|
|
1155
|
+
first: 0,
|
|
1156
|
+
end: 0
|
|
1157
|
+
},
|
|
1158
|
+
parsing: {
|
|
1159
|
+
start: 0,
|
|
1160
|
+
end: 0
|
|
1161
|
+
},
|
|
1162
|
+
buffering: {
|
|
1163
|
+
start: 0,
|
|
1164
|
+
first: 0,
|
|
1165
|
+
end: 0
|
|
1166
|
+
}
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
function Xe(e) {
|
|
1170
|
+
return e === "audio" ? "audio" : "main";
|
|
1171
|
+
}
|
|
1172
|
+
function Ze(e, t) {
|
|
1173
|
+
let n = [];
|
|
1174
|
+
t.initSegment?.url && !t.initSegment.data && n.push({
|
|
1175
|
+
url: t.initSegment.url,
|
|
1176
|
+
kind: "init"
|
|
1177
|
+
});
|
|
1178
|
+
let r = ((t.type === "audio" ? e.audioTracks?.[e.audioTrack]?.details : typeof t.level == "number" ? e.levels?.[t.level]?.details : void 0)?.partList ?? []).filter((e) => e.fragment.sn === t.sn);
|
|
1179
|
+
if (r.length) for (let e of r) e.url && n.push({
|
|
1180
|
+
url: e.url,
|
|
1181
|
+
kind: "media"
|
|
1182
|
+
});
|
|
1183
|
+
else t.url && n.push({
|
|
1184
|
+
url: t.url,
|
|
1185
|
+
kind: "media"
|
|
1186
|
+
});
|
|
1187
|
+
return n;
|
|
1188
|
+
}
|
|
1189
|
+
//#endregion
|
|
934
1190
|
//#region src/core/engine/hls.ts
|
|
935
|
-
function
|
|
1191
|
+
function Qe() {
|
|
936
1192
|
return e.isSupported();
|
|
937
1193
|
}
|
|
938
|
-
var
|
|
939
|
-
function
|
|
1194
|
+
var $e = 3, et = 5, tt = 3, nt = 3e4, rt = 12e3, it = 3e3, at = 6e3, ot = 5e3, st = 4e3, ct = 2, lt = 5, ut = 2, dt = 2, ft = 4, pt = 4, mt = 2e3, ht = 3e4, gt = 2, _t = 9, vt = .5, yt = 64;
|
|
1195
|
+
function bt(e) {
|
|
940
1196
|
if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
|
|
941
1197
|
delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
|
|
942
1198
|
return;
|
|
943
1199
|
}
|
|
944
|
-
e.liveSyncDuration ??=
|
|
945
|
-
let t = Math.max(12, e.liveSyncDuration +
|
|
946
|
-
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t),
|
|
1200
|
+
e.liveSyncDuration ??= gt;
|
|
1201
|
+
let t = Math.max(12, e.liveSyncDuration + _t);
|
|
1202
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), xt(e, e.liveSyncDuration);
|
|
947
1203
|
}
|
|
948
|
-
function
|
|
1204
|
+
function xt(e, t) {
|
|
949
1205
|
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
950
1206
|
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
951
1207
|
}
|
|
952
|
-
var
|
|
1208
|
+
var St = class {
|
|
953
1209
|
name = "hls";
|
|
954
1210
|
hls = null;
|
|
955
1211
|
deps;
|
|
956
1212
|
licenseUrl;
|
|
957
1213
|
detectedLowLatency = !1;
|
|
958
1214
|
bytesLoaded = 0;
|
|
1215
|
+
prefetch = null;
|
|
1216
|
+
reportedFirstPlaylist = !1;
|
|
1217
|
+
reportedFirstBytes = !1;
|
|
1218
|
+
reportedDrmReady = !1;
|
|
959
1219
|
playlistBytesLoaded = 0;
|
|
960
1220
|
renditionSwitches = 0;
|
|
961
1221
|
licenseTimeMs = 0;
|
|
@@ -993,6 +1253,11 @@ var W = class {
|
|
|
993
1253
|
kickPending = !1;
|
|
994
1254
|
kickTicks = 0;
|
|
995
1255
|
starvationRebuilds = 0;
|
|
1256
|
+
kickKind = null;
|
|
1257
|
+
starvedFrames = 0;
|
|
1258
|
+
deadTicks = 0;
|
|
1259
|
+
mainFragsSinceTick = 0;
|
|
1260
|
+
recentMainFrags = [];
|
|
996
1261
|
chaseSuspended = !1;
|
|
997
1262
|
savedLiveMaxLatency;
|
|
998
1263
|
savedMaxSyncRate;
|
|
@@ -1008,7 +1273,7 @@ var W = class {
|
|
|
1008
1273
|
this.deps = e, this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
|
|
1009
1274
|
}
|
|
1010
1275
|
async load() {
|
|
1011
|
-
let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a =
|
|
1276
|
+
let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = q(r) && J(), o = !!e.drm?.widevine?.licenseUrl && !a;
|
|
1012
1277
|
if (e.drmEnabled && !o) {
|
|
1013
1278
|
i({
|
|
1014
1279
|
type: "error",
|
|
@@ -1017,7 +1282,7 @@ var W = class {
|
|
|
1017
1282
|
});
|
|
1018
1283
|
return;
|
|
1019
1284
|
}
|
|
1020
|
-
this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
|
|
1285
|
+
e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Te(r), ke()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
|
|
1021
1286
|
let e = this.hls;
|
|
1022
1287
|
if (document.visibilityState !== "visible" || !e) return;
|
|
1023
1288
|
let t = e.liveSyncPosition;
|
|
@@ -1040,11 +1305,11 @@ var W = class {
|
|
|
1040
1305
|
}
|
|
1041
1306
|
this.loadSuspended = !0;
|
|
1042
1307
|
}
|
|
1043
|
-
},
|
|
1308
|
+
}, ot));
|
|
1044
1309
|
}
|
|
1045
1310
|
resumeLoading() {
|
|
1046
1311
|
if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
|
|
1047
|
-
this.lastAdvanceMs = Date.now(), this.lastFragLoadingMs = 0, this.
|
|
1312
|
+
this.lastAdvanceMs = Date.now(), this.lastFragLoadingMs = 0, this.resetStarvationWindow(), this.clearKick();
|
|
1048
1313
|
try {
|
|
1049
1314
|
this.hls.startLoad(-1);
|
|
1050
1315
|
} catch {}
|
|
@@ -1072,11 +1337,11 @@ var W = class {
|
|
|
1072
1337
|
let t = e.liveSyncPosition;
|
|
1073
1338
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
1074
1339
|
let { video: n } = this.deps;
|
|
1075
|
-
n.currentTime <= t +
|
|
1340
|
+
n.currentTime <= t + vt || (n.currentTime = t);
|
|
1076
1341
|
}
|
|
1077
1342
|
startHls() {
|
|
1078
1343
|
let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
|
|
1079
|
-
this.
|
|
1344
|
+
this.clearKick(), this.resetStarvationWindow(), this.lastFragLoadingMs = 0, this.lastEndSN = -1, this.lastAdvanceMs = 0;
|
|
1080
1345
|
let u = n.drmEnabled && !!(n.drm?.widevine?.licenseUrl || n.drm?.fairplay?.licenseUrl), d = {
|
|
1081
1346
|
debug: s === !0,
|
|
1082
1347
|
enableWorker: !o,
|
|
@@ -1091,17 +1356,17 @@ var W = class {
|
|
|
1091
1356
|
emeEnabled: !0,
|
|
1092
1357
|
drmSystems: { ...this.licenseUrl ? { "com.widevine.alpha": { licenseUrl: this.licenseUrl } } : {} },
|
|
1093
1358
|
drmSystemOptions: {
|
|
1094
|
-
videoRobustness:
|
|
1095
|
-
audioRobustness:
|
|
1096
|
-
videoEncryptionScheme:
|
|
1097
|
-
audioEncryptionScheme:
|
|
1359
|
+
videoRobustness: I.video,
|
|
1360
|
+
audioRobustness: I.audio,
|
|
1361
|
+
videoEncryptionScheme: I.scheme,
|
|
1362
|
+
audioEncryptionScheme: I.scheme
|
|
1098
1363
|
},
|
|
1099
|
-
...
|
|
1364
|
+
...N() ? { requestMediaKeySystemAccessFunc: we(t) } : {},
|
|
1100
1365
|
licenseXhrSetup: (e, t) => {
|
|
1101
1366
|
e.open("POST", this.licenseUrl ?? t, !0), e.setRequestHeader("x-api-key", r.apiKey), e.setRequestHeader("X-Match-Urn", n.matchUrn), e.setRequestHeader("X-Device-Id", i), a && e.setRequestHeader("X-User-Id", a), this.licenseRequested = !0;
|
|
1102
1367
|
let o = performance.now();
|
|
1103
1368
|
e.addEventListener("loadend", () => {
|
|
1104
|
-
this.licenseTimeMs = Math.max(1, Math.round(performance.now() - o));
|
|
1369
|
+
this.licenseTimeMs === 0 && (this.licenseTimeMs = Math.max(1, Math.round(performance.now() - o)));
|
|
1105
1370
|
});
|
|
1106
1371
|
}
|
|
1107
1372
|
} : {},
|
|
@@ -1112,39 +1377,54 @@ var W = class {
|
|
|
1112
1377
|
} } : {},
|
|
1113
1378
|
...c
|
|
1114
1379
|
};
|
|
1115
|
-
|
|
1380
|
+
if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !d.fLoader) {
|
|
1381
|
+
let e = new qe({
|
|
1382
|
+
sessionId: n.analytics?.sid,
|
|
1383
|
+
contentId: n.matchUrn
|
|
1384
|
+
}), t = Je(e);
|
|
1385
|
+
t && (this.prefetch = e, d.fLoader = t);
|
|
1386
|
+
}
|
|
1387
|
+
bt(d), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.loadStarted = d.autoStartLoad !== !1;
|
|
1116
1388
|
let f = new e(d);
|
|
1117
|
-
this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
|
|
1118
|
-
this.mediaRecoveries = 0, this.networkRecoveries = 0;
|
|
1119
|
-
let e = f.levels.map((e) => e.height).filter((e) => !!e);
|
|
1120
|
-
this.ladderHeights = e.length ? [...new Set(e)].sort((e, t) => e - t) : void 0, this.ladderTopBitrateKbps = f.levels.length ? Math.round(Math.max(...f.levels.map((e) => e.bitrate)) / 1e3) : 0, this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
|
|
1389
|
+
if (this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
|
|
1390
|
+
this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(f), this.measureLadder(f), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
|
|
1121
1391
|
}), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
|
|
1122
|
-
t?.frag?.type === "main" && (this.
|
|
1392
|
+
t?.frag?.type === "main" && (this.kickKind !== "dead" && this.clearKick(), (this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0 || this.starvationKicks > 0 || this.starvationRebuilds > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
|
|
1123
1393
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
|
|
1124
|
-
},
|
|
1394
|
+
}, nt)));
|
|
1125
1395
|
}), f.on(e.Events.FRAG_LOADING, (e, t) => {
|
|
1126
1396
|
t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
|
|
1127
1397
|
}), f.on(e.Events.FRAG_LOADED, (e, t) => {
|
|
1398
|
+
t?.frag?.type === "main" && (this.mainFragsSinceTick += 1);
|
|
1128
1399
|
let n = t?.frag?.stats, r = n?.loaded;
|
|
1129
|
-
typeof r == "number" && (this.bytesLoaded += r);
|
|
1400
|
+
typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
|
|
1130
1401
|
let i = n?.loading;
|
|
1131
|
-
i && i.end > 0 && i.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(i.end - i.start))), this.requestTimesMs.length >
|
|
1402
|
+
i && i.end > 0 && i.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(i.end - i.start))), this.requestTimesMs.length > yt && this.requestTimesMs.shift());
|
|
1132
1403
|
let a = t?.frag?.url;
|
|
1133
1404
|
if (a) {
|
|
1134
|
-
let e =
|
|
1405
|
+
let e = G(a);
|
|
1135
1406
|
e && (this.cdnHost = e);
|
|
1136
1407
|
}
|
|
1137
1408
|
}), f.on(e.Events.LEVEL_LOADED, (e, t) => {
|
|
1138
1409
|
let n = t?.stats?.loaded;
|
|
1139
|
-
if (typeof n == "number" && (this.playlistBytesLoaded += n), this.detectedLowLatency) return;
|
|
1410
|
+
if (typeof n == "number" && (this.playlistBytesLoaded += n), this.reportedFirstPlaylist || (this.reportedFirstPlaylist = !0, l({ type: "firstPlaylist" })), this.detectedLowLatency) return;
|
|
1140
1411
|
let r = t.details;
|
|
1141
1412
|
(r?.partList?.length || (r?.partTarget ?? 0) > 0) && (this.detectedLowLatency = !0, l({
|
|
1142
1413
|
type: "lowLatencyDetected",
|
|
1143
1414
|
value: !0
|
|
1144
1415
|
}));
|
|
1145
|
-
}), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.
|
|
1416
|
+
}), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
|
|
1417
|
+
let t = this.prefetch;
|
|
1418
|
+
f.on(e.Events.KEY_LOADING, (e, n) => {
|
|
1419
|
+
let r = n?.frag, i = Xe(r?.type);
|
|
1420
|
+
if (r && t.isActive(i)) for (let e of Ze(f, r)) t.prefetch(e.url, i, e.kind);
|
|
1421
|
+
}), f.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(Xe(n?.frag?.type)));
|
|
1422
|
+
}
|
|
1423
|
+
f.on(e.Events.KEY_LOADED, () => {
|
|
1424
|
+
u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
|
|
1425
|
+
}), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
|
|
1146
1426
|
this.checkEndStale(), this.checkStarvation();
|
|
1147
|
-
},
|
|
1427
|
+
}, it), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
1148
1428
|
this.renditionSwitches += 1;
|
|
1149
1429
|
let n = this.lastLevelIndex >= 0 ? f.levels[this.lastLevelIndex] : void 0, r = f.levels[t.level];
|
|
1150
1430
|
n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
|
|
@@ -1208,11 +1488,33 @@ var W = class {
|
|
|
1208
1488
|
return;
|
|
1209
1489
|
}
|
|
1210
1490
|
this.capTimer && clearTimeout(this.capTimer);
|
|
1211
|
-
let t = e > this.sizeCapLevel ?
|
|
1491
|
+
let t = e > this.sizeCapLevel ? mt : ht;
|
|
1212
1492
|
this.capTimer = setTimeout(() => {
|
|
1213
1493
|
this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
|
|
1214
1494
|
}, t);
|
|
1215
1495
|
}
|
|
1496
|
+
measureLadder(e) {
|
|
1497
|
+
let t = e.levels.map((e) => e.height).filter((e) => !!e);
|
|
1498
|
+
this.ladderHeights = t.length ? [...new Set(t)].sort((e, t) => e - t) : void 0, this.ladderTopBitrateKbps = e.levels.length ? Math.round(Math.max(...e.levels.map((e) => e.bitrate)) / 1e3) : 0;
|
|
1499
|
+
}
|
|
1500
|
+
dropLevelsWidevineCannotPlay(e) {
|
|
1501
|
+
this.removeLevelsWhere(e, (e) => Ae(e) !== !0);
|
|
1502
|
+
let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && L(e) !== "avc" && !!L(e)));
|
|
1503
|
+
for (let n of t) Oe(n).then((t) => {
|
|
1504
|
+
t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
|
|
1505
|
+
});
|
|
1506
|
+
}
|
|
1507
|
+
removeLevelsWhere(e, t) {
|
|
1508
|
+
let n = e.levels ?? [], r = [], i = /* @__PURE__ */ new Set();
|
|
1509
|
+
if (n.forEach((e, n) => {
|
|
1510
|
+
let a = e.videoCodec;
|
|
1511
|
+
a && L(a) && t(a) && (r.push(n), i.add(a));
|
|
1512
|
+
}), !r.length) return !1;
|
|
1513
|
+
let a = [...i].join(", ");
|
|
1514
|
+
if (!n.some((e, t) => r.includes(t) ? !1 : !L(e.videoCodec) || Ae(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
|
|
1515
|
+
for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
|
|
1516
|
+
return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
|
|
1517
|
+
}
|
|
1216
1518
|
applySizeCap() {
|
|
1217
1519
|
if (!this.sizeCapManaged) return;
|
|
1218
1520
|
this.capTimer &&= (clearTimeout(this.capTimer), null);
|
|
@@ -1255,7 +1557,7 @@ var W = class {
|
|
|
1255
1557
|
e.widevine && (this.licenseUrl = e.widevine);
|
|
1256
1558
|
}
|
|
1257
1559
|
getStats() {
|
|
1258
|
-
let e = this.hls, t =
|
|
1560
|
+
let e = this.hls, t = K(this.deps.video), n = {
|
|
1259
1561
|
droppedFrames: t.dropped,
|
|
1260
1562
|
decodedFrames: t.totalFrames,
|
|
1261
1563
|
lowLatency: this.detectedLowLatency,
|
|
@@ -1301,32 +1603,41 @@ var W = class {
|
|
|
1301
1603
|
return;
|
|
1302
1604
|
}
|
|
1303
1605
|
let e = Date.now() - this.lastAdvanceMs;
|
|
1304
|
-
!this.chaseSuspended && e >
|
|
1606
|
+
!this.chaseSuspended && e > at && this.suspendChasing(), e > rt && this.emitEnded("stalled");
|
|
1607
|
+
}
|
|
1608
|
+
resetStarvationWindow() {
|
|
1609
|
+
this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
|
|
1610
|
+
}
|
|
1611
|
+
clearKick() {
|
|
1612
|
+
this.kickPending = !1, this.kickTicks = 0, this.kickKind = null;
|
|
1305
1613
|
}
|
|
1306
1614
|
checkStarvation() {
|
|
1307
1615
|
let e = this.hls, { video: t } = this.deps;
|
|
1308
1616
|
if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended) return;
|
|
1309
1617
|
if (typeof document < "u" && document.hidden || this.loadSuspended) {
|
|
1310
|
-
this.
|
|
1618
|
+
this.resetStarvationWindow();
|
|
1311
1619
|
return;
|
|
1312
1620
|
}
|
|
1313
|
-
let n = this.lastAdvanceMs !== 0 &&
|
|
1314
|
-
if (
|
|
1315
|
-
this.
|
|
1621
|
+
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < at, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > st, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = K(t), c = o - s, l = c !== this.starvedFrames;
|
|
1622
|
+
if (this.starvedFrames = c, !a || l) {
|
|
1623
|
+
(t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
|
|
1316
1624
|
return;
|
|
1317
1625
|
}
|
|
1318
|
-
if (
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1626
|
+
if (!r) {
|
|
1627
|
+
this.resetStarvationWindow();
|
|
1628
|
+
return;
|
|
1629
|
+
}
|
|
1630
|
+
if (this.kickPending && (this.kickKind === "dead" || i) && (this.kickTicks += 1), this.starvedTicks = i ? this.starvedTicks + 1 : 0, this.deadTicks += 1, this.recentMainFrags.push(this.mainFragsSinceTick), this.mainFragsSinceTick = 0, this.recentMainFrags.length > ft && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= ut && (this.clearKick(), this.starvationRebuilds < dt)) {
|
|
1631
|
+
this.starvationRebuilds += 1, this.resetStarvationWindow(), this.clearRecoveryReset(), console.warn("havik-player: restarting the load did not resume video (the wedge is in hls.js state that only a rebuild clears) — rebuilding the player"), this.rebuildInstance("starvation rebuild");
|
|
1632
|
+
return;
|
|
1633
|
+
}
|
|
1634
|
+
let u = i && this.starvedTicks >= ct, d = !i && this.deadTicks >= ft && this.recentMainFrags.reduce((e, t) => e + t, 0) >= pt;
|
|
1635
|
+
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= lt))) {
|
|
1636
|
+
this.starvationKicks += 1, this.kickPending = !0, this.kickTicks = 0, this.kickKind = d ? "dead" : "quiet", this.clearRecoveryReset(), console.warn(d ? "havik-player: video starved while hls.js keeps loading media it never plays (dead pipeline at the live edge) — restarting the load" : "havik-player: video starved while the live playlist advances (wedged hls.js fragment pipeline) — restarting the load");
|
|
1637
|
+
try {
|
|
1638
|
+
e.stopLoad(), e.startLoad(-1);
|
|
1639
|
+
} catch (e) {
|
|
1640
|
+
console.warn("havik-player: starvation kick failed", e);
|
|
1330
1641
|
}
|
|
1331
1642
|
}
|
|
1332
1643
|
}
|
|
@@ -1346,7 +1657,7 @@ var W = class {
|
|
|
1346
1657
|
}));
|
|
1347
1658
|
}
|
|
1348
1659
|
stop() {
|
|
1349
|
-
this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.
|
|
1660
|
+
this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.clearKick(), this.stopped = !0, this.loadSuspended = !1, this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null);
|
|
1350
1661
|
try {
|
|
1351
1662
|
this.hls?.stopLoad();
|
|
1352
1663
|
} catch {}
|
|
@@ -1355,7 +1666,7 @@ var W = class {
|
|
|
1355
1666
|
} catch {}
|
|
1356
1667
|
}
|
|
1357
1668
|
destroy() {
|
|
1358
|
-
if (this.clearRecoveryReset(), this.capTimer &&= (clearTimeout(this.capTimer), null), this.capObserver &&= (this.capObserver.disconnect(), null), this.unwatchDprChanges(), this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.onSeeking &&= (this.deps.video.removeEventListener("seeking", this.onSeeking), null), this.onPause &&= (this.deps.video.removeEventListener("pause", this.onPause), null), this.onPlay &&= (this.deps.video.removeEventListener("play", this.onPlay), null), this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), this.licenseRetryTimer &&= (clearTimeout(this.licenseRetryTimer), null), this.hls) {
|
|
1669
|
+
if (this.prefetch?.destroy(), this.prefetch = null, this.clearRecoveryReset(), this.capTimer &&= (clearTimeout(this.capTimer), null), this.capObserver &&= (this.capObserver.disconnect(), null), this.unwatchDprChanges(), this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.onSeeking &&= (this.deps.video.removeEventListener("seeking", this.onSeeking), null), this.onPause &&= (this.deps.video.removeEventListener("pause", this.onPause), null), this.onPlay &&= (this.deps.video.removeEventListener("play", this.onPlay), null), this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), this.licenseRetryTimer &&= (clearTimeout(this.licenseRetryTimer), null), this.hls) {
|
|
1359
1670
|
try {
|
|
1360
1671
|
this.hls.destroy();
|
|
1361
1672
|
} catch (e) {
|
|
@@ -1370,7 +1681,7 @@ var W = class {
|
|
|
1370
1681
|
scheduleLicenseRetry(t) {
|
|
1371
1682
|
if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
|
|
1372
1683
|
let n = t.response?.code ?? 0;
|
|
1373
|
-
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >=
|
|
1684
|
+
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= tt) return !1;
|
|
1374
1685
|
this.licenseRecoveries += 1;
|
|
1375
1686
|
let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
|
|
1376
1687
|
return this.licenseRetryTimer = setTimeout(() => {
|
|
@@ -1402,7 +1713,7 @@ var W = class {
|
|
|
1402
1713
|
return;
|
|
1403
1714
|
}
|
|
1404
1715
|
if (t.type === e.ErrorTypes.NETWORK_ERROR) {
|
|
1405
|
-
if (this.networkRecoveries <
|
|
1716
|
+
if (this.networkRecoveries < et) {
|
|
1406
1717
|
this.networkRecoveries += 1;
|
|
1407
1718
|
let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
|
|
1408
1719
|
this.networkRetryTimer = setTimeout(() => {
|
|
@@ -1419,7 +1730,7 @@ var W = class {
|
|
|
1419
1730
|
return;
|
|
1420
1731
|
}
|
|
1421
1732
|
if (t.type === e.ErrorTypes.MEDIA_ERROR) {
|
|
1422
|
-
if (this.mediaRecoveries <
|
|
1733
|
+
if (this.mediaRecoveries < $e) {
|
|
1423
1734
|
this.mediaRecoveries += 1, n.recoverMediaError();
|
|
1424
1735
|
return;
|
|
1425
1736
|
}
|
|
@@ -1443,19 +1754,19 @@ var W = class {
|
|
|
1443
1754
|
let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
|
|
1444
1755
|
return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
|
|
1445
1756
|
}
|
|
1446
|
-
},
|
|
1757
|
+
}, Ct = 15e3, wt = 6e5, Tt = 3e5, Et = 100, X = 1, Dt = 1e3, Ot = 3e4, kt = 1e3, At = {
|
|
1447
1758
|
inline: "PRESENTATION_INLINE",
|
|
1448
1759
|
fullscreen: "PRESENTATION_FULLSCREEN",
|
|
1449
1760
|
pip: "PRESENTATION_PIP"
|
|
1450
|
-
},
|
|
1761
|
+
}, jt = {
|
|
1451
1762
|
widevine: "KEY_SYSTEM_WIDEVINE",
|
|
1452
1763
|
fairplay: "KEY_SYSTEM_FAIRPLAY",
|
|
1453
1764
|
none: "KEY_SYSTEM_NONE"
|
|
1454
1765
|
};
|
|
1455
|
-
function
|
|
1766
|
+
function Mt(e, t) {
|
|
1456
1767
|
return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
|
|
1457
1768
|
}
|
|
1458
|
-
var
|
|
1769
|
+
var Nt = /* @__PURE__ */ new Set([
|
|
1459
1770
|
"INVALID_URN",
|
|
1460
1771
|
"NOT_FOUND",
|
|
1461
1772
|
"GONE",
|
|
@@ -1465,7 +1776,7 @@ var pt = /* @__PURE__ */ new Set([
|
|
|
1465
1776
|
"FORBIDDEN",
|
|
1466
1777
|
"RATE_LIMITED",
|
|
1467
1778
|
"TIMEOUT"
|
|
1468
|
-
]),
|
|
1779
|
+
]), Z = {
|
|
1469
1780
|
idle: "PLAYER_STATE_IDLE",
|
|
1470
1781
|
waiting: "PLAYER_STATE_WAITING",
|
|
1471
1782
|
loading: "PLAYER_STATE_LOADING",
|
|
@@ -1475,7 +1786,7 @@ var pt = /* @__PURE__ */ new Set([
|
|
|
1475
1786
|
ended: "PLAYER_STATE_ENDED",
|
|
1476
1787
|
error: "PLAYER_STATE_ERROR"
|
|
1477
1788
|
};
|
|
1478
|
-
function
|
|
1789
|
+
function Pt(e) {
|
|
1479
1790
|
try {
|
|
1480
1791
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
1481
1792
|
return !n || r.length === 0 || n !== "feed" && !n.startsWith("feed-") ? void 0 : (t.hostname = [n.replace(/^feed/, "beacons"), ...r].join("."), t.pathname = "", t.search = "", t.origin);
|
|
@@ -1483,14 +1794,14 @@ function mt(e) {
|
|
|
1483
1794
|
return;
|
|
1484
1795
|
}
|
|
1485
1796
|
}
|
|
1486
|
-
var
|
|
1487
|
-
function
|
|
1488
|
-
return
|
|
1797
|
+
var Ft = /* @__PURE__ */ new Set();
|
|
1798
|
+
function It(e, t) {
|
|
1799
|
+
return Ft.has(e) || (Ft.add(e), console.warn(`havik-player: ${t}`)), { disabledReason: t };
|
|
1489
1800
|
}
|
|
1490
|
-
function
|
|
1801
|
+
function Lt(e, t) {
|
|
1491
1802
|
if (t) return { endpoint: t };
|
|
1492
|
-
if (t !== void 0) return
|
|
1493
|
-
let n =
|
|
1803
|
+
if (t !== void 0) return It("empty-endpoint", "analytics is disabled: no QoE beacons will be sent. analytics.endpoint was supplied but empty. Pass a real beacons origin, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, or omit the option to derive it from baseUrl (or analytics: false to opt out).");
|
|
1804
|
+
let n = Pt(e);
|
|
1494
1805
|
if (n) return { endpoint: n };
|
|
1495
1806
|
let r;
|
|
1496
1807
|
try {
|
|
@@ -1498,9 +1809,9 @@ function ht(e, t) {
|
|
|
1498
1809
|
} catch {
|
|
1499
1810
|
r = e;
|
|
1500
1811
|
}
|
|
1501
|
-
return
|
|
1812
|
+
return It(r, `analytics is disabled: no QoE beacons will be sent. The beacons endpoint cannot be derived from the baseUrl host "${r}" — the convention is feed[-dev].<domain> → beacons[-dev].<domain>. Pass an explicit endpoint, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, to createPlayer (or analytics: false to opt out deliberately).`);
|
|
1502
1813
|
}
|
|
1503
|
-
var
|
|
1814
|
+
var Rt = class {
|
|
1504
1815
|
opts;
|
|
1505
1816
|
url;
|
|
1506
1817
|
now;
|
|
@@ -1567,6 +1878,8 @@ var gt = class {
|
|
|
1567
1878
|
startupTimeMs = 0;
|
|
1568
1879
|
manifestLoadMs = 0;
|
|
1569
1880
|
firstFragLoadMs = 0;
|
|
1881
|
+
firstPlaylistMs = 0;
|
|
1882
|
+
drmSetupMs = 0;
|
|
1570
1883
|
onPagehide = () => this.end("END_REASON_PAGEHIDE");
|
|
1571
1884
|
onFreeze = () => {
|
|
1572
1885
|
this.endedFlag || this.flush(!0);
|
|
@@ -1578,8 +1891,8 @@ var gt = class {
|
|
|
1578
1891
|
constructor(e) {
|
|
1579
1892
|
this.opts = {
|
|
1580
1893
|
...e,
|
|
1581
|
-
heartbeatMs: e.heartbeatMs ??
|
|
1582
|
-
idleMs: e.idleMs ??
|
|
1894
|
+
heartbeatMs: e.heartbeatMs ?? Ct,
|
|
1895
|
+
idleMs: e.idleMs ?? wt
|
|
1583
1896
|
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`, this.now = e.now ?? (() => Date.now()), this.bornMs = this.now(), this.presentationSinceMs = this.bornMs, this.startupAnchorMs = this.bornMs;
|
|
1584
1897
|
}
|
|
1585
1898
|
start() {
|
|
@@ -1589,11 +1902,11 @@ var gt = class {
|
|
|
1589
1902
|
sdkVersion: this.opts.sdkVersion,
|
|
1590
1903
|
...this.opts.environment
|
|
1591
1904
|
};
|
|
1592
|
-
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(),
|
|
1905
|
+
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Dt), this.lastTickMs = this.now(), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), document.addEventListener("freeze", this.onFreeze), document.addEventListener("resume", this.onResume), this.onVisibility());
|
|
1593
1906
|
}
|
|
1594
1907
|
checkSuspension(e) {
|
|
1595
1908
|
if (this.endedFlag || !this.opts.idleMs) return !1;
|
|
1596
|
-
let t = Math.max(this.opts.idleMs,
|
|
1909
|
+
let t = Math.max(this.opts.idleMs, Tt);
|
|
1597
1910
|
return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
|
|
1598
1911
|
}
|
|
1599
1912
|
syncIdle(e) {
|
|
@@ -1607,21 +1920,21 @@ var gt = class {
|
|
|
1607
1920
|
noteStateChange(e, t, n, r) {
|
|
1608
1921
|
if (this.endedFlag || e === t) return;
|
|
1609
1922
|
let i = this.now();
|
|
1610
|
-
if (t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(
|
|
1923
|
+
if (t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(X, i - this.startupAnchorMs)), this.firstAudioMs === 0 && !this.isMuted && (this.firstAudioMs = Math.max(X, i - this.startupAnchorMs)), this.isMuted && this.mutedSinceMs === null && (this.mutedSinceMs = i)) : this.playingSinceMs !== null && (this.playingTotalMs += i - this.playingSinceMs, this.playingSinceMs = null, this.mutedSinceMs !== null && (this.mutedTotalMs += i - this.mutedSinceMs, this.mutedSinceMs = null)), this.isPlaying = t === "playing", this.syncActive(), t === "waiting" ? this.waitingSinceMs = i : this.waitingSinceMs !== null && (this.waitingTotalMs += i - this.waitingSinceMs, this.waitingSinceMs = null), t === "buffering" && e === "playing") {
|
|
1611
1924
|
this.stallIsSeekInduced = this.seekInduced(i);
|
|
1612
1925
|
let e = !this.isHidden && !this.stallIsSeekInduced;
|
|
1613
|
-
e && (this.rebufferCount += 1), this.isBuffering = !0, this.lastStallMs = i, e && this.timeToFirstStallMs === 0 && (this.timeToFirstStallMs = Math.max(
|
|
1926
|
+
e && (this.rebufferCount += 1), this.isBuffering = !0, this.lastStallMs = i, e && this.timeToFirstStallMs === 0 && (this.timeToFirstStallMs = Math.max(X, Math.round(this.playingTotalMs)));
|
|
1614
1927
|
} else e === "buffering" && (this.isBuffering = !1, this.stallIsSeekInduced = !1);
|
|
1615
1928
|
this.syncBuffering(), t === "paused" && (this.pauseCount += 1), this.syncIdle(t);
|
|
1616
1929
|
let a = {
|
|
1617
|
-
fromState:
|
|
1618
|
-
toState:
|
|
1619
|
-
presentation:
|
|
1930
|
+
fromState: Z[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
1931
|
+
toState: Z[t] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
1932
|
+
presentation: At[this.presentation]
|
|
1620
1933
|
}, o = this.causeOf(e, t, i);
|
|
1621
1934
|
o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
1622
1935
|
}
|
|
1623
1936
|
seekInduced(e) {
|
|
1624
|
-
return this.lastSeekMs >= 0 && e - this.lastSeekMs <
|
|
1937
|
+
return this.lastSeekMs >= 0 && e - this.lastSeekMs < kt;
|
|
1625
1938
|
}
|
|
1626
1939
|
causeOf(e, t, n) {
|
|
1627
1940
|
if (t === "error") return "TRANSITION_CAUSE_ERROR";
|
|
@@ -1658,19 +1971,25 @@ var gt = class {
|
|
|
1658
1971
|
}
|
|
1659
1972
|
this.muteChanges += 1;
|
|
1660
1973
|
let r = this.now();
|
|
1661
|
-
n ? this.isPlaying && this.mutedSinceMs === null && (this.mutedSinceMs = r) : (this.mutedSinceMs !== null && (this.mutedTotalMs += r - this.mutedSinceMs, this.mutedSinceMs = null), this.firstAudioMs === 0 && this.isPlaying && (this.firstAudioMs = Math.max(
|
|
1974
|
+
n ? this.isPlaying && this.mutedSinceMs === null && (this.mutedSinceMs = r) : (this.mutedSinceMs !== null && (this.mutedTotalMs += r - this.mutedSinceMs, this.mutedSinceMs = null), this.firstAudioMs === 0 && this.isPlaying && (this.firstAudioMs = Math.max(X, r - this.startupAnchorMs))), this.isMuted = n, this.syncActive();
|
|
1662
1975
|
}
|
|
1663
1976
|
notePresentation(e) {
|
|
1664
1977
|
this.endedFlag || e === this.presentation || (this.closePresentation(), this.presentation = e);
|
|
1665
1978
|
}
|
|
1666
1979
|
notePlayIntent() {
|
|
1667
|
-
this.endedFlag || this.startupTimeMs > 0 || (this.startupAnchorMs = this.now(), this.manifestLoadMs > 0 && (this.manifestLoadMs =
|
|
1980
|
+
this.endedFlag || this.startupTimeMs > 0 || (this.startupAnchorMs = this.now(), this.manifestLoadMs > 0 && (this.manifestLoadMs = X), this.firstPlaylistMs > 0 && (this.firstPlaylistMs = X), this.firstFragLoadMs > 0 && (this.firstFragLoadMs = X), this.drmSetupMs > 0 && (this.drmSetupMs = X));
|
|
1668
1981
|
}
|
|
1669
1982
|
noteReady() {
|
|
1670
|
-
this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(
|
|
1983
|
+
this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(X, this.now() - this.startupAnchorMs));
|
|
1984
|
+
}
|
|
1985
|
+
noteFirstPlaylist() {
|
|
1986
|
+
this.firstPlaylistMs === 0 && (this.firstPlaylistMs = Math.max(X, this.now() - this.startupAnchorMs));
|
|
1987
|
+
}
|
|
1988
|
+
noteDrmReady() {
|
|
1989
|
+
this.drmSetupMs === 0 && (this.drmSetupMs = Math.max(X, this.now() - this.startupAnchorMs));
|
|
1671
1990
|
}
|
|
1672
1991
|
noteFirstBytes() {
|
|
1673
|
-
this.sawFirstBytes = !0, this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(
|
|
1992
|
+
this.sawFirstBytes = !0, this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(X, this.now() - this.startupAnchorMs));
|
|
1674
1993
|
}
|
|
1675
1994
|
noteSeek() {
|
|
1676
1995
|
this.endedFlag || (this.seekCount += 1, this.lastSeekMs = this.now());
|
|
@@ -1689,7 +2008,7 @@ var gt = class {
|
|
|
1689
2008
|
let r = n ?? "";
|
|
1690
2009
|
if (r !== "") return /^fragLoad/i.test(r) ? this.sawFirstBytes ? "ERROR_STAGE_SEGMENT" : "ERROR_STAGE_FIRST_SEGMENT" : /^(manifest|level|audioTrack|subtitleTrack)/i.test(r) ? "ERROR_STAGE_MANIFEST" : /key|licen[cs]e/i.test(r) ? "ERROR_STAGE_DRM" : /parsing|append|buffer|remux|decrypt|media/i.test(r) ? "ERROR_STAGE_DECODE" : "ERROR_STAGE_OTHER";
|
|
1691
2010
|
if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
|
|
1692
|
-
if (
|
|
2011
|
+
if (Nt.has(e)) return "ERROR_STAGE_RESOLVE";
|
|
1693
2012
|
let i = t ?? "";
|
|
1694
2013
|
return /frag|segment/i.test(i) ? this.sawFirstBytes ? "ERROR_STAGE_SEGMENT" : "ERROR_STAGE_FIRST_SEGMENT" : /manifest|level|playlist/i.test(i) ? "ERROR_STAGE_MANIFEST" : /key|licen[cs]e/i.test(i) ? "ERROR_STAGE_DRM" : /buffer|decode|media|append/i.test(i) ? "ERROR_STAGE_DECODE" : "ERROR_STAGE_OTHER";
|
|
1695
2014
|
}
|
|
@@ -1721,7 +2040,7 @@ var gt = class {
|
|
|
1721
2040
|
let l = t.droppedFrames ?? 0;
|
|
1722
2041
|
l > this.lastDropped && (o.droppedFramesDelta = l - this.lastDropped), this.lastDropped = l;
|
|
1723
2042
|
let u = t.renditionSwitches ?? 0;
|
|
1724
|
-
u > this.lastSwitches && (o.renditionSwitchesDelta = u - this.lastSwitches), this.lastSwitches = u, n > this.lastHbPlayingMs && (o.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (o.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, i > this.lastHbRebufferMs && (o.rebufferMsDelta = Math.round(i - this.lastHbRebufferMs)), this.lastHbRebufferMs = i, this.rebufferCount > this.lastHbRebufferCount && (o.rebufferCountDelta = this.rebufferCount - this.lastHbRebufferCount), this.lastHbRebufferCount = this.rebufferCount, a > this.lastHbActiveMs && (o.activeMsDelta = Math.round(a - this.lastHbActiveMs)), this.lastHbActiveMs = a, typeof t.latencySeconds == "number" && (o.latencyMs = Math.round(t.latencySeconds * 1e3)), typeof t.targetLatencySeconds == "number" && (o.targetLatencyMs = Math.round(t.targetLatencySeconds * 1e3)), typeof t.bandwidthKbps == "number" && (o.bandwidthEstKbps = t.bandwidthKbps), typeof t.levelHeight == "number" && (o.renditionHeight = t.levelHeight), typeof t.renditionBitrateKbps == "number" && (o.renditionBitrateKbps = t.renditionBitrateKbps), t.atLiveEdge === !0 && (o.atLiveEdge = !0), typeof t.bufferedMs == "number" && t.bufferedMs > 0 && (o.bufferedMs = Math.round(t.bufferedMs)), o.playerState =
|
|
2043
|
+
u > this.lastSwitches && (o.renditionSwitchesDelta = u - this.lastSwitches), this.lastSwitches = u, n > this.lastHbPlayingMs && (o.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (o.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, i > this.lastHbRebufferMs && (o.rebufferMsDelta = Math.round(i - this.lastHbRebufferMs)), this.lastHbRebufferMs = i, this.rebufferCount > this.lastHbRebufferCount && (o.rebufferCountDelta = this.rebufferCount - this.lastHbRebufferCount), this.lastHbRebufferCount = this.rebufferCount, a > this.lastHbActiveMs && (o.activeMsDelta = Math.round(a - this.lastHbActiveMs)), this.lastHbActiveMs = a, typeof t.latencySeconds == "number" && (o.latencyMs = Math.round(t.latencySeconds * 1e3)), typeof t.targetLatencySeconds == "number" && (o.targetLatencyMs = Math.round(t.targetLatencySeconds * 1e3)), typeof t.bandwidthKbps == "number" && (o.bandwidthEstKbps = t.bandwidthKbps), typeof t.levelHeight == "number" && (o.renditionHeight = t.levelHeight), typeof t.renditionBitrateKbps == "number" && (o.renditionBitrateKbps = t.renditionBitrateKbps), t.atLiveEdge === !0 && (o.atLiveEdge = !0), typeof t.bufferedMs == "number" && t.bufferedMs > 0 && (o.bufferedMs = Math.round(t.bufferedMs)), o.playerState = Z[t.state] ?? "PLAYER_STATE_UNSPECIFIED";
|
|
1725
2044
|
let d = this.mutedTotalMs;
|
|
1726
2045
|
this.mutedSinceMs !== null && (d += e - this.mutedSinceMs), d > this.lastHbMutedMs && (o.mutedMsDelta = Math.round(d - this.lastHbMutedMs)), this.lastHbMutedMs = d;
|
|
1727
2046
|
let f = t.upshifts ?? 0;
|
|
@@ -1736,14 +2055,14 @@ var gt = class {
|
|
|
1736
2055
|
if (this.lastRequestCount = g, _ > 0) {
|
|
1737
2056
|
o.requestCountDelta = _;
|
|
1738
2057
|
let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
|
|
1739
|
-
n.length > 0 && (o.requestTimeP50Ms =
|
|
2058
|
+
n.length > 0 && (o.requestTimeP50Ms = Mt(n, 50), o.requestTimeP95Ms = Mt(n, 95));
|
|
1740
2059
|
}
|
|
1741
2060
|
typeof t.latencySeconds == "number" && typeof t.targetLatencySeconds == "number" && (o.driftMs = Math.round((t.latencySeconds - t.targetLatencySeconds) * 1e3)), typeof t.playbackRate == "number" && t.playbackRate > 0 && (o.playbackRate = t.playbackRate), t.qualityPinned === !0 && (o.qualityPinned = !0), t.cdnHost && (o.cdnHost = t.cdnHost), this.maybeEmitMediaInfo(t), this.enqueue({ heartbeat: o }), this.flush(), s > 0 && this.noteFirstBytes();
|
|
1742
2061
|
}
|
|
1743
2062
|
maybeEmitMediaInfo(e) {
|
|
1744
2063
|
if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
|
|
1745
2064
|
let t = {};
|
|
1746
|
-
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem =
|
|
2065
|
+
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = jt[e.keySystem]), e.drmSecurityLevel && (t.drmSecurityLevel = e.drmSecurityLevel), e.ladderHeights?.length && (t.ladderHeights = e.ladderHeights), e.ladderTopBitrateKbps && (t.ladderTopBitrateKbps = e.ladderTopBitrateKbps), e.lowLatency && (t.lowLatency = !0);
|
|
1747
2066
|
let n = JSON.stringify(t);
|
|
1748
2067
|
n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
|
|
1749
2068
|
}
|
|
@@ -1755,7 +2074,7 @@ var gt = class {
|
|
|
1755
2074
|
let r = this.safeSample();
|
|
1756
2075
|
r && this.maybeEmitMediaInfo(r);
|
|
1757
2076
|
let i = { reason: e }, a = r?.bytesLoaded ?? this.lastBytes;
|
|
1758
|
-
a > 0 && (i.bytesDownloadedTotal = a), this.playingTotalMs > 0 && (i.watchTimeMs = Math.round(this.playingTotalMs)), this.rebufferCount > 0 && (i.rebufferCount = this.rebufferCount), this.rebufferTotalMs > 0 && (i.rebufferTimeMs = Math.round(this.rebufferTotalMs)), this.startupTimeMs > 0 && (i.startupTimeMs = Math.round(this.startupTimeMs)), this.manifestLoadMs > 0 && (i.manifestLoadMs = Math.round(this.manifestLoadMs)), this.firstFragLoadMs > 0 && (i.firstFragLoadMs = Math.round(this.firstFragLoadMs));
|
|
2077
|
+
a > 0 && (i.bytesDownloadedTotal = a), this.playingTotalMs > 0 && (i.watchTimeMs = Math.round(this.playingTotalMs)), this.rebufferCount > 0 && (i.rebufferCount = this.rebufferCount), this.rebufferTotalMs > 0 && (i.rebufferTimeMs = Math.round(this.rebufferTotalMs)), this.startupTimeMs > 0 && (i.startupTimeMs = Math.round(this.startupTimeMs)), this.manifestLoadMs > 0 && (i.manifestLoadMs = Math.round(this.manifestLoadMs)), this.firstPlaylistMs > 0 && (i.firstPlaylistMs = Math.round(this.firstPlaylistMs)), this.firstFragLoadMs > 0 && (i.firstFragLoadMs = Math.round(this.firstFragLoadMs)), this.drmSetupMs > 0 && (i.drmSetupMs = Math.round(this.drmSetupMs));
|
|
1759
2078
|
let o = r?.licenseTimeMs ?? 0;
|
|
1760
2079
|
o > 0 && (i.licenseTimeMs = Math.round(o));
|
|
1761
2080
|
let s = r?.droppedFrames ?? this.lastDropped;
|
|
@@ -1763,9 +2082,9 @@ var gt = class {
|
|
|
1763
2082
|
let c = r?.positionMs ?? 0;
|
|
1764
2083
|
c > 0 && (i.exitPositionMs = Math.round(c)), this.activeTotalMs > 0 && (i.activeWatchTimeMs = Math.round(this.activeTotalMs)), this.mutedTotalMs > 0 && (i.mutedTimeMs = Math.round(this.mutedTotalMs));
|
|
1765
2084
|
let l = e !== "END_REASON_ENDED";
|
|
1766
|
-
l && this.lastStallMs > 0 && n - this.lastStallMs <=
|
|
2085
|
+
l && this.lastStallMs > 0 && n - this.lastStallMs <= Ot && (i.abandonAfterStallMs = Math.max(X, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Ot && (i.abandonAfterErrorMs = Math.max(X, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
|
|
1767
2086
|
let u = r?.decodedFrames ?? this.lastDecoded;
|
|
1768
|
-
u > 0 && (i.decodedFramesTotal = u), this.startupTimeMs === 0 && (i.failedStage = this.lastErrorStage ?? (this.manifestLoadMs === 0 ? "ERROR_STAGE_MANIFEST" : this.firstFragLoadMs === 0 ? "ERROR_STAGE_FIRST_SEGMENT" : "ERROR_STAGE_OTHER")), this.pending.push(this.wrap({ sessionEnd: i })), this.flush(e === "END_REASON_PAGEHIDE");
|
|
2087
|
+
u > 0 && (i.decodedFramesTotal = u), e === "END_REASON_STOPPED" && this.startupTimeMs === 0 && this.lastErrorStage === null && (e = "END_REASON_ABORTED", i.reason = e), this.startupTimeMs === 0 && e !== "END_REASON_ABORTED" && (i.failedStage = this.lastErrorStage ?? (this.manifestLoadMs === 0 ? "ERROR_STAGE_MANIFEST" : this.firstFragLoadMs === 0 ? "ERROR_STAGE_FIRST_SEGMENT" : "ERROR_STAGE_OTHER")), this.pending.push(this.wrap({ sessionEnd: i })), this.flush(e === "END_REASON_PAGEHIDE");
|
|
1769
2088
|
}
|
|
1770
2089
|
safeSample() {
|
|
1771
2090
|
try {
|
|
@@ -1783,7 +2102,7 @@ var gt = class {
|
|
|
1783
2102
|
};
|
|
1784
2103
|
}
|
|
1785
2104
|
enqueue(e) {
|
|
1786
|
-
for (this.pending.push(this.wrap(e)); this.pending.length >
|
|
2105
|
+
for (this.pending.push(this.wrap(e)); this.pending.length > Et;) {
|
|
1787
2106
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
1788
2107
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
1789
2108
|
}
|
|
@@ -1806,7 +2125,7 @@ var gt = class {
|
|
|
1806
2125
|
};
|
|
1807
2126
|
//#endregion
|
|
1808
2127
|
//#region src/core/environment.ts
|
|
1809
|
-
function
|
|
2128
|
+
function zt() {
|
|
1810
2129
|
if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
|
|
1811
2130
|
let e;
|
|
1812
2131
|
try {
|
|
@@ -1831,14 +2150,14 @@ function _t() {
|
|
|
1831
2150
|
integration: "INTEGRATION_KIND_IFRAME"
|
|
1832
2151
|
};
|
|
1833
2152
|
}
|
|
1834
|
-
function
|
|
2153
|
+
function Bt() {
|
|
1835
2154
|
if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
|
|
1836
2155
|
let e = navigator.userAgentData, t = e?.platform ?? "";
|
|
1837
2156
|
if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
|
|
1838
2157
|
let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
|
|
1839
2158
|
return e?.mobile ?? (typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1 && n > 0 && n < 900) ? n >= 600 ? "DEVICE_CLASS_TABLET" : "DEVICE_CLASS_PHONE" : e || n >= 900 || /mac|win|linux|chrome os/i.test(t) ? "DEVICE_CLASS_DESKTOP" : "DEVICE_CLASS_OTHER";
|
|
1840
2159
|
}
|
|
1841
|
-
function
|
|
2160
|
+
function Vt() {
|
|
1842
2161
|
let e = typeof navigator < "u" ? navigator.connection : void 0;
|
|
1843
2162
|
if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
|
|
1844
2163
|
let t = {
|
|
@@ -1857,17 +2176,17 @@ function yt() {
|
|
|
1857
2176
|
}
|
|
1858
2177
|
return typeof e.downlink == "number" && e.downlink > 0 && (i.downlinkKbps = Math.round(e.downlink * 1e3)), typeof e.rtt == "number" && e.rtt > 0 && (i.rttMs = Math.round(e.rtt)), e.saveData && (i.saveData = !0), i;
|
|
1859
2178
|
}
|
|
1860
|
-
function
|
|
1861
|
-
let t =
|
|
1862
|
-
deviceClass:
|
|
2179
|
+
function Ht(e) {
|
|
2180
|
+
let t = zt(), n = {
|
|
2181
|
+
deviceClass: Bt(),
|
|
1863
2182
|
integration: t.integration,
|
|
1864
|
-
...
|
|
2183
|
+
...Vt()
|
|
1865
2184
|
};
|
|
1866
2185
|
t.host && (n.host = t.host), typeof screen < "u" && screen.width > 0 && (n.screenWidth = screen.width, n.screenHeight = screen.height), typeof window < "u" && window.devicePixelRatio > 0 && (n.devicePixelRatio = Math.round(window.devicePixelRatio * 100) / 100);
|
|
1867
2186
|
let r = e.getBoundingClientRect?.();
|
|
1868
2187
|
return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
|
|
1869
2188
|
}
|
|
1870
|
-
async function
|
|
2189
|
+
async function Ut() {
|
|
1871
2190
|
let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
|
|
1872
2191
|
if (!e?.getHighEntropyValues) return {};
|
|
1873
2192
|
try {
|
|
@@ -1879,7 +2198,7 @@ async function xt() {
|
|
|
1879
2198
|
}
|
|
1880
2199
|
//#endregion
|
|
1881
2200
|
//#region src/core/version.ts
|
|
1882
|
-
var
|
|
2201
|
+
var Wt = "2.11.1", Gt = {
|
|
1883
2202
|
accent: "#E1B600",
|
|
1884
2203
|
accentText: "#1B1C23",
|
|
1885
2204
|
background: "#0e0f13",
|
|
@@ -1890,7 +2209,7 @@ var St = "2.10.0", Ct = {
|
|
|
1890
2209
|
border: "rgba(255, 255, 255, 0.1)",
|
|
1891
2210
|
radius: "8px",
|
|
1892
2211
|
fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
|
|
1893
|
-
},
|
|
2212
|
+
}, Kt = {
|
|
1894
2213
|
accent: "--havik-accent",
|
|
1895
2214
|
accentText: "--havik-accent-text",
|
|
1896
2215
|
background: "--havik-bg",
|
|
@@ -1902,25 +2221,25 @@ var St = "2.10.0", Ct = {
|
|
|
1902
2221
|
radius: "--havik-radius",
|
|
1903
2222
|
fontFamily: "--havik-font"
|
|
1904
2223
|
};
|
|
1905
|
-
function
|
|
2224
|
+
function qt(e, t) {
|
|
1906
2225
|
let n = {
|
|
1907
|
-
...
|
|
2226
|
+
...Gt,
|
|
1908
2227
|
...t
|
|
1909
2228
|
};
|
|
1910
|
-
for (let t of Object.keys(
|
|
2229
|
+
for (let t of Object.keys(Kt)) e.style.setProperty(Kt[t], n[t]);
|
|
1911
2230
|
n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
|
|
1912
2231
|
}
|
|
1913
2232
|
//#endregion
|
|
1914
2233
|
//#region src/ui/styles.ts
|
|
1915
|
-
var
|
|
1916
|
-
function
|
|
1917
|
-
if (e.getElementById(
|
|
2234
|
+
var Jt = "havik-player-styles", Yt = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n/* Absolutely centred, NOT a flex sibling of .havik-center: the hidden center\n button (.havik-gone) still occupies its 74px in the row, which pushed an\n in-flow spinner 37px right of centre. */\n.havik-spinner{position:absolute;inset:0;margin:auto;width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n";
|
|
2235
|
+
function Xt(e = document) {
|
|
2236
|
+
if (e.getElementById(Jt)) return;
|
|
1918
2237
|
let t = e.createElement("style");
|
|
1919
|
-
t.id =
|
|
2238
|
+
t.id = Jt, t.textContent = Yt, e.head.appendChild(t);
|
|
1920
2239
|
}
|
|
1921
2240
|
//#endregion
|
|
1922
2241
|
//#region src/ui/icons.ts
|
|
1923
|
-
var
|
|
2242
|
+
var Zt = {
|
|
1924
2243
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
1925
2244
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
1926
2245
|
volumeHigh: "<path d=\"M3 10v4h4l5 5V5L7 10H3zm13.5 2a4.5 4.5 0 0 0-2.5-4v8a4.5 4.5 0 0 0 2.5-4zm-2.5-9v2.06A7 7 0 0 1 14 19v2a9 9 0 0 0 0-18z\"/>",
|
|
@@ -1933,21 +2252,21 @@ var kt = {
|
|
|
1933
2252
|
liveDot: "<circle cx=\"12\" cy=\"12\" r=\"6\"/>",
|
|
1934
2253
|
retry: "<path d=\"M17.65 6.35A8 8 0 1 0 19.73 13h-2.08A6 6 0 1 1 12 6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z\"/>"
|
|
1935
2254
|
};
|
|
1936
|
-
function
|
|
1937
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
2255
|
+
function Q(e) {
|
|
2256
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Zt[e]}</svg>`;
|
|
1938
2257
|
}
|
|
1939
2258
|
//#endregion
|
|
1940
2259
|
//#region src/ui/controls.ts
|
|
1941
|
-
var
|
|
2260
|
+
var Qt = 3e3, $t = /* @__PURE__ */ new Set([
|
|
1942
2261
|
"GONE",
|
|
1943
2262
|
"NOT_FOUND",
|
|
1944
2263
|
"INVALID_URN",
|
|
1945
2264
|
"UNAUTHORIZED"
|
|
1946
2265
|
]);
|
|
1947
|
-
function
|
|
1948
|
-
return new
|
|
2266
|
+
function en(e) {
|
|
2267
|
+
return new tn(e);
|
|
1949
2268
|
}
|
|
1950
|
-
var
|
|
2269
|
+
var tn = class {
|
|
1951
2270
|
root;
|
|
1952
2271
|
video;
|
|
1953
2272
|
player;
|
|
@@ -1989,7 +2308,7 @@ var Nt = class {
|
|
|
1989
2308
|
scrubbing = !1;
|
|
1990
2309
|
offFns = [];
|
|
1991
2310
|
constructor(e) {
|
|
1992
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
2311
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Qt, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, Xt(this.doc), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
|
|
1993
2312
|
let t = (e, t, n) => {
|
|
1994
2313
|
let r = this.doc.createElement(e);
|
|
1995
2314
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -2000,12 +2319,12 @@ var Nt = class {
|
|
|
2000
2319
|
"aria-label": r,
|
|
2001
2320
|
title: r
|
|
2002
2321
|
});
|
|
2003
|
-
return i.innerHTML =
|
|
2322
|
+
return i.innerHTML = Q(n), i;
|
|
2004
2323
|
};
|
|
2005
2324
|
this.overlay = t("div", "havik-overlay"), this.center = t("button", "havik-center", {
|
|
2006
2325
|
type: "button",
|
|
2007
2326
|
"aria-label": "Play"
|
|
2008
|
-
}), this.center.innerHTML =
|
|
2327
|
+
}), this.center.innerHTML = Q("play"), this.spinner = t("div", "havik-spinner"), this.spinner.style.display = "none", this.overlay.append(this.center, this.spinner), this.gradient = t("div", "havik-gradient"), this.bar = t("div", "havik-bar"), this.seek = t("div", "havik-seek", {
|
|
2009
2328
|
role: "slider",
|
|
2010
2329
|
"aria-label": "Seek",
|
|
2011
2330
|
"aria-valuemin": "0",
|
|
@@ -2023,7 +2342,7 @@ var Nt = class {
|
|
|
2023
2342
|
"aria-label": "Volume"
|
|
2024
2343
|
});
|
|
2025
2344
|
let a = t("div", "havik-vol");
|
|
2026
|
-
a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML =
|
|
2345
|
+
a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML = Q("liveDot");
|
|
2027
2346
|
let o = this.doc.createElement("span");
|
|
2028
2347
|
o.textContent = "LIVE", this.liveGo = t("button", "havik-live__go", { type: "button" }), this.liveGo.textContent = "Go live", this.live.append(o, this.liveGo), this.time = t("div", "havik-time"), this.time.textContent = "0:00", this.time.style.display = "none";
|
|
2029
2348
|
let s = t("div", "havik-spacer");
|
|
@@ -2077,12 +2396,12 @@ var Nt = class {
|
|
|
2077
2396
|
}
|
|
2078
2397
|
if (e === "preplay") {
|
|
2079
2398
|
let e = this.doc.createElement("button");
|
|
2080
|
-
e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML =
|
|
2399
|
+
e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = Q("play"), e.addEventListener("click", () => void this.player.play()), n.append(e);
|
|
2081
2400
|
} else {
|
|
2082
2401
|
let r = this.doc.createElement("div");
|
|
2083
|
-
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError &&
|
|
2402
|
+
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !$t.has(this.lastError.code)) {
|
|
2084
2403
|
let e = this.doc.createElement("button");
|
|
2085
|
-
e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${
|
|
2404
|
+
e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${Q("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), n.append(e);
|
|
2086
2405
|
}
|
|
2087
2406
|
}
|
|
2088
2407
|
this.root.append(n), this.statusBox = n, this.show();
|
|
@@ -2121,11 +2440,11 @@ var Nt = class {
|
|
|
2121
2440
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
2122
2441
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
2123
2442
|
}
|
|
2124
|
-
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${
|
|
2443
|
+
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${nn(this.video.currentTime)} / ${nn(this.video.duration)}`);
|
|
2125
2444
|
}
|
|
2126
2445
|
syncLive() {
|
|
2127
2446
|
let e = this.player.getStats(), t = e.isLive !== !1;
|
|
2128
|
-
this.live.style.display = t ? "" : "none", this.time.style.display = t ? "none" : "", this.live.classList.toggle("is-live", e.atLiveEdge !== !1 && t);
|
|
2447
|
+
this.live.style.display = t ? "" : "none", this.time.style.display = t ? "none" : "", this.seek.style.display = t ? "none" : "", this.live.classList.toggle("is-live", e.atLiveEdge !== !1 && t);
|
|
2129
2448
|
}
|
|
2130
2449
|
onSeekDown(e) {
|
|
2131
2450
|
let t = this.seekableRange();
|
|
@@ -2171,17 +2490,17 @@ var Nt = class {
|
|
|
2171
2490
|
renderQualityMenu() {
|
|
2172
2491
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
2173
2492
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
2174
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
2493
|
+
for (let n of e) this.menu.append(this.menuItem(rn(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
2175
2494
|
}
|
|
2176
2495
|
renderAudioMenu() {
|
|
2177
2496
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
2178
2497
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
2179
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2498
|
+
for (let t of e) this.menu.append(this.menuItem(an(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
2180
2499
|
}
|
|
2181
2500
|
renderCcMenu() {
|
|
2182
2501
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
2183
2502
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
2184
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2503
|
+
for (let t of e) this.menu.append(this.menuItem(on(t), !1, () => this.player.setTextTrack(t.id)));
|
|
2185
2504
|
}
|
|
2186
2505
|
onTracksChanged() {
|
|
2187
2506
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -2201,11 +2520,11 @@ var Nt = class {
|
|
|
2201
2520
|
}
|
|
2202
2521
|
async toggleFullscreen() {
|
|
2203
2522
|
try {
|
|
2204
|
-
|
|
2523
|
+
w(this.video, this.root) ? await E(this.video, this.root) : await T(this.video, this.root);
|
|
2205
2524
|
} catch {}
|
|
2206
2525
|
}
|
|
2207
2526
|
syncFullscreen() {
|
|
2208
|
-
let e =
|
|
2527
|
+
let e = w(this.video, this.root);
|
|
2209
2528
|
this.setIcon(this.fsBtn, e ? "fullscreenExit" : "fullscreen"), this.fsBtn.setAttribute("aria-label", e ? "Exit fullscreen" : "Fullscreen");
|
|
2210
2529
|
}
|
|
2211
2530
|
poke() {
|
|
@@ -2264,7 +2583,7 @@ var Nt = class {
|
|
|
2264
2583
|
}
|
|
2265
2584
|
}
|
|
2266
2585
|
setIcon(e, t) {
|
|
2267
|
-
e.innerHTML =
|
|
2586
|
+
e.innerHTML = Q(t);
|
|
2268
2587
|
}
|
|
2269
2588
|
destroy() {
|
|
2270
2589
|
this.hideTimer && clearTimeout(this.hideTimer);
|
|
@@ -2281,41 +2600,41 @@ var Nt = class {
|
|
|
2281
2600
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
2282
2601
|
}
|
|
2283
2602
|
};
|
|
2284
|
-
function
|
|
2603
|
+
function nn(e) {
|
|
2285
2604
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
2286
2605
|
let t = Math.floor(e % 60), n = Math.floor(e / 60 % 60), r = Math.floor(e / 3600), i = r > 0 ? String(n).padStart(2, "0") : String(n), a = String(t).padStart(2, "0");
|
|
2287
2606
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
2288
2607
|
}
|
|
2289
|
-
function
|
|
2608
|
+
function rn(e) {
|
|
2290
2609
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
2291
2610
|
}
|
|
2292
|
-
function
|
|
2611
|
+
function an(e) {
|
|
2293
2612
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2294
2613
|
}
|
|
2295
|
-
function
|
|
2614
|
+
function on(e) {
|
|
2296
2615
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2297
2616
|
}
|
|
2298
2617
|
//#endregion
|
|
2299
2618
|
//#region src/managed/index.ts
|
|
2300
|
-
var
|
|
2301
|
-
function
|
|
2619
|
+
var sn = 6e3, cn = 45e3, ln = 2e3, un = 3, dn = 2e3, fn = 48e4;
|
|
2620
|
+
function pn(e) {
|
|
2302
2621
|
if (e.env !== void 0 && e.baseUrl !== void 0) throw new n("INTERNAL", 0, `createPlayer: pass env OR baseUrl, not both (got env=${JSON.stringify(e.env)} and baseUrl=${JSON.stringify(e.baseUrl)})`);
|
|
2303
|
-
if (e.env !== void 0) return
|
|
2622
|
+
if (e.env !== void 0) return U(e.env);
|
|
2304
2623
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
|
|
2305
2624
|
return e.baseUrl;
|
|
2306
2625
|
}
|
|
2307
|
-
async function
|
|
2626
|
+
async function mn(e) {
|
|
2308
2627
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
2309
|
-
let t =
|
|
2628
|
+
let t = pn(e);
|
|
2310
2629
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
2311
2630
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
2312
|
-
let r = new
|
|
2631
|
+
let r = new hn({
|
|
2313
2632
|
...e,
|
|
2314
2633
|
baseUrl: t
|
|
2315
2634
|
});
|
|
2316
2635
|
return await r.start(), r;
|
|
2317
2636
|
}
|
|
2318
|
-
var
|
|
2637
|
+
var hn = class {
|
|
2319
2638
|
opts;
|
|
2320
2639
|
abort = new AbortController();
|
|
2321
2640
|
listeners = {};
|
|
@@ -2382,7 +2701,7 @@ var Gt = class {
|
|
|
2382
2701
|
};
|
|
2383
2702
|
}
|
|
2384
2703
|
beginArming(e, t, n = !1) {
|
|
2385
|
-
let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ??
|
|
2704
|
+
let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? O(this.opts.baseUrl);
|
|
2386
2705
|
r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
|
|
2387
2706
|
}
|
|
2388
2707
|
beginArmingByPolling(e) {
|
|
@@ -2403,7 +2722,7 @@ var Gt = class {
|
|
|
2403
2722
|
setTimeout(() => {
|
|
2404
2723
|
a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
2405
2724
|
phase: i ? "unavailable" : "tooEarly",
|
|
2406
|
-
retryInMs:
|
|
2725
|
+
retryInMs: cn,
|
|
2407
2726
|
attempt: 1,
|
|
2408
2727
|
elapsedMs: 0,
|
|
2409
2728
|
...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
|
|
@@ -2442,13 +2761,13 @@ var Gt = class {
|
|
|
2442
2761
|
!a && !p() && h();
|
|
2443
2762
|
}, e);
|
|
2444
2763
|
};
|
|
2445
|
-
_(
|
|
2764
|
+
_(sn), this.armingSub = D({
|
|
2446
2765
|
eventsBaseUrl: t,
|
|
2447
2766
|
matchUrn: this.opts.matchUrn,
|
|
2448
2767
|
credential: this.opts.credential,
|
|
2449
|
-
onAlive: () => _(
|
|
2768
|
+
onAlive: () => _(cn),
|
|
2450
2769
|
onState: (e) => {
|
|
2451
|
-
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() *
|
|
2770
|
+
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * ln);
|
|
2452
2771
|
},
|
|
2453
2772
|
onError: () => h()
|
|
2454
2773
|
});
|
|
@@ -2471,7 +2790,7 @@ var Gt = class {
|
|
|
2471
2790
|
let n = await s(this.opts.credential);
|
|
2472
2791
|
if (this.destroyed || t !== this.loadGen) return;
|
|
2473
2792
|
this.setState("loading");
|
|
2474
|
-
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a =
|
|
2793
|
+
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = Be(this.opts.video, (e) => {
|
|
2475
2794
|
this._state !== "ended" && this._state !== "error" && this.setState(e);
|
|
2476
2795
|
});
|
|
2477
2796
|
if (await i.load(), this.destroyed || t !== this.loadGen) {
|
|
@@ -2493,23 +2812,23 @@ var Gt = class {
|
|
|
2493
2812
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
|
|
2494
2813
|
let i = e.analytics?.sid;
|
|
2495
2814
|
if (!i) return;
|
|
2496
|
-
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } =
|
|
2815
|
+
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = Lt(this.opts.baseUrl, a);
|
|
2497
2816
|
if (!o) {
|
|
2498
2817
|
s && setTimeout(() => {
|
|
2499
2818
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
|
|
2500
2819
|
}, 0);
|
|
2501
2820
|
return;
|
|
2502
2821
|
}
|
|
2503
|
-
let c = this.opts.video, l = new
|
|
2822
|
+
let c = this.opts.video, l = new Rt({
|
|
2504
2823
|
endpoint: o,
|
|
2505
2824
|
sid: i,
|
|
2506
2825
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
2507
|
-
sdkVersion:
|
|
2508
|
-
environment:
|
|
2826
|
+
sdkVersion: Wt,
|
|
2827
|
+
environment: Ht(c),
|
|
2509
2828
|
idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
|
|
2510
2829
|
onIdle: () => this.onAnalyticsIdle(t),
|
|
2511
2830
|
sample: () => {
|
|
2512
|
-
let e = this.engine?.getStats() ??
|
|
2831
|
+
let e = this.engine?.getStats() ?? W, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
|
|
2513
2832
|
return {
|
|
2514
2833
|
...e,
|
|
2515
2834
|
bufferedMs: Math.round(t * 1e3),
|
|
@@ -2523,7 +2842,7 @@ var Gt = class {
|
|
|
2523
2842
|
let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
|
|
2524
2843
|
c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
|
|
2525
2844
|
c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
|
|
2526
|
-
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()),
|
|
2845
|
+
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), Ut().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
|
|
2527
2846
|
}
|
|
2528
2847
|
currentPresentation() {
|
|
2529
2848
|
let e = this.opts.video;
|
|
@@ -2538,24 +2857,34 @@ var Gt = class {
|
|
|
2538
2857
|
video: this.opts.video,
|
|
2539
2858
|
descriptor: e,
|
|
2540
2859
|
credential: t,
|
|
2541
|
-
deviceId:
|
|
2860
|
+
deviceId: j(),
|
|
2542
2861
|
userId: this.opts.userId,
|
|
2543
2862
|
lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
|
|
2544
2863
|
snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
|
|
2864
|
+
mediaDuringKey: this.opts.mediaDuringKey,
|
|
2545
2865
|
debug: this.opts.debug,
|
|
2546
2866
|
deferLoad: r,
|
|
2547
2867
|
hlsConfig: i,
|
|
2548
2868
|
emit: (e) => this.onEngineEvent(e)
|
|
2549
2869
|
}, o = this.opts.engine ?? "auto";
|
|
2550
|
-
if (o === "native") return new
|
|
2551
|
-
if (o === "hls") return new
|
|
2552
|
-
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl &&
|
|
2553
|
-
if (
|
|
2554
|
-
if (
|
|
2870
|
+
if (o === "native") return new Y(a);
|
|
2871
|
+
if (o === "hls") return new St(a);
|
|
2872
|
+
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && q(this.opts.video) && J()) return new Y(a);
|
|
2873
|
+
if (Qe()) return new St(a);
|
|
2874
|
+
if (q(this.opts.video)) return new Y(a);
|
|
2555
2875
|
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
2556
2876
|
}
|
|
2557
2877
|
onEngineEvent(e) {
|
|
2558
2878
|
if (!this.destroyed) switch (e.type) {
|
|
2879
|
+
case "firstPlaylist":
|
|
2880
|
+
this.analyticsSession?.noteFirstPlaylist();
|
|
2881
|
+
break;
|
|
2882
|
+
case "firstBytes":
|
|
2883
|
+
this.analyticsSession?.noteFirstBytes();
|
|
2884
|
+
break;
|
|
2885
|
+
case "drmReady":
|
|
2886
|
+
this.analyticsSession?.noteDrmReady();
|
|
2887
|
+
break;
|
|
2559
2888
|
case "ready":
|
|
2560
2889
|
this.analyticsSession?.noteReady(), this.emit("ready"), (this.opts.autoplay !== !1 || this.playRequested) && this.play();
|
|
2561
2890
|
break;
|
|
@@ -2579,11 +2908,11 @@ var Gt = class {
|
|
|
2579
2908
|
}
|
|
2580
2909
|
startLiveState(e) {
|
|
2581
2910
|
if (this.opts.liveStateEvents === !1) return;
|
|
2582
|
-
let t = this.opts.eventsBaseUrl ??
|
|
2911
|
+
let t = this.opts.eventsBaseUrl ?? O(this.opts.baseUrl);
|
|
2583
2912
|
if (!t) return;
|
|
2584
2913
|
this.closeLiveState();
|
|
2585
2914
|
let r = 0, i = !1;
|
|
2586
|
-
this.liveStateSub =
|
|
2915
|
+
this.liveStateSub = D({
|
|
2587
2916
|
eventsBaseUrl: t,
|
|
2588
2917
|
matchUrn: this.opts.matchUrn,
|
|
2589
2918
|
credential: this.opts.credential,
|
|
@@ -2594,7 +2923,7 @@ var Gt = class {
|
|
|
2594
2923
|
r = 0, i = !1;
|
|
2595
2924
|
},
|
|
2596
2925
|
onError: () => {
|
|
2597
|
-
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >=
|
|
2926
|
+
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= un && (i = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${r} attempts — end-of-stream detection degraded to the HLS staleness watchdog. Check the events host, the api-key's allowed origins, and CSP connect-src.`))));
|
|
2598
2927
|
}
|
|
2599
2928
|
});
|
|
2600
2929
|
}
|
|
@@ -2616,7 +2945,7 @@ var Gt = class {
|
|
|
2616
2945
|
scheduleRejoin(e) {
|
|
2617
2946
|
this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
|
|
2618
2947
|
this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
|
|
2619
|
-
}, Math.random() *
|
|
2948
|
+
}, Math.random() * ln));
|
|
2620
2949
|
}
|
|
2621
2950
|
cancelRejoin() {
|
|
2622
2951
|
this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
|
|
@@ -2640,7 +2969,7 @@ var Gt = class {
|
|
|
2640
2969
|
}
|
|
2641
2970
|
t.controls = !1;
|
|
2642
2971
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
2643
|
-
r && r.insertBefore(n, t), n.appendChild(t),
|
|
2972
|
+
r && r.insertBefore(n, t), n.appendChild(t), qt(n, this.opts.theme), this.container = n, this.controlBar = en({
|
|
2644
2973
|
root: n,
|
|
2645
2974
|
video: t,
|
|
2646
2975
|
player: this,
|
|
@@ -2670,7 +2999,7 @@ var Gt = class {
|
|
|
2670
2999
|
}
|
|
2671
3000
|
startStats() {
|
|
2672
3001
|
this.stopStats();
|
|
2673
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
3002
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? dn);
|
|
2674
3003
|
this.statsTimer = setInterval(() => {
|
|
2675
3004
|
if (!this.engine) return;
|
|
2676
3005
|
let e = this.engine.getStats();
|
|
@@ -2682,7 +3011,7 @@ var Gt = class {
|
|
|
2682
3011
|
}
|
|
2683
3012
|
scheduleLicenseRefresh() {
|
|
2684
3013
|
this.stopRefresh();
|
|
2685
|
-
let e = this.opts.licenseRefreshMs ??
|
|
3014
|
+
let e = this.opts.licenseRefreshMs ?? fn;
|
|
2686
3015
|
e && this._descriptor?.drmEnabled && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
2687
3016
|
}
|
|
2688
3017
|
stopRefresh() {
|
|
@@ -2727,7 +3056,7 @@ var Gt = class {
|
|
|
2727
3056
|
this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
|
|
2728
3057
|
}
|
|
2729
3058
|
getStats() {
|
|
2730
|
-
return this.engine?.getStats() ??
|
|
3059
|
+
return this.engine?.getStats() ?? W;
|
|
2731
3060
|
}
|
|
2732
3061
|
getQualityLevels() {
|
|
2733
3062
|
return this.engine?.getQualityLevels() ?? [];
|
|
@@ -2766,10 +3095,10 @@ var Gt = class {
|
|
|
2766
3095
|
e.pictureInPictureElement === this.opts.video && typeof e.exitPictureInPicture == "function" && await e.exitPictureInPicture();
|
|
2767
3096
|
}
|
|
2768
3097
|
async enterFullscreen() {
|
|
2769
|
-
return !this.destroyed &&
|
|
3098
|
+
return !this.destroyed && T(this.opts.video, this.container ?? void 0);
|
|
2770
3099
|
}
|
|
2771
3100
|
async exitFullscreen() {
|
|
2772
|
-
await
|
|
3101
|
+
await E(this.opts.video, this.container ?? void 0);
|
|
2773
3102
|
}
|
|
2774
3103
|
retry() {
|
|
2775
3104
|
return this.reload();
|
|
@@ -2837,7 +3166,7 @@ function $(e) {
|
|
|
2837
3166
|
}
|
|
2838
3167
|
//#endregion
|
|
2839
3168
|
//#region src/embed/host.ts
|
|
2840
|
-
function
|
|
3169
|
+
function gn(e) {
|
|
2841
3170
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
2842
3171
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
2843
3172
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -2896,15 +3225,15 @@ function Kt(e) {
|
|
|
2896
3225
|
}
|
|
2897
3226
|
//#endregion
|
|
2898
3227
|
//#region src/embed/page.ts
|
|
2899
|
-
var
|
|
2900
|
-
function
|
|
3228
|
+
var _n = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
3229
|
+
function vn(e) {
|
|
2901
3230
|
if (typeof e == "boolean") return e;
|
|
2902
3231
|
if (typeof e == "object" && e) {
|
|
2903
3232
|
let t = e.endpoint;
|
|
2904
3233
|
return typeof t == "string" ? { endpoint: t } : {};
|
|
2905
3234
|
}
|
|
2906
3235
|
}
|
|
2907
|
-
function
|
|
3236
|
+
function yn() {
|
|
2908
3237
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
2909
3238
|
if (e) return {
|
|
2910
3239
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -2914,7 +3243,7 @@ function Yt() {
|
|
|
2914
3243
|
autoplay: e.autoplay ?? !0,
|
|
2915
3244
|
muted: e.muted ?? !0,
|
|
2916
3245
|
waitForLive: e.waitForLive ?? !0,
|
|
2917
|
-
analytics:
|
|
3246
|
+
analytics: vn(e.analytics)
|
|
2918
3247
|
};
|
|
2919
3248
|
let t = new URLSearchParams(location.search);
|
|
2920
3249
|
return {
|
|
@@ -2927,9 +3256,9 @@ function Yt() {
|
|
|
2927
3256
|
waitForLive: !0
|
|
2928
3257
|
};
|
|
2929
3258
|
}
|
|
2930
|
-
async function
|
|
2931
|
-
let e =
|
|
2932
|
-
|
|
3259
|
+
async function bn() {
|
|
3260
|
+
let e = yn();
|
|
3261
|
+
Sn();
|
|
2933
3262
|
let t = document.createElement("video");
|
|
2934
3263
|
t.setAttribute("playsinline", ""), t.muted = e.muted ?? !0, t.style.cssText = "width:100%;height:100%;object-fit:contain;background:#000;aspect-ratio:auto", document.body.appendChild(t);
|
|
2935
3264
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -2984,12 +3313,12 @@ async function Xt() {
|
|
|
2984
3313
|
code: e.code,
|
|
2985
3314
|
message: e.message
|
|
2986
3315
|
})), e.on("autoplayblocked", () => {
|
|
2987
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
3316
|
+
i({ type: "oddin:autoplayblocked" }), xn(t, e);
|
|
2988
3317
|
});
|
|
2989
3318
|
}, s = async (r) => {
|
|
2990
3319
|
a?.destroy(), a = null;
|
|
2991
3320
|
try {
|
|
2992
|
-
let n = await
|
|
3321
|
+
let n = await mn({
|
|
2993
3322
|
video: t,
|
|
2994
3323
|
baseUrl: e.baseUrl,
|
|
2995
3324
|
matchUrn: r,
|
|
@@ -3051,7 +3380,7 @@ async function Xt() {
|
|
|
3051
3380
|
a?.retry();
|
|
3052
3381
|
break;
|
|
3053
3382
|
case "oddin:load":
|
|
3054
|
-
typeof e.matchUrn == "string" &&
|
|
3383
|
+
typeof e.matchUrn == "string" && _n.test(e.matchUrn) && s(e.matchUrn);
|
|
3055
3384
|
break;
|
|
3056
3385
|
case "oddin:destroy": c();
|
|
3057
3386
|
}
|
|
@@ -3063,18 +3392,18 @@ async function Xt() {
|
|
|
3063
3392
|
protocol: 1
|
|
3064
3393
|
});
|
|
3065
3394
|
}
|
|
3066
|
-
function
|
|
3395
|
+
function xn(e, t) {
|
|
3067
3396
|
if (document.getElementById("havik-tap")) return;
|
|
3068
3397
|
let n = document.createElement("button");
|
|
3069
3398
|
n.id = "havik-tap", n.textContent = "▶ Tap to play", n.style.cssText = "position:fixed;inset:0;width:100%;height:100%;border:0;background:rgba(0,0,0,.55);color:#fff;font:600 18px system-ui,sans-serif;cursor:pointer;z-index:9", n.addEventListener("click", () => {
|
|
3070
3399
|
n.remove(), t.play();
|
|
3071
3400
|
}), document.body.appendChild(n);
|
|
3072
3401
|
}
|
|
3073
|
-
function
|
|
3402
|
+
function Sn() {
|
|
3074
3403
|
let e = document.createElement("style");
|
|
3075
3404
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
3076
3405
|
}
|
|
3077
3406
|
//#endregion
|
|
3078
|
-
export {
|
|
3407
|
+
export { Gt as ODDIN_THEME, n as PlaybackError, qt as applyTheme, U as baseUrlForEnv, bn as bootEmbed, ye as clearDeviceId, mn as createPlayer, O as deriveEventsBaseUrl, Fe as detectDrmSupport, T as enterVideoFullscreen, E as exitVideoFullscreen, fe as fetchCatalog, me as fetchTournament, ge as flattenMatches, j as getDeviceId, Le as isLowLatencyManifest, $ as isOddinMessage, xe as licenseRequestHeaders, gn as mountEmbed, v as pollToLive, b as resolveStream, D as subscribeLiveState, w as videoFullscreenActive, _e as watchStatus };
|
|
3079
3408
|
|
|
3080
3409
|
//# sourceMappingURL=index.js.map
|