@oddin-gg/havik-player 2.18.0 → 2.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/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 +28 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +340 -325
- package/dist/index.js.map +1 -1
- package/docs/API.md +20 -1
- package/embed/index.html +1 -1
- package/examples/vanilla.html +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -287,35 +287,42 @@ function he(e, t) {
|
|
|
287
287
|
}
|
|
288
288
|
//#endregion
|
|
289
289
|
//#region src/core/fullscreen.ts
|
|
290
|
-
function
|
|
290
|
+
function x(e) {
|
|
291
291
|
return e.ownerDocument ?? document;
|
|
292
292
|
}
|
|
293
|
-
function
|
|
293
|
+
function ge(e) {
|
|
294
294
|
return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
|
|
295
295
|
}
|
|
296
|
-
function
|
|
297
|
-
let n =
|
|
296
|
+
function S(e, t) {
|
|
297
|
+
let n = ge(x(e));
|
|
298
298
|
return n != null && (n === e || t != null && n === t) || e.webkitDisplayingFullscreen === !0;
|
|
299
299
|
}
|
|
300
|
-
|
|
300
|
+
function C(e, t) {
|
|
301
|
+
let n = t ?? e, r = x(e);
|
|
302
|
+
if (typeof n.requestFullscreen == "function") return r.fullscreenEnabled !== !1;
|
|
303
|
+
if (typeof n.webkitRequestFullscreen == "function") return r.webkitFullscreenEnabled !== !1;
|
|
304
|
+
let i = e;
|
|
305
|
+
return i.webkitSupportsFullscreen === !0 && typeof i.webkitEnterFullscreen == "function" || e.readyState < 1;
|
|
306
|
+
}
|
|
307
|
+
async function w(e, t) {
|
|
301
308
|
let n = t ?? e;
|
|
302
309
|
if (typeof n.requestFullscreen == "function") return await n.requestFullscreen(), !0;
|
|
303
310
|
if (typeof n.webkitRequestFullscreen == "function") return n.webkitRequestFullscreen(), !0;
|
|
304
311
|
let r = e;
|
|
305
312
|
return r.webkitSupportsFullscreen && typeof r.webkitEnterFullscreen == "function" ? (r.webkitEnterFullscreen(), !0) : !1;
|
|
306
313
|
}
|
|
307
|
-
async function
|
|
314
|
+
async function T(e, t) {
|
|
308
315
|
let n = e;
|
|
309
316
|
if (n.webkitDisplayingFullscreen) {
|
|
310
317
|
n.webkitExitFullscreen?.();
|
|
311
318
|
return;
|
|
312
319
|
}
|
|
313
|
-
let r =
|
|
320
|
+
let r = x(e), i = ge(r);
|
|
314
321
|
i != null && (i === e || t != null && i === t) && (typeof r.exitFullscreen == "function" ? await r.exitFullscreen() : r.webkitExitFullscreen?.());
|
|
315
322
|
}
|
|
316
323
|
//#endregion
|
|
317
324
|
//#region src/core/catalog.ts
|
|
318
|
-
async function
|
|
325
|
+
async function _e(e) {
|
|
319
326
|
let t = new URLSearchParams();
|
|
320
327
|
e.status && t.set("status", Array.isArray(e.status) ? e.status.join(",") : e.status), e.sport && t.set("sport", e.sport);
|
|
321
328
|
let i = t.toString(), a = d(e.baseUrl, "/v1/catalog" + (i ? `?${i}` : "")), o = new Headers();
|
|
@@ -333,12 +340,12 @@ async function ve(e) {
|
|
|
333
340
|
};
|
|
334
341
|
if (!s.ok) throw new n(r(s.status), s.status, `catalog request failed (HTTP ${s.status})`);
|
|
335
342
|
return {
|
|
336
|
-
tournaments:
|
|
343
|
+
tournaments: ve(await s.json()),
|
|
337
344
|
etag: s.headers.get("etag") ?? void 0,
|
|
338
345
|
notModified: !1
|
|
339
346
|
};
|
|
340
347
|
}
|
|
341
|
-
function
|
|
348
|
+
function ve(e) {
|
|
342
349
|
return (e.tournaments ?? []).map((e) => {
|
|
343
350
|
let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
|
|
344
351
|
return {
|
|
@@ -360,7 +367,7 @@ function ye(e) {
|
|
|
360
367
|
};
|
|
361
368
|
});
|
|
362
369
|
}
|
|
363
|
-
async function
|
|
370
|
+
async function ye(e) {
|
|
364
371
|
let t = d(e.baseUrl, `/v1/tournaments/${encodeURIComponent(e.urn)}`), i = new Headers();
|
|
365
372
|
e.etag && i.set("If-None-Match", e.etag);
|
|
366
373
|
let a = await p(t, {
|
|
@@ -380,13 +387,13 @@ async function be(e) {
|
|
|
380
387
|
};
|
|
381
388
|
if (!a.ok) throw new n(r(a.status), a.status, `tournament request failed (HTTP ${a.status})`);
|
|
382
389
|
return {
|
|
383
|
-
tournament:
|
|
390
|
+
tournament: be(await a.json()),
|
|
384
391
|
etag: a.headers.get("etag") ?? void 0,
|
|
385
392
|
notModified: !1,
|
|
386
393
|
notFound: !1
|
|
387
394
|
};
|
|
388
395
|
}
|
|
389
|
-
function
|
|
396
|
+
function be(e) {
|
|
390
397
|
let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
|
|
391
398
|
return {
|
|
392
399
|
urn: t,
|
|
@@ -406,17 +413,17 @@ function xe(e) {
|
|
|
406
413
|
}))
|
|
407
414
|
};
|
|
408
415
|
}
|
|
409
|
-
function
|
|
416
|
+
function xe(e) {
|
|
410
417
|
return e.tournaments.flatMap((e) => e.matches);
|
|
411
418
|
}
|
|
412
419
|
//#endregion
|
|
413
420
|
//#region src/core/poll.ts
|
|
414
|
-
var
|
|
421
|
+
var Se = /* @__PURE__ */ new Set([
|
|
415
422
|
"NOT_FOUND",
|
|
416
423
|
"GONE",
|
|
417
424
|
"INVALID_URN"
|
|
418
425
|
]);
|
|
419
|
-
function
|
|
426
|
+
function Ce(e) {
|
|
420
427
|
let t = Math.max(2e3, e.intervalMs ?? 1e4), i = new AbortController(), a, o, s, u = !1, f = () => {
|
|
421
428
|
u || (a = setTimeout(m, t));
|
|
422
429
|
}, m = async () => {
|
|
@@ -449,7 +456,7 @@ function we(e) {
|
|
|
449
456
|
} catch (t) {
|
|
450
457
|
if (!i.signal.aborted) {
|
|
451
458
|
let r = t instanceof n ? t : new n("NETWORK", 0, String(t));
|
|
452
|
-
|
|
459
|
+
Se.has(r.code) && (u = !0), e.onError?.(r);
|
|
453
460
|
}
|
|
454
461
|
} finally {
|
|
455
462
|
f();
|
|
@@ -461,9 +468,9 @@ function we(e) {
|
|
|
461
468
|
}
|
|
462
469
|
//#endregion
|
|
463
470
|
//#region src/core/events.ts
|
|
464
|
-
var
|
|
465
|
-
function
|
|
466
|
-
let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = e.idleTimeoutMs ??
|
|
471
|
+
var we = 45e3;
|
|
472
|
+
function E(e) {
|
|
473
|
+
let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = e.idleTimeoutMs ?? we, i = Number.isFinite(r) && r > 0 ? r : 0, a = new AbortController(), o = !1, c = (e) => new Promise((t) => {
|
|
467
474
|
if (a.signal.aborted) return t();
|
|
468
475
|
let n = setTimeout(t, e);
|
|
469
476
|
a.signal.addEventListener("abort", () => {
|
|
@@ -545,7 +552,7 @@ function w(e) {
|
|
|
545
552
|
o || (o = !0, a.abort());
|
|
546
553
|
} };
|
|
547
554
|
}
|
|
548
|
-
function
|
|
555
|
+
function D(e) {
|
|
549
556
|
try {
|
|
550
557
|
let t = new URL(e);
|
|
551
558
|
return t.hostname = `events.${t.hostname}`, t.pathname = "", t.search = "", t.origin;
|
|
@@ -555,27 +562,27 @@ function T(e) {
|
|
|
555
562
|
}
|
|
556
563
|
//#endregion
|
|
557
564
|
//#region src/core/drm/deviceId.ts
|
|
558
|
-
var
|
|
559
|
-
function
|
|
560
|
-
if (
|
|
565
|
+
var O = "havik.player.deviceId", k;
|
|
566
|
+
function A() {
|
|
567
|
+
if (k) return k;
|
|
561
568
|
try {
|
|
562
|
-
let e = globalThis.localStorage?.getItem(
|
|
563
|
-
if (e) return
|
|
569
|
+
let e = globalThis.localStorage?.getItem(O);
|
|
570
|
+
if (e) return k = e, e;
|
|
564
571
|
} catch {}
|
|
565
|
-
let e =
|
|
566
|
-
|
|
572
|
+
let e = Ee();
|
|
573
|
+
k = e;
|
|
567
574
|
try {
|
|
568
|
-
globalThis.localStorage?.setItem(
|
|
575
|
+
globalThis.localStorage?.setItem(O, e);
|
|
569
576
|
} catch {}
|
|
570
577
|
return e;
|
|
571
578
|
}
|
|
572
|
-
function
|
|
573
|
-
|
|
579
|
+
function Te() {
|
|
580
|
+
k = void 0;
|
|
574
581
|
try {
|
|
575
|
-
globalThis.localStorage?.removeItem(
|
|
582
|
+
globalThis.localStorage?.removeItem(O);
|
|
576
583
|
} catch {}
|
|
577
584
|
}
|
|
578
|
-
function
|
|
585
|
+
function Ee() {
|
|
579
586
|
let e = globalThis.crypto;
|
|
580
587
|
if (e && typeof e.randomUUID == "function") return e.randomUUID();
|
|
581
588
|
let t = /* @__PURE__ */ new Uint8Array(16);
|
|
@@ -587,32 +594,32 @@ function De() {
|
|
|
587
594
|
}
|
|
588
595
|
//#endregion
|
|
589
596
|
//#region src/core/drm/headers.ts
|
|
590
|
-
function
|
|
597
|
+
function De(e, t, n = {}) {
|
|
591
598
|
let r = {
|
|
592
599
|
"x-api-key": t.apiKey,
|
|
593
600
|
"X-Match-Urn": e.matchUrn,
|
|
594
|
-
"X-Device-Id": n.deviceId ??
|
|
601
|
+
"X-Device-Id": n.deviceId ?? A(),
|
|
595
602
|
"Content-Type": "application/octet-stream"
|
|
596
603
|
};
|
|
597
604
|
return n.userId && (r["X-User-Id"] = n.userId), r;
|
|
598
605
|
}
|
|
599
606
|
//#endregion
|
|
600
607
|
//#region src/core/bandwidthMemory.ts
|
|
601
|
-
var
|
|
602
|
-
function
|
|
608
|
+
var j = "havik.player.bandwidth", Oe = .8, ke = 2e7, Ae = 3e5;
|
|
609
|
+
function M() {
|
|
603
610
|
return globalThis.navigator?.connection;
|
|
604
611
|
}
|
|
605
|
-
function
|
|
606
|
-
let e =
|
|
612
|
+
function je() {
|
|
613
|
+
let e = M()?.type;
|
|
607
614
|
return typeof e == "string" && e !== "" && e !== "unknown" ? e : "any";
|
|
608
615
|
}
|
|
609
|
-
function
|
|
610
|
-
let e =
|
|
616
|
+
function Me() {
|
|
617
|
+
let e = M()?.downlink;
|
|
611
618
|
return typeof e == "number" && Number.isFinite(e) && e > 0 ? e * 1e6 : void 0;
|
|
612
619
|
}
|
|
613
|
-
function
|
|
620
|
+
function Ne() {
|
|
614
621
|
try {
|
|
615
|
-
let e = globalThis.localStorage?.getItem(
|
|
622
|
+
let e = globalThis.localStorage?.getItem(j);
|
|
616
623
|
if (!e) return {};
|
|
617
624
|
let t = JSON.parse(e);
|
|
618
625
|
return t && typeof t == "object" && !Array.isArray(t) ? t : {};
|
|
@@ -620,36 +627,36 @@ function Fe() {
|
|
|
620
627
|
return {};
|
|
621
628
|
}
|
|
622
629
|
}
|
|
623
|
-
function
|
|
624
|
-
let t =
|
|
630
|
+
function Pe(e = Date.now()) {
|
|
631
|
+
let t = Ne()[je()];
|
|
625
632
|
if (!t || typeof t.bps != "number" || typeof t.at != "number" || !Number.isFinite(t.bps) || t.bps <= 0) return;
|
|
626
633
|
let n = e - t.at;
|
|
627
634
|
if (n < 0 || n > 2592e5) return;
|
|
628
|
-
let r =
|
|
629
|
-
return Math.round(Math.min(
|
|
635
|
+
let r = Me(), i = r === void 0 ? t.bps : Math.min(t.bps, r);
|
|
636
|
+
return Math.round(Math.min(ke, Math.max(Ae, i * Oe)));
|
|
630
637
|
}
|
|
631
|
-
function
|
|
638
|
+
function Fe(e, t = Date.now()) {
|
|
632
639
|
if (!Number.isFinite(e) || e <= 0) return;
|
|
633
|
-
let n =
|
|
634
|
-
n[
|
|
640
|
+
let n = Ne();
|
|
641
|
+
n[je()] = {
|
|
635
642
|
bps: Math.round(e),
|
|
636
643
|
at: t
|
|
637
644
|
};
|
|
638
645
|
try {
|
|
639
|
-
globalThis.localStorage?.setItem(
|
|
646
|
+
globalThis.localStorage?.setItem(j, JSON.stringify(n));
|
|
640
647
|
} catch {}
|
|
641
648
|
}
|
|
642
|
-
function
|
|
649
|
+
function Ie() {
|
|
643
650
|
try {
|
|
644
|
-
globalThis.localStorage?.removeItem(
|
|
651
|
+
globalThis.localStorage?.removeItem(j);
|
|
645
652
|
} catch {}
|
|
646
653
|
}
|
|
647
654
|
//#endregion
|
|
648
655
|
//#region src/core/drm/cdm.ts
|
|
649
|
-
var
|
|
650
|
-
function
|
|
651
|
-
let n =
|
|
652
|
-
n || (n = /* @__PURE__ */ new Map(),
|
|
656
|
+
var Le = /* @__PURE__ */ new WeakMap();
|
|
657
|
+
function Re(e, t) {
|
|
658
|
+
let n = Le.get(e);
|
|
659
|
+
n || (n = /* @__PURE__ */ new Map(), Le.set(e, n));
|
|
653
660
|
let r = n.get(t.keySystem);
|
|
654
661
|
if (r) return r;
|
|
655
662
|
let i = t.createMediaKeys().catch((e) => {
|
|
@@ -657,22 +664,22 @@ function Be(e, t) {
|
|
|
657
664
|
});
|
|
658
665
|
return n.set(t.keySystem, i), i;
|
|
659
666
|
}
|
|
660
|
-
function
|
|
667
|
+
function N() {
|
|
661
668
|
return typeof navigator < "u" && typeof navigator.requestMediaKeySystemAccess == "function";
|
|
662
669
|
}
|
|
663
|
-
var
|
|
664
|
-
function
|
|
670
|
+
var P = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
|
|
671
|
+
function ze(e) {
|
|
665
672
|
return e.startsWith("com.widevine");
|
|
666
673
|
}
|
|
667
|
-
function
|
|
668
|
-
if (!
|
|
674
|
+
function F(e, t) {
|
|
675
|
+
if (!ze(e)) return t;
|
|
669
676
|
let n = (e, t) => {
|
|
670
677
|
let n = e.videoCapabilities;
|
|
671
678
|
return !n?.length || !n.some((e) => e.robustness) ? !1 : n.every((e) => {
|
|
672
|
-
let n =
|
|
673
|
-
return n === -1 ||
|
|
679
|
+
let n = P.indexOf(e.robustness);
|
|
680
|
+
return n === -1 || P.indexOf(t) > n;
|
|
674
681
|
});
|
|
675
|
-
}, r =
|
|
682
|
+
}, r = P.flatMap((e) => t.filter((t) => n(t, e)).map((t) => ({
|
|
676
683
|
...t,
|
|
677
684
|
videoCapabilities: t.videoCapabilities?.map((t) => ({
|
|
678
685
|
...t,
|
|
@@ -681,53 +688,53 @@ function M(e, t) {
|
|
|
681
688
|
})));
|
|
682
689
|
return [...t, ...r];
|
|
683
690
|
}
|
|
684
|
-
function
|
|
685
|
-
return (t, n) =>
|
|
691
|
+
function Be(e) {
|
|
692
|
+
return (t, n) => N() ? navigator.requestMediaKeySystemAccess(t, F(t, n)).then((t) => ({
|
|
686
693
|
keySystem: t.keySystem,
|
|
687
694
|
getConfiguration: () => t.getConfiguration(),
|
|
688
|
-
createMediaKeys: () =>
|
|
695
|
+
createMediaKeys: () => Re(e, t)
|
|
689
696
|
})) : Promise.reject(/* @__PURE__ */ Error("navigator.requestMediaKeySystemAccess is unavailable — EME needs a secure context (https, or localhost)"));
|
|
690
697
|
}
|
|
691
|
-
var
|
|
698
|
+
var I = {
|
|
692
699
|
video: "SW_SECURE_DECODE",
|
|
693
700
|
audio: "SW_SECURE_CRYPTO",
|
|
694
701
|
scheme: "cbcs"
|
|
695
702
|
};
|
|
696
|
-
function
|
|
697
|
-
if (!
|
|
703
|
+
function Ve(e) {
|
|
704
|
+
if (!N()) return;
|
|
698
705
|
let t = (e, t) => ({
|
|
699
706
|
contentType: e,
|
|
700
707
|
robustness: t,
|
|
701
|
-
encryptionScheme:
|
|
708
|
+
encryptionScheme: I.scheme
|
|
702
709
|
});
|
|
703
|
-
|
|
710
|
+
Be(e)("com.widevine.alpha", [{
|
|
704
711
|
initDataTypes: ["cenc"],
|
|
705
712
|
distinctiveIdentifier: "optional",
|
|
706
713
|
persistentState: "optional",
|
|
707
714
|
sessionTypes: ["temporary"],
|
|
708
|
-
audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"",
|
|
709
|
-
videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"",
|
|
715
|
+
audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"", I.audio)],
|
|
716
|
+
videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"", I.video)]
|
|
710
717
|
}]).then((e) => e.createMediaKeys()).catch(() => {});
|
|
711
718
|
}
|
|
712
|
-
function
|
|
713
|
-
let t =
|
|
719
|
+
function L(e) {
|
|
720
|
+
let t = R(e);
|
|
714
721
|
if (/^avc[13]/.test(t)) return "avc";
|
|
715
722
|
if (/^(hvc1|hev1)/.test(t)) return "hevc";
|
|
716
723
|
if (/^(dvh1|dvhe)/.test(t)) return "dv";
|
|
717
724
|
if (t.startsWith("av01")) return "av1";
|
|
718
725
|
if (/^vp0?9/.test(t)) return "vp9";
|
|
719
726
|
}
|
|
720
|
-
function
|
|
727
|
+
function R(e) {
|
|
721
728
|
return (e ?? "").trim().toLowerCase();
|
|
722
729
|
}
|
|
723
|
-
var
|
|
730
|
+
var He = {
|
|
724
731
|
hevc: "hvc1.1.6.L93.90",
|
|
725
732
|
dv: "dvh1.05.06",
|
|
726
733
|
av1: "av01.0.05M.08",
|
|
727
734
|
vp9: "vp09.00.10.08"
|
|
728
|
-
},
|
|
729
|
-
function
|
|
730
|
-
let t =
|
|
735
|
+
}, Ue = /* @__PURE__ */ new Map(), z = /* @__PURE__ */ new Map();
|
|
736
|
+
function We(e) {
|
|
737
|
+
let t = R(e), n = Ue.get(t);
|
|
731
738
|
if (n) return n;
|
|
732
739
|
let r = {
|
|
733
740
|
initDataTypes: ["cenc"],
|
|
@@ -736,32 +743,32 @@ function Ke(e) {
|
|
|
736
743
|
sessionTypes: ["temporary"],
|
|
737
744
|
videoCapabilities: [{
|
|
738
745
|
contentType: `video/mp4; codecs="${e.trim()}"`,
|
|
739
|
-
robustness:
|
|
740
|
-
encryptionScheme:
|
|
746
|
+
robustness: I.video,
|
|
747
|
+
encryptionScheme: I.scheme
|
|
741
748
|
}]
|
|
742
749
|
}, i = (async () => {
|
|
743
750
|
try {
|
|
744
|
-
return await navigator.requestMediaKeySystemAccess("com.widevine.alpha",
|
|
751
|
+
return await navigator.requestMediaKeySystemAccess("com.widevine.alpha", F("com.widevine.alpha", [r])), !0;
|
|
745
752
|
} catch {
|
|
746
753
|
return !1;
|
|
747
754
|
}
|
|
748
|
-
})().then((e) => (
|
|
749
|
-
return
|
|
755
|
+
})().then((e) => (z.set(t, e), e));
|
|
756
|
+
return Ue.set(t, i), i;
|
|
750
757
|
}
|
|
751
|
-
function
|
|
752
|
-
if (
|
|
758
|
+
function Ge() {
|
|
759
|
+
if (N()) for (let e of Object.values(He)) We(e);
|
|
753
760
|
}
|
|
754
|
-
function
|
|
755
|
-
let t =
|
|
756
|
-
if (t) return t === "avc" ? !0 :
|
|
761
|
+
function Ke(e) {
|
|
762
|
+
let t = L(e);
|
|
763
|
+
if (t) return t === "avc" ? !0 : z.get(R(e)) ?? z.get(R(He[t]));
|
|
757
764
|
}
|
|
758
765
|
//#endregion
|
|
759
766
|
//#region src/core/drm/support.ts
|
|
760
|
-
var
|
|
767
|
+
var qe = 5e3, Je = "video/mp4; codecs=\"avc1.42E01E\"", Ye = "audio/mp4; codecs=\"mp4a.40.2\"", Xe = {
|
|
761
768
|
widevine: ["com.widevine.alpha"],
|
|
762
769
|
fairplay: ["com.apple.fps"]
|
|
763
770
|
};
|
|
764
|
-
function
|
|
771
|
+
function Ze(e) {
|
|
765
772
|
return e === "fairplay" ? [{
|
|
766
773
|
initDataTypes: [
|
|
767
774
|
"sinf",
|
|
@@ -769,30 +776,30 @@ function $e(e) {
|
|
|
769
776
|
"cenc"
|
|
770
777
|
],
|
|
771
778
|
videoCapabilities: [{
|
|
772
|
-
contentType:
|
|
779
|
+
contentType: Je,
|
|
773
780
|
robustness: "",
|
|
774
781
|
encryptionScheme: "cbcs"
|
|
775
782
|
}],
|
|
776
783
|
audioCapabilities: [{
|
|
777
|
-
contentType:
|
|
784
|
+
contentType: Ye,
|
|
778
785
|
robustness: "",
|
|
779
786
|
encryptionScheme: "cbcs"
|
|
780
787
|
}]
|
|
781
|
-
}] :
|
|
788
|
+
}] : F("com.widevine.alpha", [{
|
|
782
789
|
initDataTypes: ["cenc"],
|
|
783
790
|
videoCapabilities: [{
|
|
784
|
-
contentType:
|
|
785
|
-
robustness:
|
|
786
|
-
encryptionScheme:
|
|
791
|
+
contentType: Je,
|
|
792
|
+
robustness: I.video,
|
|
793
|
+
encryptionScheme: I.scheme
|
|
787
794
|
}],
|
|
788
795
|
audioCapabilities: [{
|
|
789
|
-
contentType:
|
|
790
|
-
robustness:
|
|
791
|
-
encryptionScheme:
|
|
796
|
+
contentType: Ye,
|
|
797
|
+
robustness: I.audio,
|
|
798
|
+
encryptionScheme: I.scheme
|
|
792
799
|
}]
|
|
793
800
|
}]);
|
|
794
801
|
}
|
|
795
|
-
function
|
|
802
|
+
function Qe(e, t) {
|
|
796
803
|
return new Promise((n, r) => {
|
|
797
804
|
let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
|
|
798
805
|
e.then((e) => {
|
|
@@ -802,8 +809,8 @@ function et(e, t) {
|
|
|
802
809
|
});
|
|
803
810
|
});
|
|
804
811
|
}
|
|
805
|
-
async function
|
|
806
|
-
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ??
|
|
812
|
+
async function $e(e = {}) {
|
|
813
|
+
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? qe, r = {};
|
|
807
814
|
if (typeof window < "u" && window.isSecureContext === !1) return {
|
|
808
815
|
verdict: "insecure-context",
|
|
809
816
|
detail: r
|
|
@@ -815,7 +822,7 @@ async function tt(e = {}) {
|
|
|
815
822
|
};
|
|
816
823
|
let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
|
|
817
824
|
for (let e of t) {
|
|
818
|
-
let t =
|
|
825
|
+
let t = Xe[e];
|
|
819
826
|
if (!t) {
|
|
820
827
|
r[e] = "unknown system";
|
|
821
828
|
continue;
|
|
@@ -826,7 +833,7 @@ async function tt(e = {}) {
|
|
|
826
833
|
break;
|
|
827
834
|
}
|
|
828
835
|
try {
|
|
829
|
-
return await
|
|
836
|
+
return await Qe((await Qe(i(n, Ze(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
|
|
830
837
|
verdict: "supported",
|
|
831
838
|
system: e,
|
|
832
839
|
detail: r
|
|
@@ -850,37 +857,37 @@ async function tt(e = {}) {
|
|
|
850
857
|
}
|
|
851
858
|
//#endregion
|
|
852
859
|
//#region src/core/manifest.ts
|
|
853
|
-
var
|
|
854
|
-
function
|
|
855
|
-
return
|
|
860
|
+
var et = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
|
|
861
|
+
function tt(e) {
|
|
862
|
+
return et.test(e);
|
|
856
863
|
}
|
|
857
864
|
//#endregion
|
|
858
865
|
//#region src/core/env.ts
|
|
859
|
-
var
|
|
866
|
+
var nt = {
|
|
860
867
|
integration: "https://feed-dev.oddin-video.gg",
|
|
861
868
|
production: "https://feed.oddin-video.gg"
|
|
862
869
|
};
|
|
863
|
-
function
|
|
864
|
-
let t = Object.prototype.hasOwnProperty.call(
|
|
870
|
+
function rt(e) {
|
|
871
|
+
let t = Object.prototype.hasOwnProperty.call(nt, e) ? nt[e] : void 0;
|
|
865
872
|
if (!t) throw new n("INTERNAL", 0, `unknown env ${JSON.stringify(e)} — expected 'integration' or 'production'`);
|
|
866
873
|
return t;
|
|
867
874
|
}
|
|
868
875
|
//#endregion
|
|
869
876
|
//#region src/core/stats.ts
|
|
870
|
-
var
|
|
871
|
-
function
|
|
877
|
+
var it = { droppedFrames: 0 };
|
|
878
|
+
function at(e) {
|
|
872
879
|
try {
|
|
873
880
|
return new URL(e).host;
|
|
874
881
|
} catch {
|
|
875
882
|
return "";
|
|
876
883
|
}
|
|
877
884
|
}
|
|
878
|
-
var
|
|
879
|
-
function
|
|
885
|
+
var ot = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
|
|
886
|
+
function st(e) {
|
|
880
887
|
if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
|
|
881
888
|
let t = "", n = -1, r = performance.getEntriesByType("resource");
|
|
882
|
-
for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" ||
|
|
883
|
-
let e =
|
|
889
|
+
for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || ot.test(i.name)) && i.startTime >= n) {
|
|
890
|
+
let e = at(i.name);
|
|
884
891
|
e && (t = e, n = i.startTime);
|
|
885
892
|
}
|
|
886
893
|
return t;
|
|
@@ -892,7 +899,7 @@ function B(e) {
|
|
|
892
899
|
totalFrames: t?.totalVideoFrames ?? 0
|
|
893
900
|
};
|
|
894
901
|
}
|
|
895
|
-
var
|
|
902
|
+
var ct = class {
|
|
896
903
|
video;
|
|
897
904
|
baseFrames = 0;
|
|
898
905
|
baseDropped = 0;
|
|
@@ -915,7 +922,7 @@ var st = class {
|
|
|
915
922
|
};
|
|
916
923
|
}
|
|
917
924
|
};
|
|
918
|
-
function
|
|
925
|
+
function lt(e, t) {
|
|
919
926
|
let n = [
|
|
920
927
|
["playing", () => t("playing")],
|
|
921
928
|
["waiting", () => t("buffering")],
|
|
@@ -932,8 +939,8 @@ function ct(e, t) {
|
|
|
932
939
|
}
|
|
933
940
|
//#endregion
|
|
934
941
|
//#region src/core/engine/native.ts
|
|
935
|
-
var
|
|
936
|
-
function
|
|
942
|
+
var ut = 2e3, dt = 3, V = 500, ft = 6e3, pt = .25, mt = 250, ht = .05, gt = 4, _t = 12e3, vt = .25, yt = 1e3;
|
|
943
|
+
function bt(e) {
|
|
937
944
|
try {
|
|
938
945
|
let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
|
|
939
946
|
return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
|
|
@@ -949,7 +956,7 @@ function U() {
|
|
|
949
956
|
let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
|
|
950
957
|
return e || t;
|
|
951
958
|
}
|
|
952
|
-
function
|
|
959
|
+
function xt() {
|
|
953
960
|
if (typeof navigator > "u" || !U()) return !1;
|
|
954
961
|
let e = navigator.userAgent ?? "";
|
|
955
962
|
return /iPhone|iPad|iPod/.test(e) ? !0 : /Macintosh/.test(e) && typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1;
|
|
@@ -984,7 +991,7 @@ var W = class {
|
|
|
984
991
|
frameCounter;
|
|
985
992
|
detachFrames = null;
|
|
986
993
|
constructor(e) {
|
|
987
|
-
this.deps = e, this.frameCounter = new
|
|
994
|
+
this.deps = e, this.frameCounter = new ct(e.video), this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
|
|
988
995
|
}
|
|
989
996
|
async load() {
|
|
990
997
|
this.detachFrames ??= this.frameCounter.attach();
|
|
@@ -1005,7 +1012,7 @@ var W = class {
|
|
|
1005
1012
|
type: "error",
|
|
1006
1013
|
error: new n("INTERNAL", 0, "native HLS playback error"),
|
|
1007
1014
|
fatal: !0
|
|
1008
|
-
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src =
|
|
1015
|
+
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Ct(t.manifestUrl, t.analytics?.sid), e.load();
|
|
1009
1016
|
}
|
|
1010
1017
|
startLoad() {
|
|
1011
1018
|
this.loadStarted || (this.loadStarted = !0, this.restorePreload());
|
|
@@ -1027,7 +1034,7 @@ var W = class {
|
|
|
1027
1034
|
});
|
|
1028
1035
|
this.onEncrypted = (n) => {
|
|
1029
1036
|
let i = n;
|
|
1030
|
-
i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV =
|
|
1037
|
+
i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = bt(i.initData), (async () => {
|
|
1031
1038
|
try {
|
|
1032
1039
|
let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
|
|
1033
1040
|
initDataTypes: [i.initDataType],
|
|
@@ -1126,10 +1133,10 @@ var W = class {
|
|
|
1126
1133
|
droppedFrames: t.dropped,
|
|
1127
1134
|
decodedFrames: t.totalFrames
|
|
1128
1135
|
};
|
|
1129
|
-
if (this.cdnHost ||=
|
|
1136
|
+
if (this.cdnHost ||= st(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity) {
|
|
1130
1137
|
n.isLive = !0;
|
|
1131
1138
|
let t = this.liveEdgeEstimate(), r = t == null ? NaN : t - e.currentTime;
|
|
1132
|
-
Number.isFinite(r) && (n.atLiveEdge = r <=
|
|
1139
|
+
Number.isFinite(r) && (n.atLiveEdge = r <= gt, !e.paused && r >= 0 && (n.latencySeconds = r));
|
|
1133
1140
|
} else Number.isFinite(e.duration) && e.duration > 0 && (n.isLive = !1);
|
|
1134
1141
|
return n;
|
|
1135
1142
|
}
|
|
@@ -1147,7 +1154,7 @@ var W = class {
|
|
|
1147
1154
|
return;
|
|
1148
1155
|
}
|
|
1149
1156
|
let t = this.hiddenSince;
|
|
1150
|
-
this.hiddenSince = null, t != null && e - t >=
|
|
1157
|
+
this.hiddenSince = null, t != null && e - t >= ut && this.armRefocus();
|
|
1151
1158
|
}, this.onPageShow = (e) => {
|
|
1152
1159
|
e.persisted && this.armRefocus();
|
|
1153
1160
|
}, document.addEventListener("visibilitychange", this.onVisibility), typeof window < "u" && window.addEventListener("pageshow", this.onPageShow));
|
|
@@ -1157,7 +1164,7 @@ var W = class {
|
|
|
1157
1164
|
let e = this.liveEnd(), t = G, n = t(), r = 0, i = () => {
|
|
1158
1165
|
if (this.refocusTimer = null, Number.isFinite(this.deps.video.duration)) return;
|
|
1159
1166
|
r += V;
|
|
1160
|
-
let a = this.liveEnd(), o = a != null && (e == null || a >= e +
|
|
1167
|
+
let a = this.liveEnd(), o = a != null && (e == null || a >= e + pt), s = Math.max(r, t() - n) >= ft;
|
|
1161
1168
|
if (o || s && a != null) {
|
|
1162
1169
|
this.snapToLive();
|
|
1163
1170
|
return;
|
|
@@ -1177,9 +1184,9 @@ var W = class {
|
|
|
1177
1184
|
}, e.addEventListener("seeking", this.onEdgeReset), e.addEventListener("emptied", this.onEdgeReset), this.edgeTimer = setInterval(() => {
|
|
1178
1185
|
if (e.duration !== Infinity) return;
|
|
1179
1186
|
this.checkEndStale();
|
|
1180
|
-
let t =
|
|
1181
|
-
t != null && ((this.lastBufferedEnd == null || Math.abs(t - this.lastBufferedEnd) >=
|
|
1182
|
-
},
|
|
1187
|
+
let t = St(e, e.currentTime);
|
|
1188
|
+
t != null && ((this.lastBufferedEnd == null || Math.abs(t - this.lastBufferedEnd) >= ht) && (this.bufferedAdvancedAt = G()), this.lastBufferedEnd = t);
|
|
1189
|
+
}, mt);
|
|
1183
1190
|
}
|
|
1184
1191
|
checkEndStale() {
|
|
1185
1192
|
if (this.endedEmitted) return;
|
|
@@ -1187,14 +1194,14 @@ var W = class {
|
|
|
1187
1194
|
this.lastTickAt = e;
|
|
1188
1195
|
let n = this.liveEnd();
|
|
1189
1196
|
if (n == null) return;
|
|
1190
|
-
let r = this.lastSeekableEnd == null || Math.abs(n - this.lastSeekableEnd) >=
|
|
1197
|
+
let r = this.lastSeekableEnd == null || Math.abs(n - this.lastSeekableEnd) >= vt;
|
|
1191
1198
|
this.lastSeekableEnd = n;
|
|
1192
1199
|
let i = this.deps.video, a = typeof document < "u" && document.visibilityState === "hidden";
|
|
1193
|
-
if (r || t >
|
|
1200
|
+
if (r || t > yt || a || i.paused) {
|
|
1194
1201
|
this.edgeStampedAt = e;
|
|
1195
1202
|
return;
|
|
1196
1203
|
}
|
|
1197
|
-
e - (this.edgeStampedAt ?? e) >
|
|
1204
|
+
e - (this.edgeStampedAt ?? e) > _t && (this.endedEmitted = !0, this.deps.emit({
|
|
1198
1205
|
type: "ended",
|
|
1199
1206
|
reason: "stalled"
|
|
1200
1207
|
}));
|
|
@@ -1208,7 +1215,7 @@ var W = class {
|
|
|
1208
1215
|
liveEdgeEstimate() {
|
|
1209
1216
|
let e = this.deps.video;
|
|
1210
1217
|
if (e.duration !== Infinity) return null;
|
|
1211
|
-
let t = this.liveEnd(), n =
|
|
1218
|
+
let t = this.liveEnd(), n = St(e, e.currentTime) ?? this.lastBufferedEnd;
|
|
1212
1219
|
if (n != null) {
|
|
1213
1220
|
let e = this.bufferedAdvancedAt, r = n + (e == null ? 0 : Math.max(0, (G() - e) / 1e3));
|
|
1214
1221
|
(t == null || r > t) && (t = r);
|
|
@@ -1224,7 +1231,7 @@ var W = class {
|
|
|
1224
1231
|
snapToLive() {
|
|
1225
1232
|
let e = this.deps.video, t = this.liveEnd();
|
|
1226
1233
|
if (t == null) return;
|
|
1227
|
-
let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t -
|
|
1234
|
+
let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t - dt, r);
|
|
1228
1235
|
try {
|
|
1229
1236
|
e.currentTime = i;
|
|
1230
1237
|
} catch {}
|
|
@@ -1245,7 +1252,7 @@ var W = class {
|
|
|
1245
1252
|
function G() {
|
|
1246
1253
|
return typeof performance < "u" ? performance.now() : Date.now();
|
|
1247
1254
|
}
|
|
1248
|
-
function
|
|
1255
|
+
function St(e, t) {
|
|
1249
1256
|
let n = e.buffered;
|
|
1250
1257
|
if (!n || !Number.isFinite(t)) return null;
|
|
1251
1258
|
for (let e = 0; e < n.length; e += 1) if (n.start(e) <= t + .1 && n.end(e) > t) {
|
|
@@ -1254,7 +1261,7 @@ function xt(e, t) {
|
|
|
1254
1261
|
}
|
|
1255
1262
|
return null;
|
|
1256
1263
|
}
|
|
1257
|
-
function
|
|
1264
|
+
function Ct(e, t) {
|
|
1258
1265
|
return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
|
|
1259
1266
|
}
|
|
1260
1267
|
//#endregion
|
|
@@ -1271,8 +1278,8 @@ function K(e, t = Date.now()) {
|
|
|
1271
1278
|
}
|
|
1272
1279
|
//#endregion
|
|
1273
1280
|
//#region src/core/engine/prefetch.ts
|
|
1274
|
-
var
|
|
1275
|
-
function
|
|
1281
|
+
var wt = 15e3, Tt = 5e3, Et = 6;
|
|
1282
|
+
function Dt(e) {
|
|
1276
1283
|
try {
|
|
1277
1284
|
let t = new URL(e);
|
|
1278
1285
|
return t.searchParams.delete("CMCD"), t.toString();
|
|
@@ -1280,7 +1287,7 @@ function Et(e) {
|
|
|
1280
1287
|
return e;
|
|
1281
1288
|
}
|
|
1282
1289
|
}
|
|
1283
|
-
var
|
|
1290
|
+
var Ot = class {
|
|
1284
1291
|
cmcd;
|
|
1285
1292
|
entries = /* @__PURE__ */ new Map();
|
|
1286
1293
|
keyed = /* @__PURE__ */ new Set();
|
|
@@ -1303,10 +1310,10 @@ var Dt = class {
|
|
|
1303
1310
|
}
|
|
1304
1311
|
prefetch(e, t, n) {
|
|
1305
1312
|
if (!this.isActive(t)) return;
|
|
1306
|
-
let r =
|
|
1313
|
+
let r = Dt(e);
|
|
1307
1314
|
if (this.entries.has(r)) return;
|
|
1308
1315
|
let i = this.perTrack.get(t) ?? 0;
|
|
1309
|
-
if (i >=
|
|
1316
|
+
if (i >= Et) return;
|
|
1310
1317
|
this.perTrack.set(t, i + 1);
|
|
1311
1318
|
let a = new AbortController(), o = {
|
|
1312
1319
|
started: performance.now(),
|
|
@@ -1320,10 +1327,10 @@ var Dt = class {
|
|
|
1320
1327
|
signal: a.signal
|
|
1321
1328
|
}).then(async (e) => (o.first = performance.now(), e.ok ? e.arrayBuffer() : null)).catch(() => null), this.entries.set(r, o), this.stats.started += 1, setTimeout(() => {
|
|
1322
1329
|
this.entries.get(r) === o && (this.entries.delete(r), a.abort(), this.stats.expired += 1);
|
|
1323
|
-
},
|
|
1330
|
+
}, wt);
|
|
1324
1331
|
}
|
|
1325
1332
|
take(e) {
|
|
1326
|
-
let t =
|
|
1333
|
+
let t = Dt(e), n = this.entries.get(t);
|
|
1327
1334
|
return n && this.entries.delete(t), n;
|
|
1328
1335
|
}
|
|
1329
1336
|
destroy() {
|
|
@@ -1343,13 +1350,13 @@ var Dt = class {
|
|
|
1343
1350
|
}
|
|
1344
1351
|
}
|
|
1345
1352
|
};
|
|
1346
|
-
function
|
|
1353
|
+
function kt(t) {
|
|
1347
1354
|
let n = e.DefaultConfig?.loader;
|
|
1348
1355
|
if (typeof n != "function") return;
|
|
1349
1356
|
class r extends n {
|
|
1350
1357
|
served = !1;
|
|
1351
1358
|
cancelled = !1;
|
|
1352
|
-
stats =
|
|
1359
|
+
stats = At();
|
|
1353
1360
|
load(e, n, r) {
|
|
1354
1361
|
let i = e.rangeEnd ? void 0 : t.take(e.url);
|
|
1355
1362
|
if (!i) {
|
|
@@ -1357,7 +1364,7 @@ function Ot(t) {
|
|
|
1357
1364
|
return;
|
|
1358
1365
|
}
|
|
1359
1366
|
this.served = !0;
|
|
1360
|
-
let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs ||
|
|
1367
|
+
let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || Tt, s = setTimeout(() => {
|
|
1361
1368
|
!this.cancelled && this.served && (i.abort.abort(), t.stats.failed += 1, this.served = !1, super.load(e, n, r));
|
|
1362
1369
|
}, o);
|
|
1363
1370
|
i.bytes.then((o) => {
|
|
@@ -1384,7 +1391,7 @@ function Ot(t) {
|
|
|
1384
1391
|
}
|
|
1385
1392
|
return r;
|
|
1386
1393
|
}
|
|
1387
|
-
function
|
|
1394
|
+
function At() {
|
|
1388
1395
|
return {
|
|
1389
1396
|
aborted: !1,
|
|
1390
1397
|
loaded: 0,
|
|
@@ -1408,10 +1415,10 @@ function kt() {
|
|
|
1408
1415
|
}
|
|
1409
1416
|
};
|
|
1410
1417
|
}
|
|
1411
|
-
function
|
|
1418
|
+
function jt(e) {
|
|
1412
1419
|
return e === "audio" ? "audio" : "main";
|
|
1413
1420
|
}
|
|
1414
|
-
function
|
|
1421
|
+
function Mt(e, t) {
|
|
1415
1422
|
let n = [];
|
|
1416
1423
|
t.initSegment?.url && !t.initSegment.data && n.push({
|
|
1417
1424
|
url: t.initSegment.url,
|
|
@@ -1430,24 +1437,24 @@ function jt(e, t) {
|
|
|
1430
1437
|
}
|
|
1431
1438
|
//#endregion
|
|
1432
1439
|
//#region src/core/engine/hls.ts
|
|
1433
|
-
function
|
|
1440
|
+
function Nt() {
|
|
1434
1441
|
return e.isSupported();
|
|
1435
1442
|
}
|
|
1436
|
-
var
|
|
1437
|
-
function
|
|
1443
|
+
var Pt = 1e6, Ft = 20, It = 1e4, Lt = 3, Rt = 5, zt = 3, Bt = 1e4, Vt = 3e4, Ht = 12e3, Ut = 3e3, Wt = .02, Gt = 6e3, Kt = .5, qt = 3, Jt = .5, Yt = 1.1, Xt = .25, Zt = 5e3, Qt = 4e3, $t = 2, en = 5, tn = 2, nn = 2, rn = 4, an = 4, on = 2e3, sn = 3e4, cn = .2, ln = 30, un = 2, dn = 2, fn = 9, pn = .5, mn = 64;
|
|
1444
|
+
function hn(e) {
|
|
1438
1445
|
if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
|
|
1439
1446
|
delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
|
|
1440
1447
|
return;
|
|
1441
1448
|
}
|
|
1442
|
-
e.liveSyncDuration ??=
|
|
1443
|
-
let t = Math.max(12, e.liveSyncDuration +
|
|
1444
|
-
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t),
|
|
1449
|
+
e.liveSyncDuration ??= dn;
|
|
1450
|
+
let t = Math.max(12, e.liveSyncDuration + fn);
|
|
1451
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), gn(e, e.liveSyncDuration);
|
|
1445
1452
|
}
|
|
1446
|
-
function
|
|
1453
|
+
function gn(e, t) {
|
|
1447
1454
|
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
1448
1455
|
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
1449
1456
|
}
|
|
1450
|
-
var
|
|
1457
|
+
var _n = class {
|
|
1451
1458
|
name = "hls";
|
|
1452
1459
|
hls = null;
|
|
1453
1460
|
deps;
|
|
@@ -1531,7 +1538,7 @@ var gn = class {
|
|
|
1531
1538
|
frameCounter;
|
|
1532
1539
|
detachFrames = null;
|
|
1533
1540
|
constructor(e) {
|
|
1534
|
-
this.deps = e, this.frameCounter = new
|
|
1541
|
+
this.deps = e, this.frameCounter = new ct(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
|
|
1535
1542
|
}
|
|
1536
1543
|
async load() {
|
|
1537
1544
|
this.detachFrames ??= this.frameCounter.attach();
|
|
@@ -1544,7 +1551,7 @@ var gn = class {
|
|
|
1544
1551
|
});
|
|
1545
1552
|
return;
|
|
1546
1553
|
}
|
|
1547
|
-
e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (
|
|
1554
|
+
e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ve(r), Ge()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
|
|
1548
1555
|
let e = this.hls;
|
|
1549
1556
|
if (document.visibilityState !== "visible" || !e) return;
|
|
1550
1557
|
let t = e.liveSyncPosition;
|
|
@@ -1567,7 +1574,7 @@ var gn = class {
|
|
|
1567
1574
|
}
|
|
1568
1575
|
this.loadSuspended = !0;
|
|
1569
1576
|
}
|
|
1570
|
-
},
|
|
1577
|
+
}, Zt));
|
|
1571
1578
|
}
|
|
1572
1579
|
resumeLoading() {
|
|
1573
1580
|
if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
|
|
@@ -1599,7 +1606,7 @@ var gn = class {
|
|
|
1599
1606
|
let t = e.liveSyncPosition;
|
|
1600
1607
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
1601
1608
|
let { video: n } = this.deps;
|
|
1602
|
-
n.currentTime <= t +
|
|
1609
|
+
n.currentTime <= t + pn || (n.currentTime = t);
|
|
1603
1610
|
}
|
|
1604
1611
|
reanchorPartTimeline(e, t) {
|
|
1605
1612
|
let { frag: n, part: r } = t;
|
|
@@ -1611,7 +1618,7 @@ var gn = class {
|
|
|
1611
1618
|
let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
|
|
1612
1619
|
if (!s) return;
|
|
1613
1620
|
let c = a.startPTS - s.start;
|
|
1614
|
-
if (!(!Number.isFinite(c) || Math.abs(c) <
|
|
1621
|
+
if (!(!Number.isFinite(c) || Math.abs(c) < Wt)) {
|
|
1615
1622
|
for (let e of i.fragments) e && e.setStart(e.start + c);
|
|
1616
1623
|
i.fragmentHint?.setStart(i.fragmentHint.start + c), this.deps.debug === !0 && console.info(`havik-player: LL-HLS timeline re-anchored by ${c >= 0 ? "+" : ""}${c.toFixed(3)}s at sn ${n.sn} (level ${n.level})`);
|
|
1617
1624
|
}
|
|
@@ -1634,12 +1641,12 @@ var gn = class {
|
|
|
1634
1641
|
emeEnabled: !0,
|
|
1635
1642
|
drmSystems: { ...this.licenseUrl ? { "com.widevine.alpha": { licenseUrl: this.licenseUrl } } : {} },
|
|
1636
1643
|
drmSystemOptions: {
|
|
1637
|
-
videoRobustness:
|
|
1638
|
-
audioRobustness:
|
|
1639
|
-
videoEncryptionScheme:
|
|
1640
|
-
audioEncryptionScheme:
|
|
1644
|
+
videoRobustness: I.video,
|
|
1645
|
+
audioRobustness: I.audio,
|
|
1646
|
+
videoEncryptionScheme: I.scheme,
|
|
1647
|
+
audioEncryptionScheme: I.scheme
|
|
1641
1648
|
},
|
|
1642
|
-
...
|
|
1649
|
+
...N() ? { requestMediaKeySystemAccessFunc: Be(t) } : {},
|
|
1643
1650
|
licenseXhrSetup: (e, t) => {
|
|
1644
1651
|
let o = performance.now(), s = () => {
|
|
1645
1652
|
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, e.addEventListener("loadend", () => {
|
|
@@ -1651,7 +1658,7 @@ var gn = class {
|
|
|
1651
1658
|
return;
|
|
1652
1659
|
}
|
|
1653
1660
|
let l = this.hls, u, d = new Promise((e) => {
|
|
1654
|
-
u = setTimeout(() => e(void 0),
|
|
1661
|
+
u = setTimeout(() => e(void 0), Bt);
|
|
1655
1662
|
});
|
|
1656
1663
|
return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
|
|
1657
1664
|
if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
|
|
@@ -1667,20 +1674,20 @@ var gn = class {
|
|
|
1667
1674
|
...c
|
|
1668
1675
|
};
|
|
1669
1676
|
if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !f.fLoader) {
|
|
1670
|
-
let e = new
|
|
1677
|
+
let e = new Ot({
|
|
1671
1678
|
sessionId: n.analytics?.sid,
|
|
1672
1679
|
contentId: n.matchUrn
|
|
1673
|
-
}), t =
|
|
1680
|
+
}), t = kt(e);
|
|
1674
1681
|
t && (this.prefetch = e, f.fLoader = t);
|
|
1675
1682
|
}
|
|
1676
|
-
|
|
1683
|
+
hn(f), this.catchUpRate = typeof f.maxLiveSyncPlaybackRate == "number" ? f.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (f.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = f.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = f.autoStartLoad !== !1;
|
|
1677
1684
|
let p = new e(f);
|
|
1678
1685
|
if (this.hls = p, p.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(p, t)), p.on(e.Events.MANIFEST_PARSED, () => {
|
|
1679
1686
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(p), this.measureLadder(p), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
|
|
1680
1687
|
}), p.on(e.Events.FRAG_BUFFERED, (e, t) => {
|
|
1681
1688
|
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(() => {
|
|
1682
1689
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
|
|
1683
|
-
},
|
|
1690
|
+
}, Vt)));
|
|
1684
1691
|
}), p.on(e.Events.FRAG_LOADING, (e, t) => {
|
|
1685
1692
|
t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
|
|
1686
1693
|
}), p.on(e.Events.FRAG_LOADED, (e, t) => {
|
|
@@ -1688,10 +1695,10 @@ var gn = class {
|
|
|
1688
1695
|
let n = t?.frag?.stats, r = n?.loaded;
|
|
1689
1696
|
typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
|
|
1690
1697
|
let i = n?.loading;
|
|
1691
|
-
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 >
|
|
1698
|
+
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 > mn && this.requestTimesMs.shift());
|
|
1692
1699
|
let a = t?.frag?.url;
|
|
1693
1700
|
if (a) {
|
|
1694
|
-
let e =
|
|
1701
|
+
let e = at(a);
|
|
1695
1702
|
e && (this.cdnHost = e);
|
|
1696
1703
|
}
|
|
1697
1704
|
}), p.on(e.Events.LEVEL_LOADED, (e, t) => {
|
|
@@ -1705,15 +1712,15 @@ var gn = class {
|
|
|
1705
1712
|
}), p.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
|
|
1706
1713
|
let t = this.prefetch;
|
|
1707
1714
|
p.on(e.Events.KEY_LOADING, (e, n) => {
|
|
1708
|
-
let r = n?.frag, i =
|
|
1709
|
-
if (r && t.isActive(i)) for (let e of
|
|
1710
|
-
}), p.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(
|
|
1715
|
+
let r = n?.frag, i = jt(r?.type);
|
|
1716
|
+
if (r && t.isActive(i)) for (let e of Mt(p, r)) t.prefetch(e.url, i, e.kind);
|
|
1717
|
+
}), p.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(jt(n?.frag?.type)));
|
|
1711
1718
|
}
|
|
1712
1719
|
p.on(e.Events.KEY_LOADED, () => {
|
|
1713
1720
|
u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
|
|
1714
1721
|
}), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
|
|
1715
1722
|
this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.checkFrameDrops();
|
|
1716
|
-
},
|
|
1723
|
+
}, Ut), p.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
1717
1724
|
this.renditionSwitches += 1;
|
|
1718
1725
|
let n = this.lastLevelIndex >= 0 ? p.levels[this.lastLevelIndex] : void 0, r = p.levels[t.level];
|
|
1719
1726
|
n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
|
|
@@ -1777,7 +1784,7 @@ var gn = class {
|
|
|
1777
1784
|
return;
|
|
1778
1785
|
}
|
|
1779
1786
|
this.capTimer && clearTimeout(this.capTimer);
|
|
1780
|
-
let t = e > this.sizeCapLevel ?
|
|
1787
|
+
let t = e > this.sizeCapLevel ? on : sn;
|
|
1781
1788
|
this.capTimer = setTimeout(() => {
|
|
1782
1789
|
this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
|
|
1783
1790
|
}, t);
|
|
@@ -1787,9 +1794,9 @@ var gn = class {
|
|
|
1787
1794
|
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;
|
|
1788
1795
|
}
|
|
1789
1796
|
dropLevelsWidevineCannotPlay(e) {
|
|
1790
|
-
this.removeLevelsWhere(e, (e) =>
|
|
1791
|
-
let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e &&
|
|
1792
|
-
for (let n of t)
|
|
1797
|
+
this.removeLevelsWhere(e, (e) => Ke(e) !== !0);
|
|
1798
|
+
let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && L(e) !== "avc" && !!L(e)));
|
|
1799
|
+
for (let n of t) We(n).then((t) => {
|
|
1793
1800
|
t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
|
|
1794
1801
|
});
|
|
1795
1802
|
}
|
|
@@ -1797,10 +1804,10 @@ var gn = class {
|
|
|
1797
1804
|
let n = e.levels ?? [], r = [], i = /* @__PURE__ */ new Set();
|
|
1798
1805
|
if (n.forEach((e, n) => {
|
|
1799
1806
|
let a = e.videoCodec;
|
|
1800
|
-
a &&
|
|
1807
|
+
a && L(a) && t(a) && (r.push(n), i.add(a));
|
|
1801
1808
|
}), !r.length) return !1;
|
|
1802
1809
|
let a = [...i].join(", ");
|
|
1803
|
-
if (!n.some((e, t) => r.includes(t) ? !1 : !
|
|
1810
|
+
if (!n.some((e, t) => r.includes(t) ? !1 : !L(e.videoCodec) || Ke(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
|
|
1804
1811
|
for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
|
|
1805
1812
|
return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
|
|
1806
1813
|
}
|
|
@@ -1906,7 +1913,7 @@ var gn = class {
|
|
|
1906
1913
|
return;
|
|
1907
1914
|
}
|
|
1908
1915
|
let e = Date.now() - this.lastAdvanceMs;
|
|
1909
|
-
!this.chaseSuspended && e >
|
|
1916
|
+
!this.chaseSuspended && e > Gt && this.suspendChasing(), e > Ht && this.emitEnded("stalled");
|
|
1910
1917
|
}
|
|
1911
1918
|
resetStarvationWindow() {
|
|
1912
1919
|
this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
|
|
@@ -1921,7 +1928,7 @@ var gn = class {
|
|
|
1921
1928
|
this.resetStarvationWindow();
|
|
1922
1929
|
return;
|
|
1923
1930
|
}
|
|
1924
|
-
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs <
|
|
1931
|
+
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < Gt, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > Qt, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = B(t), c = o - s, l = c !== this.starvedFrames;
|
|
1925
1932
|
if (this.starvedFrames = c, !a || l) {
|
|
1926
1933
|
(t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
|
|
1927
1934
|
return;
|
|
@@ -1930,12 +1937,12 @@ var gn = class {
|
|
|
1930
1937
|
this.resetStarvationWindow();
|
|
1931
1938
|
return;
|
|
1932
1939
|
}
|
|
1933
|
-
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 >
|
|
1940
|
+
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 > rn && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= tn && (this.clearKick(), this.starvationRebuilds < nn)) {
|
|
1934
1941
|
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");
|
|
1935
1942
|
return;
|
|
1936
1943
|
}
|
|
1937
|
-
let u = i && this.starvedTicks >=
|
|
1938
|
-
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >=
|
|
1944
|
+
let u = i && this.starvedTicks >= $t, d = !i && this.deadTicks >= rn && this.recentMainFrags.reduce((e, t) => e + t, 0) >= an;
|
|
1945
|
+
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= en))) {
|
|
1939
1946
|
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");
|
|
1940
1947
|
try {
|
|
1941
1948
|
e.stopLoad(), e.startLoad(-1);
|
|
@@ -1950,7 +1957,7 @@ var gn = class {
|
|
|
1950
1957
|
let t = e.latency, n = e.targetLatency;
|
|
1951
1958
|
if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
|
|
1952
1959
|
let r = t - n;
|
|
1953
|
-
!this.catchUpEngaged && r >
|
|
1960
|
+
!this.catchUpEngaged && r > Kt ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= Kt && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
|
|
1954
1961
|
let i = this.catchUpEngaged ? this.catchUpRate : 1;
|
|
1955
1962
|
e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
|
|
1956
1963
|
}
|
|
@@ -1972,15 +1979,15 @@ var gn = class {
|
|
|
1972
1979
|
return;
|
|
1973
1980
|
}
|
|
1974
1981
|
let { totalFrames: n, dropped: r } = B(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
|
|
1975
|
-
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a <
|
|
1982
|
+
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < ln || o < 0) {
|
|
1976
1983
|
this.fpsBadTicks = 0;
|
|
1977
1984
|
return;
|
|
1978
1985
|
}
|
|
1979
|
-
if (o <=
|
|
1986
|
+
if (o <= cn * a) {
|
|
1980
1987
|
this.fpsBadTicks = 0;
|
|
1981
1988
|
return;
|
|
1982
1989
|
}
|
|
1983
|
-
if (this.fpsBadTicks += 1, this.fpsBadTicks <
|
|
1990
|
+
if (this.fpsBadTicks += 1, this.fpsBadTicks < un) return;
|
|
1984
1991
|
this.fpsBadTicks = 0;
|
|
1985
1992
|
let s = e.levels, c = s[e.currentLevel];
|
|
1986
1993
|
if (!c) return;
|
|
@@ -1997,20 +2004,20 @@ var gn = class {
|
|
|
1997
2004
|
return;
|
|
1998
2005
|
}
|
|
1999
2006
|
let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
|
|
2000
|
-
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(
|
|
2007
|
+
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(Yt, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
|
|
2001
2008
|
this.resetChaseWindow();
|
|
2002
2009
|
return;
|
|
2003
2010
|
}
|
|
2004
|
-
if (this.chaseLatency < 0 || this.chaseLatency - n >=
|
|
2011
|
+
if (this.chaseLatency < 0 || this.chaseLatency - n >= Jt) {
|
|
2005
2012
|
this.chaseLatency = n, this.chaseTicks = 0;
|
|
2006
2013
|
return;
|
|
2007
2014
|
}
|
|
2008
|
-
if (this.chaseTicks += 1, this.chaseTicks <
|
|
2015
|
+
if (this.chaseTicks += 1, this.chaseTicks < qt) return;
|
|
2009
2016
|
this.resetChaseWindow();
|
|
2010
2017
|
let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
|
|
2011
2018
|
if (!(a > 1)) return;
|
|
2012
2019
|
let o = typeof e.targetLatency == "number" ? e.targetLatency : 0, s = Math.min(n, a - 1);
|
|
2013
|
-
s < o +
|
|
2020
|
+
s < o + Xt || (console.warn(`havik-player: catch-up at ${r}x not gaining on the live edge (latency ${n.toFixed(1)}s); holding at ${s.toFixed(1)}s`), this.liveRetargets += 1, e.targetLatency = s);
|
|
2014
2021
|
}
|
|
2015
2022
|
suspendChasing() {
|
|
2016
2023
|
let e = this.hls;
|
|
@@ -2040,14 +2047,14 @@ var gn = class {
|
|
|
2040
2047
|
} catch {}
|
|
2041
2048
|
}
|
|
2042
2049
|
startEstimate() {
|
|
2043
|
-
return this.deps.rememberBandwidth === !1 ?
|
|
2050
|
+
return this.deps.rememberBandwidth === !1 ? Pt : Pe() ?? Pt;
|
|
2044
2051
|
}
|
|
2045
2052
|
maybeRememberBandwidth(e) {
|
|
2046
|
-
if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded <
|
|
2053
|
+
if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < Ft) return;
|
|
2047
2054
|
let t = Date.now();
|
|
2048
|
-
if (!e && t - this.bwSavedAt <
|
|
2055
|
+
if (!e && t - this.bwSavedAt < It) return;
|
|
2049
2056
|
let n = this.hls?.bandwidthEstimate;
|
|
2050
|
-
typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t,
|
|
2057
|
+
typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Fe(n));
|
|
2051
2058
|
}
|
|
2052
2059
|
destroy() {
|
|
2053
2060
|
if (this.maybeRememberBandwidth(!0), this.detachFrames?.(), this.detachFrames = null, 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.onTimeUpdate &&= (this.deps.video.removeEventListener("timeupdate", this.onTimeUpdate), 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) {
|
|
@@ -2065,7 +2072,7 @@ var gn = class {
|
|
|
2065
2072
|
scheduleLicenseRetry(t) {
|
|
2066
2073
|
if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
|
|
2067
2074
|
let n = t.response?.code ?? 0;
|
|
2068
|
-
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >=
|
|
2075
|
+
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= zt) return !1;
|
|
2069
2076
|
this.licenseRecoveries += 1;
|
|
2070
2077
|
let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
|
|
2071
2078
|
return this.licenseRetryTimer = setTimeout(() => {
|
|
@@ -2097,7 +2104,7 @@ var gn = class {
|
|
|
2097
2104
|
return;
|
|
2098
2105
|
}
|
|
2099
2106
|
if (t.type === e.ErrorTypes.NETWORK_ERROR) {
|
|
2100
|
-
if (this.networkRecoveries <
|
|
2107
|
+
if (this.networkRecoveries < Rt) {
|
|
2101
2108
|
this.networkRecoveries += 1;
|
|
2102
2109
|
let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
|
|
2103
2110
|
this.networkRetryTimer = setTimeout(() => {
|
|
@@ -2114,7 +2121,7 @@ var gn = class {
|
|
|
2114
2121
|
return;
|
|
2115
2122
|
}
|
|
2116
2123
|
if (t.type === e.ErrorTypes.MEDIA_ERROR) {
|
|
2117
|
-
if (this.mediaRecoveries <
|
|
2124
|
+
if (this.mediaRecoveries < Lt) {
|
|
2118
2125
|
this.mediaRecoveries += 1, n.recoverMediaError();
|
|
2119
2126
|
return;
|
|
2120
2127
|
}
|
|
@@ -2138,19 +2145,19 @@ var gn = class {
|
|
|
2138
2145
|
let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
|
|
2139
2146
|
return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
|
|
2140
2147
|
}
|
|
2141
|
-
},
|
|
2148
|
+
}, vn = 15e3, yn = 6e5, bn = 3e5, xn = 100, q = 1, Sn = 1e3, Cn = 3e4, wn = 1e3, Tn = {
|
|
2142
2149
|
inline: "PRESENTATION_INLINE",
|
|
2143
2150
|
fullscreen: "PRESENTATION_FULLSCREEN",
|
|
2144
2151
|
pip: "PRESENTATION_PIP"
|
|
2145
|
-
},
|
|
2152
|
+
}, En = {
|
|
2146
2153
|
widevine: "KEY_SYSTEM_WIDEVINE",
|
|
2147
2154
|
fairplay: "KEY_SYSTEM_FAIRPLAY",
|
|
2148
2155
|
none: "KEY_SYSTEM_NONE"
|
|
2149
2156
|
};
|
|
2150
|
-
function
|
|
2157
|
+
function Dn(e, t) {
|
|
2151
2158
|
return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
|
|
2152
2159
|
}
|
|
2153
|
-
var
|
|
2160
|
+
var On = /* @__PURE__ */ new Set([
|
|
2154
2161
|
"INVALID_URN",
|
|
2155
2162
|
"NOT_FOUND",
|
|
2156
2163
|
"GONE",
|
|
@@ -2170,7 +2177,7 @@ var Dn = /* @__PURE__ */ new Set([
|
|
|
2170
2177
|
ended: "PLAYER_STATE_ENDED",
|
|
2171
2178
|
error: "PLAYER_STATE_ERROR"
|
|
2172
2179
|
};
|
|
2173
|
-
function
|
|
2180
|
+
function kn(e) {
|
|
2174
2181
|
try {
|
|
2175
2182
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
2176
2183
|
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);
|
|
@@ -2178,8 +2185,8 @@ function On(e) {
|
|
|
2178
2185
|
return;
|
|
2179
2186
|
}
|
|
2180
2187
|
}
|
|
2181
|
-
var
|
|
2182
|
-
function
|
|
2188
|
+
var An = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), jn = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), Mn = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
|
|
2189
|
+
function Nn(e) {
|
|
2183
2190
|
if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
|
|
2184
2191
|
let t;
|
|
2185
2192
|
try {
|
|
@@ -2188,19 +2195,19 @@ function Mn(e) {
|
|
|
2188
2195
|
} catch {
|
|
2189
2196
|
return;
|
|
2190
2197
|
}
|
|
2191
|
-
if (
|
|
2192
|
-
Y.add(t), g(
|
|
2198
|
+
if (jn.has(t) && !Y.has(t)) {
|
|
2199
|
+
Y.add(t), g(Mn(new URL(t).origin));
|
|
2193
2200
|
for (let e of X) e.noteCspBlocked();
|
|
2194
2201
|
}
|
|
2195
2202
|
}
|
|
2196
|
-
function
|
|
2203
|
+
function Pn(e, t) {
|
|
2197
2204
|
return g(t, e), { disabledReason: t };
|
|
2198
2205
|
}
|
|
2199
|
-
function
|
|
2200
|
-
if (n) return t && !
|
|
2206
|
+
function Fn(e, t, n) {
|
|
2207
|
+
if (n) return t && !An(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
|
|
2201
2208
|
if (t) return { endpoint: t };
|
|
2202
|
-
if (t !== void 0) return
|
|
2203
|
-
let r =
|
|
2209
|
+
if (t !== void 0) return Pn("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).");
|
|
2210
|
+
let r = kn(e);
|
|
2204
2211
|
if (r) return { endpoint: r };
|
|
2205
2212
|
let i;
|
|
2206
2213
|
try {
|
|
@@ -2208,9 +2215,9 @@ function Pn(e, t, n) {
|
|
|
2208
2215
|
} catch {
|
|
2209
2216
|
i = e;
|
|
2210
2217
|
}
|
|
2211
|
-
return
|
|
2218
|
+
return Pn(i, `analytics is disabled: no QoE beacons will be sent. The beacons endpoint cannot be derived from the baseUrl host "${i}" — 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).`);
|
|
2212
2219
|
}
|
|
2213
|
-
var
|
|
2220
|
+
var In = class {
|
|
2214
2221
|
opts;
|
|
2215
2222
|
url;
|
|
2216
2223
|
cspKey;
|
|
@@ -2292,8 +2299,8 @@ var Fn = class {
|
|
|
2292
2299
|
constructor(e) {
|
|
2293
2300
|
this.opts = {
|
|
2294
2301
|
...e,
|
|
2295
|
-
heartbeatMs: e.heartbeatMs ??
|
|
2296
|
-
idleMs: e.idleMs ??
|
|
2302
|
+
heartbeatMs: e.heartbeatMs ?? vn,
|
|
2303
|
+
idleMs: e.idleMs ?? yn
|
|
2297
2304
|
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
|
|
2298
2305
|
try {
|
|
2299
2306
|
let e = new URL(this.url);
|
|
@@ -2310,11 +2317,11 @@ var Fn = class {
|
|
|
2310
2317
|
sdkVersion: this.opts.sdkVersion,
|
|
2311
2318
|
...this.opts.environment
|
|
2312
2319
|
};
|
|
2313
|
-
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(),
|
|
2320
|
+
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Sn), 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.cspKey && jn.add(this.cspKey), document.addEventListener("securitypolicyviolation", Nn), X.add(this), this.noteCspBlocked(), this.onVisibility());
|
|
2314
2321
|
}
|
|
2315
2322
|
checkSuspension(e) {
|
|
2316
2323
|
if (this.endedFlag || !this.opts.idleMs) return !1;
|
|
2317
|
-
let t = Math.max(this.opts.idleMs,
|
|
2324
|
+
let t = Math.max(this.opts.idleMs, bn);
|
|
2318
2325
|
return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
|
|
2319
2326
|
}
|
|
2320
2327
|
syncIdle(e) {
|
|
@@ -2337,12 +2344,12 @@ var Fn = class {
|
|
|
2337
2344
|
let a = {
|
|
2338
2345
|
fromState: J[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2339
2346
|
toState: J[t] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2340
|
-
presentation:
|
|
2347
|
+
presentation: Tn[this.presentation]
|
|
2341
2348
|
}, o = this.causeOf(e, t, i);
|
|
2342
2349
|
o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
2343
2350
|
}
|
|
2344
2351
|
seekInduced(e) {
|
|
2345
|
-
return this.lastSeekMs >= 0 && e - this.lastSeekMs <
|
|
2352
|
+
return this.lastSeekMs >= 0 && e - this.lastSeekMs < wn;
|
|
2346
2353
|
}
|
|
2347
2354
|
causeOf(e, t, n) {
|
|
2348
2355
|
if (t === "error") return "TRANSITION_CAUSE_ERROR";
|
|
@@ -2416,7 +2423,7 @@ var Fn = class {
|
|
|
2416
2423
|
let r = n ?? "";
|
|
2417
2424
|
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";
|
|
2418
2425
|
if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
|
|
2419
|
-
if (
|
|
2426
|
+
if (On.has(e)) return "ERROR_STAGE_RESOLVE";
|
|
2420
2427
|
let i = t ?? "";
|
|
2421
2428
|
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";
|
|
2422
2429
|
}
|
|
@@ -2463,14 +2470,14 @@ var Fn = class {
|
|
|
2463
2470
|
if (this.lastRequestCount = g, _ > 0) {
|
|
2464
2471
|
o.requestCountDelta = _;
|
|
2465
2472
|
let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
|
|
2466
|
-
n.length > 0 && (o.requestTimeP50Ms =
|
|
2473
|
+
n.length > 0 && (o.requestTimeP50Ms = Dn(n, 50), o.requestTimeP95Ms = Dn(n, 95));
|
|
2467
2474
|
}
|
|
2468
2475
|
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();
|
|
2469
2476
|
}
|
|
2470
2477
|
maybeEmitMediaInfo(e) {
|
|
2471
2478
|
if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
|
|
2472
2479
|
let t = {};
|
|
2473
|
-
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem =
|
|
2480
|
+
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = En[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);
|
|
2474
2481
|
let n = JSON.stringify(t);
|
|
2475
2482
|
n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
|
|
2476
2483
|
}
|
|
@@ -2490,7 +2497,7 @@ var Fn = class {
|
|
|
2490
2497
|
let c = r?.positionMs ?? 0;
|
|
2491
2498
|
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));
|
|
2492
2499
|
let l = e !== "END_REASON_ENDED";
|
|
2493
|
-
l && this.lastStallMs > 0 && n - this.lastStallMs <=
|
|
2500
|
+
l && this.lastStallMs > 0 && n - this.lastStallMs <= Cn && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Cn && (i.abandonAfterErrorMs = Math.max(q, 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);
|
|
2494
2501
|
let u = r?.decodedFrames ?? this.lastDecoded;
|
|
2495
2502
|
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");
|
|
2496
2503
|
}
|
|
@@ -2510,13 +2517,13 @@ var Fn = class {
|
|
|
2510
2517
|
};
|
|
2511
2518
|
}
|
|
2512
2519
|
noteCspBlocked() {
|
|
2513
|
-
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(
|
|
2520
|
+
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(Mn(new URL(this.url).origin)));
|
|
2514
2521
|
}
|
|
2515
2522
|
cspBlocked() {
|
|
2516
2523
|
return !!this.cspKey && Y.has(this.cspKey);
|
|
2517
2524
|
}
|
|
2518
2525
|
enqueue(e) {
|
|
2519
|
-
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length >
|
|
2526
|
+
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > xn;) {
|
|
2520
2527
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
2521
2528
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
2522
2529
|
}
|
|
@@ -2543,7 +2550,7 @@ var Fn = class {
|
|
|
2543
2550
|
};
|
|
2544
2551
|
//#endregion
|
|
2545
2552
|
//#region src/core/environment.ts
|
|
2546
|
-
function
|
|
2553
|
+
function Ln() {
|
|
2547
2554
|
if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
|
|
2548
2555
|
let e;
|
|
2549
2556
|
try {
|
|
@@ -2568,14 +2575,14 @@ function In() {
|
|
|
2568
2575
|
integration: "INTEGRATION_KIND_IFRAME"
|
|
2569
2576
|
};
|
|
2570
2577
|
}
|
|
2571
|
-
function
|
|
2578
|
+
function Rn() {
|
|
2572
2579
|
if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
|
|
2573
2580
|
let e = navigator.userAgentData, t = e?.platform ?? "";
|
|
2574
2581
|
if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
|
|
2575
2582
|
let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
|
|
2576
2583
|
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";
|
|
2577
2584
|
}
|
|
2578
|
-
function
|
|
2585
|
+
function zn() {
|
|
2579
2586
|
let e = typeof navigator < "u" ? navigator.connection : void 0;
|
|
2580
2587
|
if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
|
|
2581
2588
|
let t = {
|
|
@@ -2594,17 +2601,17 @@ function Rn() {
|
|
|
2594
2601
|
}
|
|
2595
2602
|
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;
|
|
2596
2603
|
}
|
|
2597
|
-
function
|
|
2598
|
-
let t =
|
|
2599
|
-
deviceClass:
|
|
2604
|
+
function Bn(e) {
|
|
2605
|
+
let t = Ln(), n = {
|
|
2606
|
+
deviceClass: Rn(),
|
|
2600
2607
|
integration: t.integration,
|
|
2601
|
-
...
|
|
2608
|
+
...zn()
|
|
2602
2609
|
};
|
|
2603
2610
|
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);
|
|
2604
2611
|
let r = e.getBoundingClientRect?.();
|
|
2605
2612
|
return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
|
|
2606
2613
|
}
|
|
2607
|
-
async function
|
|
2614
|
+
async function Vn() {
|
|
2608
2615
|
let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
|
|
2609
2616
|
if (!e?.getHighEntropyValues) return {};
|
|
2610
2617
|
try {
|
|
@@ -2616,7 +2623,7 @@ async function Bn() {
|
|
|
2616
2623
|
}
|
|
2617
2624
|
//#endregion
|
|
2618
2625
|
//#region src/core/version.ts
|
|
2619
|
-
var
|
|
2626
|
+
var Hn = "2.19.0", Un = {
|
|
2620
2627
|
accent: "#E1B600",
|
|
2621
2628
|
accentText: "#1B1C23",
|
|
2622
2629
|
background: "#0e0f13",
|
|
@@ -2627,7 +2634,7 @@ var Vn = "2.18.0", Hn = {
|
|
|
2627
2634
|
border: "rgba(255, 255, 255, 0.1)",
|
|
2628
2635
|
radius: "8px",
|
|
2629
2636
|
fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
|
|
2630
|
-
},
|
|
2637
|
+
}, Wn = {
|
|
2631
2638
|
accent: "--havik-accent",
|
|
2632
2639
|
accentText: "--havik-accent-text",
|
|
2633
2640
|
background: "--havik-bg",
|
|
@@ -2639,26 +2646,26 @@ var Vn = "2.18.0", Hn = {
|
|
|
2639
2646
|
radius: "--havik-radius",
|
|
2640
2647
|
fontFamily: "--havik-font"
|
|
2641
2648
|
};
|
|
2642
|
-
function
|
|
2649
|
+
function Z(e, t) {
|
|
2643
2650
|
let n = {
|
|
2644
|
-
...
|
|
2651
|
+
...Un,
|
|
2645
2652
|
...t
|
|
2646
2653
|
};
|
|
2647
|
-
for (let t of Object.keys(
|
|
2654
|
+
for (let t of Object.keys(Wn)) e.style.setProperty(Wn[t], n[t]);
|
|
2648
2655
|
n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
|
|
2649
2656
|
}
|
|
2650
2657
|
//#endregion
|
|
2651
2658
|
//#region src/ui/styles.ts
|
|
2652
|
-
var Gn = "havik-player-styles", Kn = "\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 touch-action:manipulation}\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",
|
|
2653
|
-
function
|
|
2659
|
+
var Gn = "havik-player-styles", Kn = "\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 touch-action:manipulation}\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", qn = /* @__PURE__ */ new WeakMap();
|
|
2660
|
+
function Jn(e = document, t) {
|
|
2654
2661
|
let n = e.querySelector(`style#${Gn}`);
|
|
2655
|
-
if (n && (!t ||
|
|
2662
|
+
if (n && (!t || qn.get(n) === t)) return;
|
|
2656
2663
|
let r = e.createElement("style");
|
|
2657
|
-
r.id = Gn, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = Kn,
|
|
2664
|
+
r.id = Gn, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = Kn, qn.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
|
|
2658
2665
|
}
|
|
2659
2666
|
//#endregion
|
|
2660
2667
|
//#region src/ui/icons.ts
|
|
2661
|
-
var
|
|
2668
|
+
var Yn = {
|
|
2662
2669
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
2663
2670
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
2664
2671
|
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\"/>",
|
|
@@ -2672,20 +2679,20 @@ var Jn = {
|
|
|
2672
2679
|
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\"/>"
|
|
2673
2680
|
};
|
|
2674
2681
|
function Q(e) {
|
|
2675
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
2682
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Yn[e]}</svg>`;
|
|
2676
2683
|
}
|
|
2677
2684
|
//#endregion
|
|
2678
2685
|
//#region src/ui/controls.ts
|
|
2679
|
-
var
|
|
2686
|
+
var Xn = 3e3, Zn = 250, Qn = /* @__PURE__ */ new Set([
|
|
2680
2687
|
"GONE",
|
|
2681
2688
|
"NOT_FOUND",
|
|
2682
2689
|
"INVALID_URN",
|
|
2683
2690
|
"UNAUTHORIZED"
|
|
2684
2691
|
]);
|
|
2685
|
-
function
|
|
2686
|
-
return new
|
|
2692
|
+
function $n(e) {
|
|
2693
|
+
return new er(e);
|
|
2687
2694
|
}
|
|
2688
|
-
var
|
|
2695
|
+
var er = class {
|
|
2689
2696
|
root;
|
|
2690
2697
|
video;
|
|
2691
2698
|
player;
|
|
@@ -2716,6 +2723,7 @@ var $n = class {
|
|
|
2716
2723
|
statusKind = null;
|
|
2717
2724
|
statusMsg = null;
|
|
2718
2725
|
hasPlayed = !1;
|
|
2726
|
+
fsSupported = !0;
|
|
2719
2727
|
lastError = null;
|
|
2720
2728
|
logoUrl;
|
|
2721
2729
|
statusOverlays;
|
|
@@ -2732,7 +2740,7 @@ var $n = class {
|
|
|
2732
2740
|
scrubbing = !1;
|
|
2733
2741
|
offFns = [];
|
|
2734
2742
|
constructor(e) {
|
|
2735
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
2743
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Xn, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.streamEnded = e.streamEnded ?? (() => !1), this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, Jn(this.doc, e.cspNonce), 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");
|
|
2736
2744
|
let t = (e, t, n) => {
|
|
2737
2745
|
let r = this.doc.createElement(e);
|
|
2738
2746
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -2770,7 +2778,7 @@ var $n = class {
|
|
|
2770
2778
|
let o = this.doc.createElement("span");
|
|
2771
2779
|
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";
|
|
2772
2780
|
let s = t("div", "havik-spacer");
|
|
2773
|
-
if (this.ccBtn = n("havik-btn", "cc", "Subtitles"), this.audioBtn = n("havik-btn", "settings", "Audio track"), this.qualityBtn = n("havik-btn", "settings", "Quality"), this.pipBtn = n("havik-btn", "pip", "Picture in picture"), this.fsBtn = n("havik-btn", "fullscreen", "Fullscreen"), this.ccBtn.style.display = "none", this.audioBtn.style.display = "none", this.qualityBtn.style.display = "none", this.pipSupported() || (this.pipBtn.style.display = "none"), i.append(this.playBtn, a, this.live, this.time, s, this.ccBtn, this.audioBtn, this.qualityBtn, this.pipBtn, this.fsBtn), this.bar.append(this.seek, i), this.menu = t("div", "havik-menu", { role: "menu" }), this.menu.hidden = !0, this.root.append(this.gradient, this.overlay, this.bar, this.menu), e.logoUrl) {
|
|
2781
|
+
if (this.ccBtn = n("havik-btn", "cc", "Subtitles"), this.audioBtn = n("havik-btn", "settings", "Audio track"), this.qualityBtn = n("havik-btn", "settings", "Quality"), this.pipBtn = n("havik-btn", "pip", "Picture in picture"), this.fsBtn = n("havik-btn", "fullscreen", "Fullscreen"), this.ccBtn.style.display = "none", this.audioBtn.style.display = "none", this.qualityBtn.style.display = "none", this.pipSupported() || (this.pipBtn.style.display = "none"), this.syncFullscreenSupport(), i.append(this.playBtn, a, this.live, this.time, s, this.ccBtn, this.audioBtn, this.qualityBtn, this.pipBtn, this.fsBtn), this.bar.append(this.seek, i), this.menu = t("div", "havik-menu", { role: "menu" }), this.menu.hidden = !0, this.root.append(this.gradient, this.overlay, this.bar, this.menu), e.logoUrl) {
|
|
2774
2782
|
let n = t("div", "havik-watermark");
|
|
2775
2783
|
n.style.backgroundImage = `url("${e.logoUrl}")`, this.root.append(n);
|
|
2776
2784
|
}
|
|
@@ -2788,7 +2796,7 @@ var $n = class {
|
|
|
2788
2796
|
}), this.on(this.muteBtn, "click", () => this.player.setMuted(!e.muted)), this.on(this.volSlider, "input", () => {
|
|
2789
2797
|
let t = Number(this.volSlider.value);
|
|
2790
2798
|
this.setVolumeFill(t), this.player.setVolume(t), t > 0 && e.muted && this.player.setMuted(!1);
|
|
2791
|
-
}), this.on(this.liveGo, "click", () => this.player.seekToLive()), this.on(this.pipBtn, "click", () => void this.togglePip()), this.on(this.fsBtn, "click", () => void this.toggleFullscreen()), this.on(this.ccBtn, "click", () => this.toggleMenu("cc")), this.on(this.audioBtn, "click", () => this.toggleMenu("audio")), this.on(this.qualityBtn, "click", () => this.toggleMenu("quality")), this.on(this.seek, "pointerdown", (e) => this.onSeekDown(e)), this.on(this.seek, "keydown", (e) => this.onSeekKey(e)), this.on(e, "play", () => this.syncPlayPause()), this.on(e, "pause", () => this.syncPlayPause()), this.on(e, "volumechange", () => this.syncVolume()), this.on(e, "timeupdate", () => this.syncProgress()), this.on(e, "progress", () => this.syncProgress()), this.on(e, "durationchange", () => this.syncProgress()), this.offFns.push(this.player.on("statechange", () => this.syncState())), this.offFns.push(this.player.on("ended", () => this.syncState())), this.offFns.push(this.player.on("ready", () => this.refreshTracks())), this.offFns.push(this.player.on("qualitychange", () => this.onTracksChanged())), this.offFns.push(this.player.on("audiotrackchange", () => this.onTracksChanged())), this.offFns.push(this.player.on("texttrackchange", () => this.onTracksChanged())), this.offFns.push(this.player.on("pipchange", (e) => this.syncPip(e))), this.offFns.push(this.player.on("stats", () => this.syncLive())), this.offFns.push(this.player.on("error", (e) => {
|
|
2799
|
+
}), this.on(this.liveGo, "click", () => this.player.seekToLive()), this.on(this.pipBtn, "click", () => void this.togglePip()), this.on(this.fsBtn, "click", () => void this.toggleFullscreen()), this.on(this.ccBtn, "click", () => this.toggleMenu("cc")), this.on(this.audioBtn, "click", () => this.toggleMenu("audio")), this.on(this.qualityBtn, "click", () => this.toggleMenu("quality")), this.on(this.seek, "pointerdown", (e) => this.onSeekDown(e)), this.on(this.seek, "keydown", (e) => this.onSeekKey(e)), this.on(e, "play", () => this.syncPlayPause()), this.on(e, "pause", () => this.syncPlayPause()), this.on(e, "volumechange", () => this.syncVolume()), this.on(e, "timeupdate", () => this.syncProgress()), this.on(e, "progress", () => this.syncProgress()), this.on(e, "durationchange", () => this.syncProgress()), this.on(e, "loadedmetadata", () => this.syncFullscreenSupport()), this.offFns.push(this.player.on("statechange", () => this.syncState())), this.offFns.push(this.player.on("ended", () => this.syncState())), this.offFns.push(this.player.on("ready", () => this.refreshTracks())), this.offFns.push(this.player.on("qualitychange", () => this.onTracksChanged())), this.offFns.push(this.player.on("audiotrackchange", () => this.onTracksChanged())), this.offFns.push(this.player.on("texttrackchange", () => this.onTracksChanged())), this.offFns.push(this.player.on("pipchange", (e) => this.syncPip(e))), this.offFns.push(this.player.on("stats", () => this.syncLive())), this.offFns.push(this.player.on("error", (e) => {
|
|
2792
2800
|
this.lastError = e, this.statusKind = null, this.syncState();
|
|
2793
2801
|
}));
|
|
2794
2802
|
let t = (e) => e.pointerType !== "touch";
|
|
@@ -2818,7 +2826,7 @@ var $n = class {
|
|
|
2818
2826
|
let t = this.surfaceWasHidden;
|
|
2819
2827
|
this.tapTimer = setTimeout(() => {
|
|
2820
2828
|
this.tapTimer = void 0, this.toggleBar(t);
|
|
2821
|
-
},
|
|
2829
|
+
}, Zn);
|
|
2822
2830
|
}
|
|
2823
2831
|
toggleBar(e) {
|
|
2824
2832
|
e ? this.poke() : this.hideIfIdle();
|
|
@@ -2853,7 +2861,7 @@ var $n = class {
|
|
|
2853
2861
|
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);
|
|
2854
2862
|
} else {
|
|
2855
2863
|
let r = this.doc.createElement("div");
|
|
2856
|
-
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !
|
|
2864
|
+
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Qn.has(this.lastError.code)) {
|
|
2857
2865
|
let e = this.doc.createElement("button");
|
|
2858
2866
|
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);
|
|
2859
2867
|
}
|
|
@@ -2894,7 +2902,7 @@ var $n = class {
|
|
|
2894
2902
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
2895
2903
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
2896
2904
|
}
|
|
2897
|
-
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${
|
|
2905
|
+
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${tr(this.video.currentTime)} / ${tr(this.video.duration)}`);
|
|
2898
2906
|
}
|
|
2899
2907
|
syncLive() {
|
|
2900
2908
|
let e = this.player.getStats(), t = e.isLive !== !1, n = this.player.state === "ended", r = !t && !this.streamEnded();
|
|
@@ -2944,17 +2952,17 @@ var $n = class {
|
|
|
2944
2952
|
renderQualityMenu() {
|
|
2945
2953
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
2946
2954
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
2947
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
2955
|
+
for (let n of e) this.menu.append(this.menuItem(nr(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
2948
2956
|
}
|
|
2949
2957
|
renderAudioMenu() {
|
|
2950
2958
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
2951
2959
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
2952
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2960
|
+
for (let t of e) this.menu.append(this.menuItem(rr(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
2953
2961
|
}
|
|
2954
2962
|
renderCcMenu() {
|
|
2955
2963
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
2956
2964
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
2957
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2965
|
+
for (let t of e) this.menu.append(this.menuItem(ir(t), !1, () => this.player.setTextTrack(t.id)));
|
|
2958
2966
|
}
|
|
2959
2967
|
onTracksChanged() {
|
|
2960
2968
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -2974,11 +2982,14 @@ var $n = class {
|
|
|
2974
2982
|
}
|
|
2975
2983
|
async toggleFullscreen() {
|
|
2976
2984
|
try {
|
|
2977
|
-
|
|
2985
|
+
S(this.video, this.root) ? await T(this.video, this.root) : await w(this.video, this.root);
|
|
2978
2986
|
} catch {}
|
|
2979
2987
|
}
|
|
2988
|
+
syncFullscreenSupport() {
|
|
2989
|
+
this.fsSupported = C(this.video, this.root), this.fsBtn.style.display = this.fsSupported ? "" : "none";
|
|
2990
|
+
}
|
|
2980
2991
|
syncFullscreen() {
|
|
2981
|
-
let e =
|
|
2992
|
+
let e = S(this.video, this.root);
|
|
2982
2993
|
this.setIcon(this.fsBtn, e ? "fullscreenExit" : "fullscreen"), this.fsBtn.setAttribute("aria-label", e ? "Exit fullscreen" : "Fullscreen");
|
|
2983
2994
|
}
|
|
2984
2995
|
poke() {
|
|
@@ -3012,6 +3023,7 @@ var $n = class {
|
|
|
3012
3023
|
this.player.setMuted(!this.video.muted);
|
|
3013
3024
|
break;
|
|
3014
3025
|
case "f":
|
|
3026
|
+
if (!this.fsSupported) return;
|
|
3015
3027
|
this.toggleFullscreen();
|
|
3016
3028
|
break;
|
|
3017
3029
|
case "c":
|
|
@@ -3055,41 +3067,41 @@ var $n = class {
|
|
|
3055
3067
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
3056
3068
|
}
|
|
3057
3069
|
};
|
|
3058
|
-
function
|
|
3070
|
+
function tr(e) {
|
|
3059
3071
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
3060
3072
|
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");
|
|
3061
3073
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
3062
3074
|
}
|
|
3063
|
-
function
|
|
3075
|
+
function nr(e) {
|
|
3064
3076
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
3065
3077
|
}
|
|
3066
|
-
function
|
|
3078
|
+
function rr(e) {
|
|
3067
3079
|
return e.name || e.lang || `Track ${e.id}`;
|
|
3068
3080
|
}
|
|
3069
|
-
function
|
|
3081
|
+
function ir(e) {
|
|
3070
3082
|
return e.name || e.lang || `Track ${e.id}`;
|
|
3071
3083
|
}
|
|
3072
3084
|
//#endregion
|
|
3073
3085
|
//#region src/managed/index.ts
|
|
3074
|
-
var
|
|
3075
|
-
function
|
|
3086
|
+
var ar = 6e3, or = 45e3, sr = 2e3, cr = 3, lr = 5e3, ur = 2e3, dr = 48e4, fr = "keySystemLicenseRequestFailed";
|
|
3087
|
+
function pr(e) {
|
|
3076
3088
|
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)})`);
|
|
3077
|
-
if (e.env !== void 0) return
|
|
3089
|
+
if (e.env !== void 0) return rt(e.env);
|
|
3078
3090
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
|
|
3079
3091
|
return e.baseUrl;
|
|
3080
3092
|
}
|
|
3081
|
-
async function
|
|
3093
|
+
async function mr(e) {
|
|
3082
3094
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
3083
|
-
let t =
|
|
3095
|
+
let t = pr(e);
|
|
3084
3096
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
3085
3097
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
3086
|
-
let r = new
|
|
3098
|
+
let r = new hr({
|
|
3087
3099
|
...e,
|
|
3088
3100
|
baseUrl: t
|
|
3089
3101
|
});
|
|
3090
3102
|
return await r.start(), r;
|
|
3091
3103
|
}
|
|
3092
|
-
var
|
|
3104
|
+
var hr = class {
|
|
3093
3105
|
opts;
|
|
3094
3106
|
abort = new AbortController();
|
|
3095
3107
|
listeners = {};
|
|
@@ -3163,7 +3175,7 @@ var mr = class {
|
|
|
3163
3175
|
};
|
|
3164
3176
|
}
|
|
3165
3177
|
beginArming(e, t, n = !1) {
|
|
3166
|
-
let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ??
|
|
3178
|
+
let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? D(this.opts.baseUrl);
|
|
3167
3179
|
r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
|
|
3168
3180
|
}
|
|
3169
3181
|
beginArmingByPolling(e) {
|
|
@@ -3184,7 +3196,7 @@ var mr = class {
|
|
|
3184
3196
|
setTimeout(() => {
|
|
3185
3197
|
a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
3186
3198
|
phase: i ? "unavailable" : "tooEarly",
|
|
3187
|
-
retryInMs:
|
|
3199
|
+
retryInMs: or,
|
|
3188
3200
|
attempt: 1,
|
|
3189
3201
|
elapsedMs: 0,
|
|
3190
3202
|
...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
|
|
@@ -3223,13 +3235,13 @@ var mr = class {
|
|
|
3223
3235
|
!a && !p() && h();
|
|
3224
3236
|
}, e);
|
|
3225
3237
|
};
|
|
3226
|
-
_(
|
|
3238
|
+
_(ar), this.armingSub = E({
|
|
3227
3239
|
eventsBaseUrl: t,
|
|
3228
3240
|
matchUrn: this.opts.matchUrn,
|
|
3229
3241
|
credential: this.opts.credential,
|
|
3230
|
-
onAlive: () => _(
|
|
3242
|
+
onAlive: () => _(or),
|
|
3231
3243
|
onState: (e) => {
|
|
3232
|
-
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() *
|
|
3244
|
+
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * sr);
|
|
3233
3245
|
},
|
|
3234
3246
|
onError: () => h()
|
|
3235
3247
|
});
|
|
@@ -3252,7 +3264,7 @@ var mr = class {
|
|
|
3252
3264
|
let n = await s(this.opts.credential);
|
|
3253
3265
|
if (this.destroyed || t !== this.loadGen) return;
|
|
3254
3266
|
this.setState("loading");
|
|
3255
|
-
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a =
|
|
3267
|
+
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = lt(this.opts.video, (e) => {
|
|
3256
3268
|
this._state !== "ended" && this._state !== "error" && this.setState(e);
|
|
3257
3269
|
});
|
|
3258
3270
|
if (await i.load(), this.destroyed || t !== this.loadGen) {
|
|
@@ -3274,26 +3286,26 @@ var mr = class {
|
|
|
3274
3286
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
|
|
3275
3287
|
let i = e.analytics?.sid;
|
|
3276
3288
|
if (!i) return;
|
|
3277
|
-
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } =
|
|
3289
|
+
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = Fn(this.opts.baseUrl, a, e.analytics?.endpoint);
|
|
3278
3290
|
if (!o) {
|
|
3279
3291
|
s && setTimeout(() => {
|
|
3280
3292
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
|
|
3281
3293
|
}, 0);
|
|
3282
3294
|
return;
|
|
3283
3295
|
}
|
|
3284
|
-
let c = this.opts.video, l = new
|
|
3296
|
+
let c = this.opts.video, l = new In({
|
|
3285
3297
|
endpoint: o,
|
|
3286
3298
|
sid: i,
|
|
3287
3299
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
3288
|
-
sdkVersion:
|
|
3289
|
-
environment:
|
|
3300
|
+
sdkVersion: Hn,
|
|
3301
|
+
environment: Bn(c),
|
|
3290
3302
|
idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
|
|
3291
3303
|
onIdle: () => this.onAnalyticsIdle(t),
|
|
3292
3304
|
onBlocked: (e) => setTimeout(() => {
|
|
3293
3305
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
|
|
3294
3306
|
}, 0),
|
|
3295
3307
|
sample: () => {
|
|
3296
|
-
let e = this.engine?.getStats() ??
|
|
3308
|
+
let e = this.engine?.getStats() ?? it, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
|
|
3297
3309
|
return {
|
|
3298
3310
|
...e,
|
|
3299
3311
|
bufferedMs: Math.round(t * 1e3),
|
|
@@ -3307,7 +3319,7 @@ var mr = class {
|
|
|
3307
3319
|
let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
|
|
3308
3320
|
c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
|
|
3309
3321
|
c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
|
|
3310
|
-
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()),
|
|
3322
|
+
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), Vn().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
|
|
3311
3323
|
}
|
|
3312
3324
|
currentPresentation() {
|
|
3313
3325
|
let e = this.opts.video;
|
|
@@ -3322,7 +3334,7 @@ var mr = class {
|
|
|
3322
3334
|
video: this.opts.video,
|
|
3323
3335
|
descriptor: e,
|
|
3324
3336
|
credential: t,
|
|
3325
|
-
deviceId:
|
|
3337
|
+
deviceId: A(),
|
|
3326
3338
|
userId: this.opts.userId,
|
|
3327
3339
|
lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
|
|
3328
3340
|
snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
|
|
@@ -3335,9 +3347,9 @@ var mr = class {
|
|
|
3335
3347
|
freshLicenseUrl: () => this.refreshLicense()
|
|
3336
3348
|
}, o = this.opts.engine ?? "auto";
|
|
3337
3349
|
if (o === "native") return new W(a);
|
|
3338
|
-
if (o === "hls") return new
|
|
3339
|
-
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && H(this.opts.video) && U() || !e.drmEnabled &&
|
|
3340
|
-
if (
|
|
3350
|
+
if (o === "hls") return new _n(a);
|
|
3351
|
+
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && H(this.opts.video) && U() || !e.drmEnabled && xt() && H(this.opts.video)) return new W(a);
|
|
3352
|
+
if (Nt()) return new _n(a);
|
|
3341
3353
|
if (H(this.opts.video)) return new W(a);
|
|
3342
3354
|
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
3343
3355
|
}
|
|
@@ -3385,11 +3397,11 @@ var mr = class {
|
|
|
3385
3397
|
}
|
|
3386
3398
|
startLiveState(e) {
|
|
3387
3399
|
if (this.opts.liveStateEvents === !1) return;
|
|
3388
|
-
let t = this.opts.eventsBaseUrl ??
|
|
3400
|
+
let t = this.opts.eventsBaseUrl ?? D(this.opts.baseUrl);
|
|
3389
3401
|
if (!t) return;
|
|
3390
3402
|
this.closeLiveState();
|
|
3391
3403
|
let r = 0, i = !1;
|
|
3392
|
-
this.liveStateSub =
|
|
3404
|
+
this.liveStateSub = E({
|
|
3393
3405
|
eventsBaseUrl: t,
|
|
3394
3406
|
matchUrn: this.opts.matchUrn,
|
|
3395
3407
|
credential: this.opts.credential,
|
|
@@ -3400,7 +3412,7 @@ var mr = class {
|
|
|
3400
3412
|
r = 0, i = !1;
|
|
3401
3413
|
},
|
|
3402
3414
|
onError: () => {
|
|
3403
|
-
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >=
|
|
3415
|
+
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= cr && (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.`))));
|
|
3404
3416
|
}
|
|
3405
3417
|
});
|
|
3406
3418
|
}
|
|
@@ -3414,7 +3426,7 @@ var mr = class {
|
|
|
3414
3426
|
return;
|
|
3415
3427
|
}
|
|
3416
3428
|
let e = this.hiddenAtMs;
|
|
3417
|
-
this.hiddenAtMs = null, e != null && Date.now() - e >=
|
|
3429
|
+
this.hiddenAtMs = null, e != null && Date.now() - e >= lr && this.resyncLiveState();
|
|
3418
3430
|
}, this.onReturnPageShow = (e) => {
|
|
3419
3431
|
e.persisted && this.resyncLiveState();
|
|
3420
3432
|
}, document.addEventListener("visibilitychange", this.onReturnVisible), typeof window < "u" && window.addEventListener("pageshow", this.onReturnPageShow));
|
|
@@ -3446,7 +3458,7 @@ var mr = class {
|
|
|
3446
3458
|
scheduleRejoin(e) {
|
|
3447
3459
|
this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
|
|
3448
3460
|
this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
|
|
3449
|
-
}, Math.random() *
|
|
3461
|
+
}, Math.random() * sr));
|
|
3450
3462
|
}
|
|
3451
3463
|
cancelRejoin() {
|
|
3452
3464
|
this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
|
|
@@ -3470,7 +3482,7 @@ var mr = class {
|
|
|
3470
3482
|
}
|
|
3471
3483
|
t.controls = !1;
|
|
3472
3484
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
3473
|
-
r && r.insertBefore(n, t), n.appendChild(t),
|
|
3485
|
+
r && r.insertBefore(n, t), n.appendChild(t), Z(n, this.opts.theme), this.container = n, this.controlBar = $n({
|
|
3474
3486
|
root: n,
|
|
3475
3487
|
video: t,
|
|
3476
3488
|
player: this,
|
|
@@ -3508,7 +3520,7 @@ var mr = class {
|
|
|
3508
3520
|
}
|
|
3509
3521
|
startStats() {
|
|
3510
3522
|
this.stopStats();
|
|
3511
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
3523
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? ur);
|
|
3512
3524
|
this.statsTimer = setInterval(() => {
|
|
3513
3525
|
if (!this.engine) return;
|
|
3514
3526
|
let e = this.engine.getStats();
|
|
@@ -3519,14 +3531,14 @@ var mr = class {
|
|
|
3519
3531
|
this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
|
|
3520
3532
|
}
|
|
3521
3533
|
isStaleLicenseDenial(e) {
|
|
3522
|
-
return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !==
|
|
3534
|
+
return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== fr || e.error.httpStatus !== 403 ? !1 : K(this._descriptor?.drm?.widevine?.licenseUrl);
|
|
3523
3535
|
}
|
|
3524
3536
|
scheduleLicenseRefresh() {
|
|
3525
3537
|
if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
|
|
3526
3538
|
typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
|
|
3527
3539
|
document.visibilityState !== "visible" || this.destroyed || K(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
|
|
3528
3540
|
}, document.addEventListener("visibilitychange", this.onRefocus));
|
|
3529
|
-
let e = this.opts.licenseRefreshMs ??
|
|
3541
|
+
let e = this.opts.licenseRefreshMs ?? dr;
|
|
3530
3542
|
e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
3531
3543
|
}
|
|
3532
3544
|
stopRefresh() {
|
|
@@ -3583,7 +3595,7 @@ var mr = class {
|
|
|
3583
3595
|
this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
|
|
3584
3596
|
}
|
|
3585
3597
|
getStats() {
|
|
3586
|
-
return this.engine?.getStats() ??
|
|
3598
|
+
return this.engine?.getStats() ?? it;
|
|
3587
3599
|
}
|
|
3588
3600
|
getQualityLevels() {
|
|
3589
3601
|
return this.engine?.getQualityLevels() ?? [];
|
|
@@ -3622,10 +3634,13 @@ var mr = class {
|
|
|
3622
3634
|
e.pictureInPictureElement === this.opts.video && typeof e.exitPictureInPicture == "function" && await e.exitPictureInPicture();
|
|
3623
3635
|
}
|
|
3624
3636
|
async enterFullscreen() {
|
|
3625
|
-
return !this.destroyed &&
|
|
3637
|
+
return !this.destroyed && w(this.opts.video, this.container ?? void 0);
|
|
3626
3638
|
}
|
|
3627
3639
|
async exitFullscreen() {
|
|
3628
|
-
await
|
|
3640
|
+
await T(this.opts.video, this.container ?? void 0);
|
|
3641
|
+
}
|
|
3642
|
+
fullscreenSupported() {
|
|
3643
|
+
return !this.destroyed && C(this.opts.video, this.container ?? void 0);
|
|
3629
3644
|
}
|
|
3630
3645
|
retry() {
|
|
3631
3646
|
return this.reload();
|
|
@@ -3693,7 +3708,7 @@ function $(e) {
|
|
|
3693
3708
|
}
|
|
3694
3709
|
//#endregion
|
|
3695
3710
|
//#region src/embed/host.ts
|
|
3696
|
-
function
|
|
3711
|
+
function gr(e) {
|
|
3697
3712
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
3698
3713
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
3699
3714
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -3752,15 +3767,15 @@ function hr(e) {
|
|
|
3752
3767
|
}
|
|
3753
3768
|
//#endregion
|
|
3754
3769
|
//#region src/embed/page.ts
|
|
3755
|
-
var
|
|
3756
|
-
function
|
|
3770
|
+
var _r = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
3771
|
+
function vr(e) {
|
|
3757
3772
|
if (typeof e == "boolean") return e;
|
|
3758
3773
|
if (typeof e == "object" && e) {
|
|
3759
3774
|
let t = e.endpoint;
|
|
3760
3775
|
return typeof t == "string" ? { endpoint: t } : {};
|
|
3761
3776
|
}
|
|
3762
3777
|
}
|
|
3763
|
-
function
|
|
3778
|
+
function yr() {
|
|
3764
3779
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
3765
3780
|
if (e) return {
|
|
3766
3781
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -3770,7 +3785,7 @@ function vr() {
|
|
|
3770
3785
|
autoplay: e.autoplay ?? !0,
|
|
3771
3786
|
muted: e.muted ?? !0,
|
|
3772
3787
|
waitForLive: e.waitForLive ?? !0,
|
|
3773
|
-
analytics:
|
|
3788
|
+
analytics: vr(e.analytics)
|
|
3774
3789
|
};
|
|
3775
3790
|
let t = new URLSearchParams(location.search);
|
|
3776
3791
|
return {
|
|
@@ -3783,9 +3798,9 @@ function vr() {
|
|
|
3783
3798
|
waitForLive: !0
|
|
3784
3799
|
};
|
|
3785
3800
|
}
|
|
3786
|
-
async function
|
|
3787
|
-
let e =
|
|
3788
|
-
|
|
3801
|
+
async function br() {
|
|
3802
|
+
let e = yr();
|
|
3803
|
+
Sr();
|
|
3789
3804
|
let t = document.createElement("video");
|
|
3790
3805
|
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);
|
|
3791
3806
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -3840,12 +3855,12 @@ async function yr() {
|
|
|
3840
3855
|
code: e.code,
|
|
3841
3856
|
message: e.message
|
|
3842
3857
|
})), e.on("autoplayblocked", () => {
|
|
3843
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
3858
|
+
i({ type: "oddin:autoplayblocked" }), xr(t, e);
|
|
3844
3859
|
});
|
|
3845
3860
|
}, s = async (r) => {
|
|
3846
3861
|
a?.destroy(), a = null;
|
|
3847
3862
|
try {
|
|
3848
|
-
let n = await
|
|
3863
|
+
let n = await mr({
|
|
3849
3864
|
video: t,
|
|
3850
3865
|
baseUrl: e.baseUrl,
|
|
3851
3866
|
matchUrn: r,
|
|
@@ -3907,7 +3922,7 @@ async function yr() {
|
|
|
3907
3922
|
a?.retry();
|
|
3908
3923
|
break;
|
|
3909
3924
|
case "oddin:load":
|
|
3910
|
-
typeof e.matchUrn == "string" &&
|
|
3925
|
+
typeof e.matchUrn == "string" && _r.test(e.matchUrn) && s(e.matchUrn);
|
|
3911
3926
|
break;
|
|
3912
3927
|
case "oddin:destroy": c();
|
|
3913
3928
|
}
|
|
@@ -3919,18 +3934,18 @@ async function yr() {
|
|
|
3919
3934
|
protocol: 1
|
|
3920
3935
|
});
|
|
3921
3936
|
}
|
|
3922
|
-
function
|
|
3937
|
+
function xr(e, t) {
|
|
3923
3938
|
if (document.getElementById("havik-tap")) return;
|
|
3924
3939
|
let n = document.createElement("button");
|
|
3925
3940
|
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", () => {
|
|
3926
3941
|
n.remove(), t.play();
|
|
3927
3942
|
}), document.body.appendChild(n);
|
|
3928
3943
|
}
|
|
3929
|
-
function
|
|
3944
|
+
function Sr() {
|
|
3930
3945
|
let e = document.createElement("style");
|
|
3931
3946
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
3932
3947
|
}
|
|
3933
3948
|
//#endregion
|
|
3934
|
-
export {
|
|
3949
|
+
export { Un as ODDIN_THEME, n as PlaybackError, Z as applyTheme, rt as baseUrlForEnv, br as bootEmbed, Te as clearDeviceId, Ie as clearRememberedBandwidth, mr as createPlayer, D as deriveEventsBaseUrl, $e as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, _e as fetchCatalog, ye as fetchTournament, xe as flattenMatches, C as fullscreenSupported, A as getDeviceId, tt as isLowLatencyManifest, $ as isOddinMessage, De as licenseRequestHeaders, gr as mountEmbed, de as pollToLive, y as resolveStream, E as subscribeLiveState, S as videoFullscreenActive, Ce as watchStatus };
|
|
3935
3950
|
|
|
3936
3951
|
//# sourceMappingURL=index.js.map
|