@oddin-gg/havik-player 1.15.1 → 1.16.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/README.md +27 -13
- package/dist/havik-player.global.js +17 -17
- 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 +41 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +202 -173
- package/dist/index.js.map +1 -1
- package/docs/API.md +1265 -0
- package/docs/STABILITY.md +56 -0
- package/embed/index.html +1 -1
- package/examples/vanilla.html +1 -1
- package/package.json +9 -1
package/dist/index.js
CHANGED
|
@@ -110,16 +110,16 @@ function ne(e) {
|
|
|
110
110
|
let t = Date.parse(e);
|
|
111
111
|
return Number.isFinite(t) ? t : void 0;
|
|
112
112
|
}
|
|
113
|
-
function
|
|
113
|
+
function re(e, t, n) {
|
|
114
114
|
return Math.min(n, Math.max(t, e));
|
|
115
115
|
}
|
|
116
|
-
function
|
|
116
|
+
function ie(e) {
|
|
117
117
|
return Math.round(e * (1 + .15 * Math.random()));
|
|
118
118
|
}
|
|
119
|
-
function
|
|
119
|
+
function ae(e, t, n, r) {
|
|
120
120
|
let i = r ?? n.kickoffMs, a = i == null ? void 0 : Math.max(0, i - t), o = Math.max(n.floorMs, e ?? 0);
|
|
121
121
|
if (a == null || a <= n.imminentMs) return {
|
|
122
|
-
delay:
|
|
122
|
+
delay: re(e ?? n.floorMs, o, n.ceilMs),
|
|
123
123
|
ttkMs: a
|
|
124
124
|
};
|
|
125
125
|
let s = Math.min(Math.floor(a / 10), n.sanityFloorMs, a);
|
|
@@ -128,7 +128,7 @@ function ie(e, t, n, r) {
|
|
|
128
128
|
ttkMs: a
|
|
129
129
|
};
|
|
130
130
|
}
|
|
131
|
-
function
|
|
131
|
+
function oe(e, t) {
|
|
132
132
|
return new Promise((r, i) => {
|
|
133
133
|
if (t?.aborted) {
|
|
134
134
|
i(new n("ABORTED", 0, "wait-for-live aborted"));
|
|
@@ -142,7 +142,7 @@ function ae(e, t) {
|
|
|
142
142
|
t?.addEventListener("abort", a, { once: !0 });
|
|
143
143
|
});
|
|
144
144
|
}
|
|
145
|
-
async function
|
|
145
|
+
async function _(e, t, r) {
|
|
146
146
|
let i = te(t), a = Date.now(), s = i.timeoutMs == null ? Infinity : a + i.timeoutMs, c = 0, l;
|
|
147
147
|
for (;;) {
|
|
148
148
|
if (r?.aborted) throw new n("ABORTED", 0, "wait-for-live aborted");
|
|
@@ -151,8 +151,8 @@ async function v(e, t, r) {
|
|
|
151
151
|
} catch (e) {
|
|
152
152
|
if (!(e instanceof n) || !o(e.code)) throw e;
|
|
153
153
|
c += 1, e.liveStartsAtMs != null && Number.isFinite(e.liveStartsAtMs) && (l = e.liveStartsAtMs);
|
|
154
|
-
let t = Date.now(), u =
|
|
155
|
-
if (i.jitter && (f =
|
|
154
|
+
let t = Date.now(), u = ae(e.retryAfterMs, t, i, l), d = u.ttkMs, f = u.delay;
|
|
155
|
+
if (i.jitter && (f = ie(f)), t + f > s) throw new n("TIMEOUT", e.httpStatus, `timed out after ${i.timeoutMs}ms waiting for the stream to go live`, {
|
|
156
156
|
retryAfterMs: e.retryAfterMs,
|
|
157
157
|
cause: e
|
|
158
158
|
});
|
|
@@ -162,27 +162,27 @@ async function v(e, t, r) {
|
|
|
162
162
|
attempt: c,
|
|
163
163
|
elapsedMs: t - a,
|
|
164
164
|
ttkMs: d
|
|
165
|
-
}), await
|
|
165
|
+
}), await oe(f, r);
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
169
|
//#endregion
|
|
170
170
|
//#region src/core/resolve.ts
|
|
171
|
-
async function
|
|
171
|
+
async function v(e) {
|
|
172
172
|
if (!e.matchUrn || typeof e.matchUrn != "string") throw new n("INVALID_URN", 0, "resolveStream: a non-empty matchUrn is required");
|
|
173
173
|
let t = await u(c(e.baseUrl, `/v1/playback/${encodeURIComponent(e.matchUrn)}`), {
|
|
174
174
|
credential: e.credential,
|
|
175
175
|
signal: e.signal,
|
|
176
176
|
apiHeaders: e.apiHeaders
|
|
177
177
|
});
|
|
178
|
-
if (!t.ok) throw await
|
|
179
|
-
return
|
|
178
|
+
if (!t.ok) throw await se(t);
|
|
179
|
+
return le(await t.json(), e.matchUrn);
|
|
180
180
|
}
|
|
181
|
-
function
|
|
182
|
-
let t = () =>
|
|
183
|
-
return e.waitForLive ?
|
|
181
|
+
function y(e) {
|
|
182
|
+
let t = () => v(e);
|
|
183
|
+
return e.waitForLive ? _(t, e.waitForLive, e.signal) : t();
|
|
184
184
|
}
|
|
185
|
-
async function
|
|
185
|
+
async function se(e) {
|
|
186
186
|
let t = l(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;
|
|
187
187
|
try {
|
|
188
188
|
let t = await e.json();
|
|
@@ -198,7 +198,7 @@ async function oe(e) {
|
|
|
198
198
|
liveStartsAtMs: s
|
|
199
199
|
});
|
|
200
200
|
}
|
|
201
|
-
var
|
|
201
|
+
var ce = /* @__PURE__ */ new Set([
|
|
202
202
|
"matchUrn",
|
|
203
203
|
"protocol",
|
|
204
204
|
"drmEnabled",
|
|
@@ -209,7 +209,7 @@ var x = /* @__PURE__ */ new Set([
|
|
|
209
209
|
"expiresAt",
|
|
210
210
|
"analytics"
|
|
211
211
|
]);
|
|
212
|
-
function
|
|
212
|
+
function b(e, t) {
|
|
213
213
|
let r;
|
|
214
214
|
try {
|
|
215
215
|
r = new URL(t);
|
|
@@ -219,29 +219,57 @@ function S(e, t) {
|
|
|
219
219
|
if (r.protocol !== "https:" && r.protocol !== "http:") throw new n("INTERNAL", 0, `playback ${e} has a disallowed scheme: ${r.protocol}`);
|
|
220
220
|
return t;
|
|
221
221
|
}
|
|
222
|
-
function
|
|
222
|
+
function le(e, t) {
|
|
223
223
|
if (!e.manifestUrl) throw new n("INTERNAL", 0, "playback response is missing manifestUrl");
|
|
224
224
|
let r = e.drmEnabled ?? !!e.drm, i = {
|
|
225
225
|
matchUrn: e.matchUrn ?? t,
|
|
226
226
|
protocol: "hls",
|
|
227
227
|
drmEnabled: r,
|
|
228
|
-
manifestUrl:
|
|
228
|
+
manifestUrl: b("manifestUrl", e.manifestUrl),
|
|
229
229
|
serverTime: e.serverTime ?? ""
|
|
230
230
|
};
|
|
231
231
|
if (e.liveStartsAt && (i.liveStartsAt = e.liveStartsAt), typeof e.analytics?.sid == "string" && e.analytics.sid && (i.analytics = { sid: e.analytics.sid }), r && e.drm) {
|
|
232
232
|
let t = {};
|
|
233
|
-
e.drm.widevine?.licenseUrl && (t.widevine = { licenseUrl:
|
|
234
|
-
licenseUrl:
|
|
235
|
-
certificateUrl:
|
|
233
|
+
e.drm.widevine?.licenseUrl && (t.widevine = { licenseUrl: b("widevine licenseUrl", e.drm.widevine.licenseUrl) }), e.drm.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && (t.fairplay = {
|
|
234
|
+
licenseUrl: b("fairplay licenseUrl", e.drm.fairplay.licenseUrl),
|
|
235
|
+
certificateUrl: b("fairplay certificateUrl", e.drm.fairplay.certificateUrl)
|
|
236
236
|
}), (t.widevine || t.fairplay) && (i.drm = t);
|
|
237
237
|
}
|
|
238
238
|
let a = {};
|
|
239
|
-
for (let [t, n] of Object.entries(e))
|
|
239
|
+
for (let [t, n] of Object.entries(e)) ce.has(t) || (a[t] = n);
|
|
240
240
|
return Object.keys(a).length > 0 && (i.extensions = a), i;
|
|
241
241
|
}
|
|
242
242
|
//#endregion
|
|
243
|
+
//#region src/core/fullscreen.ts
|
|
244
|
+
function x(e) {
|
|
245
|
+
return e.ownerDocument ?? document;
|
|
246
|
+
}
|
|
247
|
+
function S(e) {
|
|
248
|
+
return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
|
|
249
|
+
}
|
|
250
|
+
function C(e, t) {
|
|
251
|
+
let n = S(x(e));
|
|
252
|
+
return n != null && (n === e || t != null && n === t) || e.webkitDisplayingFullscreen === !0;
|
|
253
|
+
}
|
|
254
|
+
async function w(e, t) {
|
|
255
|
+
let n = t ?? e;
|
|
256
|
+
if (typeof n.requestFullscreen == "function") return await n.requestFullscreen(), !0;
|
|
257
|
+
if (typeof n.webkitRequestFullscreen == "function") return n.webkitRequestFullscreen(), !0;
|
|
258
|
+
let r = e;
|
|
259
|
+
return r.webkitSupportsFullscreen && typeof r.webkitEnterFullscreen == "function" ? (r.webkitEnterFullscreen(), !0) : !1;
|
|
260
|
+
}
|
|
261
|
+
async function T(e, t) {
|
|
262
|
+
let n = e;
|
|
263
|
+
if (n.webkitDisplayingFullscreen) {
|
|
264
|
+
n.webkitExitFullscreen?.();
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
let r = x(e), i = S(r);
|
|
268
|
+
i != null && (i === e || t != null && i === t) && (typeof r.exitFullscreen == "function" ? await r.exitFullscreen() : r.webkitExitFullscreen?.());
|
|
269
|
+
}
|
|
270
|
+
//#endregion
|
|
243
271
|
//#region src/core/catalog.ts
|
|
244
|
-
async function
|
|
272
|
+
async function ue(e) {
|
|
245
273
|
let t = new URLSearchParams();
|
|
246
274
|
e.status && t.set("status", Array.isArray(e.status) ? e.status.join(",") : e.status), e.sport && t.set("sport", e.sport);
|
|
247
275
|
let i = t.toString(), a = c(e.baseUrl, "/v1/catalog" + (i ? `?${i}` : "")), o = new Headers();
|
|
@@ -259,12 +287,12 @@ async function ce(e) {
|
|
|
259
287
|
};
|
|
260
288
|
if (!s.ok) throw new n(r(s.status), s.status, `catalog request failed (HTTP ${s.status})`);
|
|
261
289
|
return {
|
|
262
|
-
tournaments:
|
|
290
|
+
tournaments: de(await s.json()),
|
|
263
291
|
etag: s.headers.get("etag") ?? void 0,
|
|
264
292
|
notModified: !1
|
|
265
293
|
};
|
|
266
294
|
}
|
|
267
|
-
function
|
|
295
|
+
function de(e) {
|
|
268
296
|
return (e.tournaments ?? []).map((e) => {
|
|
269
297
|
let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
|
|
270
298
|
return {
|
|
@@ -284,7 +312,7 @@ function le(e) {
|
|
|
284
312
|
};
|
|
285
313
|
});
|
|
286
314
|
}
|
|
287
|
-
async function
|
|
315
|
+
async function fe(e) {
|
|
288
316
|
let t = c(e.baseUrl, `/v1/tournaments/${encodeURIComponent(e.urn)}`), i = new Headers();
|
|
289
317
|
e.etag && i.set("If-None-Match", e.etag);
|
|
290
318
|
let a = await u(t, {
|
|
@@ -304,13 +332,13 @@ async function ue(e) {
|
|
|
304
332
|
};
|
|
305
333
|
if (!a.ok) throw new n(r(a.status), a.status, `tournament request failed (HTTP ${a.status})`);
|
|
306
334
|
return {
|
|
307
|
-
tournament:
|
|
335
|
+
tournament: pe(await a.json()),
|
|
308
336
|
etag: a.headers.get("etag") ?? void 0,
|
|
309
337
|
notModified: !1,
|
|
310
338
|
notFound: !1
|
|
311
339
|
};
|
|
312
340
|
}
|
|
313
|
-
function
|
|
341
|
+
function pe(e) {
|
|
314
342
|
let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
|
|
315
343
|
return {
|
|
316
344
|
urn: t,
|
|
@@ -328,12 +356,12 @@ function de(e) {
|
|
|
328
356
|
}))
|
|
329
357
|
};
|
|
330
358
|
}
|
|
331
|
-
function
|
|
359
|
+
function me(e) {
|
|
332
360
|
return e.tournaments.flatMap((e) => e.matches);
|
|
333
361
|
}
|
|
334
362
|
//#endregion
|
|
335
363
|
//#region src/core/poll.ts
|
|
336
|
-
function
|
|
364
|
+
function he(e) {
|
|
337
365
|
let t = Math.max(2e3, e.intervalMs ?? 1e4), i = new AbortController(), a, o, s, l = !1, d = () => {
|
|
338
366
|
l || (a = setTimeout(f, t));
|
|
339
367
|
}, f = async () => {
|
|
@@ -369,7 +397,7 @@ function pe(e) {
|
|
|
369
397
|
}
|
|
370
398
|
//#endregion
|
|
371
399
|
//#region src/core/events.ts
|
|
372
|
-
function
|
|
400
|
+
function E(e) {
|
|
373
401
|
let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = new AbortController(), i = !1, a = (e) => new Promise((t) => {
|
|
374
402
|
if (r.signal.aborted) return t();
|
|
375
403
|
let n = setTimeout(t, e);
|
|
@@ -436,7 +464,7 @@ function C(e) {
|
|
|
436
464
|
i || (i = !0, r.abort());
|
|
437
465
|
} };
|
|
438
466
|
}
|
|
439
|
-
function
|
|
467
|
+
function D(e) {
|
|
440
468
|
try {
|
|
441
469
|
let t = new URL(e);
|
|
442
470
|
return t.hostname = `events.${t.hostname}`, t.pathname = "", t.search = "", t.origin;
|
|
@@ -446,27 +474,27 @@ function w(e) {
|
|
|
446
474
|
}
|
|
447
475
|
//#endregion
|
|
448
476
|
//#region src/core/drm/deviceId.ts
|
|
449
|
-
var
|
|
450
|
-
function
|
|
451
|
-
if (
|
|
477
|
+
var O = "havik.player.deviceId", k;
|
|
478
|
+
function A() {
|
|
479
|
+
if (k) return k;
|
|
452
480
|
try {
|
|
453
|
-
let e = globalThis.localStorage?.getItem(
|
|
454
|
-
if (e) return
|
|
481
|
+
let e = globalThis.localStorage?.getItem(O);
|
|
482
|
+
if (e) return k = e, e;
|
|
455
483
|
} catch {}
|
|
456
|
-
let e =
|
|
457
|
-
|
|
484
|
+
let e = _e();
|
|
485
|
+
k = e;
|
|
458
486
|
try {
|
|
459
|
-
globalThis.localStorage?.setItem(
|
|
487
|
+
globalThis.localStorage?.setItem(O, e);
|
|
460
488
|
} catch {}
|
|
461
489
|
return e;
|
|
462
490
|
}
|
|
463
|
-
function
|
|
464
|
-
|
|
491
|
+
function ge() {
|
|
492
|
+
k = void 0;
|
|
465
493
|
try {
|
|
466
|
-
globalThis.localStorage?.removeItem(
|
|
494
|
+
globalThis.localStorage?.removeItem(O);
|
|
467
495
|
} catch {}
|
|
468
496
|
}
|
|
469
|
-
function
|
|
497
|
+
function _e() {
|
|
470
498
|
let e = globalThis.crypto;
|
|
471
499
|
if (e && typeof e.randomUUID == "function") return e.randomUUID();
|
|
472
500
|
let t = /* @__PURE__ */ new Uint8Array(16);
|
|
@@ -478,22 +506,22 @@ function he() {
|
|
|
478
506
|
}
|
|
479
507
|
//#endregion
|
|
480
508
|
//#region src/core/drm/headers.ts
|
|
481
|
-
function
|
|
509
|
+
function ve(e, t, n = {}) {
|
|
482
510
|
let r = {
|
|
483
511
|
"x-api-key": t.apiKey,
|
|
484
512
|
"X-Match-Urn": e.matchUrn,
|
|
485
|
-
"X-Device-Id": n.deviceId ??
|
|
513
|
+
"X-Device-Id": n.deviceId ?? A(),
|
|
486
514
|
"Content-Type": "application/octet-stream"
|
|
487
515
|
};
|
|
488
516
|
return n.userId && (r["X-User-Id"] = n.userId), r;
|
|
489
517
|
}
|
|
490
518
|
//#endregion
|
|
491
519
|
//#region src/core/drm/support.ts
|
|
492
|
-
var
|
|
520
|
+
var ye = 5e3, j = "video/mp4; codecs=\"avc1.42E01E\"", M = "audio/mp4; codecs=\"mp4a.40.2\"", be = {
|
|
493
521
|
widevine: ["com.widevine.alpha"],
|
|
494
522
|
fairplay: ["com.apple.fps"]
|
|
495
523
|
};
|
|
496
|
-
function
|
|
524
|
+
function N(e) {
|
|
497
525
|
return e === "fairplay" ? [{
|
|
498
526
|
initDataTypes: [
|
|
499
527
|
"sinf",
|
|
@@ -501,30 +529,30 @@ function A(e) {
|
|
|
501
529
|
"cenc"
|
|
502
530
|
],
|
|
503
531
|
videoCapabilities: [{
|
|
504
|
-
contentType:
|
|
532
|
+
contentType: j,
|
|
505
533
|
robustness: "",
|
|
506
534
|
encryptionScheme: "cbcs"
|
|
507
535
|
}],
|
|
508
536
|
audioCapabilities: [{
|
|
509
|
-
contentType:
|
|
537
|
+
contentType: M,
|
|
510
538
|
robustness: "",
|
|
511
539
|
encryptionScheme: "cbcs"
|
|
512
540
|
}]
|
|
513
541
|
}] : [{
|
|
514
542
|
initDataTypes: ["cenc"],
|
|
515
543
|
videoCapabilities: [{
|
|
516
|
-
contentType:
|
|
544
|
+
contentType: j,
|
|
517
545
|
robustness: "SW_SECURE_DECODE",
|
|
518
546
|
encryptionScheme: "cbcs"
|
|
519
547
|
}],
|
|
520
548
|
audioCapabilities: [{
|
|
521
|
-
contentType:
|
|
549
|
+
contentType: M,
|
|
522
550
|
robustness: "SW_SECURE_CRYPTO",
|
|
523
551
|
encryptionScheme: "cbcs"
|
|
524
552
|
}]
|
|
525
553
|
}];
|
|
526
554
|
}
|
|
527
|
-
function
|
|
555
|
+
function P(e, t) {
|
|
528
556
|
return new Promise((n, r) => {
|
|
529
557
|
let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
|
|
530
558
|
e.then((e) => {
|
|
@@ -534,8 +562,8 @@ function j(e, t) {
|
|
|
534
562
|
});
|
|
535
563
|
});
|
|
536
564
|
}
|
|
537
|
-
async function
|
|
538
|
-
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ??
|
|
565
|
+
async function xe(e = {}) {
|
|
566
|
+
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? ye, r = {};
|
|
539
567
|
if (typeof window < "u" && window.isSecureContext === !1) return {
|
|
540
568
|
verdict: "insecure-context",
|
|
541
569
|
detail: r
|
|
@@ -547,7 +575,7 @@ async function M(e = {}) {
|
|
|
547
575
|
};
|
|
548
576
|
let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
|
|
549
577
|
for (let e of t) {
|
|
550
|
-
let t =
|
|
578
|
+
let t = be[e];
|
|
551
579
|
if (!t) {
|
|
552
580
|
r[e] = "unknown system";
|
|
553
581
|
continue;
|
|
@@ -558,7 +586,7 @@ async function M(e = {}) {
|
|
|
558
586
|
break;
|
|
559
587
|
}
|
|
560
588
|
try {
|
|
561
|
-
return await
|
|
589
|
+
return await P((await P(i(n, N(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
|
|
562
590
|
verdict: "supported",
|
|
563
591
|
system: e,
|
|
564
592
|
detail: r
|
|
@@ -582,9 +610,9 @@ async function M(e = {}) {
|
|
|
582
610
|
}
|
|
583
611
|
//#endregion
|
|
584
612
|
//#region src/core/manifest.ts
|
|
585
|
-
var
|
|
586
|
-
function
|
|
587
|
-
return
|
|
613
|
+
var Se = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
|
|
614
|
+
function Ce(e) {
|
|
615
|
+
return Se.test(e);
|
|
588
616
|
}
|
|
589
617
|
//#endregion
|
|
590
618
|
//#region src/core/stats.ts
|
|
@@ -592,7 +620,7 @@ var F = { droppedFrames: 0 };
|
|
|
592
620
|
function I(e) {
|
|
593
621
|
return e.getVideoPlaybackQuality?.()?.droppedVideoFrames ?? 0;
|
|
594
622
|
}
|
|
595
|
-
function
|
|
623
|
+
function we(e, t) {
|
|
596
624
|
let n = [
|
|
597
625
|
["playing", () => t("playing")],
|
|
598
626
|
["waiting", () => t("buffering")],
|
|
@@ -609,7 +637,7 @@ function ye(e, t) {
|
|
|
609
637
|
}
|
|
610
638
|
//#endregion
|
|
611
639
|
//#region src/core/engine/native.ts
|
|
612
|
-
function
|
|
640
|
+
function Te(e) {
|
|
613
641
|
try {
|
|
614
642
|
let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
|
|
615
643
|
return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
|
|
@@ -655,7 +683,7 @@ var z = class {
|
|
|
655
683
|
type: "error",
|
|
656
684
|
error: new n("INTERNAL", 0, "native HLS playback error"),
|
|
657
685
|
fatal: !0
|
|
658
|
-
}), e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src =
|
|
686
|
+
}), e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Ee(t.manifestUrl, t.analytics?.sid), e.load();
|
|
659
687
|
}
|
|
660
688
|
armFairPlay() {
|
|
661
689
|
let { video: e, descriptor: t, credential: r, deviceId: a, userId: o, emit: s } = this.deps, c = t.drm?.fairplay;
|
|
@@ -668,7 +696,7 @@ var z = class {
|
|
|
668
696
|
});
|
|
669
697
|
this.onEncrypted = (n) => {
|
|
670
698
|
let i = n;
|
|
671
|
-
!i.initData || this.fairplayArmed || (this.fairplayArmed = !0, this.fairplayKeyIV =
|
|
699
|
+
!i.initData || this.fairplayArmed || (this.fairplayArmed = !0, this.fairplayKeyIV = Te(i.initData), (async () => {
|
|
672
700
|
try {
|
|
673
701
|
let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
|
|
674
702
|
initDataTypes: [i.initDataType],
|
|
@@ -783,29 +811,29 @@ var z = class {
|
|
|
783
811
|
} catch {}
|
|
784
812
|
}
|
|
785
813
|
};
|
|
786
|
-
function
|
|
814
|
+
function Ee(e, t) {
|
|
787
815
|
return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
|
|
788
816
|
}
|
|
789
817
|
//#endregion
|
|
790
818
|
//#region src/core/engine/hls.ts
|
|
791
|
-
function
|
|
819
|
+
function De() {
|
|
792
820
|
return e.isSupported();
|
|
793
821
|
}
|
|
794
|
-
var
|
|
795
|
-
function
|
|
822
|
+
var Oe = 3, ke = 5, Ae = 3, je = 3e4, Me = 12e3, Ne = 3e3, B = 6e3, Pe = 4e3, Fe = 2, Ie = 5, Le = 2e3, Re = 3e4, ze = 2, Be = 9, V = .5;
|
|
823
|
+
function Ve(e) {
|
|
796
824
|
if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
|
|
797
825
|
delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
|
|
798
826
|
return;
|
|
799
827
|
}
|
|
800
|
-
e.liveSyncDuration ??=
|
|
801
|
-
let t = Math.max(12, e.liveSyncDuration +
|
|
802
|
-
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t),
|
|
828
|
+
e.liveSyncDuration ??= ze;
|
|
829
|
+
let t = Math.max(12, e.liveSyncDuration + Be);
|
|
830
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), He(e, e.liveSyncDuration);
|
|
803
831
|
}
|
|
804
|
-
function
|
|
832
|
+
function He(e, t) {
|
|
805
833
|
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
806
834
|
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
807
835
|
}
|
|
808
|
-
var
|
|
836
|
+
var H = class {
|
|
809
837
|
name = "hls";
|
|
810
838
|
hls = null;
|
|
811
839
|
deps;
|
|
@@ -882,7 +910,7 @@ var V = class {
|
|
|
882
910
|
let t = e.liveSyncPosition;
|
|
883
911
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
884
912
|
let { video: n } = this.deps;
|
|
885
|
-
n.currentTime <= t +
|
|
913
|
+
n.currentTime <= t + V || (n.currentTime = t);
|
|
886
914
|
}
|
|
887
915
|
startHls() {
|
|
888
916
|
let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps, u = n.drmEnabled && !!(n.drm?.widevine?.licenseUrl || n.drm?.fairplay?.licenseUrl), d = {
|
|
@@ -918,14 +946,14 @@ var V = class {
|
|
|
918
946
|
} } : {},
|
|
919
947
|
...c
|
|
920
948
|
};
|
|
921
|
-
|
|
949
|
+
Ve(d), this.sizeCapManaged = d.capLevelToPlayerSize !== !0;
|
|
922
950
|
let f = new e(d);
|
|
923
951
|
this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
|
|
924
952
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.applySizeCap(), l({ type: "ready" });
|
|
925
953
|
}), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
|
|
926
954
|
t?.frag?.type === "main" && (this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0 || this.starvationKicks > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
|
|
927
955
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.recoveryResetTimer = null;
|
|
928
|
-
},
|
|
956
|
+
}, je));
|
|
929
957
|
}), f.on(e.Events.FRAG_LOADING, (e, t) => {
|
|
930
958
|
t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
|
|
931
959
|
}), f.on(e.Events.FRAG_LOADED, (e, t) => {
|
|
@@ -941,7 +969,7 @@ var V = class {
|
|
|
941
969
|
}));
|
|
942
970
|
}), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.endWatchdog = setInterval(() => {
|
|
943
971
|
this.checkEndStale(), this.checkStarvation();
|
|
944
|
-
},
|
|
972
|
+
}, Ne), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
945
973
|
this.renditionSwitches += 1, l({
|
|
946
974
|
type: "qualitychange",
|
|
947
975
|
index: t.level
|
|
@@ -1003,7 +1031,7 @@ var V = class {
|
|
|
1003
1031
|
return;
|
|
1004
1032
|
}
|
|
1005
1033
|
this.capTimer && clearTimeout(this.capTimer);
|
|
1006
|
-
let t = e > this.sizeCapLevel ?
|
|
1034
|
+
let t = e > this.sizeCapLevel ? Le : Re;
|
|
1007
1035
|
this.capTimer = setTimeout(() => {
|
|
1008
1036
|
this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
|
|
1009
1037
|
}, t);
|
|
@@ -1084,7 +1112,7 @@ var V = class {
|
|
|
1084
1112
|
return;
|
|
1085
1113
|
}
|
|
1086
1114
|
let e = Date.now() - this.lastAdvanceMs;
|
|
1087
|
-
!this.chaseSuspended && e > B && this.suspendChasing(), e >
|
|
1115
|
+
!this.chaseSuspended && e > B && this.suspendChasing(), e > Me && this.emitEnded("stalled");
|
|
1088
1116
|
}
|
|
1089
1117
|
checkStarvation() {
|
|
1090
1118
|
let e = this.hls, { video: t } = this.deps;
|
|
@@ -1093,12 +1121,12 @@ var V = class {
|
|
|
1093
1121
|
this.starvedTicks = 0;
|
|
1094
1122
|
return;
|
|
1095
1123
|
}
|
|
1096
|
-
let n = this.lastAdvanceMs !== 0 && Date.now() - this.lastAdvanceMs < B, r = this.lastFragLoadingMs !== 0 && Date.now() - this.lastFragLoadingMs >
|
|
1124
|
+
let n = this.lastAdvanceMs !== 0 && Date.now() - this.lastAdvanceMs < B, r = this.lastFragLoadingMs !== 0 && Date.now() - this.lastFragLoadingMs > Pe;
|
|
1097
1125
|
if (!(t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused && n && r)) {
|
|
1098
1126
|
this.starvedTicks = 0;
|
|
1099
1127
|
return;
|
|
1100
1128
|
}
|
|
1101
|
-
if (!(++this.starvedTicks <
|
|
1129
|
+
if (!(++this.starvedTicks < Fe) && (this.starvedTicks = 0, !(this.starvationKicks >= Ie))) {
|
|
1102
1130
|
this.starvationKicks += 1, console.warn("havik-player: video starved while the live playlist advances (wedged hls.js fragment pipeline) — restarting load at the live edge");
|
|
1103
1131
|
try {
|
|
1104
1132
|
e.stopLoad(), e.startLoad(-1);
|
|
@@ -1147,7 +1175,7 @@ var V = class {
|
|
|
1147
1175
|
scheduleLicenseRetry(t) {
|
|
1148
1176
|
if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
|
|
1149
1177
|
let n = t.response?.code ?? 0;
|
|
1150
|
-
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >=
|
|
1178
|
+
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Ae) return !1;
|
|
1151
1179
|
this.licenseRecoveries += 1;
|
|
1152
1180
|
let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
|
|
1153
1181
|
return this.licenseRetryTimer = setTimeout(() => {
|
|
@@ -1175,7 +1203,7 @@ var V = class {
|
|
|
1175
1203
|
return;
|
|
1176
1204
|
}
|
|
1177
1205
|
if (t.type === e.ErrorTypes.NETWORK_ERROR) {
|
|
1178
|
-
if (this.networkRecoveries <
|
|
1206
|
+
if (this.networkRecoveries < ke) {
|
|
1179
1207
|
this.networkRecoveries += 1;
|
|
1180
1208
|
let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
|
|
1181
1209
|
this.networkRetryTimer = setTimeout(() => {
|
|
@@ -1191,7 +1219,7 @@ var V = class {
|
|
|
1191
1219
|
return;
|
|
1192
1220
|
}
|
|
1193
1221
|
if (t.type === e.ErrorTypes.MEDIA_ERROR) {
|
|
1194
|
-
if (this.mediaRecoveries <
|
|
1222
|
+
if (this.mediaRecoveries < Oe) {
|
|
1195
1223
|
this.mediaRecoveries += 1, n.recoverMediaError();
|
|
1196
1224
|
return;
|
|
1197
1225
|
}
|
|
@@ -1213,7 +1241,7 @@ var V = class {
|
|
|
1213
1241
|
let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
|
|
1214
1242
|
return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
|
|
1215
1243
|
}
|
|
1216
|
-
},
|
|
1244
|
+
}, Ue = 15e3, We = 100, U = 1, W = {
|
|
1217
1245
|
idle: "PLAYER_STATE_IDLE",
|
|
1218
1246
|
waiting: "PLAYER_STATE_WAITING",
|
|
1219
1247
|
loading: "PLAYER_STATE_LOADING",
|
|
@@ -1223,7 +1251,7 @@ var V = class {
|
|
|
1223
1251
|
ended: "PLAYER_STATE_ENDED",
|
|
1224
1252
|
error: "PLAYER_STATE_ERROR"
|
|
1225
1253
|
};
|
|
1226
|
-
function
|
|
1254
|
+
function Ge(e) {
|
|
1227
1255
|
try {
|
|
1228
1256
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
1229
1257
|
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);
|
|
@@ -1231,7 +1259,7 @@ function Ve(e) {
|
|
|
1231
1259
|
return;
|
|
1232
1260
|
}
|
|
1233
1261
|
}
|
|
1234
|
-
var
|
|
1262
|
+
var Ke = class {
|
|
1235
1263
|
opts;
|
|
1236
1264
|
url;
|
|
1237
1265
|
now;
|
|
@@ -1266,7 +1294,7 @@ var He = class {
|
|
|
1266
1294
|
constructor(e) {
|
|
1267
1295
|
this.opts = {
|
|
1268
1296
|
...e,
|
|
1269
|
-
heartbeatMs: e.heartbeatMs ??
|
|
1297
|
+
heartbeatMs: e.heartbeatMs ?? Ue
|
|
1270
1298
|
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`, this.now = e.now ?? (() => Date.now()), this.bornMs = this.now();
|
|
1271
1299
|
}
|
|
1272
1300
|
start() {
|
|
@@ -1278,18 +1306,18 @@ var He = class {
|
|
|
1278
1306
|
noteStateChange(e, t, n, r) {
|
|
1279
1307
|
if (this.endedFlag || e === t) return;
|
|
1280
1308
|
let i = this.now();
|
|
1281
|
-
t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(
|
|
1309
|
+
t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(U, i - this.bornMs))) : this.playingSinceMs !== null && (this.playingTotalMs += i - this.playingSinceMs, this.playingSinceMs = null), t === "buffering" && e === "playing" ? (this.rebufferCount += 1, this.bufferingSinceMs = i) : e === "buffering" && this.bufferingSinceMs !== null && (this.rebufferTotalMs += i - this.bufferingSinceMs, this.bufferingSinceMs = null), t === "paused" && (this.pauseCount += 1);
|
|
1282
1310
|
let a = {
|
|
1283
|
-
fromState:
|
|
1284
|
-
toState:
|
|
1311
|
+
fromState: W[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
1312
|
+
toState: W[t] ?? "PLAYER_STATE_UNSPECIFIED"
|
|
1285
1313
|
};
|
|
1286
1314
|
n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
1287
1315
|
}
|
|
1288
1316
|
noteReady() {
|
|
1289
|
-
this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(
|
|
1317
|
+
this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(U, this.now() - this.bornMs));
|
|
1290
1318
|
}
|
|
1291
1319
|
noteFirstBytes() {
|
|
1292
|
-
this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(
|
|
1320
|
+
this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(U, this.now() - this.bornMs));
|
|
1293
1321
|
}
|
|
1294
1322
|
noteSeek() {
|
|
1295
1323
|
this.endedFlag || (this.seekCount += 1);
|
|
@@ -1324,7 +1352,7 @@ var He = class {
|
|
|
1324
1352
|
let c = e.renditionSwitches ?? 0;
|
|
1325
1353
|
c > this.lastSwitches && (i.renditionSwitchesDelta = c - this.lastSwitches), this.lastSwitches = c, n > this.lastHbPlayingMs && (i.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (i.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, typeof e.latencySeconds == "number" && (i.latencyMs = Math.round(e.latencySeconds * 1e3)), typeof e.targetLatencySeconds == "number" && (i.targetLatencyMs = Math.round(e.targetLatencySeconds * 1e3)), typeof e.bandwidthKbps == "number" && (i.bandwidthEstKbps = e.bandwidthKbps), typeof e.levelHeight == "number" && (i.renditionHeight = e.levelHeight), typeof e.renditionBitrateKbps == "number" && (i.renditionBitrateKbps = e.renditionBitrateKbps), e.atLiveEdge === !0 && (i.atLiveEdge = !0);
|
|
1326
1354
|
let l = this.bufferedMsFrom(e);
|
|
1327
|
-
l > 0 && (i.bufferedMs = l), i.playerState =
|
|
1355
|
+
l > 0 && (i.bufferedMs = l), i.playerState = W[e.state] ?? "PLAYER_STATE_UNSPECIFIED", this.enqueue({ heartbeat: i }), this.flush(), a > 0 && this.noteFirstBytes();
|
|
1328
1356
|
}
|
|
1329
1357
|
bufferedMsFrom(e) {
|
|
1330
1358
|
let t = e;
|
|
@@ -1358,7 +1386,7 @@ var He = class {
|
|
|
1358
1386
|
};
|
|
1359
1387
|
}
|
|
1360
1388
|
enqueue(e) {
|
|
1361
|
-
for (this.pending.push(this.wrap(e)); this.pending.length >
|
|
1389
|
+
for (this.pending.push(this.wrap(e)); this.pending.length > We;) {
|
|
1362
1390
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
1363
1391
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
1364
1392
|
}
|
|
@@ -1380,7 +1408,7 @@ var He = class {
|
|
|
1380
1408
|
keepalive: !0
|
|
1381
1409
|
}).catch(() => {});
|
|
1382
1410
|
}
|
|
1383
|
-
},
|
|
1411
|
+
}, qe = "1.16.1", G = {
|
|
1384
1412
|
accent: "#E1B600",
|
|
1385
1413
|
accentText: "#1B1C23",
|
|
1386
1414
|
background: "#0e0f13",
|
|
@@ -1391,7 +1419,7 @@ var He = class {
|
|
|
1391
1419
|
border: "rgba(255, 255, 255, 0.1)",
|
|
1392
1420
|
radius: "8px",
|
|
1393
1421
|
fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
|
|
1394
|
-
},
|
|
1422
|
+
}, K = {
|
|
1395
1423
|
accent: "--havik-accent",
|
|
1396
1424
|
accentText: "--havik-accent-text",
|
|
1397
1425
|
background: "--havik-bg",
|
|
@@ -1403,25 +1431,25 @@ var He = class {
|
|
|
1403
1431
|
radius: "--havik-radius",
|
|
1404
1432
|
fontFamily: "--havik-font"
|
|
1405
1433
|
};
|
|
1406
|
-
function
|
|
1434
|
+
function q(e, t) {
|
|
1407
1435
|
let n = {
|
|
1408
|
-
...
|
|
1436
|
+
...G,
|
|
1409
1437
|
...t
|
|
1410
1438
|
};
|
|
1411
|
-
for (let t of Object.keys(
|
|
1439
|
+
for (let t of Object.keys(K)) e.style.setProperty(K[t], n[t]);
|
|
1412
1440
|
n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
|
|
1413
1441
|
}
|
|
1414
1442
|
//#endregion
|
|
1415
1443
|
//#region src/ui/styles.ts
|
|
1416
|
-
var
|
|
1417
|
-
function
|
|
1418
|
-
if (e.getElementById(
|
|
1444
|
+
var J = "havik-player-styles", Je = "\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.havik-spinner{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";
|
|
1445
|
+
function Ye(e = document) {
|
|
1446
|
+
if (e.getElementById(J)) return;
|
|
1419
1447
|
let t = e.createElement("style");
|
|
1420
|
-
t.id =
|
|
1448
|
+
t.id = J, t.textContent = Je, e.head.appendChild(t);
|
|
1421
1449
|
}
|
|
1422
1450
|
//#endregion
|
|
1423
1451
|
//#region src/ui/icons.ts
|
|
1424
|
-
var
|
|
1452
|
+
var Xe = {
|
|
1425
1453
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
1426
1454
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
1427
1455
|
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\"/>",
|
|
@@ -1434,21 +1462,21 @@ var Ke = {
|
|
|
1434
1462
|
liveDot: "<circle cx=\"12\" cy=\"12\" r=\"6\"/>",
|
|
1435
1463
|
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\"/>"
|
|
1436
1464
|
};
|
|
1437
|
-
function
|
|
1438
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
1465
|
+
function Y(e) {
|
|
1466
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Xe[e]}</svg>`;
|
|
1439
1467
|
}
|
|
1440
1468
|
//#endregion
|
|
1441
1469
|
//#region src/ui/controls.ts
|
|
1442
|
-
var
|
|
1470
|
+
var Ze = 3e3, Qe = /* @__PURE__ */ new Set([
|
|
1443
1471
|
"GONE",
|
|
1444
1472
|
"NOT_FOUND",
|
|
1445
1473
|
"INVALID_URN",
|
|
1446
1474
|
"UNAUTHORIZED"
|
|
1447
1475
|
]);
|
|
1448
|
-
function
|
|
1449
|
-
return new
|
|
1476
|
+
function $e(e) {
|
|
1477
|
+
return new et(e);
|
|
1450
1478
|
}
|
|
1451
|
-
var
|
|
1479
|
+
var et = class {
|
|
1452
1480
|
root;
|
|
1453
1481
|
video;
|
|
1454
1482
|
player;
|
|
@@ -1488,7 +1516,7 @@ var Xe = class {
|
|
|
1488
1516
|
scrubbing = !1;
|
|
1489
1517
|
offFns = [];
|
|
1490
1518
|
constructor(e) {
|
|
1491
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
1519
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Ze, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.errorMessage = e.errorMessage, Ye(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");
|
|
1492
1520
|
let t = (e, t, n) => {
|
|
1493
1521
|
let r = this.doc.createElement(e);
|
|
1494
1522
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -1499,12 +1527,12 @@ var Xe = class {
|
|
|
1499
1527
|
"aria-label": r,
|
|
1500
1528
|
title: r
|
|
1501
1529
|
});
|
|
1502
|
-
return i.innerHTML =
|
|
1530
|
+
return i.innerHTML = Y(n), i;
|
|
1503
1531
|
};
|
|
1504
1532
|
this.overlay = t("div", "havik-overlay"), this.center = t("button", "havik-center", {
|
|
1505
1533
|
type: "button",
|
|
1506
1534
|
"aria-label": "Play"
|
|
1507
|
-
}), this.center.innerHTML =
|
|
1535
|
+
}), this.center.innerHTML = Y("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", {
|
|
1508
1536
|
role: "slider",
|
|
1509
1537
|
"aria-label": "Seek",
|
|
1510
1538
|
"aria-valuemin": "0",
|
|
@@ -1522,7 +1550,7 @@ var Xe = class {
|
|
|
1522
1550
|
"aria-label": "Volume"
|
|
1523
1551
|
});
|
|
1524
1552
|
let a = t("div", "havik-vol");
|
|
1525
|
-
a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML =
|
|
1553
|
+
a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML = Y("liveDot");
|
|
1526
1554
|
let o = this.doc.createElement("span");
|
|
1527
1555
|
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";
|
|
1528
1556
|
let s = t("div", "havik-spacer");
|
|
@@ -1572,12 +1600,12 @@ var Xe = class {
|
|
|
1572
1600
|
}
|
|
1573
1601
|
if (e === "preplay") {
|
|
1574
1602
|
let e = this.doc.createElement("button");
|
|
1575
|
-
e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML =
|
|
1603
|
+
e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = Y("play"), e.addEventListener("click", () => void this.player.play()), t.append(e);
|
|
1576
1604
|
} else {
|
|
1577
1605
|
let n = this.doc.createElement("div");
|
|
1578
|
-
if (n.className = "havik-status__msg", n.textContent = e === "ended" ? this.endedMessage : e === "waiting" ? "Starting soon…" : this.errorMessage ?? this.lastError?.message ?? "Playback unavailable", t.append(n), e === "error" && this.lastError && !
|
|
1606
|
+
if (n.className = "havik-status__msg", n.textContent = e === "ended" ? this.endedMessage : e === "waiting" ? "Starting soon…" : this.errorMessage ?? this.lastError?.message ?? "Playback unavailable", t.append(n), e === "error" && this.lastError && !Qe.has(this.lastError.code)) {
|
|
1579
1607
|
let e = this.doc.createElement("button");
|
|
1580
|
-
e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${
|
|
1608
|
+
e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${Y("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), t.append(e);
|
|
1581
1609
|
}
|
|
1582
1610
|
}
|
|
1583
1611
|
this.root.append(t), this.statusBox = t, this.show();
|
|
@@ -1616,7 +1644,7 @@ var Xe = class {
|
|
|
1616
1644
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
1617
1645
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
1618
1646
|
}
|
|
1619
|
-
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${
|
|
1647
|
+
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${X(this.video.currentTime)} / ${X(this.video.duration)}`);
|
|
1620
1648
|
}
|
|
1621
1649
|
syncLive() {
|
|
1622
1650
|
let e = this.player.getStats(), t = e.isLive !== !1;
|
|
@@ -1666,17 +1694,17 @@ var Xe = class {
|
|
|
1666
1694
|
renderQualityMenu() {
|
|
1667
1695
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
1668
1696
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
1669
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
1697
|
+
for (let n of e) this.menu.append(this.menuItem(tt(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
1670
1698
|
}
|
|
1671
1699
|
renderAudioMenu() {
|
|
1672
1700
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
1673
1701
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
1674
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
1702
|
+
for (let t of e) this.menu.append(this.menuItem(nt(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
1675
1703
|
}
|
|
1676
1704
|
renderCcMenu() {
|
|
1677
1705
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
1678
1706
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
1679
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
1707
|
+
for (let t of e) this.menu.append(this.menuItem(rt(t), !1, () => this.player.setTextTrack(t.id)));
|
|
1680
1708
|
}
|
|
1681
1709
|
onTracksChanged() {
|
|
1682
1710
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -1695,18 +1723,13 @@ var Xe = class {
|
|
|
1695
1723
|
this.pipBtn.setAttribute("aria-pressed", e ? "true" : "false");
|
|
1696
1724
|
}
|
|
1697
1725
|
async toggleFullscreen() {
|
|
1698
|
-
let e = this.root, t = this.doc, n = this.video;
|
|
1699
1726
|
try {
|
|
1700
|
-
|
|
1701
|
-
t.fullscreenElement ?? t.webkitFullscreenElement ? typeof t.exitFullscreen == "function" ? await t.exitFullscreen() : t.webkitExitFullscreen?.() : typeof e.requestFullscreen == "function" ? await e.requestFullscreen() : e.webkitRequestFullscreen?.();
|
|
1702
|
-
return;
|
|
1703
|
-
}
|
|
1704
|
-
n.webkitSupportsFullscreen && typeof n.webkitEnterFullscreen == "function" && (n.webkitDisplayingFullscreen ? n.webkitExitFullscreen?.() : n.webkitEnterFullscreen());
|
|
1727
|
+
C(this.video, this.root) ? await T(this.video, this.root) : await w(this.video, this.root);
|
|
1705
1728
|
} catch {}
|
|
1706
1729
|
}
|
|
1707
1730
|
syncFullscreen() {
|
|
1708
|
-
let e = this.
|
|
1709
|
-
this.setIcon(this.fsBtn,
|
|
1731
|
+
let e = C(this.video, this.root);
|
|
1732
|
+
this.setIcon(this.fsBtn, e ? "fullscreenExit" : "fullscreen"), this.fsBtn.setAttribute("aria-label", e ? "Exit fullscreen" : "Fullscreen");
|
|
1710
1733
|
}
|
|
1711
1734
|
poke() {
|
|
1712
1735
|
this.show(), this.scheduleHide();
|
|
@@ -1764,7 +1787,7 @@ var Xe = class {
|
|
|
1764
1787
|
}
|
|
1765
1788
|
}
|
|
1766
1789
|
setIcon(e, t) {
|
|
1767
|
-
e.innerHTML =
|
|
1790
|
+
e.innerHTML = Y(t);
|
|
1768
1791
|
}
|
|
1769
1792
|
destroy() {
|
|
1770
1793
|
this.hideTimer && clearTimeout(this.hideTimer);
|
|
@@ -1781,32 +1804,32 @@ var Xe = class {
|
|
|
1781
1804
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
1782
1805
|
}
|
|
1783
1806
|
};
|
|
1784
|
-
function
|
|
1807
|
+
function X(e) {
|
|
1785
1808
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
1786
1809
|
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");
|
|
1787
1810
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
1788
1811
|
}
|
|
1789
|
-
function
|
|
1812
|
+
function tt(e) {
|
|
1790
1813
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
1791
1814
|
}
|
|
1792
|
-
function
|
|
1815
|
+
function nt(e) {
|
|
1793
1816
|
return e.name || e.lang || `Track ${e.id}`;
|
|
1794
1817
|
}
|
|
1795
|
-
function
|
|
1818
|
+
function rt(e) {
|
|
1796
1819
|
return e.name || e.lang || `Track ${e.id}`;
|
|
1797
1820
|
}
|
|
1798
1821
|
//#endregion
|
|
1799
1822
|
//#region src/managed/index.ts
|
|
1800
|
-
var
|
|
1823
|
+
var it = 6e3, Z = 45e3, at = 2e3, ot = 3, st = 2e3, ct = 48e4;
|
|
1801
1824
|
async function Q(e) {
|
|
1802
1825
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
1803
1826
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: baseUrl is required");
|
|
1804
1827
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
1805
1828
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
1806
|
-
let t = new
|
|
1829
|
+
let t = new lt(e);
|
|
1807
1830
|
return await t.start(), t;
|
|
1808
1831
|
}
|
|
1809
|
-
var
|
|
1832
|
+
var lt = class {
|
|
1810
1833
|
opts;
|
|
1811
1834
|
abort = new AbortController();
|
|
1812
1835
|
listeners = {};
|
|
@@ -1842,7 +1865,7 @@ var it = class {
|
|
|
1842
1865
|
this.opts.muted && (this.opts.video.muted = !0), this.opts.poster && (this.opts.video.poster = this.opts.poster), this.mountControls(), this.attachPipListeners(), this.setState("loading");
|
|
1843
1866
|
let e = ++this.loadGen, t = this.resolveOptions();
|
|
1844
1867
|
try {
|
|
1845
|
-
let n = await
|
|
1868
|
+
let n = await v(t);
|
|
1846
1869
|
if (await this.onResolved(n, e), e === this.loadGen && this._state === "error" && this._lastError) {
|
|
1847
1870
|
let e = this._lastError;
|
|
1848
1871
|
throw this.destroy(), e;
|
|
@@ -1865,11 +1888,11 @@ var it = class {
|
|
|
1865
1888
|
};
|
|
1866
1889
|
}
|
|
1867
1890
|
beginArming(e, t) {
|
|
1868
|
-
let n = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ??
|
|
1891
|
+
let n = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? D(this.opts.baseUrl);
|
|
1869
1892
|
n ? this.armWithSse(e, n, t) : this.beginArmingByPolling(e);
|
|
1870
1893
|
}
|
|
1871
1894
|
beginArmingByPolling(e) {
|
|
1872
|
-
|
|
1895
|
+
y({
|
|
1873
1896
|
...this.resolveOptions(),
|
|
1874
1897
|
signal: this.abort.signal,
|
|
1875
1898
|
waitForLive: this.buildWaitConfig(e)
|
|
@@ -1903,7 +1926,7 @@ var it = class {
|
|
|
1903
1926
|
}
|
|
1904
1927
|
}
|
|
1905
1928
|
}, m = () => {
|
|
1906
|
-
i || a || f() || (a = !0,
|
|
1929
|
+
i || a || f() || (a = !0, y({
|
|
1907
1930
|
...this.resolveOptions(),
|
|
1908
1931
|
signal: s.signal,
|
|
1909
1932
|
waitForLive: this.buildWaitConfig(e)
|
|
@@ -1911,7 +1934,7 @@ var it = class {
|
|
|
1911
1934
|
i || f() || s.signal.aborted || (i = !0, this.closeArming(), this.fail(e instanceof n ? e : new n("INTERNAL", 0, String(e))));
|
|
1912
1935
|
}));
|
|
1913
1936
|
}, h = () => {
|
|
1914
|
-
i || f() ||
|
|
1937
|
+
i || f() || v(this.resolveOptions()).then((e) => p(e)).catch((e) => {
|
|
1915
1938
|
i || f() || e instanceof n && o(e.code) || (i = !0, this.closeArming(), s.abort(), this.fail(e instanceof n ? e : new n("INTERNAL", 0, String(e))));
|
|
1916
1939
|
});
|
|
1917
1940
|
}, g = (e) => {
|
|
@@ -1919,13 +1942,13 @@ var it = class {
|
|
|
1919
1942
|
!i && !f() && m();
|
|
1920
1943
|
}, e);
|
|
1921
1944
|
};
|
|
1922
|
-
g(
|
|
1945
|
+
g(it), this.armingSub = E({
|
|
1923
1946
|
eventsBaseUrl: t,
|
|
1924
1947
|
matchUrn: this.opts.matchUrn,
|
|
1925
1948
|
credential: this.opts.credential,
|
|
1926
1949
|
onAlive: () => g(Z),
|
|
1927
1950
|
onState: (e) => {
|
|
1928
|
-
i || f() || (e.state === "live" || e.state === "gone") && setTimeout(h, Math.random() *
|
|
1951
|
+
i || f() || (e.state === "live" || e.state === "gone") && setTimeout(h, Math.random() * at);
|
|
1929
1952
|
},
|
|
1930
1953
|
onError: () => m()
|
|
1931
1954
|
});
|
|
@@ -1948,7 +1971,7 @@ var it = class {
|
|
|
1948
1971
|
let n = await s(this.opts.credential);
|
|
1949
1972
|
if (this.destroyed || t !== this.loadGen) return;
|
|
1950
1973
|
this.setState("loading");
|
|
1951
|
-
let r = this.createEngine(e, n), i =
|
|
1974
|
+
let r = this.createEngine(e, n), i = we(this.opts.video, (e) => {
|
|
1952
1975
|
this._state !== "ended" && this._state !== "error" && this.setState(e);
|
|
1953
1976
|
});
|
|
1954
1977
|
if (await r.load(), this.destroyed || t !== this.loadGen) {
|
|
@@ -1965,14 +1988,14 @@ var it = class {
|
|
|
1965
1988
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachSeekListener?.(), this.opts.analytics === !1) return;
|
|
1966
1989
|
let r = e.analytics?.sid;
|
|
1967
1990
|
if (!r) return;
|
|
1968
|
-
let i = (typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0) ??
|
|
1991
|
+
let i = (typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0) ?? Ge(this.opts.baseUrl);
|
|
1969
1992
|
if (!i) return;
|
|
1970
|
-
let a = this.opts.video, o = new
|
|
1993
|
+
let a = this.opts.video, o = new Ke({
|
|
1971
1994
|
endpoint: i,
|
|
1972
1995
|
sid: r,
|
|
1973
1996
|
apiKey: n,
|
|
1974
1997
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
1975
|
-
sdkVersion:
|
|
1998
|
+
sdkVersion: qe,
|
|
1976
1999
|
sample: () => {
|
|
1977
2000
|
let e = this.engine?.getStats() ?? F, t = a.buffered.length ? Math.max(0, a.buffered.end(a.buffered.length - 1) - a.currentTime) : 0;
|
|
1978
2001
|
return {
|
|
@@ -1994,7 +2017,7 @@ var it = class {
|
|
|
1994
2017
|
video: this.opts.video,
|
|
1995
2018
|
descriptor: e,
|
|
1996
2019
|
credential: t,
|
|
1997
|
-
deviceId:
|
|
2020
|
+
deviceId: A(),
|
|
1998
2021
|
userId: this.opts.userId,
|
|
1999
2022
|
lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
|
|
2000
2023
|
snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
|
|
@@ -2003,9 +2026,9 @@ var it = class {
|
|
|
2003
2026
|
emit: (e) => this.onEngineEvent(e)
|
|
2004
2027
|
}, a = this.opts.engine ?? "auto";
|
|
2005
2028
|
if (a === "native") return new z(i);
|
|
2006
|
-
if (a === "hls") return new
|
|
2029
|
+
if (a === "hls") return new H(i);
|
|
2007
2030
|
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && L(this.opts.video) && R()) return new z(i);
|
|
2008
|
-
if (
|
|
2031
|
+
if (De()) return new H(i);
|
|
2009
2032
|
if (L(this.opts.video)) return new z(i);
|
|
2010
2033
|
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
2011
2034
|
}
|
|
@@ -2034,11 +2057,11 @@ var it = class {
|
|
|
2034
2057
|
}
|
|
2035
2058
|
startLiveState(e) {
|
|
2036
2059
|
if (this.opts.liveStateEvents === !1) return;
|
|
2037
|
-
let t = this.opts.eventsBaseUrl ??
|
|
2060
|
+
let t = this.opts.eventsBaseUrl ?? D(this.opts.baseUrl);
|
|
2038
2061
|
if (!t) return;
|
|
2039
2062
|
this.closeLiveState();
|
|
2040
2063
|
let r = 0, i = !1;
|
|
2041
|
-
this.liveStateSub =
|
|
2064
|
+
this.liveStateSub = E({
|
|
2042
2065
|
eventsBaseUrl: t,
|
|
2043
2066
|
matchUrn: this.opts.matchUrn,
|
|
2044
2067
|
credential: this.opts.credential,
|
|
@@ -2049,7 +2072,7 @@ var it = class {
|
|
|
2049
2072
|
r = 0, i = !1;
|
|
2050
2073
|
},
|
|
2051
2074
|
onError: () => {
|
|
2052
|
-
this.destroyed || e !== this.loadGen || i || (r += 1, r >=
|
|
2075
|
+
this.destroyed || e !== this.loadGen || i || (r += 1, r >= ot && (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.`))));
|
|
2053
2076
|
}
|
|
2054
2077
|
});
|
|
2055
2078
|
}
|
|
@@ -2071,7 +2094,7 @@ var it = class {
|
|
|
2071
2094
|
}
|
|
2072
2095
|
t.controls = !1;
|
|
2073
2096
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
2074
|
-
r && r.insertBefore(n, t), n.appendChild(t),
|
|
2097
|
+
r && r.insertBefore(n, t), n.appendChild(t), q(n, this.opts.theme), this.container = n, this.controlBar = $e({
|
|
2075
2098
|
root: n,
|
|
2076
2099
|
video: t,
|
|
2077
2100
|
player: this,
|
|
@@ -2094,7 +2117,7 @@ var it = class {
|
|
|
2094
2117
|
}
|
|
2095
2118
|
startStats() {
|
|
2096
2119
|
this.stopStats();
|
|
2097
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
2120
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? st);
|
|
2098
2121
|
this.statsTimer = setInterval(() => {
|
|
2099
2122
|
if (!this.engine) return;
|
|
2100
2123
|
let e = this.engine.getStats();
|
|
@@ -2106,7 +2129,7 @@ var it = class {
|
|
|
2106
2129
|
}
|
|
2107
2130
|
scheduleLicenseRefresh() {
|
|
2108
2131
|
this.stopRefresh();
|
|
2109
|
-
let e = this.opts.licenseRefreshMs ??
|
|
2132
|
+
let e = this.opts.licenseRefreshMs ?? ct;
|
|
2110
2133
|
!e || !this._descriptor?.drmEnabled || (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
2111
2134
|
}
|
|
2112
2135
|
stopRefresh() {
|
|
@@ -2115,7 +2138,7 @@ var it = class {
|
|
|
2115
2138
|
async refreshLicense() {
|
|
2116
2139
|
let e = this.engine;
|
|
2117
2140
|
if (!(this.destroyed || !e)) try {
|
|
2118
|
-
let t = await
|
|
2141
|
+
let t = await v(this.resolveOptions());
|
|
2119
2142
|
if (this.destroyed || this.engine !== e) return;
|
|
2120
2143
|
let n = t.drm?.widevine?.licenseUrl, r = t.drm?.fairplay?.licenseUrl;
|
|
2121
2144
|
(n || r) && (e.setLicenseUrls({
|
|
@@ -2181,6 +2204,12 @@ var it = class {
|
|
|
2181
2204
|
let e = document;
|
|
2182
2205
|
e.pictureInPictureElement === this.opts.video && typeof e.exitPictureInPicture == "function" && await e.exitPictureInPicture();
|
|
2183
2206
|
}
|
|
2207
|
+
async enterFullscreen() {
|
|
2208
|
+
return !this.destroyed && w(this.opts.video, this.container ?? void 0);
|
|
2209
|
+
}
|
|
2210
|
+
async exitFullscreen() {
|
|
2211
|
+
await T(this.opts.video, this.container ?? void 0);
|
|
2212
|
+
}
|
|
2184
2213
|
retry() {
|
|
2185
2214
|
return this.reload();
|
|
2186
2215
|
}
|
|
@@ -2189,7 +2218,7 @@ var it = class {
|
|
|
2189
2218
|
let e = ++this.loadGen;
|
|
2190
2219
|
this.stopStats(), this.stopRefresh(), this.closeArming(), this.closeLiveState(), this.detachMedia?.(), this.engine?.destroy(), this.engine = null;
|
|
2191
2220
|
try {
|
|
2192
|
-
let t = await
|
|
2221
|
+
let t = await y({
|
|
2193
2222
|
...this.resolveOptions(),
|
|
2194
2223
|
waitForLive: this.opts.waitForLive ? this.buildWaitConfig(e) : void 0
|
|
2195
2224
|
});
|
|
@@ -2247,7 +2276,7 @@ function $(e) {
|
|
|
2247
2276
|
}
|
|
2248
2277
|
//#endregion
|
|
2249
2278
|
//#region src/embed/host.ts
|
|
2250
|
-
function
|
|
2279
|
+
function ut(e) {
|
|
2251
2280
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
2252
2281
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
2253
2282
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -2306,8 +2335,8 @@ function at(e) {
|
|
|
2306
2335
|
}
|
|
2307
2336
|
//#endregion
|
|
2308
2337
|
//#region src/embed/page.ts
|
|
2309
|
-
var
|
|
2310
|
-
function
|
|
2338
|
+
var dt = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
2339
|
+
function ft() {
|
|
2311
2340
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
2312
2341
|
if (e) return {
|
|
2313
2342
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -2329,9 +2358,9 @@ function st() {
|
|
|
2329
2358
|
waitForLive: !0
|
|
2330
2359
|
};
|
|
2331
2360
|
}
|
|
2332
|
-
async function
|
|
2333
|
-
let e =
|
|
2334
|
-
|
|
2361
|
+
async function pt() {
|
|
2362
|
+
let e = ft();
|
|
2363
|
+
ht();
|
|
2335
2364
|
let t = document.createElement("video");
|
|
2336
2365
|
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);
|
|
2337
2366
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -2386,7 +2415,7 @@ async function ct() {
|
|
|
2386
2415
|
code: e.code,
|
|
2387
2416
|
message: e.message
|
|
2388
2417
|
})), e.on("autoplayblocked", () => {
|
|
2389
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
2418
|
+
i({ type: "oddin:autoplayblocked" }), mt(t, e);
|
|
2390
2419
|
});
|
|
2391
2420
|
}, s = async (r) => {
|
|
2392
2421
|
a?.destroy(), a = null;
|
|
@@ -2452,7 +2481,7 @@ async function ct() {
|
|
|
2452
2481
|
a?.retry();
|
|
2453
2482
|
break;
|
|
2454
2483
|
case "oddin:load":
|
|
2455
|
-
typeof e.matchUrn == "string" &&
|
|
2484
|
+
typeof e.matchUrn == "string" && dt.test(e.matchUrn) && s(e.matchUrn);
|
|
2456
2485
|
break;
|
|
2457
2486
|
case "oddin:destroy": c();
|
|
2458
2487
|
}
|
|
@@ -2464,18 +2493,18 @@ async function ct() {
|
|
|
2464
2493
|
protocol: 1
|
|
2465
2494
|
});
|
|
2466
2495
|
}
|
|
2467
|
-
function
|
|
2496
|
+
function mt(e, t) {
|
|
2468
2497
|
if (document.getElementById("havik-tap")) return;
|
|
2469
2498
|
let n = document.createElement("button");
|
|
2470
2499
|
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", () => {
|
|
2471
2500
|
n.remove(), t.play();
|
|
2472
2501
|
}), document.body.appendChild(n);
|
|
2473
2502
|
}
|
|
2474
|
-
function
|
|
2503
|
+
function ht() {
|
|
2475
2504
|
let e = document.createElement("style");
|
|
2476
2505
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
2477
2506
|
}
|
|
2478
2507
|
//#endregion
|
|
2479
|
-
export {
|
|
2508
|
+
export { G as ODDIN_THEME, n as PlaybackError, q as applyTheme, pt as bootEmbed, ge as clearDeviceId, Q as createPlayer, D as deriveEventsBaseUrl, xe as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, ue as fetchCatalog, fe as fetchTournament, me as flattenMatches, A as getDeviceId, Ce as isLowLatencyManifest, $ as isOddinMessage, ve as licenseRequestHeaders, ut as mountEmbed, _ as pollToLive, y as resolveStream, E as subscribeLiveState, C as videoFullscreenActive, he as watchStatus };
|
|
2480
2509
|
|
|
2481
2510
|
//# sourceMappingURL=index.js.map
|