@oddin-gg/havik-player 2.24.0 → 2.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/havik-player.global.js +2 -2
- 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 +34 -1
- package/dist/index.d.ts +34 -1
- package/dist/index.js +440 -370
- package/dist/index.js.map +1 -1
- package/docs/API.md +106 -58
- package/embed/index.html +1 -1
- package/examples/vanilla.html +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -315,25 +315,25 @@ function x(e) {
|
|
|
315
315
|
function _e(e) {
|
|
316
316
|
return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
|
|
317
317
|
}
|
|
318
|
-
function
|
|
318
|
+
function ve(e, t) {
|
|
319
319
|
let n = _e(x(e));
|
|
320
320
|
return n != null && (n === e || t != null && n === t) || e.webkitDisplayingFullscreen === !0;
|
|
321
321
|
}
|
|
322
|
-
function
|
|
322
|
+
function ye(e, t) {
|
|
323
323
|
let n = t ?? e, r = x(e);
|
|
324
324
|
if (typeof n.requestFullscreen == "function") return r.fullscreenEnabled !== !1;
|
|
325
325
|
if (typeof n.webkitRequestFullscreen == "function") return r.webkitFullscreenEnabled !== !1;
|
|
326
326
|
let i = e;
|
|
327
327
|
return i.webkitSupportsFullscreen === !0 && typeof i.webkitEnterFullscreen == "function" || e.readyState < 1;
|
|
328
328
|
}
|
|
329
|
-
async function
|
|
329
|
+
async function S(e, t) {
|
|
330
330
|
let n = t ?? e;
|
|
331
331
|
if (typeof n.requestFullscreen == "function") return await n.requestFullscreen(), !0;
|
|
332
332
|
if (typeof n.webkitRequestFullscreen == "function") return n.webkitRequestFullscreen(), !0;
|
|
333
333
|
let r = e;
|
|
334
334
|
return r.webkitSupportsFullscreen && typeof r.webkitEnterFullscreen == "function" ? (r.webkitEnterFullscreen(), !0) : !1;
|
|
335
335
|
}
|
|
336
|
-
async function
|
|
336
|
+
async function C(e, t) {
|
|
337
337
|
let n = e;
|
|
338
338
|
if (n.webkitDisplayingFullscreen) {
|
|
339
339
|
n.webkitExitFullscreen?.();
|
|
@@ -344,7 +344,7 @@ async function T(e, t) {
|
|
|
344
344
|
}
|
|
345
345
|
//#endregion
|
|
346
346
|
//#region src/core/catalog.ts
|
|
347
|
-
async function
|
|
347
|
+
async function be(e) {
|
|
348
348
|
let t = new URLSearchParams();
|
|
349
349
|
e.status && t.set("status", Array.isArray(e.status) ? e.status.join(",") : e.status), e.sport && t.set("sport", e.sport);
|
|
350
350
|
let i = t.toString(), a = f(e.baseUrl, "/v1/catalog" + (i ? `?${i}` : "")), o = new Headers();
|
|
@@ -362,12 +362,12 @@ async function ve(e) {
|
|
|
362
362
|
};
|
|
363
363
|
if (!s.ok) throw new n(r(s.status), s.status, `catalog request failed (HTTP ${s.status})`);
|
|
364
364
|
return {
|
|
365
|
-
tournaments:
|
|
365
|
+
tournaments: xe(await s.json()),
|
|
366
366
|
etag: s.headers.get("etag") ?? void 0,
|
|
367
367
|
notModified: !1
|
|
368
368
|
};
|
|
369
369
|
}
|
|
370
|
-
function
|
|
370
|
+
function xe(e) {
|
|
371
371
|
return (e.tournaments ?? []).map((e) => {
|
|
372
372
|
let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
|
|
373
373
|
return {
|
|
@@ -389,7 +389,7 @@ function ye(e) {
|
|
|
389
389
|
};
|
|
390
390
|
});
|
|
391
391
|
}
|
|
392
|
-
async function
|
|
392
|
+
async function Se(e) {
|
|
393
393
|
let t = f(e.baseUrl, `/v1/tournaments/${encodeURIComponent(e.urn)}`), i = new Headers();
|
|
394
394
|
e.etag && i.set("If-None-Match", e.etag);
|
|
395
395
|
let a = await m(t, {
|
|
@@ -409,13 +409,13 @@ async function be(e) {
|
|
|
409
409
|
};
|
|
410
410
|
if (!a.ok) throw new n(r(a.status), a.status, `tournament request failed (HTTP ${a.status})`);
|
|
411
411
|
return {
|
|
412
|
-
tournament:
|
|
412
|
+
tournament: Ce(await a.json()),
|
|
413
413
|
etag: a.headers.get("etag") ?? void 0,
|
|
414
414
|
notModified: !1,
|
|
415
415
|
notFound: !1
|
|
416
416
|
};
|
|
417
417
|
}
|
|
418
|
-
function
|
|
418
|
+
function Ce(e) {
|
|
419
419
|
let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
|
|
420
420
|
return {
|
|
421
421
|
urn: t,
|
|
@@ -435,18 +435,18 @@ function xe(e) {
|
|
|
435
435
|
}))
|
|
436
436
|
};
|
|
437
437
|
}
|
|
438
|
-
function
|
|
438
|
+
function we(e) {
|
|
439
439
|
return e.tournaments.flatMap((e) => e.matches);
|
|
440
440
|
}
|
|
441
441
|
//#endregion
|
|
442
442
|
//#region src/core/poll.ts
|
|
443
|
-
var
|
|
443
|
+
var Te = /* @__PURE__ */ new Set([
|
|
444
444
|
"NOT_FOUND",
|
|
445
445
|
"GEO_DENIED",
|
|
446
446
|
"GONE",
|
|
447
447
|
"INVALID_URN"
|
|
448
448
|
]);
|
|
449
|
-
function
|
|
449
|
+
function Ee(e) {
|
|
450
450
|
let t = Math.max(2e3, e.intervalMs ?? 1e4), i = new AbortController(), a, o, s, c = !1, d = () => {
|
|
451
451
|
c || (a = setTimeout(p, t));
|
|
452
452
|
}, p = async () => {
|
|
@@ -479,7 +479,7 @@ function we(e) {
|
|
|
479
479
|
} catch (t) {
|
|
480
480
|
if (!i.signal.aborted) {
|
|
481
481
|
let r = t instanceof n ? t : new n("NETWORK", 0, String(t));
|
|
482
|
-
|
|
482
|
+
Te.has(r.code) && (c = !0), e.onError?.(r);
|
|
483
483
|
}
|
|
484
484
|
} finally {
|
|
485
485
|
d();
|
|
@@ -491,16 +491,16 @@ function we(e) {
|
|
|
491
491
|
}
|
|
492
492
|
//#endregion
|
|
493
493
|
//#region src/core/events.ts
|
|
494
|
-
var
|
|
494
|
+
var De = 45e3, w = class extends Error {
|
|
495
495
|
status;
|
|
496
496
|
terminal;
|
|
497
497
|
constructor(e) {
|
|
498
498
|
let t = e === 410;
|
|
499
499
|
super(t ? `live-state subscribe failed: HTTP ${e} — match is gone, not retrying` : e === 404 ? `live-state subscribe failed: HTTP ${e} — match not in the catalog, retrying slowly` : `live-state subscribe failed: HTTP ${e}`), this.name = "LiveStateHttpError", this.status = e, this.terminal = t;
|
|
500
500
|
}
|
|
501
|
-
},
|
|
502
|
-
function
|
|
503
|
-
let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = Math.max(t, e.notFoundRetryMs ??
|
|
501
|
+
}, Oe = 3e5;
|
|
502
|
+
function T(e) {
|
|
503
|
+
let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = Math.max(t, e.notFoundRetryMs ?? Oe), i = e.idleTimeoutMs ?? De, a = Number.isFinite(i) && i > 0 ? i : 0, o = new AbortController(), s = !1, l = (e) => new Promise((t) => {
|
|
504
504
|
if (o.signal.aborted) return t();
|
|
505
505
|
let n = setTimeout(t, e);
|
|
506
506
|
o.signal.addEventListener("abort", () => {
|
|
@@ -567,7 +567,7 @@ function D(e) {
|
|
|
567
567
|
});
|
|
568
568
|
if (clearTimeout(_), s) return;
|
|
569
569
|
if (!o.ok || !o.body) {
|
|
570
|
-
let t = new
|
|
570
|
+
let t = new w(o.status);
|
|
571
571
|
h = t.terminal, g = o.status === 404, e.onError?.(t);
|
|
572
572
|
} else await p(o.body, () => {
|
|
573
573
|
i = t;
|
|
@@ -585,7 +585,7 @@ function D(e) {
|
|
|
585
585
|
s || (s = !0, o.abort());
|
|
586
586
|
} };
|
|
587
587
|
}
|
|
588
|
-
function
|
|
588
|
+
function E(e) {
|
|
589
589
|
try {
|
|
590
590
|
let t = new URL(e);
|
|
591
591
|
return t.hostname = `events.${t.hostname}`, t.pathname = "", t.search = "", t.origin;
|
|
@@ -595,27 +595,27 @@ function O(e) {
|
|
|
595
595
|
}
|
|
596
596
|
//#endregion
|
|
597
597
|
//#region src/core/drm/deviceId.ts
|
|
598
|
-
var
|
|
599
|
-
function
|
|
600
|
-
if (
|
|
598
|
+
var D = "havik.player.deviceId", O;
|
|
599
|
+
function k() {
|
|
600
|
+
if (O) return O;
|
|
601
601
|
try {
|
|
602
|
-
let e = globalThis.localStorage?.getItem(
|
|
603
|
-
if (e) return
|
|
602
|
+
let e = globalThis.localStorage?.getItem(D);
|
|
603
|
+
if (e) return O = e, e;
|
|
604
604
|
} catch {}
|
|
605
|
-
let e =
|
|
606
|
-
|
|
605
|
+
let e = Ae();
|
|
606
|
+
O = e;
|
|
607
607
|
try {
|
|
608
|
-
globalThis.localStorage?.setItem(
|
|
608
|
+
globalThis.localStorage?.setItem(D, e);
|
|
609
609
|
} catch {}
|
|
610
610
|
return e;
|
|
611
611
|
}
|
|
612
|
-
function
|
|
613
|
-
|
|
612
|
+
function ke() {
|
|
613
|
+
O = void 0;
|
|
614
614
|
try {
|
|
615
|
-
globalThis.localStorage?.removeItem(
|
|
615
|
+
globalThis.localStorage?.removeItem(D);
|
|
616
616
|
} catch {}
|
|
617
617
|
}
|
|
618
|
-
function
|
|
618
|
+
function Ae() {
|
|
619
619
|
let e = globalThis.crypto;
|
|
620
620
|
if (e && typeof e.randomUUID == "function") return e.randomUUID();
|
|
621
621
|
let t = /* @__PURE__ */ new Uint8Array(16);
|
|
@@ -627,32 +627,32 @@ function Oe() {
|
|
|
627
627
|
}
|
|
628
628
|
//#endregion
|
|
629
629
|
//#region src/core/drm/headers.ts
|
|
630
|
-
function
|
|
630
|
+
function je(e, t, n = {}) {
|
|
631
631
|
let r = {
|
|
632
632
|
"x-api-key": t.apiKey,
|
|
633
633
|
"X-Match-Urn": e.matchUrn,
|
|
634
|
-
"X-Device-Id": n.deviceId ??
|
|
634
|
+
"X-Device-Id": n.deviceId ?? k(),
|
|
635
635
|
"Content-Type": "application/octet-stream"
|
|
636
636
|
};
|
|
637
637
|
return n.userId && (r["X-User-Id"] = n.userId), r;
|
|
638
638
|
}
|
|
639
639
|
//#endregion
|
|
640
640
|
//#region src/core/bandwidthMemory.ts
|
|
641
|
-
var
|
|
642
|
-
function
|
|
641
|
+
var A = "havik.player.bandwidth", Me = .8, Ne = 2e7, Pe = 3e5;
|
|
642
|
+
function Fe() {
|
|
643
643
|
return globalThis.navigator?.connection;
|
|
644
644
|
}
|
|
645
|
-
function
|
|
646
|
-
let e =
|
|
645
|
+
function Ie() {
|
|
646
|
+
let e = Fe()?.type;
|
|
647
647
|
return typeof e == "string" && e !== "" && e !== "unknown" ? e : "any";
|
|
648
648
|
}
|
|
649
|
-
function
|
|
650
|
-
let e =
|
|
649
|
+
function Le() {
|
|
650
|
+
let e = Fe()?.downlink;
|
|
651
651
|
return typeof e == "number" && Number.isFinite(e) && e > 0 ? e * 1e6 : void 0;
|
|
652
652
|
}
|
|
653
|
-
function
|
|
653
|
+
function Re() {
|
|
654
654
|
try {
|
|
655
|
-
let e = globalThis.localStorage?.getItem(
|
|
655
|
+
let e = globalThis.localStorage?.getItem(A);
|
|
656
656
|
if (!e) return {};
|
|
657
657
|
let t = JSON.parse(e);
|
|
658
658
|
return t && typeof t == "object" && !Array.isArray(t) ? t : {};
|
|
@@ -660,36 +660,36 @@ function Ie() {
|
|
|
660
660
|
return {};
|
|
661
661
|
}
|
|
662
662
|
}
|
|
663
|
-
function
|
|
664
|
-
let t =
|
|
663
|
+
function ze(e = Date.now()) {
|
|
664
|
+
let t = Re()[Ie()];
|
|
665
665
|
if (!t || typeof t.bps != "number" || typeof t.at != "number" || !Number.isFinite(t.bps) || t.bps <= 0) return;
|
|
666
666
|
let n = e - t.at;
|
|
667
667
|
if (n < 0 || n > 2592e5) return;
|
|
668
|
-
let r =
|
|
669
|
-
return Math.round(Math.min(
|
|
668
|
+
let r = Le(), i = r === void 0 ? t.bps : Math.min(t.bps, r);
|
|
669
|
+
return Math.round(Math.min(Ne, Math.max(Pe, i * Me)));
|
|
670
670
|
}
|
|
671
|
-
function
|
|
671
|
+
function Be(e, t = Date.now()) {
|
|
672
672
|
if (!Number.isFinite(e) || e <= 0) return;
|
|
673
|
-
let n =
|
|
674
|
-
n[
|
|
673
|
+
let n = Re();
|
|
674
|
+
n[Ie()] = {
|
|
675
675
|
bps: Math.round(e),
|
|
676
676
|
at: t
|
|
677
677
|
};
|
|
678
678
|
try {
|
|
679
|
-
globalThis.localStorage?.setItem(
|
|
679
|
+
globalThis.localStorage?.setItem(A, JSON.stringify(n));
|
|
680
680
|
} catch {}
|
|
681
681
|
}
|
|
682
|
-
function
|
|
682
|
+
function Ve() {
|
|
683
683
|
try {
|
|
684
|
-
globalThis.localStorage?.removeItem(
|
|
684
|
+
globalThis.localStorage?.removeItem(A);
|
|
685
685
|
} catch {}
|
|
686
686
|
}
|
|
687
687
|
//#endregion
|
|
688
688
|
//#region src/core/drm/cdm.ts
|
|
689
|
-
var
|
|
690
|
-
function
|
|
691
|
-
let n =
|
|
692
|
-
n || (n = /* @__PURE__ */ new Map(),
|
|
689
|
+
var He = /* @__PURE__ */ new WeakMap();
|
|
690
|
+
function Ue(e, t) {
|
|
691
|
+
let n = He.get(e);
|
|
692
|
+
n || (n = /* @__PURE__ */ new Map(), He.set(e, n));
|
|
693
693
|
let r = n.get(t.keySystem);
|
|
694
694
|
if (r) return r;
|
|
695
695
|
let i = t.createMediaKeys().catch((e) => {
|
|
@@ -697,22 +697,22 @@ function Ve(e, t) {
|
|
|
697
697
|
});
|
|
698
698
|
return n.set(t.keySystem, i), i;
|
|
699
699
|
}
|
|
700
|
-
function
|
|
700
|
+
function j() {
|
|
701
701
|
return typeof navigator < "u" && typeof navigator.requestMediaKeySystemAccess == "function";
|
|
702
702
|
}
|
|
703
|
-
var
|
|
704
|
-
function
|
|
703
|
+
var M = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
|
|
704
|
+
function We(e) {
|
|
705
705
|
return e.startsWith("com.widevine");
|
|
706
706
|
}
|
|
707
|
-
function
|
|
708
|
-
if (!
|
|
707
|
+
function N(e, t) {
|
|
708
|
+
if (!We(e)) return t;
|
|
709
709
|
let n = (e, t) => {
|
|
710
710
|
let n = e.videoCapabilities;
|
|
711
711
|
return !n?.length || !n.some((e) => e.robustness) ? !1 : n.every((e) => {
|
|
712
|
-
let n =
|
|
713
|
-
return n === -1 ||
|
|
712
|
+
let n = M.indexOf(e.robustness);
|
|
713
|
+
return n === -1 || M.indexOf(t) > n;
|
|
714
714
|
});
|
|
715
|
-
}, r =
|
|
715
|
+
}, r = M.flatMap((e) => t.filter((t) => n(t, e)).map((t) => ({
|
|
716
716
|
...t,
|
|
717
717
|
videoCapabilities: t.videoCapabilities?.map((t) => ({
|
|
718
718
|
...t,
|
|
@@ -721,53 +721,53 @@ function P(e, t) {
|
|
|
721
721
|
})));
|
|
722
722
|
return [...t, ...r];
|
|
723
723
|
}
|
|
724
|
-
function
|
|
725
|
-
return (t, n) =>
|
|
724
|
+
function Ge(e) {
|
|
725
|
+
return (t, n) => j() ? navigator.requestMediaKeySystemAccess(t, N(t, n)).then((t) => ({
|
|
726
726
|
keySystem: t.keySystem,
|
|
727
727
|
getConfiguration: () => t.getConfiguration(),
|
|
728
|
-
createMediaKeys: () =>
|
|
728
|
+
createMediaKeys: () => Ue(e, t)
|
|
729
729
|
})) : Promise.reject(/* @__PURE__ */ Error("navigator.requestMediaKeySystemAccess is unavailable — EME needs a secure context (https, or localhost)"));
|
|
730
730
|
}
|
|
731
|
-
var
|
|
731
|
+
var P = {
|
|
732
732
|
video: "SW_SECURE_DECODE",
|
|
733
733
|
audio: "SW_SECURE_CRYPTO",
|
|
734
734
|
scheme: "cbcs"
|
|
735
735
|
};
|
|
736
|
-
function
|
|
737
|
-
if (!
|
|
736
|
+
function Ke(e) {
|
|
737
|
+
if (!j()) return;
|
|
738
738
|
let t = (e, t) => ({
|
|
739
739
|
contentType: e,
|
|
740
740
|
robustness: t,
|
|
741
|
-
encryptionScheme:
|
|
741
|
+
encryptionScheme: P.scheme
|
|
742
742
|
});
|
|
743
|
-
|
|
743
|
+
Ge(e)("com.widevine.alpha", [{
|
|
744
744
|
initDataTypes: ["cenc"],
|
|
745
745
|
distinctiveIdentifier: "optional",
|
|
746
746
|
persistentState: "optional",
|
|
747
747
|
sessionTypes: ["temporary"],
|
|
748
|
-
audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"",
|
|
749
|
-
videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"",
|
|
748
|
+
audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"", P.audio)],
|
|
749
|
+
videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"", P.video)]
|
|
750
750
|
}]).then((e) => e.createMediaKeys()).catch(() => {});
|
|
751
751
|
}
|
|
752
|
-
function
|
|
753
|
-
let t =
|
|
752
|
+
function F(e) {
|
|
753
|
+
let t = I(e);
|
|
754
754
|
if (/^avc[13]/.test(t)) return "avc";
|
|
755
755
|
if (/^(hvc1|hev1)/.test(t)) return "hevc";
|
|
756
756
|
if (/^(dvh1|dvhe)/.test(t)) return "dv";
|
|
757
757
|
if (t.startsWith("av01")) return "av1";
|
|
758
758
|
if (/^vp0?9/.test(t)) return "vp9";
|
|
759
759
|
}
|
|
760
|
-
function
|
|
760
|
+
function I(e) {
|
|
761
761
|
return (e ?? "").trim().toLowerCase();
|
|
762
762
|
}
|
|
763
|
-
var
|
|
763
|
+
var qe = {
|
|
764
764
|
hevc: "hvc1.1.6.L93.90",
|
|
765
765
|
dv: "dvh1.05.06",
|
|
766
766
|
av1: "av01.0.05M.08",
|
|
767
767
|
vp9: "vp09.00.10.08"
|
|
768
|
-
},
|
|
769
|
-
function
|
|
770
|
-
let t =
|
|
768
|
+
}, Je = /* @__PURE__ */ new Map(), L = /* @__PURE__ */ new Map();
|
|
769
|
+
function Ye(e) {
|
|
770
|
+
let t = I(e), n = Je.get(t);
|
|
771
771
|
if (n) return n;
|
|
772
772
|
let r = {
|
|
773
773
|
initDataTypes: ["cenc"],
|
|
@@ -776,32 +776,32 @@ function Je(e) {
|
|
|
776
776
|
sessionTypes: ["temporary"],
|
|
777
777
|
videoCapabilities: [{
|
|
778
778
|
contentType: `video/mp4; codecs="${e.trim()}"`,
|
|
779
|
-
robustness:
|
|
780
|
-
encryptionScheme:
|
|
779
|
+
robustness: P.video,
|
|
780
|
+
encryptionScheme: P.scheme
|
|
781
781
|
}]
|
|
782
782
|
}, i = (async () => {
|
|
783
783
|
try {
|
|
784
|
-
return await navigator.requestMediaKeySystemAccess("com.widevine.alpha",
|
|
784
|
+
return await navigator.requestMediaKeySystemAccess("com.widevine.alpha", N("com.widevine.alpha", [r])), !0;
|
|
785
785
|
} catch {
|
|
786
786
|
return !1;
|
|
787
787
|
}
|
|
788
|
-
})().then((e) => (
|
|
789
|
-
return
|
|
788
|
+
})().then((e) => (L.set(t, e), e));
|
|
789
|
+
return Je.set(t, i), i;
|
|
790
790
|
}
|
|
791
|
-
function
|
|
792
|
-
if (
|
|
791
|
+
function Xe() {
|
|
792
|
+
if (j()) for (let e of Object.values(qe)) Ye(e);
|
|
793
793
|
}
|
|
794
|
-
function
|
|
795
|
-
let t =
|
|
796
|
-
if (t) return t === "avc" ? !0 :
|
|
794
|
+
function Ze(e) {
|
|
795
|
+
let t = F(e);
|
|
796
|
+
if (t) return t === "avc" ? !0 : L.get(I(e)) ?? L.get(I(qe[t]));
|
|
797
797
|
}
|
|
798
798
|
//#endregion
|
|
799
799
|
//#region src/core/drm/support.ts
|
|
800
|
-
var
|
|
800
|
+
var Qe = 5e3, $e = "video/mp4; codecs=\"avc1.42E01E\"", et = "audio/mp4; codecs=\"mp4a.40.2\"", tt = {
|
|
801
801
|
widevine: ["com.widevine.alpha"],
|
|
802
802
|
fairplay: ["com.apple.fps"]
|
|
803
803
|
};
|
|
804
|
-
function
|
|
804
|
+
function nt(e) {
|
|
805
805
|
return e === "fairplay" ? [{
|
|
806
806
|
initDataTypes: [
|
|
807
807
|
"sinf",
|
|
@@ -809,30 +809,30 @@ function tt(e) {
|
|
|
809
809
|
"cenc"
|
|
810
810
|
],
|
|
811
811
|
videoCapabilities: [{
|
|
812
|
-
contentType:
|
|
812
|
+
contentType: $e,
|
|
813
813
|
robustness: "",
|
|
814
814
|
encryptionScheme: "cbcs"
|
|
815
815
|
}],
|
|
816
816
|
audioCapabilities: [{
|
|
817
|
-
contentType:
|
|
817
|
+
contentType: et,
|
|
818
818
|
robustness: "",
|
|
819
819
|
encryptionScheme: "cbcs"
|
|
820
820
|
}]
|
|
821
|
-
}] :
|
|
821
|
+
}] : N("com.widevine.alpha", [{
|
|
822
822
|
initDataTypes: ["cenc"],
|
|
823
823
|
videoCapabilities: [{
|
|
824
|
-
contentType:
|
|
825
|
-
robustness:
|
|
826
|
-
encryptionScheme:
|
|
824
|
+
contentType: $e,
|
|
825
|
+
robustness: P.video,
|
|
826
|
+
encryptionScheme: P.scheme
|
|
827
827
|
}],
|
|
828
828
|
audioCapabilities: [{
|
|
829
|
-
contentType:
|
|
830
|
-
robustness:
|
|
831
|
-
encryptionScheme:
|
|
829
|
+
contentType: et,
|
|
830
|
+
robustness: P.audio,
|
|
831
|
+
encryptionScheme: P.scheme
|
|
832
832
|
}]
|
|
833
833
|
}]);
|
|
834
834
|
}
|
|
835
|
-
function
|
|
835
|
+
function rt(e, t) {
|
|
836
836
|
return new Promise((n, r) => {
|
|
837
837
|
let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
|
|
838
838
|
e.then((e) => {
|
|
@@ -842,8 +842,8 @@ function nt(e, t) {
|
|
|
842
842
|
});
|
|
843
843
|
});
|
|
844
844
|
}
|
|
845
|
-
async function
|
|
846
|
-
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ??
|
|
845
|
+
async function it(e = {}) {
|
|
846
|
+
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Qe, r = {};
|
|
847
847
|
if (typeof window < "u" && window.isSecureContext === !1) return {
|
|
848
848
|
verdict: "insecure-context",
|
|
849
849
|
detail: r
|
|
@@ -855,7 +855,7 @@ async function rt(e = {}) {
|
|
|
855
855
|
};
|
|
856
856
|
let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
|
|
857
857
|
for (let e of t) {
|
|
858
|
-
let t =
|
|
858
|
+
let t = tt[e];
|
|
859
859
|
if (!t) {
|
|
860
860
|
r[e] = "unknown system";
|
|
861
861
|
continue;
|
|
@@ -866,7 +866,7 @@ async function rt(e = {}) {
|
|
|
866
866
|
break;
|
|
867
867
|
}
|
|
868
868
|
try {
|
|
869
|
-
return await
|
|
869
|
+
return await rt((await rt(i(n, nt(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
|
|
870
870
|
verdict: "supported",
|
|
871
871
|
system: e,
|
|
872
872
|
detail: r
|
|
@@ -890,37 +890,58 @@ async function rt(e = {}) {
|
|
|
890
890
|
}
|
|
891
891
|
//#endregion
|
|
892
892
|
//#region src/core/manifest.ts
|
|
893
|
-
var
|
|
894
|
-
function
|
|
895
|
-
return
|
|
893
|
+
var at = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
|
|
894
|
+
function ot(e) {
|
|
895
|
+
return at.test(e);
|
|
896
896
|
}
|
|
897
897
|
//#endregion
|
|
898
898
|
//#region src/core/env.ts
|
|
899
|
-
var
|
|
899
|
+
var st = {
|
|
900
900
|
integration: "https://feed-dev.oddin-video.gg",
|
|
901
901
|
production: "https://feed.oddin-video.gg"
|
|
902
902
|
};
|
|
903
|
-
function
|
|
904
|
-
let t = Object.prototype.hasOwnProperty.call(
|
|
903
|
+
function ct(e) {
|
|
904
|
+
let t = Object.prototype.hasOwnProperty.call(st, e) ? st[e] : void 0;
|
|
905
905
|
if (!t) throw new n("INTERNAL", 0, `unknown env ${JSON.stringify(e)} — expected 'integration' or 'production'`);
|
|
906
906
|
return t;
|
|
907
907
|
}
|
|
908
908
|
//#endregion
|
|
909
|
+
//#region src/core/connectivity.ts
|
|
910
|
+
function R() {
|
|
911
|
+
return typeof navigator > "u" || navigator.onLine !== !1;
|
|
912
|
+
}
|
|
913
|
+
function lt() {
|
|
914
|
+
let e = /* @__PURE__ */ new Set(), t = (t) => {
|
|
915
|
+
for (let n of Array.from(e)) n(t);
|
|
916
|
+
}, n = () => t(!0), r = () => t(!1), i = typeof window < "u" && typeof window.addEventListener == "function";
|
|
917
|
+
return i && (window.addEventListener("online", n), window.addEventListener("offline", r)), {
|
|
918
|
+
isOnline: R,
|
|
919
|
+
onChange(t) {
|
|
920
|
+
return e.add(t), () => {
|
|
921
|
+
e.delete(t);
|
|
922
|
+
};
|
|
923
|
+
},
|
|
924
|
+
destroy() {
|
|
925
|
+
e.clear(), i && (window.removeEventListener("online", n), window.removeEventListener("offline", r));
|
|
926
|
+
}
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
//#endregion
|
|
909
930
|
//#region src/core/stats.ts
|
|
910
|
-
var
|
|
911
|
-
function
|
|
931
|
+
var ut = { droppedFrames: 0 };
|
|
932
|
+
function dt(e) {
|
|
912
933
|
try {
|
|
913
934
|
return new URL(e).host;
|
|
914
935
|
} catch {
|
|
915
936
|
return "";
|
|
916
937
|
}
|
|
917
938
|
}
|
|
918
|
-
var
|
|
919
|
-
function
|
|
939
|
+
var ft = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
|
|
940
|
+
function pt(e) {
|
|
920
941
|
if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
|
|
921
942
|
let t = "", n = -1, r = performance.getEntriesByType("resource");
|
|
922
|
-
for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" ||
|
|
923
|
-
let e =
|
|
943
|
+
for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || ft.test(i.name)) && i.startTime >= n) {
|
|
944
|
+
let e = dt(i.name);
|
|
924
945
|
e && (t = e, n = i.startTime);
|
|
925
946
|
}
|
|
926
947
|
return t;
|
|
@@ -932,7 +953,7 @@ function z(e) {
|
|
|
932
953
|
totalFrames: t?.totalVideoFrames ?? 0
|
|
933
954
|
};
|
|
934
955
|
}
|
|
935
|
-
var
|
|
956
|
+
var mt = class {
|
|
936
957
|
video;
|
|
937
958
|
baseFrames = 0;
|
|
938
959
|
baseDropped = 0;
|
|
@@ -955,7 +976,7 @@ var ft = class {
|
|
|
955
976
|
};
|
|
956
977
|
}
|
|
957
978
|
};
|
|
958
|
-
function
|
|
979
|
+
function ht(e, t) {
|
|
959
980
|
let n = [
|
|
960
981
|
["playing", () => t("playing")],
|
|
961
982
|
["waiting", () => t("buffering")],
|
|
@@ -972,8 +993,8 @@ function pt(e, t) {
|
|
|
972
993
|
}
|
|
973
994
|
//#endregion
|
|
974
995
|
//#region src/core/engine/native.ts
|
|
975
|
-
var
|
|
976
|
-
function
|
|
996
|
+
var gt = 2e3, _t = 3, B = 500, vt = 6e3, yt = .25, bt = 250, xt = .05, St = 4, Ct = 12e3, wt = .25, Tt = 1e3;
|
|
997
|
+
function Et(e) {
|
|
977
998
|
try {
|
|
978
999
|
let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
|
|
979
1000
|
return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
|
|
@@ -989,7 +1010,7 @@ function H() {
|
|
|
989
1010
|
let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
|
|
990
1011
|
return e || t;
|
|
991
1012
|
}
|
|
992
|
-
function
|
|
1013
|
+
function Dt() {
|
|
993
1014
|
if (typeof navigator > "u" || !H()) return !1;
|
|
994
1015
|
let e = navigator.userAgent ?? "";
|
|
995
1016
|
return /iPhone|iPad|iPod/.test(e) ? !0 : /Macintosh/.test(e) && typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1;
|
|
@@ -1024,7 +1045,7 @@ var U = class {
|
|
|
1024
1045
|
frameCounter;
|
|
1025
1046
|
detachFrames = null;
|
|
1026
1047
|
constructor(e) {
|
|
1027
|
-
this.deps = e, this.frameCounter = new
|
|
1048
|
+
this.deps = e, this.frameCounter = new mt(e.video), this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
|
|
1028
1049
|
}
|
|
1029
1050
|
async load() {
|
|
1030
1051
|
this.detachFrames ??= this.frameCounter.attach();
|
|
@@ -1043,9 +1064,9 @@ var U = class {
|
|
|
1043
1064
|
let i = !this.loadStarted;
|
|
1044
1065
|
this.onLoaded = i ? void 0 : () => r({ type: "ready" }), this.onError = () => r({
|
|
1045
1066
|
type: "error",
|
|
1046
|
-
error: new n("INTERNAL", 0, "native HLS playback error"),
|
|
1067
|
+
error: R() ? new n("INTERNAL", 0, "native HLS playback error") : new n("NETWORK", 0, "native HLS playback error while offline"),
|
|
1047
1068
|
fatal: !0
|
|
1048
|
-
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src =
|
|
1069
|
+
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = kt(t.manifestUrl, t.analytics?.sid), e.load();
|
|
1049
1070
|
}
|
|
1050
1071
|
startLoad() {
|
|
1051
1072
|
this.loadStarted || (this.loadStarted = !0, this.restorePreload());
|
|
@@ -1073,7 +1094,7 @@ var U = class {
|
|
|
1073
1094
|
};
|
|
1074
1095
|
this.onEncrypted = (n) => {
|
|
1075
1096
|
let a = n;
|
|
1076
|
-
a.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV =
|
|
1097
|
+
a.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = Et(a.initData), (async () => {
|
|
1077
1098
|
try {
|
|
1078
1099
|
let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
|
|
1079
1100
|
initDataTypes: [a.initDataType],
|
|
@@ -1173,10 +1194,10 @@ var U = class {
|
|
|
1173
1194
|
droppedFrames: t.dropped,
|
|
1174
1195
|
decodedFrames: t.totalFrames
|
|
1175
1196
|
};
|
|
1176
|
-
if (this.cdnHost ||=
|
|
1197
|
+
if (this.cdnHost ||= pt(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity) {
|
|
1177
1198
|
n.isLive = !0;
|
|
1178
1199
|
let t = this.liveEdgeEstimate(), r = t == null ? NaN : t - e.currentTime;
|
|
1179
|
-
Number.isFinite(r) && (n.atLiveEdge = r <=
|
|
1200
|
+
Number.isFinite(r) && (n.atLiveEdge = r <= St, !e.paused && r >= 0 && (n.latencySeconds = r));
|
|
1180
1201
|
} else Number.isFinite(e.duration) && e.duration > 0 && (n.isLive = !1);
|
|
1181
1202
|
return n;
|
|
1182
1203
|
}
|
|
@@ -1194,7 +1215,7 @@ var U = class {
|
|
|
1194
1215
|
return;
|
|
1195
1216
|
}
|
|
1196
1217
|
let t = this.hiddenSince;
|
|
1197
|
-
this.hiddenSince = null, t != null && e - t >=
|
|
1218
|
+
this.hiddenSince = null, t != null && e - t >= gt && this.armRefocus();
|
|
1198
1219
|
}, this.onPageShow = (e) => {
|
|
1199
1220
|
e.persisted && this.armRefocus();
|
|
1200
1221
|
}, document.addEventListener("visibilitychange", this.onVisibility), typeof window < "u" && window.addEventListener("pageshow", this.onPageShow));
|
|
@@ -1204,7 +1225,7 @@ var U = class {
|
|
|
1204
1225
|
let e = this.liveEnd(), t = W, n = t(), r = 0, i = () => {
|
|
1205
1226
|
if (this.refocusTimer = null, Number.isFinite(this.deps.video.duration)) return;
|
|
1206
1227
|
r += B;
|
|
1207
|
-
let a = this.liveEnd(), o = a != null && (e == null || a >= e +
|
|
1228
|
+
let a = this.liveEnd(), o = a != null && (e == null || a >= e + yt), s = Math.max(r, t() - n) >= vt;
|
|
1208
1229
|
if (o || s && a != null) {
|
|
1209
1230
|
this.snapToLive();
|
|
1210
1231
|
return;
|
|
@@ -1224,9 +1245,9 @@ var U = class {
|
|
|
1224
1245
|
}, e.addEventListener("seeking", this.onEdgeReset), e.addEventListener("emptied", this.onEdgeReset), this.edgeTimer = setInterval(() => {
|
|
1225
1246
|
if (e.duration !== Infinity) return;
|
|
1226
1247
|
this.checkEndStale();
|
|
1227
|
-
let t =
|
|
1228
|
-
t != null && ((this.lastBufferedEnd == null || Math.abs(t - this.lastBufferedEnd) >=
|
|
1229
|
-
},
|
|
1248
|
+
let t = Ot(e, e.currentTime);
|
|
1249
|
+
t != null && ((this.lastBufferedEnd == null || Math.abs(t - this.lastBufferedEnd) >= xt) && (this.bufferedAdvancedAt = W()), this.lastBufferedEnd = t);
|
|
1250
|
+
}, bt);
|
|
1230
1251
|
}
|
|
1231
1252
|
checkEndStale() {
|
|
1232
1253
|
if (this.endedEmitted) return;
|
|
@@ -1234,14 +1255,14 @@ var U = class {
|
|
|
1234
1255
|
this.lastTickAt = e;
|
|
1235
1256
|
let n = this.liveEnd();
|
|
1236
1257
|
if (n == null) return;
|
|
1237
|
-
let r = this.lastSeekableEnd == null || Math.abs(n - this.lastSeekableEnd) >=
|
|
1258
|
+
let r = this.lastSeekableEnd == null || Math.abs(n - this.lastSeekableEnd) >= wt;
|
|
1238
1259
|
this.lastSeekableEnd = n;
|
|
1239
1260
|
let i = this.deps.video, a = typeof document < "u" && document.visibilityState === "hidden";
|
|
1240
|
-
if (r || t >
|
|
1261
|
+
if (r || t > Tt || a || i.paused) {
|
|
1241
1262
|
this.edgeStampedAt = e;
|
|
1242
1263
|
return;
|
|
1243
1264
|
}
|
|
1244
|
-
e - (this.edgeStampedAt ?? e) >
|
|
1265
|
+
e - (this.edgeStampedAt ?? e) > Ct && (this.endedEmitted = !0, this.deps.emit({
|
|
1245
1266
|
type: "ended",
|
|
1246
1267
|
reason: "stalled"
|
|
1247
1268
|
}));
|
|
@@ -1255,7 +1276,7 @@ var U = class {
|
|
|
1255
1276
|
liveEdgeEstimate() {
|
|
1256
1277
|
let e = this.deps.video;
|
|
1257
1278
|
if (e.duration !== Infinity) return null;
|
|
1258
|
-
let t = this.liveEnd(), n =
|
|
1279
|
+
let t = this.liveEnd(), n = Ot(e, e.currentTime) ?? this.lastBufferedEnd;
|
|
1259
1280
|
if (n != null) {
|
|
1260
1281
|
let e = this.bufferedAdvancedAt, r = n + (e == null ? 0 : Math.max(0, (W() - e) / 1e3));
|
|
1261
1282
|
(t == null || r > t) && (t = r);
|
|
@@ -1271,7 +1292,7 @@ var U = class {
|
|
|
1271
1292
|
snapToLive() {
|
|
1272
1293
|
let e = this.deps.video, t = this.liveEnd();
|
|
1273
1294
|
if (t == null) return;
|
|
1274
|
-
let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t -
|
|
1295
|
+
let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t - _t, r);
|
|
1275
1296
|
try {
|
|
1276
1297
|
e.currentTime = i;
|
|
1277
1298
|
} catch {}
|
|
@@ -1292,7 +1313,7 @@ var U = class {
|
|
|
1292
1313
|
function W() {
|
|
1293
1314
|
return typeof performance < "u" ? performance.now() : Date.now();
|
|
1294
1315
|
}
|
|
1295
|
-
function
|
|
1316
|
+
function Ot(e, t) {
|
|
1296
1317
|
let n = e.buffered;
|
|
1297
1318
|
if (!n || !Number.isFinite(t)) return null;
|
|
1298
1319
|
for (let e = 0; e < n.length; e += 1) if (n.start(e) <= t + .1 && n.end(e) > t) {
|
|
@@ -1301,7 +1322,7 @@ function Et(e, t) {
|
|
|
1301
1322
|
}
|
|
1302
1323
|
return null;
|
|
1303
1324
|
}
|
|
1304
|
-
function
|
|
1325
|
+
function kt(e, t) {
|
|
1305
1326
|
return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
|
|
1306
1327
|
}
|
|
1307
1328
|
//#endregion
|
|
@@ -1318,13 +1339,13 @@ function G(e, t = Date.now()) {
|
|
|
1318
1339
|
}
|
|
1319
1340
|
//#endregion
|
|
1320
1341
|
//#region src/core/drm/xhrBody.ts
|
|
1321
|
-
var
|
|
1322
|
-
function
|
|
1342
|
+
var At = 4096;
|
|
1343
|
+
function jt(e) {
|
|
1323
1344
|
if (!e || typeof e != "object") return;
|
|
1324
1345
|
let { response: t } = e;
|
|
1325
1346
|
if (typeof t == "string") return t;
|
|
1326
1347
|
let n;
|
|
1327
|
-
if (Object.prototype.toString.call(t) === "[object ArrayBuffer]" ? n = new Uint8Array(t) : ArrayBuffer.isView(t) && (n = new Uint8Array(t.buffer, t.byteOffset, t.byteLength)), !(!n || n.byteLength === 0 || n.byteLength >
|
|
1348
|
+
if (Object.prototype.toString.call(t) === "[object ArrayBuffer]" ? n = new Uint8Array(t) : ArrayBuffer.isView(t) && (n = new Uint8Array(t.buffer, t.byteOffset, t.byteLength)), !(!n || n.byteLength === 0 || n.byteLength > At)) try {
|
|
1328
1349
|
return new TextDecoder().decode(n);
|
|
1329
1350
|
} catch {
|
|
1330
1351
|
return;
|
|
@@ -1332,7 +1353,7 @@ function kt(e) {
|
|
|
1332
1353
|
}
|
|
1333
1354
|
//#endregion
|
|
1334
1355
|
//#region src/core/engine/prefetch.ts
|
|
1335
|
-
var
|
|
1356
|
+
var Mt = 15e3, Nt = 5e3, Pt = 6, Ft = 4e3, It = 2;
|
|
1336
1357
|
function K(e) {
|
|
1337
1358
|
try {
|
|
1338
1359
|
let t = new URL(e);
|
|
@@ -1341,7 +1362,7 @@ function K(e) {
|
|
|
1341
1362
|
return e;
|
|
1342
1363
|
}
|
|
1343
1364
|
}
|
|
1344
|
-
var
|
|
1365
|
+
var Lt = class {
|
|
1345
1366
|
cmcd;
|
|
1346
1367
|
entries = /* @__PURE__ */ new Map();
|
|
1347
1368
|
keyed = /* @__PURE__ */ new Set();
|
|
@@ -1373,17 +1394,17 @@ var Ft = class {
|
|
|
1373
1394
|
let r = K(e);
|
|
1374
1395
|
if (this.entries.has(r)) return;
|
|
1375
1396
|
let i = this.perTrack.get(t) ?? 0;
|
|
1376
|
-
i >=
|
|
1397
|
+
i >= Pt || (this.perTrack.set(t, i + 1), this.start(r, this.withCmcd(e, t, n), !1, Mt), this.stats.started += 1);
|
|
1377
1398
|
}
|
|
1378
1399
|
prefetchHint(e, t) {
|
|
1379
1400
|
let n = K(e);
|
|
1380
1401
|
if (this.entries.has(n)) return;
|
|
1381
1402
|
let r = this.hints.get(t) ?? [];
|
|
1382
|
-
for (; r.length >=
|
|
1403
|
+
for (; r.length >= It;) {
|
|
1383
1404
|
let e = r.shift();
|
|
1384
1405
|
e !== void 0 && this.drop(e) && (this.stats.hintDropped += 1);
|
|
1385
1406
|
}
|
|
1386
|
-
r.push(n), this.hints.set(t, r), this.start(n, this.withCmcd(e, t, "media"), !0,
|
|
1407
|
+
r.push(n), this.hints.set(t, r), this.start(n, this.withCmcd(e, t, "media"), !0, Ft), this.stats.hintStarted += 1;
|
|
1387
1408
|
}
|
|
1388
1409
|
dropHints(e) {
|
|
1389
1410
|
for (let t of this.hints.get(e) ?? []) this.drop(t) && (this.stats.hintDropped += 1);
|
|
@@ -1436,14 +1457,14 @@ var Ft = class {
|
|
|
1436
1457
|
}
|
|
1437
1458
|
}
|
|
1438
1459
|
};
|
|
1439
|
-
function
|
|
1460
|
+
function Rt(t) {
|
|
1440
1461
|
let n = e.DefaultConfig?.loader;
|
|
1441
1462
|
if (typeof n != "function") return;
|
|
1442
1463
|
class r extends n {
|
|
1443
1464
|
served = !1;
|
|
1444
1465
|
cancelled = !1;
|
|
1445
1466
|
entry;
|
|
1446
|
-
stats =
|
|
1467
|
+
stats = zt();
|
|
1447
1468
|
load(e, n, r) {
|
|
1448
1469
|
let i = e.rangeEnd ? void 0 : t.take(e.url);
|
|
1449
1470
|
if (!i) {
|
|
@@ -1455,7 +1476,7 @@ function It(t) {
|
|
|
1455
1476
|
i.hint ? t.stats.hintFailed += 1 : t.stats.failed += 1;
|
|
1456
1477
|
}, s = () => {
|
|
1457
1478
|
!this.cancelled && this.served && (i.abort.abort(), o(), this.served = !1, this.entry = void 0, super.load(e, n, r));
|
|
1458
|
-
}, c = n?.loadPolicy, l = c?.maxTimeToFirstByteMs ||
|
|
1479
|
+
}, c = n?.loadPolicy, l = c?.maxTimeToFirstByteMs || Nt, u = setTimeout(s, l);
|
|
1459
1480
|
i.headers.then(() => {
|
|
1460
1481
|
clearTimeout(u);
|
|
1461
1482
|
let e = c?.maxLoadTimeMs;
|
|
@@ -1488,7 +1509,7 @@ function It(t) {
|
|
|
1488
1509
|
}
|
|
1489
1510
|
return r;
|
|
1490
1511
|
}
|
|
1491
|
-
function
|
|
1512
|
+
function zt() {
|
|
1492
1513
|
return {
|
|
1493
1514
|
aborted: !1,
|
|
1494
1515
|
loaded: 0,
|
|
@@ -1512,10 +1533,10 @@ function Lt() {
|
|
|
1512
1533
|
}
|
|
1513
1534
|
};
|
|
1514
1535
|
}
|
|
1515
|
-
function
|
|
1536
|
+
function Bt(e) {
|
|
1516
1537
|
return e === "audio" ? "audio" : "main";
|
|
1517
1538
|
}
|
|
1518
|
-
function
|
|
1539
|
+
function Vt(e, t) {
|
|
1519
1540
|
let n = [];
|
|
1520
1541
|
t.initSegment?.url && !t.initSegment.data && n.push({
|
|
1521
1542
|
url: t.initSegment.url,
|
|
@@ -1532,7 +1553,7 @@ function zt(e, t) {
|
|
|
1532
1553
|
});
|
|
1533
1554
|
return n;
|
|
1534
1555
|
}
|
|
1535
|
-
function
|
|
1556
|
+
function Ht(e) {
|
|
1536
1557
|
let t = e, n = t?.preloadHint;
|
|
1537
1558
|
if (!n || !t?.url || n.TYPE !== "PART" || n["BYTERANGE-START"] !== void 0 || n["BYTERANGE-LENGTH"] !== void 0) return null;
|
|
1538
1559
|
let r = n.URI;
|
|
@@ -1550,11 +1571,11 @@ function q(e, t) {
|
|
|
1550
1571
|
}
|
|
1551
1572
|
//#endregion
|
|
1552
1573
|
//#region src/core/engine/hls.ts
|
|
1553
|
-
function
|
|
1574
|
+
function Ut() {
|
|
1554
1575
|
return e.isSupported();
|
|
1555
1576
|
}
|
|
1556
|
-
var
|
|
1557
|
-
function
|
|
1577
|
+
var Wt = 3, Gt = 1e6, Kt = 20, qt = 1e4, Jt = 3, Yt = 5, Xt = 3, Zt = 1e4, Qt = 3e4, $t = 12e3, en = 3e3, tn = .02, nn = 6e3, rn = .5, an = 3, on = .5, sn = 1.1, cn = .25, ln = 5e3, un = 4e3, dn = 2, fn = 5, pn = 2, mn = 2, hn = 4, gn = 4, _n = 2e3, vn = 3e4, yn = 1, bn = 2;
|
|
1578
|
+
function xn(e, t, n) {
|
|
1558
1579
|
if (n <= 0 || t < 0 || t >= e.length) return t;
|
|
1559
1580
|
let r = (t, n) => e[t].width === e[n].width && e[t].height === e[n].height, i = (t) => {
|
|
1560
1581
|
for (; t + 1 < e.length && r(t + 1, t);) t++;
|
|
@@ -1563,11 +1584,11 @@ function yn(e, t, n) {
|
|
|
1563
1584
|
for (let t = 0; t < n && a + 1 < e.length; t++) a = i(a + 1);
|
|
1564
1585
|
return a;
|
|
1565
1586
|
}
|
|
1566
|
-
var
|
|
1567
|
-
function
|
|
1587
|
+
var Sn = .2, Cn = 30, wn = 2, Tn = 2, En = 2, Dn = 9, On = .5, kn = 64, An = 1e4, jn = 8, Mn = .6, Nn = .4, Pn = .4, Fn = 2, In = 6e4, J = .5, Ln = 3.5, Rn = 300;
|
|
1588
|
+
function zn(e) {
|
|
1568
1589
|
return (e?.part ?? e?.frag)?.stats;
|
|
1569
1590
|
}
|
|
1570
|
-
function
|
|
1591
|
+
function Bn() {
|
|
1571
1592
|
if (typeof navigator > "u") return 0;
|
|
1572
1593
|
try {
|
|
1573
1594
|
let e = navigator.connection?.rtt;
|
|
@@ -1576,20 +1597,20 @@ function Rn() {
|
|
|
1576
1597
|
return 0;
|
|
1577
1598
|
}
|
|
1578
1599
|
}
|
|
1579
|
-
function
|
|
1600
|
+
function Vn(e) {
|
|
1580
1601
|
if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
|
|
1581
1602
|
delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
|
|
1582
1603
|
return;
|
|
1583
1604
|
}
|
|
1584
|
-
e.liveSyncDuration ??=
|
|
1585
|
-
let t = Math.max(12, e.liveSyncDuration +
|
|
1586
|
-
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t),
|
|
1605
|
+
e.liveSyncDuration ??= En;
|
|
1606
|
+
let t = Math.max(12, e.liveSyncDuration + Dn);
|
|
1607
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Hn(e, e.liveSyncDuration);
|
|
1587
1608
|
}
|
|
1588
|
-
function
|
|
1609
|
+
function Hn(e, t) {
|
|
1589
1610
|
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
1590
1611
|
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
1591
1612
|
}
|
|
1592
|
-
var
|
|
1613
|
+
var Un = class {
|
|
1593
1614
|
name = "hls";
|
|
1594
1615
|
hls = null;
|
|
1595
1616
|
deps;
|
|
@@ -1619,6 +1640,9 @@ var Vn = class {
|
|
|
1619
1640
|
recoveryResetTimer = null;
|
|
1620
1641
|
networkRetryTimer = null;
|
|
1621
1642
|
licenseRetryTimer = null;
|
|
1643
|
+
offlineHold = !1;
|
|
1644
|
+
onOffline = null;
|
|
1645
|
+
onOnline = null;
|
|
1622
1646
|
onVisibility = null;
|
|
1623
1647
|
onSeeking = null;
|
|
1624
1648
|
onPause = null;
|
|
@@ -1683,7 +1707,7 @@ var Vn = class {
|
|
|
1683
1707
|
frameCounter;
|
|
1684
1708
|
detachFrames = null;
|
|
1685
1709
|
constructor(e) {
|
|
1686
|
-
this.deps = e, this.holdBackEnabled = e.adaptiveHoldBack !== !1, this.frameCounter = new
|
|
1710
|
+
this.deps = e, this.holdBackEnabled = e.adaptiveHoldBack !== !1, this.frameCounter = new mt(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
|
|
1687
1711
|
}
|
|
1688
1712
|
async load() {
|
|
1689
1713
|
this.detachFrames ??= this.frameCounter.attach();
|
|
@@ -1696,14 +1720,23 @@ var Vn = class {
|
|
|
1696
1720
|
});
|
|
1697
1721
|
return;
|
|
1698
1722
|
}
|
|
1699
|
-
e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (
|
|
1723
|
+
e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ke(r), Xe()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
|
|
1700
1724
|
let e = this.hls;
|
|
1701
1725
|
if (document.visibilityState !== "visible" || !e) return;
|
|
1702
1726
|
let t = e.liveSyncPosition;
|
|
1703
1727
|
if (typeof t != "number") return;
|
|
1704
1728
|
let n = typeof e.targetLatency == "number" && e.targetLatency > 0 ? e.targetLatency : 3;
|
|
1705
1729
|
t - r.currentTime > Math.max(n * 3, 8) && (r.currentTime = t);
|
|
1706
|
-
}, document.addEventListener("visibilitychange", this.onVisibility)), this.
|
|
1730
|
+
}, document.addEventListener("visibilitychange", this.onVisibility)), typeof window < "u" && (this.onOffline = () => {
|
|
1731
|
+
this.offlineHold = !0, this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), this.lastAdvanceMs = this.lastAdvanceMs ? Date.now() : 0, this.resetStarvationWindow(), this.clearKick();
|
|
1732
|
+
}, this.onOnline = () => {
|
|
1733
|
+
if (this.offlineHold && (this.offlineHold = !1, this.networkRecoveries = 0, this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), !this.stopped && this.hls && this.loadStarted && !this.loadSuspended)) {
|
|
1734
|
+
this.lastAdvanceMs = Date.now(), this.lastFragLoadingMs = 0, this.resetStarvationWindow(), this.resetChaseWindow(), this.clearKick();
|
|
1735
|
+
try {
|
|
1736
|
+
this.hls.startLoad(-1);
|
|
1737
|
+
} catch {}
|
|
1738
|
+
}
|
|
1739
|
+
}, window.addEventListener("offline", this.onOffline), window.addEventListener("online", this.onOnline), R() || this.onOffline()), this.onSeeking = () => {
|
|
1707
1740
|
this.clampOverSeek(), this.loadSuspended && (this.resumeLoading(), this.schedulePauseSuspend());
|
|
1708
1741
|
}, r.addEventListener("seeking", this.onSeeking), this.onTimeUpdate = () => this.updateCatchUpBand(), r.addEventListener("timeupdate", this.onTimeUpdate), this.onPause = () => this.schedulePauseSuspend(), this.onPlay = () => this.resumeLoading(), r.addEventListener("pause", this.onPause), r.addEventListener("play", this.onPlay), this.sizeCapManaged && typeof ResizeObserver < "u" && (this.capObserver = new ResizeObserver(() => this.onMediaResize()), this.capObserver.observe(r), this.watchDprChanges());
|
|
1709
1742
|
}
|
|
@@ -1719,7 +1752,7 @@ var Vn = class {
|
|
|
1719
1752
|
}
|
|
1720
1753
|
this.loadSuspended = !0;
|
|
1721
1754
|
}
|
|
1722
|
-
},
|
|
1755
|
+
}, ln));
|
|
1723
1756
|
}
|
|
1724
1757
|
resumeLoading() {
|
|
1725
1758
|
if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
|
|
@@ -1751,7 +1784,7 @@ var Vn = class {
|
|
|
1751
1784
|
let t = e.liveSyncPosition;
|
|
1752
1785
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
1753
1786
|
let { video: n } = this.deps;
|
|
1754
|
-
n.currentTime <= t +
|
|
1787
|
+
n.currentTime <= t + On || (n.currentTime = t);
|
|
1755
1788
|
}
|
|
1756
1789
|
reanchorPartTimeline(e, t) {
|
|
1757
1790
|
let { frag: n, part: r } = t;
|
|
@@ -1763,7 +1796,7 @@ var Vn = class {
|
|
|
1763
1796
|
let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
|
|
1764
1797
|
if (!s) return;
|
|
1765
1798
|
let c = a.startPTS - s.start;
|
|
1766
|
-
if (!(!Number.isFinite(c) || Math.abs(c) <
|
|
1799
|
+
if (!(!Number.isFinite(c) || Math.abs(c) < tn)) {
|
|
1767
1800
|
for (let e of i.fragments) e && e.setStart(e.start + c);
|
|
1768
1801
|
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})`);
|
|
1769
1802
|
}
|
|
@@ -1786,12 +1819,12 @@ var Vn = class {
|
|
|
1786
1819
|
emeEnabled: !0,
|
|
1787
1820
|
drmSystems: { ...this.licenseUrl ? { "com.widevine.alpha": { licenseUrl: this.licenseUrl } } : {} },
|
|
1788
1821
|
drmSystemOptions: {
|
|
1789
|
-
videoRobustness:
|
|
1790
|
-
audioRobustness:
|
|
1791
|
-
videoEncryptionScheme:
|
|
1792
|
-
audioEncryptionScheme:
|
|
1822
|
+
videoRobustness: P.video,
|
|
1823
|
+
audioRobustness: P.audio,
|
|
1824
|
+
videoEncryptionScheme: P.scheme,
|
|
1825
|
+
audioEncryptionScheme: P.scheme
|
|
1793
1826
|
},
|
|
1794
|
-
...
|
|
1827
|
+
...j() ? { requestMediaKeySystemAccessFunc: Ge(t) } : {},
|
|
1795
1828
|
licenseXhrSetup: (e, t) => {
|
|
1796
1829
|
let o = performance.now(), s = () => {
|
|
1797
1830
|
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", () => {
|
|
@@ -1803,7 +1836,7 @@ var Vn = class {
|
|
|
1803
1836
|
return;
|
|
1804
1837
|
}
|
|
1805
1838
|
let l = this.hls, u, d = new Promise((e) => {
|
|
1806
|
-
u = setTimeout(() => e(void 0),
|
|
1839
|
+
u = setTimeout(() => e(void 0), Zt);
|
|
1807
1840
|
});
|
|
1808
1841
|
return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
|
|
1809
1842
|
if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
|
|
@@ -1821,31 +1854,31 @@ var Vn = class {
|
|
|
1821
1854
|
this.prefetch?.destroy(), this.prefetch = null;
|
|
1822
1855
|
let p = !1, m = !1, h = u && this.deps.mediaDuringKey !== !1, g = this.deps.preloadHints === !0;
|
|
1823
1856
|
if ((h || g) && !f.fLoader) {
|
|
1824
|
-
let e = new
|
|
1857
|
+
let e = new Lt({
|
|
1825
1858
|
sessionId: n.analytics?.sid,
|
|
1826
1859
|
contentId: n.matchUrn
|
|
1827
|
-
}), t =
|
|
1860
|
+
}), t = Rt(e);
|
|
1828
1861
|
t && (this.prefetch = e, p = h, m = g, f.fLoader = t);
|
|
1829
1862
|
}
|
|
1830
|
-
|
|
1863
|
+
Vn(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;
|
|
1831
1864
|
let _ = new e(f);
|
|
1832
1865
|
if (this.hls = _, this.armHoldBack(_, f), _.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(_, t)), _.on(e.Events.MANIFEST_PARSED, () => {
|
|
1833
1866
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(_), this.measureLadder(_), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
|
|
1834
1867
|
}), _.on(e.Events.FRAG_BUFFERED, (e, t) => {
|
|
1835
1868
|
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(() => {
|
|
1836
1869
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
|
|
1837
|
-
},
|
|
1870
|
+
}, Qt)));
|
|
1838
1871
|
}), _.on(e.Events.FRAG_LOADING, (e, t) => {
|
|
1839
1872
|
t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
|
|
1840
1873
|
}), _.on(e.Events.FRAG_LOADED, (e, t) => {
|
|
1841
1874
|
t?.frag?.type === "main" && (this.mainFragsSinceTick += 1, this.bwFragsLoaded += 1, this.maybeRememberBandwidth(!1));
|
|
1842
|
-
let n = t?.frag, r =
|
|
1875
|
+
let n = t?.frag, r = zn(t), i = r?.loaded;
|
|
1843
1876
|
typeof i == "number" && (this.bytesLoaded += i), !this.reportedFirstBytes && typeof i == "number" && i > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
|
|
1844
1877
|
let a = r?.loading;
|
|
1845
|
-
a && a.end > 0 && a.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(a.end - a.start))), this.requestTimesMs.length >
|
|
1878
|
+
a && a.end > 0 && a.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(a.end - a.start))), this.requestTimesMs.length > kn && this.requestTimesMs.shift()), this.sampleHoldBack(t);
|
|
1846
1879
|
let o = n?.url;
|
|
1847
1880
|
if (o) {
|
|
1848
|
-
let e =
|
|
1881
|
+
let e = dt(o);
|
|
1849
1882
|
e && (this.cdnHost = e);
|
|
1850
1883
|
}
|
|
1851
1884
|
}), _.on(e.Events.LEVEL_LOADED, (e, t) => {
|
|
@@ -1862,8 +1895,8 @@ var Vn = class {
|
|
|
1862
1895
|
let i = e;
|
|
1863
1896
|
if (!i?.live || !i.partList?.length || typeof i.edge != "number") return;
|
|
1864
1897
|
let a = n.buffered, o = a.length ? a.end(a.length - 1) : 0;
|
|
1865
|
-
if (i.edge - o >
|
|
1866
|
-
let s =
|
|
1898
|
+
if (i.edge - o > Wt * (i.partTarget || .5)) return;
|
|
1899
|
+
let s = Ht(e);
|
|
1867
1900
|
s && t.prefetchHint(s, r);
|
|
1868
1901
|
};
|
|
1869
1902
|
_.on(e.Events.LEVEL_LOADED, (e, t) => {
|
|
@@ -1875,15 +1908,15 @@ var Vn = class {
|
|
|
1875
1908
|
if (this.prefetch && p) {
|
|
1876
1909
|
let t = this.prefetch;
|
|
1877
1910
|
_.on(e.Events.KEY_LOADING, (e, n) => {
|
|
1878
|
-
let r = n?.frag, i =
|
|
1879
|
-
if (r && t.isActive(i)) for (let e of
|
|
1880
|
-
}), _.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(
|
|
1911
|
+
let r = n?.frag, i = Bt(r?.type);
|
|
1912
|
+
if (r && t.isActive(i)) for (let e of Vt(_, r)) t.prefetch(e.url, i, e.kind);
|
|
1913
|
+
}), _.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(Bt(n?.frag?.type)));
|
|
1881
1914
|
}
|
|
1882
1915
|
_.on(e.Events.KEY_LOADED, () => {
|
|
1883
1916
|
u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
|
|
1884
1917
|
}), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
|
|
1885
1918
|
this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.adaptHoldBack(), this.checkFrameDrops();
|
|
1886
|
-
},
|
|
1919
|
+
}, en), _.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
1887
1920
|
this.renditionSwitches += 1;
|
|
1888
1921
|
let n = this.lastLevelIndex >= 0 ? _.levels[this.lastLevelIndex] : void 0, r = _.levels[t.level];
|
|
1889
1922
|
n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, this.armFrameDropGrace(), l({
|
|
@@ -1934,9 +1967,9 @@ var Vn = class {
|
|
|
1934
1967
|
let o = e.config ?? {}, s = typeof self < "u" && self.devicePixelRatio > 0 ? self.devicePixelRatio : 1, c = o.ignoreDevicePixelRatio ? 1 : s;
|
|
1935
1968
|
c = Math.min(c, o.maxDevicePixelRatio ?? Infinity);
|
|
1936
1969
|
let l = t.getMaxLevelByMediaSize(e.levels, i * c, a * c), u = this.deps.sizeCapHeadroom;
|
|
1937
|
-
if (u == null && s >=
|
|
1938
|
-
let d = u ??
|
|
1939
|
-
return
|
|
1970
|
+
if (u == null && s >= bn) return l;
|
|
1971
|
+
let d = u ?? yn, f = Number.isNaN(d) ? yn : d === Infinity ? e.levels.length : Math.max(0, Math.floor(d));
|
|
1972
|
+
return xn(e.levels, l, f);
|
|
1940
1973
|
}
|
|
1941
1974
|
onMediaResize() {
|
|
1942
1975
|
if (!this.sizeCapManaged) return;
|
|
@@ -1951,7 +1984,7 @@ var Vn = class {
|
|
|
1951
1984
|
return;
|
|
1952
1985
|
}
|
|
1953
1986
|
this.capTimer && clearTimeout(this.capTimer);
|
|
1954
|
-
let t = e > this.sizeCapLevel ?
|
|
1987
|
+
let t = e > this.sizeCapLevel ? _n : vn;
|
|
1955
1988
|
this.capTimer = setTimeout(() => {
|
|
1956
1989
|
this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
|
|
1957
1990
|
}, t);
|
|
@@ -1961,9 +1994,9 @@ var Vn = class {
|
|
|
1961
1994
|
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;
|
|
1962
1995
|
}
|
|
1963
1996
|
dropLevelsWidevineCannotPlay(e) {
|
|
1964
|
-
this.removeLevelsWhere(e, (e) =>
|
|
1965
|
-
let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e &&
|
|
1966
|
-
for (let n of t)
|
|
1997
|
+
this.removeLevelsWhere(e, (e) => Ze(e) !== !0);
|
|
1998
|
+
let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && F(e) !== "avc" && !!F(e)));
|
|
1999
|
+
for (let n of t) Ye(n).then((t) => {
|
|
1967
2000
|
t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
|
|
1968
2001
|
});
|
|
1969
2002
|
}
|
|
@@ -1971,10 +2004,10 @@ var Vn = class {
|
|
|
1971
2004
|
let n = e.levels ?? [], r = [], i = /* @__PURE__ */ new Set();
|
|
1972
2005
|
if (n.forEach((e, n) => {
|
|
1973
2006
|
let a = e.videoCodec;
|
|
1974
|
-
a &&
|
|
2007
|
+
a && F(a) && t(a) && (r.push(n), i.add(a));
|
|
1975
2008
|
}), !r.length) return !1;
|
|
1976
2009
|
let a = [...i].join(", ");
|
|
1977
|
-
if (!n.some((e, t) => r.includes(t) ? !1 : !
|
|
2010
|
+
if (!n.some((e, t) => r.includes(t) ? !1 : !F(e.videoCodec) || Ze(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
|
|
1978
2011
|
for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
|
|
1979
2012
|
return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
|
|
1980
2013
|
}
|
|
@@ -2077,12 +2110,12 @@ var Vn = class {
|
|
|
2077
2110
|
this.lastAdvanceMs = Date.now();
|
|
2078
2111
|
return;
|
|
2079
2112
|
}
|
|
2080
|
-
if (this.loadSuspended) {
|
|
2113
|
+
if (this.loadSuspended || this.offlineHold || !R()) {
|
|
2081
2114
|
this.lastAdvanceMs = Date.now();
|
|
2082
2115
|
return;
|
|
2083
2116
|
}
|
|
2084
2117
|
let e = Date.now() - this.lastAdvanceMs;
|
|
2085
|
-
!this.chaseSuspended && e >
|
|
2118
|
+
!this.chaseSuspended && e > nn && this.suspendChasing(), e > $t && this.emitEnded("stalled");
|
|
2086
2119
|
}
|
|
2087
2120
|
resetStarvationWindow() {
|
|
2088
2121
|
this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
|
|
@@ -2093,11 +2126,11 @@ var Vn = class {
|
|
|
2093
2126
|
checkStarvation() {
|
|
2094
2127
|
let e = this.hls, { video: t } = this.deps;
|
|
2095
2128
|
if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended) return;
|
|
2096
|
-
if (typeof document < "u" && document.hidden || this.loadSuspended) {
|
|
2129
|
+
if (typeof document < "u" && document.hidden || this.loadSuspended || this.offlineHold || !R()) {
|
|
2097
2130
|
this.resetStarvationWindow();
|
|
2098
2131
|
return;
|
|
2099
2132
|
}
|
|
2100
|
-
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs <
|
|
2133
|
+
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < nn, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > un, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = z(t), c = o - s, l = c !== this.starvedFrames;
|
|
2101
2134
|
if (this.starvedFrames = c, !a || l) {
|
|
2102
2135
|
(t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
|
|
2103
2136
|
return;
|
|
@@ -2106,12 +2139,12 @@ var Vn = class {
|
|
|
2106
2139
|
this.resetStarvationWindow();
|
|
2107
2140
|
return;
|
|
2108
2141
|
}
|
|
2109
|
-
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 >
|
|
2142
|
+
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 > hn && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= pn && (this.clearKick(), this.starvationRebuilds < mn)) {
|
|
2110
2143
|
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");
|
|
2111
2144
|
return;
|
|
2112
2145
|
}
|
|
2113
|
-
let u = i && this.starvedTicks >=
|
|
2114
|
-
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >=
|
|
2146
|
+
let u = i && this.starvedTicks >= dn, d = !i && this.deadTicks >= hn && this.recentMainFrags.reduce((e, t) => e + t, 0) >= gn;
|
|
2147
|
+
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= fn))) {
|
|
2115
2148
|
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");
|
|
2116
2149
|
try {
|
|
2117
2150
|
e.stopLoad(), e.startLoad(-1);
|
|
@@ -2122,11 +2155,11 @@ var Vn = class {
|
|
|
2122
2155
|
}
|
|
2123
2156
|
updateCatchUpBand() {
|
|
2124
2157
|
let e = this.hls;
|
|
2125
|
-
if (!e || this.catchUpRate <= 1 || this.chaseSuspended || this.loadSuspended) return;
|
|
2158
|
+
if (!e || this.catchUpRate <= 1 || this.chaseSuspended || this.loadSuspended || this.offlineHold) return;
|
|
2126
2159
|
let t = e.latency, n = e.targetLatency;
|
|
2127
2160
|
if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
|
|
2128
2161
|
let r = t - n;
|
|
2129
|
-
!this.catchUpEngaged && r >
|
|
2162
|
+
!this.catchUpEngaged && r > rn ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= rn && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
|
|
2130
2163
|
let i = this.catchUpEngaged ? this.catchUpRate : 1;
|
|
2131
2164
|
e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
|
|
2132
2165
|
}
|
|
@@ -2139,19 +2172,19 @@ var Vn = class {
|
|
|
2139
2172
|
}), n < 0 ? 0 : n;
|
|
2140
2173
|
}
|
|
2141
2174
|
armFrameDropGrace() {
|
|
2142
|
-
this.fpsGraceTicks > 0 || (this.fpsGraceTicks =
|
|
2175
|
+
this.fpsGraceTicks > 0 || (this.fpsGraceTicks = Tn, this.fpsBadTicks = 0);
|
|
2143
2176
|
}
|
|
2144
2177
|
resetFrameDropWindow() {
|
|
2145
2178
|
this.fpsLastFrames = -1, this.fpsLastDropped = -1, this.fpsBadTicks = 0;
|
|
2146
2179
|
}
|
|
2147
2180
|
checkFrameDrops() {
|
|
2148
2181
|
let e = this.hls, { video: t } = this.deps;
|
|
2149
|
-
if (!e || !this.fpsCapManaged || this.loadSuspended || t.paused || !e.autoLevelEnabled || typeof document < "u" && document.hidden) {
|
|
2182
|
+
if (!e || !this.fpsCapManaged || this.loadSuspended || this.offlineHold || t.paused || !e.autoLevelEnabled || typeof document < "u" && document.hidden) {
|
|
2150
2183
|
this.resetFrameDropWindow();
|
|
2151
2184
|
return;
|
|
2152
2185
|
}
|
|
2153
2186
|
let { totalFrames: n, dropped: r } = z(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
|
|
2154
|
-
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a <
|
|
2187
|
+
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Cn || o < 0) {
|
|
2155
2188
|
this.fpsBadTicks = 0;
|
|
2156
2189
|
return;
|
|
2157
2190
|
}
|
|
@@ -2159,11 +2192,11 @@ var Vn = class {
|
|
|
2159
2192
|
--this.fpsGraceTicks, this.fpsBadTicks = 0;
|
|
2160
2193
|
return;
|
|
2161
2194
|
}
|
|
2162
|
-
if (o <=
|
|
2195
|
+
if (o <= Sn * a) {
|
|
2163
2196
|
this.fpsBadTicks = 0;
|
|
2164
2197
|
return;
|
|
2165
2198
|
}
|
|
2166
|
-
if (this.fpsBadTicks += 1, this.fpsBadTicks <
|
|
2199
|
+
if (this.fpsBadTicks += 1, this.fpsBadTicks < wn) return;
|
|
2167
2200
|
this.fpsBadTicks = 0;
|
|
2168
2201
|
let s = e.levels, c = s[e.currentLevel];
|
|
2169
2202
|
if (!c) return;
|
|
@@ -2175,27 +2208,27 @@ var Vn = class {
|
|
|
2175
2208
|
}
|
|
2176
2209
|
checkFutileChase() {
|
|
2177
2210
|
let e = this.hls, { video: t } = this.deps;
|
|
2178
|
-
if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended || this.loadSuspended || typeof document < "u" && document.hidden) {
|
|
2211
|
+
if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended || this.loadSuspended || this.offlineHold || typeof document < "u" && document.hidden) {
|
|
2179
2212
|
this.resetChaseWindow();
|
|
2180
2213
|
return;
|
|
2181
2214
|
}
|
|
2182
2215
|
let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
|
|
2183
|
-
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(
|
|
2216
|
+
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(sn, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
|
|
2184
2217
|
this.resetChaseWindow();
|
|
2185
2218
|
return;
|
|
2186
2219
|
}
|
|
2187
|
-
if (this.chaseLatency < 0 || this.chaseLatency - n >=
|
|
2220
|
+
if (this.chaseLatency < 0 || this.chaseLatency - n >= on) {
|
|
2188
2221
|
this.chaseLatency = n, this.chaseTicks = 0;
|
|
2189
2222
|
return;
|
|
2190
2223
|
}
|
|
2191
|
-
if (this.chaseTicks += 1, this.chaseTicks <
|
|
2224
|
+
if (this.chaseTicks += 1, this.chaseTicks < an) return;
|
|
2192
2225
|
this.resetChaseWindow();
|
|
2193
2226
|
let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
|
|
2194
2227
|
if (!(a > 1)) return;
|
|
2195
2228
|
let o = e.targetLatency;
|
|
2196
2229
|
if (typeof o != "number" || !(o > 0)) return;
|
|
2197
2230
|
let s = Math.min(n, a - 1);
|
|
2198
|
-
s < o +
|
|
2231
|
+
s < o + cn || (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, this.deps.emit({
|
|
2199
2232
|
type: "livetargetchange",
|
|
2200
2233
|
change: {
|
|
2201
2234
|
targetSeconds: s,
|
|
@@ -2212,13 +2245,13 @@ var Vn = class {
|
|
|
2212
2245
|
if (!this.holdBackEnabled || this.holdBackPriorChecked || !e || (this.holdBackPriorChecked = !0, this.holdBackApplied > 0 || this.holdBackStepCount > 0)) return;
|
|
2213
2246
|
let t = e.targetLatency;
|
|
2214
2247
|
if (this.holdBackBase < 0 && typeof t == "number" && t > 0 && (this.holdBackBase = t), this.holdBackBase < 0) return;
|
|
2215
|
-
let n =
|
|
2216
|
-
if (!(n >=
|
|
2248
|
+
let n = Bn();
|
|
2249
|
+
if (!(n >= Rn)) return;
|
|
2217
2250
|
let r = typeof t == "number" && t > 0 ? t : this.holdBackBase, i = Math.min(this.holdBackCeiling(e), this.holdBackBase + J);
|
|
2218
2251
|
i > r && (this.holdBackStepCount = 1, this.moveHoldBack(e, r, i, "connection-rtt", `connection rtt ${n} ms`));
|
|
2219
2252
|
}
|
|
2220
2253
|
holdBackCeiling(e) {
|
|
2221
|
-
let t = this.deps.adaptiveHoldBackCeiling, n = typeof t == "number" && Number.isFinite(t) ? t :
|
|
2254
|
+
let t = this.deps.adaptiveHoldBackCeiling, n = typeof t == "number" && Number.isFinite(t) ? t : Ln, r = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
|
|
2222
2255
|
return r > 1 ? Math.min(n, r - 1) : n;
|
|
2223
2256
|
}
|
|
2224
2257
|
sampleHoldBack(e) {
|
|
@@ -2227,7 +2260,7 @@ var Vn = class {
|
|
|
2227
2260
|
if (t !== "main" && t !== "audio") return;
|
|
2228
2261
|
let n = e.part ? e.part.duration : this.detectedLowLatency ? 0 : e.frag?.duration;
|
|
2229
2262
|
if (typeof n != "number" || !(n > 0)) return;
|
|
2230
|
-
let r =
|
|
2263
|
+
let r = zn(e)?.loading;
|
|
2231
2264
|
if (!r || !(r.start > 0) || !(r.end > 0)) return;
|
|
2232
2265
|
let i = r.first > r.start ? r.first : r.end, a = Math.max(0, i - r.start) / (n * 1e3);
|
|
2233
2266
|
this.holdBackSamples.push({
|
|
@@ -2238,24 +2271,24 @@ var Vn = class {
|
|
|
2238
2271
|
adaptHoldBack() {
|
|
2239
2272
|
if (!this.holdBackEnabled) return;
|
|
2240
2273
|
let e = this.hls;
|
|
2241
|
-
if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended || this.loadSuspended || typeof document < "u" && document.hidden) {
|
|
2274
|
+
if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended || this.loadSuspended || this.offlineHold || typeof document < "u" && document.hidden) {
|
|
2242
2275
|
this.holdBackSlowTicks = 0, this.holdBackFastSince = 0, this.holdBackSamples = [];
|
|
2243
2276
|
return;
|
|
2244
2277
|
}
|
|
2245
|
-
let t = Date.now(), n = t -
|
|
2278
|
+
let t = Date.now(), n = t - An, r = this.holdBackSamples, i = 0;
|
|
2246
2279
|
for (; i < r.length && r[i].t < n;) i += 1;
|
|
2247
2280
|
i > 0 && r.splice(0, i);
|
|
2248
2281
|
let a = e.targetLatency;
|
|
2249
2282
|
if (typeof a != "number" || !(a > 0)) return;
|
|
2250
2283
|
this.holdBackBase < 0 && (this.holdBackBase = a);
|
|
2251
2284
|
let o = this.holdBackBase, s = this.holdBackCeiling(e);
|
|
2252
|
-
if (r.length <
|
|
2285
|
+
if (r.length < jn) {
|
|
2253
2286
|
this.holdBackSlowTicks = 0;
|
|
2254
2287
|
return;
|
|
2255
2288
|
}
|
|
2256
2289
|
let c = r.map((e) => e.ratio).sort((e, t) => e - t), l = q(c, 95), u = q(c, 50), d = Math.round(l * 1e3);
|
|
2257
|
-
if (l >=
|
|
2258
|
-
if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks <
|
|
2290
|
+
if (l >= Mn && u >= Nn) {
|
|
2291
|
+
if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks < Fn) return;
|
|
2259
2292
|
this.holdBackSlowTicks = 0;
|
|
2260
2293
|
let t = Math.ceil((s - o) / J), n = Math.ceil((a - o) / J - 1e-9);
|
|
2261
2294
|
if (n > this.holdBackStepCount && (this.holdBackStepCount = n), this.holdBackStepCount >= t) return;
|
|
@@ -2265,7 +2298,7 @@ var Vn = class {
|
|
|
2265
2298
|
this.moveHoldBack(e, a, r, "slow-fetches", `part fetches slow (first byte p50 ${Math.round(u * 1e3)} / p95 ${d} ms per 1 s of media)`);
|
|
2266
2299
|
return;
|
|
2267
2300
|
}
|
|
2268
|
-
if (this.holdBackSlowTicks = 0, l >=
|
|
2301
|
+
if (this.holdBackSlowTicks = 0, l >= Pn) {
|
|
2269
2302
|
this.holdBackFastSince = 0;
|
|
2270
2303
|
return;
|
|
2271
2304
|
}
|
|
@@ -2273,7 +2306,7 @@ var Vn = class {
|
|
|
2273
2306
|
this.holdBackFastSince = t;
|
|
2274
2307
|
return;
|
|
2275
2308
|
}
|
|
2276
|
-
if (t - this.holdBackFastSince <
|
|
2309
|
+
if (t - this.holdBackFastSince < In || (this.holdBackFastSince = t, this.holdBackStepCount === 0 || a !== this.holdBackApplied)) return;
|
|
2277
2310
|
--this.holdBackStepCount;
|
|
2278
2311
|
let f = Math.max(o, o + this.holdBackStepCount * J);
|
|
2279
2312
|
f >= a || this.moveHoldBack(e, a, f, "fast-fetches", `part fetches fast again (p95 first byte ${d} ms per 1 s of media)`);
|
|
@@ -2316,17 +2349,17 @@ var Vn = class {
|
|
|
2316
2349
|
} catch {}
|
|
2317
2350
|
}
|
|
2318
2351
|
startEstimate() {
|
|
2319
|
-
return this.deps.rememberBandwidth === !1 ?
|
|
2352
|
+
return this.deps.rememberBandwidth === !1 ? Gt : ze() ?? Gt;
|
|
2320
2353
|
}
|
|
2321
2354
|
maybeRememberBandwidth(e) {
|
|
2322
|
-
if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded <
|
|
2355
|
+
if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < Kt) return;
|
|
2323
2356
|
let t = Date.now();
|
|
2324
|
-
if (!e && t - this.bwSavedAt <
|
|
2357
|
+
if (!e && t - this.bwSavedAt < qt) return;
|
|
2325
2358
|
let n = this.hls?.bandwidthEstimate;
|
|
2326
|
-
typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t,
|
|
2359
|
+
typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Be(n));
|
|
2327
2360
|
}
|
|
2328
2361
|
destroy() {
|
|
2329
|
-
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) {
|
|
2362
|
+
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.onOffline && typeof window < "u" && (window.removeEventListener("offline", this.onOffline), this.onOffline = null), this.onOnline && typeof window < "u" && (window.removeEventListener("online", this.onOnline), this.onOnline = 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) {
|
|
2330
2363
|
try {
|
|
2331
2364
|
this.hls.destroy();
|
|
2332
2365
|
} catch (e) {
|
|
@@ -2341,7 +2374,7 @@ var Vn = class {
|
|
|
2341
2374
|
scheduleLicenseRetry(t) {
|
|
2342
2375
|
if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
|
|
2343
2376
|
let n = t.response?.code ?? 0;
|
|
2344
|
-
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >=
|
|
2377
|
+
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Xt) return !1;
|
|
2345
2378
|
this.licenseRecoveries += 1;
|
|
2346
2379
|
let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
|
|
2347
2380
|
return this.licenseRetryTimer = setTimeout(() => {
|
|
@@ -2373,7 +2406,11 @@ var Vn = class {
|
|
|
2373
2406
|
return;
|
|
2374
2407
|
}
|
|
2375
2408
|
if (t.type === e.ErrorTypes.NETWORK_ERROR) {
|
|
2376
|
-
if (
|
|
2409
|
+
if (!R() && (t.response?.code ?? 0) === 0) {
|
|
2410
|
+
this.offlineHold = !0, this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null);
|
|
2411
|
+
return;
|
|
2412
|
+
}
|
|
2413
|
+
if (this.networkRecoveries < Yt) {
|
|
2377
2414
|
this.networkRecoveries += 1;
|
|
2378
2415
|
let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
|
|
2379
2416
|
this.networkRetryTimer = setTimeout(() => {
|
|
@@ -2390,7 +2427,7 @@ var Vn = class {
|
|
|
2390
2427
|
return;
|
|
2391
2428
|
}
|
|
2392
2429
|
if (t.type === e.ErrorTypes.MEDIA_ERROR) {
|
|
2393
|
-
if (this.mediaRecoveries <
|
|
2430
|
+
if (this.mediaRecoveries < Jt) {
|
|
2394
2431
|
this.mediaRecoveries += 1, n.recoverMediaError();
|
|
2395
2432
|
return;
|
|
2396
2433
|
}
|
|
@@ -2411,18 +2448,18 @@ var Vn = class {
|
|
|
2411
2448
|
}
|
|
2412
2449
|
}
|
|
2413
2450
|
toError(t, r = "PLAYBACK") {
|
|
2414
|
-
let o = t.response?.code ?? 0, s = t.details ?? t.type, c = t.reason ?? t.error?.message ?? "", l = r === "DRM" && o === 403 && t.details === e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED ? i(
|
|
2415
|
-
return new n(r === "DRM" ? a(o, l) : o === 401 ? "UNAUTHORIZED" : o === 403 ? "FORBIDDEN" : "INTERNAL", o, `${r} error: ${s}${c ? ` (${c})` : ""}`, l ? { serverCode: l } : void 0);
|
|
2451
|
+
let o = t.response?.code ?? 0, s = t.details ?? t.type, c = t.reason ?? t.error?.message ?? "", l = r === "DRM" && o === 403 && t.details === e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED ? i(jt(t.networkDetails)) : void 0;
|
|
2452
|
+
return new n(r === "DRM" ? a(o, l) : r === "NETWORK" && o === 0 ? "NETWORK" : o === 401 ? "UNAUTHORIZED" : o === 403 ? "FORBIDDEN" : "INTERNAL", o, `${r} error: ${s}${c ? ` (${c})` : ""}`, l ? { serverCode: l } : void 0);
|
|
2416
2453
|
}
|
|
2417
|
-
},
|
|
2454
|
+
}, Wn = 15e3, Gn = 6e5, Kn = 3e5, qn = 100, Y = 1, Jn = 1e3, Yn = 3e4, Xn = 1e3, Zn = {
|
|
2418
2455
|
inline: "PRESENTATION_INLINE",
|
|
2419
2456
|
fullscreen: "PRESENTATION_FULLSCREEN",
|
|
2420
2457
|
pip: "PRESENTATION_PIP"
|
|
2421
|
-
},
|
|
2458
|
+
}, Qn = {
|
|
2422
2459
|
widevine: "KEY_SYSTEM_WIDEVINE",
|
|
2423
2460
|
fairplay: "KEY_SYSTEM_FAIRPLAY",
|
|
2424
2461
|
none: "KEY_SYSTEM_NONE"
|
|
2425
|
-
},
|
|
2462
|
+
}, $n = /* @__PURE__ */ new Set([
|
|
2426
2463
|
"INVALID_URN",
|
|
2427
2464
|
"NOT_FOUND",
|
|
2428
2465
|
"GEO_DENIED",
|
|
@@ -2443,7 +2480,7 @@ var Vn = class {
|
|
|
2443
2480
|
ended: "PLAYER_STATE_ENDED",
|
|
2444
2481
|
error: "PLAYER_STATE_ERROR"
|
|
2445
2482
|
};
|
|
2446
|
-
function
|
|
2483
|
+
function er(e) {
|
|
2447
2484
|
try {
|
|
2448
2485
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
2449
2486
|
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);
|
|
@@ -2451,8 +2488,8 @@ function Qn(e) {
|
|
|
2451
2488
|
return;
|
|
2452
2489
|
}
|
|
2453
2490
|
}
|
|
2454
|
-
var
|
|
2455
|
-
function
|
|
2491
|
+
var tr = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), nr = /* @__PURE__ */ new Set(), Z = /* @__PURE__ */ new Set(), Q = /* @__PURE__ */ new Set(), rr = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
|
|
2492
|
+
function ir(e) {
|
|
2456
2493
|
if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
|
|
2457
2494
|
let t;
|
|
2458
2495
|
try {
|
|
@@ -2461,19 +2498,19 @@ function nr(e) {
|
|
|
2461
2498
|
} catch {
|
|
2462
2499
|
return;
|
|
2463
2500
|
}
|
|
2464
|
-
if (
|
|
2465
|
-
Z.add(t), _(
|
|
2501
|
+
if (nr.has(t) && !Z.has(t)) {
|
|
2502
|
+
Z.add(t), _(rr(new URL(t).origin));
|
|
2466
2503
|
for (let e of Q) e.noteCspBlocked();
|
|
2467
2504
|
}
|
|
2468
2505
|
}
|
|
2469
|
-
function
|
|
2506
|
+
function ar(e, t) {
|
|
2470
2507
|
return _(t, e), { disabledReason: t };
|
|
2471
2508
|
}
|
|
2472
|
-
function
|
|
2473
|
-
if (n) return t &&
|
|
2509
|
+
function or(e, t, n) {
|
|
2510
|
+
if (n) return t && !tr(t, n) && _(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
|
|
2474
2511
|
if (t) return { endpoint: t };
|
|
2475
|
-
if (t !== void 0) return
|
|
2476
|
-
let r =
|
|
2512
|
+
if (t !== void 0) return ar("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).");
|
|
2513
|
+
let r = er(e);
|
|
2477
2514
|
if (r) return { endpoint: r };
|
|
2478
2515
|
let i;
|
|
2479
2516
|
try {
|
|
@@ -2481,9 +2518,9 @@ function ir(e, t, n) {
|
|
|
2481
2518
|
} catch {
|
|
2482
2519
|
i = e;
|
|
2483
2520
|
}
|
|
2484
|
-
return
|
|
2521
|
+
return ar(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).`);
|
|
2485
2522
|
}
|
|
2486
|
-
var
|
|
2523
|
+
var sr = class {
|
|
2487
2524
|
opts;
|
|
2488
2525
|
url;
|
|
2489
2526
|
cspKey;
|
|
@@ -2565,8 +2602,8 @@ var ar = class {
|
|
|
2565
2602
|
constructor(e) {
|
|
2566
2603
|
this.opts = {
|
|
2567
2604
|
...e,
|
|
2568
|
-
heartbeatMs: e.heartbeatMs ??
|
|
2569
|
-
idleMs: e.idleMs ??
|
|
2605
|
+
heartbeatMs: e.heartbeatMs ?? Wn,
|
|
2606
|
+
idleMs: e.idleMs ?? Gn
|
|
2570
2607
|
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
|
|
2571
2608
|
try {
|
|
2572
2609
|
let e = new URL(this.url);
|
|
@@ -2583,11 +2620,11 @@ var ar = class {
|
|
|
2583
2620
|
sdkVersion: this.opts.sdkVersion,
|
|
2584
2621
|
...this.opts.environment
|
|
2585
2622
|
};
|
|
2586
|
-
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(),
|
|
2623
|
+
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Jn), 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 && nr.add(this.cspKey), document.addEventListener("securitypolicyviolation", ir), Q.add(this), this.noteCspBlocked(), this.onVisibility());
|
|
2587
2624
|
}
|
|
2588
2625
|
checkSuspension(e) {
|
|
2589
2626
|
if (this.endedFlag || !this.opts.idleMs) return !1;
|
|
2590
|
-
let t = Math.max(this.opts.idleMs,
|
|
2627
|
+
let t = Math.max(this.opts.idleMs, Kn);
|
|
2591
2628
|
return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
|
|
2592
2629
|
}
|
|
2593
2630
|
syncIdle(e) {
|
|
@@ -2610,12 +2647,12 @@ var ar = class {
|
|
|
2610
2647
|
let a = {
|
|
2611
2648
|
fromState: X[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2612
2649
|
toState: X[t] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2613
|
-
presentation:
|
|
2650
|
+
presentation: Zn[this.presentation]
|
|
2614
2651
|
}, o = this.causeOf(e, t, i);
|
|
2615
2652
|
o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
2616
2653
|
}
|
|
2617
2654
|
seekInduced(e) {
|
|
2618
|
-
return this.lastSeekMs >= 0 && e - this.lastSeekMs <
|
|
2655
|
+
return this.lastSeekMs >= 0 && e - this.lastSeekMs < Xn;
|
|
2619
2656
|
}
|
|
2620
2657
|
causeOf(e, t, n) {
|
|
2621
2658
|
if (t === "error") return "TRANSITION_CAUSE_ERROR";
|
|
@@ -2689,7 +2726,7 @@ var ar = class {
|
|
|
2689
2726
|
let r = n ?? "";
|
|
2690
2727
|
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";
|
|
2691
2728
|
if (e === "DRM_CLIENT" || e === "DRM_DEVICE_REVOKED") return "ERROR_STAGE_DRM";
|
|
2692
|
-
if (
|
|
2729
|
+
if ($n.has(e)) return "ERROR_STAGE_RESOLVE";
|
|
2693
2730
|
let i = t ?? "";
|
|
2694
2731
|
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";
|
|
2695
2732
|
}
|
|
@@ -2743,7 +2780,7 @@ var ar = class {
|
|
|
2743
2780
|
maybeEmitMediaInfo(e) {
|
|
2744
2781
|
if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
|
|
2745
2782
|
let t = {};
|
|
2746
|
-
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem =
|
|
2783
|
+
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = Qn[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);
|
|
2747
2784
|
let n = JSON.stringify(t);
|
|
2748
2785
|
n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
|
|
2749
2786
|
}
|
|
@@ -2763,7 +2800,7 @@ var ar = class {
|
|
|
2763
2800
|
let c = r?.positionMs ?? 0;
|
|
2764
2801
|
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));
|
|
2765
2802
|
let l = e !== "END_REASON_ENDED";
|
|
2766
|
-
l && this.lastStallMs > 0 && n - this.lastStallMs <=
|
|
2803
|
+
l && this.lastStallMs > 0 && n - this.lastStallMs <= Yn && (i.abandonAfterStallMs = Math.max(Y, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Yn && (i.abandonAfterErrorMs = Math.max(Y, 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);
|
|
2767
2804
|
let u = r?.decodedFrames ?? this.lastDecoded;
|
|
2768
2805
|
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");
|
|
2769
2806
|
}
|
|
@@ -2783,13 +2820,13 @@ var ar = class {
|
|
|
2783
2820
|
};
|
|
2784
2821
|
}
|
|
2785
2822
|
noteCspBlocked() {
|
|
2786
|
-
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(
|
|
2823
|
+
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(rr(new URL(this.url).origin)));
|
|
2787
2824
|
}
|
|
2788
2825
|
cspBlocked() {
|
|
2789
2826
|
return !!this.cspKey && Z.has(this.cspKey);
|
|
2790
2827
|
}
|
|
2791
2828
|
enqueue(e) {
|
|
2792
|
-
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length >
|
|
2829
|
+
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > qn;) {
|
|
2793
2830
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
2794
2831
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
2795
2832
|
}
|
|
@@ -2816,7 +2853,7 @@ var ar = class {
|
|
|
2816
2853
|
};
|
|
2817
2854
|
//#endregion
|
|
2818
2855
|
//#region src/core/environment.ts
|
|
2819
|
-
function
|
|
2856
|
+
function cr() {
|
|
2820
2857
|
if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
|
|
2821
2858
|
let e;
|
|
2822
2859
|
try {
|
|
@@ -2841,14 +2878,14 @@ function or() {
|
|
|
2841
2878
|
integration: "INTEGRATION_KIND_IFRAME"
|
|
2842
2879
|
};
|
|
2843
2880
|
}
|
|
2844
|
-
function
|
|
2881
|
+
function lr() {
|
|
2845
2882
|
if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
|
|
2846
2883
|
let e = navigator.userAgentData, t = e?.platform ?? "";
|
|
2847
2884
|
if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
|
|
2848
2885
|
let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
|
|
2849
2886
|
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";
|
|
2850
2887
|
}
|
|
2851
|
-
function
|
|
2888
|
+
function ur() {
|
|
2852
2889
|
let e = typeof navigator < "u" ? navigator.connection : void 0;
|
|
2853
2890
|
if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
|
|
2854
2891
|
let t = {
|
|
@@ -2867,17 +2904,17 @@ function cr() {
|
|
|
2867
2904
|
}
|
|
2868
2905
|
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;
|
|
2869
2906
|
}
|
|
2870
|
-
function
|
|
2871
|
-
let t =
|
|
2872
|
-
deviceClass:
|
|
2907
|
+
function dr(e) {
|
|
2908
|
+
let t = cr(), n = {
|
|
2909
|
+
deviceClass: lr(),
|
|
2873
2910
|
integration: t.integration,
|
|
2874
|
-
...
|
|
2911
|
+
...ur()
|
|
2875
2912
|
};
|
|
2876
2913
|
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);
|
|
2877
2914
|
let r = e.getBoundingClientRect?.();
|
|
2878
2915
|
return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
|
|
2879
2916
|
}
|
|
2880
|
-
async function
|
|
2917
|
+
async function fr() {
|
|
2881
2918
|
let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
|
|
2882
2919
|
if (!e?.getHighEntropyValues) return {};
|
|
2883
2920
|
try {
|
|
@@ -2889,7 +2926,7 @@ async function ur() {
|
|
|
2889
2926
|
}
|
|
2890
2927
|
//#endregion
|
|
2891
2928
|
//#region src/core/version.ts
|
|
2892
|
-
var
|
|
2929
|
+
var pr = "2.25.1", mr = {
|
|
2893
2930
|
accent: "#E1B600",
|
|
2894
2931
|
accentText: "#1B1C23",
|
|
2895
2932
|
background: "#0e0f13",
|
|
@@ -2900,7 +2937,7 @@ var dr = "2.24.0", fr = {
|
|
|
2900
2937
|
border: "rgba(255, 255, 255, 0.1)",
|
|
2901
2938
|
radius: "8px",
|
|
2902
2939
|
fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
|
|
2903
|
-
},
|
|
2940
|
+
}, hr = {
|
|
2904
2941
|
accent: "--havik-accent",
|
|
2905
2942
|
accentText: "--havik-accent-text",
|
|
2906
2943
|
background: "--havik-bg",
|
|
@@ -2912,26 +2949,26 @@ var dr = "2.24.0", fr = {
|
|
|
2912
2949
|
radius: "--havik-radius",
|
|
2913
2950
|
fontFamily: "--havik-font"
|
|
2914
2951
|
};
|
|
2915
|
-
function
|
|
2952
|
+
function gr(e, t) {
|
|
2916
2953
|
let n = {
|
|
2917
|
-
...
|
|
2954
|
+
...mr,
|
|
2918
2955
|
...t
|
|
2919
2956
|
};
|
|
2920
|
-
for (let t of Object.keys(
|
|
2957
|
+
for (let t of Object.keys(hr)) e.style.setProperty(hr[t], n[t]);
|
|
2921
2958
|
n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
|
|
2922
2959
|
}
|
|
2923
2960
|
//#endregion
|
|
2924
2961
|
//#region src/ui/styles.ts
|
|
2925
|
-
var
|
|
2926
|
-
function
|
|
2927
|
-
let n = e.querySelector(`style#${
|
|
2928
|
-
if (n && (!t ||
|
|
2962
|
+
var _r = "havik-player-styles", vr = "\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", yr = /* @__PURE__ */ new WeakMap();
|
|
2963
|
+
function br(e = document, t) {
|
|
2964
|
+
let n = e.querySelector(`style#${_r}`);
|
|
2965
|
+
if (n && (!t || yr.get(n) === t)) return;
|
|
2929
2966
|
let r = e.createElement("style");
|
|
2930
|
-
r.id =
|
|
2967
|
+
r.id = _r, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = vr, yr.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
|
|
2931
2968
|
}
|
|
2932
2969
|
//#endregion
|
|
2933
2970
|
//#region src/ui/icons.ts
|
|
2934
|
-
var
|
|
2971
|
+
var xr = {
|
|
2935
2972
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
2936
2973
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
2937
2974
|
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\"/>",
|
|
@@ -2945,11 +2982,11 @@ var yr = {
|
|
|
2945
2982
|
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\"/>"
|
|
2946
2983
|
};
|
|
2947
2984
|
function $(e) {
|
|
2948
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
2985
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${xr[e]}</svg>`;
|
|
2949
2986
|
}
|
|
2950
2987
|
//#endregion
|
|
2951
2988
|
//#region src/ui/controls.ts
|
|
2952
|
-
var
|
|
2989
|
+
var Sr = 3e3, Cr = 250, wr = /* @__PURE__ */ new Set([
|
|
2953
2990
|
"GONE",
|
|
2954
2991
|
"NOT_FOUND",
|
|
2955
2992
|
"GEO_DENIED",
|
|
@@ -2957,15 +2994,15 @@ var br = 3e3, xr = 250, Sr = /* @__PURE__ */ new Set([
|
|
|
2957
2994
|
"UNAUTHORIZED",
|
|
2958
2995
|
"DRM_DEVICE_REVOKED"
|
|
2959
2996
|
]);
|
|
2960
|
-
function
|
|
2997
|
+
function Tr(e) {
|
|
2961
2998
|
let t = "This match isn't available in your country";
|
|
2962
2999
|
return e ? `${t} (${e})` : t;
|
|
2963
3000
|
}
|
|
2964
|
-
var
|
|
2965
|
-
function
|
|
2966
|
-
return new
|
|
3001
|
+
var Er = "This device can't play protected video";
|
|
3002
|
+
function Dr(e) {
|
|
3003
|
+
return new Or(e);
|
|
2967
3004
|
}
|
|
2968
|
-
var
|
|
3005
|
+
var Or = class {
|
|
2969
3006
|
root;
|
|
2970
3007
|
video;
|
|
2971
3008
|
player;
|
|
@@ -3004,6 +3041,7 @@ var Er = class {
|
|
|
3004
3041
|
endedMessage;
|
|
3005
3042
|
interruptedMessage;
|
|
3006
3043
|
errorMessage;
|
|
3044
|
+
offlineMessage;
|
|
3007
3045
|
hideTimer;
|
|
3008
3046
|
tapTimer;
|
|
3009
3047
|
surfacePointerType = "";
|
|
@@ -3013,7 +3051,7 @@ var Er = class {
|
|
|
3013
3051
|
scrubbing = !1;
|
|
3014
3052
|
offFns = [];
|
|
3015
3053
|
constructor(e) {
|
|
3016
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
3054
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Sr, 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, this.offlineMessage = e.offlineMessage ?? "No internet connection — waiting to reconnect", br(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");
|
|
3017
3055
|
let t = (e, t, n) => {
|
|
3018
3056
|
let r = this.doc.createElement(e);
|
|
3019
3057
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -3069,7 +3107,7 @@ var Er = class {
|
|
|
3069
3107
|
}), this.on(this.muteBtn, "click", () => this.player.setMuted(!e.muted)), this.on(this.volSlider, "input", () => {
|
|
3070
3108
|
let t = Number(this.volSlider.value);
|
|
3071
3109
|
this.setVolumeFill(t), this.player.setVolume(t), t > 0 && e.muted && this.player.setMuted(!1);
|
|
3072
|
-
}), 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) => {
|
|
3110
|
+
}), 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("offline", () => this.syncState())), this.offFns.push(this.player.on("online", () => 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) => {
|
|
3073
3111
|
this.lastError = e, this.statusKind = null, this.syncState();
|
|
3074
3112
|
}));
|
|
3075
3113
|
let t = (e) => e.pointerType !== "touch";
|
|
@@ -3099,7 +3137,7 @@ var Er = class {
|
|
|
3099
3137
|
let t = this.surfaceWasHidden;
|
|
3100
3138
|
this.tapTimer = setTimeout(() => {
|
|
3101
3139
|
this.tapTimer = void 0, this.toggleBar(t);
|
|
3102
|
-
},
|
|
3140
|
+
}, Cr);
|
|
3103
3141
|
}
|
|
3104
3142
|
toggleBar(e) {
|
|
3105
3143
|
e ? this.poke() : this.hideIfIdle();
|
|
@@ -3116,10 +3154,14 @@ var Er = class {
|
|
|
3116
3154
|
}
|
|
3117
3155
|
syncStatus(e) {
|
|
3118
3156
|
let t = null;
|
|
3119
|
-
|
|
3157
|
+
if (this.statusOverlays) {
|
|
3158
|
+
let n = this.player.offline && e !== "ended" && e !== "idle", r = !this.hasPlayed && (e === "paused" || e === "waiting");
|
|
3159
|
+
e === "ended" ? t = "ended" : n && !r ? t = "offline" : e === "error" ? t = "error" : e === "waiting" ? t = "waiting" : !this.hasPlayed && (e === "idle" || e === "paused") && (t = "preplay");
|
|
3160
|
+
}
|
|
3161
|
+
this.renderStatus(t);
|
|
3120
3162
|
}
|
|
3121
3163
|
statusMessageFor(e) {
|
|
3122
|
-
return e === "ended" ? this.player.endedReason === "interrupted" ? this.interruptedMessage : this.endedMessage : e === "waiting" ? this.hasPlayed ? "Reconnecting — please stand by" : "Starting soon…" : e === "error" ? this.errorMessage === void 0 ? this.lastError?.code === "GEO_DENIED" ?
|
|
3164
|
+
return e === "ended" ? this.player.endedReason === "interrupted" ? this.interruptedMessage : this.endedMessage : e === "offline" ? this.offlineMessage : e === "waiting" ? this.hasPlayed ? "Reconnecting — please stand by" : "Starting soon…" : e === "error" ? this.errorMessage === void 0 ? this.lastError?.code === "GEO_DENIED" ? Tr(this.lastError.country) : this.lastError?.code === "DRM_DEVICE_REVOKED" ? Er : this.lastError?.message ?? "Playback unavailable" : this.errorMessage : null;
|
|
3123
3165
|
}
|
|
3124
3166
|
renderStatus(e) {
|
|
3125
3167
|
let t = this.statusMessageFor(e);
|
|
@@ -3134,7 +3176,7 @@ var Er = class {
|
|
|
3134
3176
|
e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = $("play"), e.addEventListener("click", () => void this.player.play()), n.append(e);
|
|
3135
3177
|
} else {
|
|
3136
3178
|
let r = this.doc.createElement("div");
|
|
3137
|
-
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !
|
|
3179
|
+
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !wr.has(this.lastError.code)) {
|
|
3138
3180
|
let e = this.doc.createElement("button");
|
|
3139
3181
|
e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${$("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), n.append(e);
|
|
3140
3182
|
}
|
|
@@ -3175,7 +3217,7 @@ var Er = class {
|
|
|
3175
3217
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
3176
3218
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
3177
3219
|
}
|
|
3178
|
-
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${
|
|
3220
|
+
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${kr(this.video.currentTime)} / ${kr(this.video.duration)}`);
|
|
3179
3221
|
}
|
|
3180
3222
|
syncLive() {
|
|
3181
3223
|
let e = this.player.getStats(), t = e.isLive !== !1, n = this.player.state === "ended", r = !t && !this.streamEnded();
|
|
@@ -3225,17 +3267,17 @@ var Er = class {
|
|
|
3225
3267
|
renderQualityMenu() {
|
|
3226
3268
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
3227
3269
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
3228
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
3270
|
+
for (let n of e) this.menu.append(this.menuItem(Ar(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
3229
3271
|
}
|
|
3230
3272
|
renderAudioMenu() {
|
|
3231
3273
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
3232
3274
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
3233
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
3275
|
+
for (let t of e) this.menu.append(this.menuItem(jr(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
3234
3276
|
}
|
|
3235
3277
|
renderCcMenu() {
|
|
3236
3278
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
3237
3279
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
3238
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
3280
|
+
for (let t of e) this.menu.append(this.menuItem(Mr(t), !1, () => this.player.setTextTrack(t.id)));
|
|
3239
3281
|
}
|
|
3240
3282
|
onTracksChanged() {
|
|
3241
3283
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -3255,14 +3297,14 @@ var Er = class {
|
|
|
3255
3297
|
}
|
|
3256
3298
|
async toggleFullscreen() {
|
|
3257
3299
|
try {
|
|
3258
|
-
|
|
3300
|
+
ve(this.video, this.root) ? await C(this.video, this.root) : await S(this.video, this.root);
|
|
3259
3301
|
} catch {}
|
|
3260
3302
|
}
|
|
3261
3303
|
syncFullscreenSupport() {
|
|
3262
|
-
this.fsSupported =
|
|
3304
|
+
this.fsSupported = ye(this.video, this.root), this.fsBtn.style.display = this.fsSupported ? "" : "none";
|
|
3263
3305
|
}
|
|
3264
3306
|
syncFullscreen() {
|
|
3265
|
-
let e =
|
|
3307
|
+
let e = ve(this.video, this.root);
|
|
3266
3308
|
this.setIcon(this.fsBtn, e ? "fullscreenExit" : "fullscreen"), this.fsBtn.setAttribute("aria-label", e ? "Exit fullscreen" : "Fullscreen");
|
|
3267
3309
|
}
|
|
3268
3310
|
poke() {
|
|
@@ -3340,41 +3382,51 @@ var Er = class {
|
|
|
3340
3382
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
3341
3383
|
}
|
|
3342
3384
|
};
|
|
3343
|
-
function
|
|
3385
|
+
function kr(e) {
|
|
3344
3386
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
3345
3387
|
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");
|
|
3346
3388
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
3347
3389
|
}
|
|
3348
|
-
function
|
|
3390
|
+
function Ar(e) {
|
|
3349
3391
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
3350
3392
|
}
|
|
3351
|
-
function
|
|
3393
|
+
function jr(e) {
|
|
3352
3394
|
return e.name || e.lang || `Track ${e.id}`;
|
|
3353
3395
|
}
|
|
3354
|
-
function
|
|
3396
|
+
function Mr(e) {
|
|
3355
3397
|
return e.name || e.lang || `Track ${e.id}`;
|
|
3356
3398
|
}
|
|
3357
3399
|
//#endregion
|
|
3358
3400
|
//#region src/managed/index.ts
|
|
3359
|
-
var
|
|
3360
|
-
|
|
3401
|
+
var Nr = 6e3, Pr = 45e3, Fr = 2e3, Ir = 3, Lr = 5e3, Rr = 2e3, zr = 48e4, Br = "keySystemLicenseRequestFailed", Vr = /* @__PURE__ */ new Set([
|
|
3402
|
+
"GONE",
|
|
3403
|
+
"NOT_FOUND",
|
|
3404
|
+
"INVALID_URN",
|
|
3405
|
+
"UNAUTHORIZED",
|
|
3406
|
+
"GEO_DENIED",
|
|
3407
|
+
"DRM_DEVICE_REVOKED"
|
|
3408
|
+
]);
|
|
3409
|
+
function Hr(e) {
|
|
3410
|
+
return !Vr.has(e);
|
|
3411
|
+
}
|
|
3412
|
+
function Ur(e) {
|
|
3361
3413
|
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)})`);
|
|
3362
|
-
if (e.env !== void 0) return
|
|
3414
|
+
if (e.env !== void 0) return ct(e.env);
|
|
3363
3415
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
|
|
3364
3416
|
return e.baseUrl;
|
|
3365
3417
|
}
|
|
3366
|
-
async function
|
|
3418
|
+
async function Wr(e) {
|
|
3367
3419
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
3368
|
-
let t =
|
|
3420
|
+
let t = Ur(e);
|
|
3369
3421
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
3370
3422
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
3371
|
-
let r = new
|
|
3423
|
+
let r = new Gr({
|
|
3372
3424
|
...e,
|
|
3373
3425
|
baseUrl: t
|
|
3374
3426
|
});
|
|
3375
3427
|
return await r.start(), r;
|
|
3376
3428
|
}
|
|
3377
|
-
var
|
|
3429
|
+
var Gr = class {
|
|
3378
3430
|
opts;
|
|
3379
3431
|
abort = new AbortController();
|
|
3380
3432
|
listeners = {};
|
|
@@ -3409,12 +3461,17 @@ var Vr = class {
|
|
|
3409
3461
|
playRequested = !1;
|
|
3410
3462
|
idleClosed = !1;
|
|
3411
3463
|
pendingStartLoad = !1;
|
|
3464
|
+
connectivity = null;
|
|
3465
|
+
failedWhileOffline = !1;
|
|
3412
3466
|
constructor(e) {
|
|
3413
3467
|
this.opts = e;
|
|
3414
3468
|
}
|
|
3415
3469
|
get state() {
|
|
3416
3470
|
return this._state;
|
|
3417
3471
|
}
|
|
3472
|
+
get offline() {
|
|
3473
|
+
return !R();
|
|
3474
|
+
}
|
|
3418
3475
|
get descriptor() {
|
|
3419
3476
|
return this._descriptor;
|
|
3420
3477
|
}
|
|
@@ -3422,7 +3479,7 @@ var Vr = class {
|
|
|
3422
3479
|
return this._endedReason;
|
|
3423
3480
|
}
|
|
3424
3481
|
async start() {
|
|
3425
|
-
this.opts.muted && (this.opts.video.muted = !0), this.opts.poster && (this.opts.video.poster = this.opts.poster), this.mountControls(), this.attachPipListeners(), this.attachEndedPlayGuard(), this.setState("loading");
|
|
3482
|
+
this.opts.muted && (this.opts.video.muted = !0), this.opts.poster && (this.opts.video.poster = this.opts.poster), this.mountControls(), this.attachPipListeners(), this.attachEndedPlayGuard(), this.watchConnectivity(), this.setState("loading");
|
|
3426
3483
|
let e = ++this.loadGen, t = this.resolveOptions();
|
|
3427
3484
|
try {
|
|
3428
3485
|
let n = await v(t);
|
|
@@ -3435,7 +3492,7 @@ var Vr = class {
|
|
|
3435
3492
|
this.setState("waiting"), this.beginArming(e, t.liveStartsAtMs);
|
|
3436
3493
|
return;
|
|
3437
3494
|
}
|
|
3438
|
-
throw t;
|
|
3495
|
+
throw this.destroy(), t;
|
|
3439
3496
|
}
|
|
3440
3497
|
}
|
|
3441
3498
|
resolveOptions() {
|
|
@@ -3448,7 +3505,7 @@ var Vr = class {
|
|
|
3448
3505
|
};
|
|
3449
3506
|
}
|
|
3450
3507
|
beginArming(e, t, n = !1) {
|
|
3451
|
-
let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ??
|
|
3508
|
+
let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? E(this.opts.baseUrl);
|
|
3452
3509
|
r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
|
|
3453
3510
|
}
|
|
3454
3511
|
beginArmingByPolling(e) {
|
|
@@ -3469,7 +3526,7 @@ var Vr = class {
|
|
|
3469
3526
|
setTimeout(() => {
|
|
3470
3527
|
a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
3471
3528
|
phase: i ? "unavailable" : "tooEarly",
|
|
3472
|
-
retryInMs:
|
|
3529
|
+
retryInMs: Pr,
|
|
3473
3530
|
attempt: 1,
|
|
3474
3531
|
elapsedMs: 0,
|
|
3475
3532
|
...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
|
|
@@ -3508,13 +3565,13 @@ var Vr = class {
|
|
|
3508
3565
|
!a && !p() && h();
|
|
3509
3566
|
}, e);
|
|
3510
3567
|
};
|
|
3511
|
-
_(
|
|
3568
|
+
_(Nr), this.armingSub = T({
|
|
3512
3569
|
eventsBaseUrl: t,
|
|
3513
3570
|
matchUrn: this.opts.matchUrn,
|
|
3514
3571
|
credential: this.opts.credential,
|
|
3515
|
-
onAlive: () => _(
|
|
3572
|
+
onAlive: () => _(Pr),
|
|
3516
3573
|
onState: (e) => {
|
|
3517
|
-
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() *
|
|
3574
|
+
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Fr);
|
|
3518
3575
|
},
|
|
3519
3576
|
onError: () => h()
|
|
3520
3577
|
});
|
|
@@ -3537,7 +3594,7 @@ var Vr = class {
|
|
|
3537
3594
|
let n = await c(this.opts.credential);
|
|
3538
3595
|
if (this.destroyed || t !== this.loadGen) return;
|
|
3539
3596
|
this.setState("loading");
|
|
3540
|
-
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a =
|
|
3597
|
+
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = ht(this.opts.video, (e) => {
|
|
3541
3598
|
this._state !== "ended" && this._state !== "error" && this.setState(e);
|
|
3542
3599
|
});
|
|
3543
3600
|
if (await i.load(), this.destroyed || t !== this.loadGen) {
|
|
@@ -3559,26 +3616,26 @@ var Vr = class {
|
|
|
3559
3616
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
|
|
3560
3617
|
let i = e.analytics?.sid;
|
|
3561
3618
|
if (!i) return;
|
|
3562
|
-
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } =
|
|
3619
|
+
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = or(this.opts.baseUrl, a, e.analytics?.endpoint);
|
|
3563
3620
|
if (!o) {
|
|
3564
3621
|
s && setTimeout(() => {
|
|
3565
3622
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
|
|
3566
3623
|
}, 0);
|
|
3567
3624
|
return;
|
|
3568
3625
|
}
|
|
3569
|
-
let c = this.opts.video, l = new
|
|
3626
|
+
let c = this.opts.video, l = new sr({
|
|
3570
3627
|
endpoint: o,
|
|
3571
3628
|
sid: i,
|
|
3572
3629
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
3573
|
-
sdkVersion:
|
|
3574
|
-
environment:
|
|
3630
|
+
sdkVersion: pr,
|
|
3631
|
+
environment: dr(c),
|
|
3575
3632
|
idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
|
|
3576
3633
|
onIdle: () => this.onAnalyticsIdle(t),
|
|
3577
3634
|
onBlocked: (e) => setTimeout(() => {
|
|
3578
3635
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
|
|
3579
3636
|
}, 0),
|
|
3580
3637
|
sample: () => {
|
|
3581
|
-
let e = this.engine?.getStats() ??
|
|
3638
|
+
let e = this.engine?.getStats() ?? ut, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
|
|
3582
3639
|
return {
|
|
3583
3640
|
...e,
|
|
3584
3641
|
bufferedMs: Math.round(t * 1e3),
|
|
@@ -3592,7 +3649,7 @@ var Vr = class {
|
|
|
3592
3649
|
let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
|
|
3593
3650
|
c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
|
|
3594
3651
|
c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
|
|
3595
|
-
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()),
|
|
3652
|
+
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), fr().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
|
|
3596
3653
|
}
|
|
3597
3654
|
currentPresentation() {
|
|
3598
3655
|
let e = this.opts.video;
|
|
@@ -3607,7 +3664,7 @@ var Vr = class {
|
|
|
3607
3664
|
video: this.opts.video,
|
|
3608
3665
|
descriptor: e,
|
|
3609
3666
|
credential: t,
|
|
3610
|
-
deviceId:
|
|
3667
|
+
deviceId: k(),
|
|
3611
3668
|
userId: this.opts.userId,
|
|
3612
3669
|
lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
|
|
3613
3670
|
snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
|
|
@@ -3624,9 +3681,9 @@ var Vr = class {
|
|
|
3624
3681
|
freshLicenseUrl: () => this.refreshLicense()
|
|
3625
3682
|
}, o = this.opts.engine ?? "auto";
|
|
3626
3683
|
if (o === "native") return new U(a);
|
|
3627
|
-
if (o === "hls") return new
|
|
3628
|
-
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && V(this.opts.video) && H() || !e.drmEnabled &&
|
|
3629
|
-
if (
|
|
3684
|
+
if (o === "hls") return new Un(a);
|
|
3685
|
+
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && V(this.opts.video) && H() || !e.drmEnabled && Dt() && V(this.opts.video)) return new U(a);
|
|
3686
|
+
if (Ut()) return new Un(a);
|
|
3630
3687
|
if (V(this.opts.video)) return new U(a);
|
|
3631
3688
|
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
3632
3689
|
}
|
|
@@ -3677,11 +3734,11 @@ var Vr = class {
|
|
|
3677
3734
|
}
|
|
3678
3735
|
startLiveState(e) {
|
|
3679
3736
|
if (this.opts.liveStateEvents === !1) return;
|
|
3680
|
-
let t = this.opts.eventsBaseUrl ??
|
|
3737
|
+
let t = this.opts.eventsBaseUrl ?? E(this.opts.baseUrl);
|
|
3681
3738
|
if (!t) return;
|
|
3682
3739
|
this.closeLiveState();
|
|
3683
3740
|
let i = 0, a = !1;
|
|
3684
|
-
this.liveStateSub =
|
|
3741
|
+
this.liveStateSub = T({
|
|
3685
3742
|
eventsBaseUrl: t,
|
|
3686
3743
|
matchUrn: this.opts.matchUrn,
|
|
3687
3744
|
credential: this.opts.credential,
|
|
@@ -3693,11 +3750,11 @@ var Vr = class {
|
|
|
3693
3750
|
},
|
|
3694
3751
|
onError: (o) => {
|
|
3695
3752
|
if (!(this.destroyed || e !== this.loadGen || a) && !this.endedHandled) {
|
|
3696
|
-
if (o instanceof
|
|
3753
|
+
if (o instanceof w && (o.terminal || o.status === 404)) {
|
|
3697
3754
|
a = !0, this.emit("warning", new n(r(o.status), o.status, `live-state events answered HTTP ${o.status} for ${this.opts.matchUrn}: the match is ` + (o.terminal ? "gone, so the subscription stopped" : "not in the catalog (ended and dropped, or not listed yet), so it retries every 5 min") + " — end-of-stream detection falls back to the HLS staleness watchdog."));
|
|
3698
3755
|
return;
|
|
3699
3756
|
}
|
|
3700
|
-
i += 1, i >=
|
|
3757
|
+
i += 1, i >= Ir && (a = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${i} 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.`)));
|
|
3701
3758
|
}
|
|
3702
3759
|
}
|
|
3703
3760
|
});
|
|
@@ -3705,6 +3762,18 @@ var Vr = class {
|
|
|
3705
3762
|
closeLiveState() {
|
|
3706
3763
|
this.liveStateSub?.close(), this.liveStateSub = null;
|
|
3707
3764
|
}
|
|
3765
|
+
watchConnectivity() {
|
|
3766
|
+
this.connectivity || (this.connectivity = lt(), this.connectivity.onChange((e) => {
|
|
3767
|
+
if (this.destroyed) return;
|
|
3768
|
+
if (!e) {
|
|
3769
|
+
this.emit("offline");
|
|
3770
|
+
return;
|
|
3771
|
+
}
|
|
3772
|
+
if (this.emit("online"), this._state !== "error" || !this._lastError) return;
|
|
3773
|
+
let t = this._lastError.code;
|
|
3774
|
+
Hr(t) && (t === "NETWORK" || this.failedWhileOffline) && this.retry().catch(() => void 0);
|
|
3775
|
+
}));
|
|
3776
|
+
}
|
|
3708
3777
|
watchReturn() {
|
|
3709
3778
|
this.onReturnVisible || typeof document > "u" || this.opts.liveStateEvents !== !1 && (document.visibilityState === "hidden" && (this.hiddenAtMs = Date.now()), this.onReturnVisible = () => {
|
|
3710
3779
|
if (document.visibilityState === "hidden") {
|
|
@@ -3712,7 +3781,7 @@ var Vr = class {
|
|
|
3712
3781
|
return;
|
|
3713
3782
|
}
|
|
3714
3783
|
let e = this.hiddenAtMs;
|
|
3715
|
-
this.hiddenAtMs = null, e != null && Date.now() - e >=
|
|
3784
|
+
this.hiddenAtMs = null, e != null && Date.now() - e >= Lr && this.resyncLiveState();
|
|
3716
3785
|
}, this.onReturnPageShow = (e) => {
|
|
3717
3786
|
e.persisted && this.resyncLiveState();
|
|
3718
3787
|
}, document.addEventListener("visibilitychange", this.onReturnVisible), typeof window < "u" && window.addEventListener("pageshow", this.onReturnPageShow));
|
|
@@ -3744,7 +3813,7 @@ var Vr = class {
|
|
|
3744
3813
|
scheduleRejoin(e) {
|
|
3745
3814
|
this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
|
|
3746
3815
|
this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
|
|
3747
|
-
}, Math.random() *
|
|
3816
|
+
}, Math.random() * Fr));
|
|
3748
3817
|
}
|
|
3749
3818
|
cancelRejoin() {
|
|
3750
3819
|
this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
|
|
@@ -3768,7 +3837,7 @@ var Vr = class {
|
|
|
3768
3837
|
}
|
|
3769
3838
|
t.controls = !1;
|
|
3770
3839
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
3771
|
-
r && r.insertBefore(n, t), n.appendChild(t),
|
|
3840
|
+
r && r.insertBefore(n, t), n.appendChild(t), gr(n, this.opts.theme), this.container = n, this.controlBar = Dr({
|
|
3772
3841
|
root: n,
|
|
3773
3842
|
video: t,
|
|
3774
3843
|
player: this,
|
|
@@ -3778,6 +3847,7 @@ var Vr = class {
|
|
|
3778
3847
|
streamEnded: () => this.streamEnded,
|
|
3779
3848
|
interruptedMessage: this.opts.interruptedMessage,
|
|
3780
3849
|
errorMessage: this.opts.errorMessage,
|
|
3850
|
+
offlineMessage: this.opts.offlineMessage,
|
|
3781
3851
|
cspNonce: this.opts.cspNonce
|
|
3782
3852
|
});
|
|
3783
3853
|
}
|
|
@@ -3806,7 +3876,7 @@ var Vr = class {
|
|
|
3806
3876
|
}
|
|
3807
3877
|
startStats() {
|
|
3808
3878
|
this.stopStats();
|
|
3809
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
3879
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? Rr);
|
|
3810
3880
|
this.statsTimer = setInterval(() => {
|
|
3811
3881
|
if (!this.engine) return;
|
|
3812
3882
|
let e = this.engine.getStats();
|
|
@@ -3817,14 +3887,14 @@ var Vr = class {
|
|
|
3817
3887
|
this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
|
|
3818
3888
|
}
|
|
3819
3889
|
isStaleLicenseDenial(e) {
|
|
3820
|
-
return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !==
|
|
3890
|
+
return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== Br || e.error.httpStatus !== 403 || e.error.code !== "FORBIDDEN" || e.error.serverCode === "license_refused" ? !1 : G(this._descriptor?.drm?.widevine?.licenseUrl);
|
|
3821
3891
|
}
|
|
3822
3892
|
scheduleLicenseRefresh() {
|
|
3823
3893
|
if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
|
|
3824
3894
|
typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
|
|
3825
3895
|
document.visibilityState !== "visible" || this.destroyed || G(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
|
|
3826
3896
|
}, document.addEventListener("visibilitychange", this.onRefocus));
|
|
3827
|
-
let e = this.opts.licenseRefreshMs ??
|
|
3897
|
+
let e = this.opts.licenseRefreshMs ?? zr;
|
|
3828
3898
|
e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
3829
3899
|
}
|
|
3830
3900
|
stopRefresh() {
|
|
@@ -3881,7 +3951,7 @@ var Vr = class {
|
|
|
3881
3951
|
this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
|
|
3882
3952
|
}
|
|
3883
3953
|
getStats() {
|
|
3884
|
-
return this.engine?.getStats() ??
|
|
3954
|
+
return this.engine?.getStats() ?? ut;
|
|
3885
3955
|
}
|
|
3886
3956
|
getQualityLevels() {
|
|
3887
3957
|
return this.engine?.getQualityLevels() ?? [];
|
|
@@ -3920,13 +3990,13 @@ var Vr = class {
|
|
|
3920
3990
|
e.pictureInPictureElement === this.opts.video && typeof e.exitPictureInPicture == "function" && await e.exitPictureInPicture();
|
|
3921
3991
|
}
|
|
3922
3992
|
async enterFullscreen() {
|
|
3923
|
-
return !this.destroyed &&
|
|
3993
|
+
return !this.destroyed && S(this.opts.video, this.container ?? void 0);
|
|
3924
3994
|
}
|
|
3925
3995
|
async exitFullscreen() {
|
|
3926
|
-
await
|
|
3996
|
+
await C(this.opts.video, this.container ?? void 0);
|
|
3927
3997
|
}
|
|
3928
3998
|
fullscreenSupported() {
|
|
3929
|
-
return !this.destroyed &&
|
|
3999
|
+
return !this.destroyed && ye(this.opts.video, this.container ?? void 0);
|
|
3930
4000
|
}
|
|
3931
4001
|
retry() {
|
|
3932
4002
|
return this.reload();
|
|
@@ -3951,13 +4021,13 @@ var Vr = class {
|
|
|
3951
4021
|
return n.add(t), () => n.delete(t);
|
|
3952
4022
|
}
|
|
3953
4023
|
destroy() {
|
|
3954
|
-
this.destroyed || (this.destroyed = !0, this.loadGen += 1, this.abort.abort(), this.stopStats(), this.stopRefresh(), this.unmountControls(), this.cancelRejoin(), this.closeArming(), this.closeLiveState(), this.unwatchReturn(), this.detachMedia?.(), this.detachPip?.(), this.detachEndedPlayGuard?.(), this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.engine?.destroy(), this.engine = null, this.setState("idle"), this.clearListeners());
|
|
4024
|
+
this.destroyed || (this.destroyed = !0, this.loadGen += 1, this.abort.abort(), this.stopStats(), this.stopRefresh(), this.unmountControls(), this.cancelRejoin(), this.closeArming(), this.closeLiveState(), this.unwatchReturn(), this.connectivity?.destroy(), this.connectivity = null, this.detachMedia?.(), this.detachPip?.(), this.detachEndedPlayGuard?.(), this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.engine?.destroy(), this.engine = null, this.setState("idle"), this.clearListeners());
|
|
3955
4025
|
}
|
|
3956
4026
|
clearListeners() {
|
|
3957
4027
|
for (let e of Object.keys(this.listeners)) this.listeners[e]?.clear();
|
|
3958
4028
|
}
|
|
3959
4029
|
fail(e) {
|
|
3960
|
-
this._lastError = e, this.setState("error"), this.analyticsSession?.noteFatal(), this.emit("error", e);
|
|
4030
|
+
this._lastError = e, this.failedWhileOffline = !R(), this.setState("error"), this.analyticsSession?.noteFatal(), this.emit("error", e);
|
|
3961
4031
|
}
|
|
3962
4032
|
setState(e) {
|
|
3963
4033
|
if (e === this._state) return;
|
|
@@ -3989,12 +4059,12 @@ var Vr = class {
|
|
|
3989
4059
|
};
|
|
3990
4060
|
//#endregion
|
|
3991
4061
|
//#region src/embed/protocol.ts
|
|
3992
|
-
function
|
|
4062
|
+
function Kr(e) {
|
|
3993
4063
|
return !!e && typeof e == "object" && typeof e.type == "string" && e.type.startsWith("oddin:");
|
|
3994
4064
|
}
|
|
3995
4065
|
//#endregion
|
|
3996
4066
|
//#region src/embed/host.ts
|
|
3997
|
-
function
|
|
4067
|
+
function qr(e) {
|
|
3998
4068
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
3999
4069
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
4000
4070
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -4003,7 +4073,7 @@ function Ur(e) {
|
|
|
4003
4073
|
let r = document.createElement("iframe");
|
|
4004
4074
|
r.src = t.toString(), r.allow = "autoplay; encrypted-media; fullscreen", r.setAttribute("allowfullscreen", ""), r.referrerPolicy = "no-referrer", r.setAttribute("sandbox", e.sandbox ?? "allow-scripts allow-same-origin allow-presentation"), r.style.cssText = "border:0;width:100%;height:100%;display:block", e.container.appendChild(r);
|
|
4005
4075
|
let i = /* @__PURE__ */ new Set(), a = (t) => {
|
|
4006
|
-
if (t.source !== r.contentWindow || t.origin !== n || !
|
|
4076
|
+
if (t.source !== r.contentWindow || t.origin !== n || !Kr(t.data)) return;
|
|
4007
4077
|
let a = t.data;
|
|
4008
4078
|
a.type === "oddin:ready" && a.protocol !== 1 && console.warn(`havik-player: embed protocol v${a.protocol} != host v1. Pin the embed page version to the SDK version to avoid skew.`), e.onEvent?.(a), i.forEach((e) => e(a));
|
|
4009
4079
|
};
|
|
@@ -4053,15 +4123,15 @@ function Ur(e) {
|
|
|
4053
4123
|
}
|
|
4054
4124
|
//#endregion
|
|
4055
4125
|
//#region src/embed/page.ts
|
|
4056
|
-
var
|
|
4057
|
-
function
|
|
4126
|
+
var Jr = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
4127
|
+
function Yr(e) {
|
|
4058
4128
|
if (typeof e == "boolean") return e;
|
|
4059
4129
|
if (typeof e == "object" && e) {
|
|
4060
4130
|
let t = e.endpoint;
|
|
4061
4131
|
return typeof t == "string" ? { endpoint: t } : {};
|
|
4062
4132
|
}
|
|
4063
4133
|
}
|
|
4064
|
-
function
|
|
4134
|
+
function Xr() {
|
|
4065
4135
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
4066
4136
|
if (e) return {
|
|
4067
4137
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -4071,7 +4141,7 @@ function Kr() {
|
|
|
4071
4141
|
autoplay: e.autoplay ?? !0,
|
|
4072
4142
|
muted: e.muted ?? !0,
|
|
4073
4143
|
waitForLive: e.waitForLive ?? !0,
|
|
4074
|
-
analytics:
|
|
4144
|
+
analytics: Yr(e.analytics)
|
|
4075
4145
|
};
|
|
4076
4146
|
let t = new URLSearchParams(location.search);
|
|
4077
4147
|
return {
|
|
@@ -4084,9 +4154,9 @@ function Kr() {
|
|
|
4084
4154
|
waitForLive: !0
|
|
4085
4155
|
};
|
|
4086
4156
|
}
|
|
4087
|
-
async function
|
|
4088
|
-
let e =
|
|
4089
|
-
|
|
4157
|
+
async function Zr() {
|
|
4158
|
+
let e = Xr();
|
|
4159
|
+
$r();
|
|
4090
4160
|
let t = document.createElement("video");
|
|
4091
4161
|
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);
|
|
4092
4162
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -4142,12 +4212,12 @@ async function qr() {
|
|
|
4142
4212
|
message: e.message,
|
|
4143
4213
|
...e.country === void 0 ? {} : { country: e.country }
|
|
4144
4214
|
})), e.on("autoplayblocked", () => {
|
|
4145
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
4215
|
+
i({ type: "oddin:autoplayblocked" }), Qr(t, e);
|
|
4146
4216
|
});
|
|
4147
4217
|
}, s = async (r) => {
|
|
4148
4218
|
a?.destroy(), a = null;
|
|
4149
4219
|
try {
|
|
4150
|
-
let n = await
|
|
4220
|
+
let n = await Wr({
|
|
4151
4221
|
video: t,
|
|
4152
4222
|
baseUrl: e.baseUrl,
|
|
4153
4223
|
matchUrn: r,
|
|
@@ -4210,30 +4280,30 @@ async function qr() {
|
|
|
4210
4280
|
a?.retry();
|
|
4211
4281
|
break;
|
|
4212
4282
|
case "oddin:load":
|
|
4213
|
-
typeof e.matchUrn == "string" &&
|
|
4283
|
+
typeof e.matchUrn == "string" && Jr.test(e.matchUrn) && s(e.matchUrn);
|
|
4214
4284
|
break;
|
|
4215
4285
|
case "oddin:destroy": c();
|
|
4216
4286
|
}
|
|
4217
4287
|
}, u = (e) => {
|
|
4218
|
-
r && e.origin === r &&
|
|
4288
|
+
r && e.origin === r && Kr(e.data) && l(e.data);
|
|
4219
4289
|
};
|
|
4220
4290
|
r && window.addEventListener("message", u), window.addEventListener("pagehide", c, { once: !0 }), await s(e.matchUrn), i({
|
|
4221
4291
|
type: "oddin:ready",
|
|
4222
4292
|
protocol: 1
|
|
4223
4293
|
});
|
|
4224
4294
|
}
|
|
4225
|
-
function
|
|
4295
|
+
function Qr(e, t) {
|
|
4226
4296
|
if (document.getElementById("havik-tap")) return;
|
|
4227
4297
|
let n = document.createElement("button");
|
|
4228
4298
|
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", () => {
|
|
4229
4299
|
n.remove(), t.play();
|
|
4230
4300
|
}), document.body.appendChild(n);
|
|
4231
4301
|
}
|
|
4232
|
-
function
|
|
4302
|
+
function $r() {
|
|
4233
4303
|
let e = document.createElement("style");
|
|
4234
4304
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
4235
4305
|
}
|
|
4236
4306
|
//#endregion
|
|
4237
|
-
export {
|
|
4307
|
+
export { w as LiveStateHttpError, mr as ODDIN_THEME, n as PlaybackError, gr as applyTheme, ct as baseUrlForEnv, Zr as bootEmbed, ke as clearDeviceId, Ve as clearRememberedBandwidth, Wr as createPlayer, E as deriveEventsBaseUrl, it as detectDrmSupport, S as enterVideoFullscreen, C as exitVideoFullscreen, be as fetchCatalog, Se as fetchTournament, we as flattenMatches, ye as fullscreenSupported, k as getDeviceId, ot as isLowLatencyManifest, Kr as isOddinMessage, je as licenseRequestHeaders, qr as mountEmbed, fe as pollToLive, y as resolveStream, T as subscribeLiveState, ve as videoFullscreenActive, Ee as watchStatus };
|
|
4238
4308
|
|
|
4239
4309
|
//# sourceMappingURL=index.js.map
|