@oddin-gg/havik-player 2.24.0 → 2.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +442 -375
- package/dist/index.js.map +1 -1
- package/docs/API.md +101 -58
- package/embed/index.html +1 -1
- package/examples/vanilla.html +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -309,42 +309,42 @@ function ge(e, t) {
|
|
|
309
309
|
}
|
|
310
310
|
//#endregion
|
|
311
311
|
//#region src/core/fullscreen.ts
|
|
312
|
-
function
|
|
312
|
+
function _e(e) {
|
|
313
313
|
return e.ownerDocument ?? document;
|
|
314
314
|
}
|
|
315
|
-
function
|
|
315
|
+
function ve(e) {
|
|
316
316
|
return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
|
|
317
317
|
}
|
|
318
|
-
function
|
|
319
|
-
let n = _e(
|
|
318
|
+
function ye(e, t) {
|
|
319
|
+
let n = ve(_e(e));
|
|
320
320
|
return n != null && (n === e || t != null && n === t) || e.webkitDisplayingFullscreen === !0;
|
|
321
321
|
}
|
|
322
|
-
function
|
|
323
|
-
let n = t ?? e, r =
|
|
322
|
+
function x(e, t) {
|
|
323
|
+
let n = t ?? e, r = _e(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?.();
|
|
340
340
|
return;
|
|
341
341
|
}
|
|
342
|
-
let r =
|
|
342
|
+
let r = _e(e), i = ve(r);
|
|
343
343
|
i != null && (i === e || t != null && i === t) && (typeof r.exitFullscreen == "function" ? await r.exitFullscreen() : r.webkitExitFullscreen?.());
|
|
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,8 @@ var Vn = class {
|
|
|
1619
1640
|
recoveryResetTimer = null;
|
|
1620
1641
|
networkRetryTimer = null;
|
|
1621
1642
|
licenseRetryTimer = null;
|
|
1643
|
+
offlineHold = !1;
|
|
1644
|
+
onOnline = null;
|
|
1622
1645
|
onVisibility = null;
|
|
1623
1646
|
onSeeking = null;
|
|
1624
1647
|
onPause = null;
|
|
@@ -1683,7 +1706,7 @@ var Vn = class {
|
|
|
1683
1706
|
frameCounter;
|
|
1684
1707
|
detachFrames = null;
|
|
1685
1708
|
constructor(e) {
|
|
1686
|
-
this.deps = e, this.holdBackEnabled = e.adaptiveHoldBack !== !1, this.frameCounter = new
|
|
1709
|
+
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
1710
|
}
|
|
1688
1711
|
async load() {
|
|
1689
1712
|
this.detachFrames ??= this.frameCounter.attach();
|
|
@@ -1696,14 +1719,21 @@ var Vn = class {
|
|
|
1696
1719
|
});
|
|
1697
1720
|
return;
|
|
1698
1721
|
}
|
|
1699
|
-
e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (
|
|
1722
|
+
e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ke(r), Xe()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
|
|
1700
1723
|
let e = this.hls;
|
|
1701
1724
|
if (document.visibilityState !== "visible" || !e) return;
|
|
1702
1725
|
let t = e.liveSyncPosition;
|
|
1703
1726
|
if (typeof t != "number") return;
|
|
1704
1727
|
let n = typeof e.targetLatency == "number" && e.targetLatency > 0 ? e.targetLatency : 3;
|
|
1705
1728
|
t - r.currentTime > Math.max(n * 3, 8) && (r.currentTime = t);
|
|
1706
|
-
}, document.addEventListener("visibilitychange", this.onVisibility)), this.
|
|
1729
|
+
}, document.addEventListener("visibilitychange", this.onVisibility)), typeof window < "u" && (this.onOnline = () => {
|
|
1730
|
+
if (this.offlineHold && (this.offlineHold = !1, this.networkRecoveries = 0, this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), !this.stopped && this.hls)) {
|
|
1731
|
+
this.lastAdvanceMs = Date.now(), this.lastFragLoadingMs = 0, this.resetStarvationWindow(), this.resetChaseWindow(), this.clearKick();
|
|
1732
|
+
try {
|
|
1733
|
+
this.hls.startLoad();
|
|
1734
|
+
} catch {}
|
|
1735
|
+
}
|
|
1736
|
+
}, window.addEventListener("online", this.onOnline)), this.onSeeking = () => {
|
|
1707
1737
|
this.clampOverSeek(), this.loadSuspended && (this.resumeLoading(), this.schedulePauseSuspend());
|
|
1708
1738
|
}, 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
1739
|
}
|
|
@@ -1719,7 +1749,7 @@ var Vn = class {
|
|
|
1719
1749
|
}
|
|
1720
1750
|
this.loadSuspended = !0;
|
|
1721
1751
|
}
|
|
1722
|
-
},
|
|
1752
|
+
}, ln));
|
|
1723
1753
|
}
|
|
1724
1754
|
resumeLoading() {
|
|
1725
1755
|
if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
|
|
@@ -1751,7 +1781,7 @@ var Vn = class {
|
|
|
1751
1781
|
let t = e.liveSyncPosition;
|
|
1752
1782
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
1753
1783
|
let { video: n } = this.deps;
|
|
1754
|
-
n.currentTime <= t +
|
|
1784
|
+
n.currentTime <= t + On || (n.currentTime = t);
|
|
1755
1785
|
}
|
|
1756
1786
|
reanchorPartTimeline(e, t) {
|
|
1757
1787
|
let { frag: n, part: r } = t;
|
|
@@ -1763,7 +1793,7 @@ var Vn = class {
|
|
|
1763
1793
|
let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
|
|
1764
1794
|
if (!s) return;
|
|
1765
1795
|
let c = a.startPTS - s.start;
|
|
1766
|
-
if (!(!Number.isFinite(c) || Math.abs(c) <
|
|
1796
|
+
if (!(!Number.isFinite(c) || Math.abs(c) < tn)) {
|
|
1767
1797
|
for (let e of i.fragments) e && e.setStart(e.start + c);
|
|
1768
1798
|
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
1799
|
}
|
|
@@ -1786,12 +1816,12 @@ var Vn = class {
|
|
|
1786
1816
|
emeEnabled: !0,
|
|
1787
1817
|
drmSystems: { ...this.licenseUrl ? { "com.widevine.alpha": { licenseUrl: this.licenseUrl } } : {} },
|
|
1788
1818
|
drmSystemOptions: {
|
|
1789
|
-
videoRobustness:
|
|
1790
|
-
audioRobustness:
|
|
1791
|
-
videoEncryptionScheme:
|
|
1792
|
-
audioEncryptionScheme:
|
|
1819
|
+
videoRobustness: P.video,
|
|
1820
|
+
audioRobustness: P.audio,
|
|
1821
|
+
videoEncryptionScheme: P.scheme,
|
|
1822
|
+
audioEncryptionScheme: P.scheme
|
|
1793
1823
|
},
|
|
1794
|
-
...
|
|
1824
|
+
...j() ? { requestMediaKeySystemAccessFunc: Ge(t) } : {},
|
|
1795
1825
|
licenseXhrSetup: (e, t) => {
|
|
1796
1826
|
let o = performance.now(), s = () => {
|
|
1797
1827
|
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 +1833,7 @@ var Vn = class {
|
|
|
1803
1833
|
return;
|
|
1804
1834
|
}
|
|
1805
1835
|
let l = this.hls, u, d = new Promise((e) => {
|
|
1806
|
-
u = setTimeout(() => e(void 0),
|
|
1836
|
+
u = setTimeout(() => e(void 0), Zt);
|
|
1807
1837
|
});
|
|
1808
1838
|
return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
|
|
1809
1839
|
if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
|
|
@@ -1821,31 +1851,31 @@ var Vn = class {
|
|
|
1821
1851
|
this.prefetch?.destroy(), this.prefetch = null;
|
|
1822
1852
|
let p = !1, m = !1, h = u && this.deps.mediaDuringKey !== !1, g = this.deps.preloadHints === !0;
|
|
1823
1853
|
if ((h || g) && !f.fLoader) {
|
|
1824
|
-
let e = new
|
|
1854
|
+
let e = new Lt({
|
|
1825
1855
|
sessionId: n.analytics?.sid,
|
|
1826
1856
|
contentId: n.matchUrn
|
|
1827
|
-
}), t =
|
|
1857
|
+
}), t = Rt(e);
|
|
1828
1858
|
t && (this.prefetch = e, p = h, m = g, f.fLoader = t);
|
|
1829
1859
|
}
|
|
1830
|
-
|
|
1860
|
+
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
1861
|
let _ = new e(f);
|
|
1832
1862
|
if (this.hls = _, this.armHoldBack(_, f), _.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(_, t)), _.on(e.Events.MANIFEST_PARSED, () => {
|
|
1833
1863
|
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
1864
|
}), _.on(e.Events.FRAG_BUFFERED, (e, t) => {
|
|
1835
1865
|
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
1866
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
|
|
1837
|
-
},
|
|
1867
|
+
}, Qt)));
|
|
1838
1868
|
}), _.on(e.Events.FRAG_LOADING, (e, t) => {
|
|
1839
1869
|
t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
|
|
1840
1870
|
}), _.on(e.Events.FRAG_LOADED, (e, t) => {
|
|
1841
1871
|
t?.frag?.type === "main" && (this.mainFragsSinceTick += 1, this.bwFragsLoaded += 1, this.maybeRememberBandwidth(!1));
|
|
1842
|
-
let n = t?.frag, r =
|
|
1872
|
+
let n = t?.frag, r = zn(t), i = r?.loaded;
|
|
1843
1873
|
typeof i == "number" && (this.bytesLoaded += i), !this.reportedFirstBytes && typeof i == "number" && i > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
|
|
1844
1874
|
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 >
|
|
1875
|
+
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
1876
|
let o = n?.url;
|
|
1847
1877
|
if (o) {
|
|
1848
|
-
let e =
|
|
1878
|
+
let e = dt(o);
|
|
1849
1879
|
e && (this.cdnHost = e);
|
|
1850
1880
|
}
|
|
1851
1881
|
}), _.on(e.Events.LEVEL_LOADED, (e, t) => {
|
|
@@ -1862,8 +1892,8 @@ var Vn = class {
|
|
|
1862
1892
|
let i = e;
|
|
1863
1893
|
if (!i?.live || !i.partList?.length || typeof i.edge != "number") return;
|
|
1864
1894
|
let a = n.buffered, o = a.length ? a.end(a.length - 1) : 0;
|
|
1865
|
-
if (i.edge - o >
|
|
1866
|
-
let s =
|
|
1895
|
+
if (i.edge - o > Wt * (i.partTarget || .5)) return;
|
|
1896
|
+
let s = Ht(e);
|
|
1867
1897
|
s && t.prefetchHint(s, r);
|
|
1868
1898
|
};
|
|
1869
1899
|
_.on(e.Events.LEVEL_LOADED, (e, t) => {
|
|
@@ -1875,15 +1905,15 @@ var Vn = class {
|
|
|
1875
1905
|
if (this.prefetch && p) {
|
|
1876
1906
|
let t = this.prefetch;
|
|
1877
1907
|
_.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(
|
|
1908
|
+
let r = n?.frag, i = Bt(r?.type);
|
|
1909
|
+
if (r && t.isActive(i)) for (let e of Vt(_, r)) t.prefetch(e.url, i, e.kind);
|
|
1910
|
+
}), _.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(Bt(n?.frag?.type)));
|
|
1881
1911
|
}
|
|
1882
1912
|
_.on(e.Events.KEY_LOADED, () => {
|
|
1883
1913
|
u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
|
|
1884
1914
|
}), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
|
|
1885
1915
|
this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.adaptHoldBack(), this.checkFrameDrops();
|
|
1886
|
-
},
|
|
1916
|
+
}, en), _.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
1887
1917
|
this.renditionSwitches += 1;
|
|
1888
1918
|
let n = this.lastLevelIndex >= 0 ? _.levels[this.lastLevelIndex] : void 0, r = _.levels[t.level];
|
|
1889
1919
|
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 +1964,9 @@ var Vn = class {
|
|
|
1934
1964
|
let o = e.config ?? {}, s = typeof self < "u" && self.devicePixelRatio > 0 ? self.devicePixelRatio : 1, c = o.ignoreDevicePixelRatio ? 1 : s;
|
|
1935
1965
|
c = Math.min(c, o.maxDevicePixelRatio ?? Infinity);
|
|
1936
1966
|
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
|
|
1967
|
+
if (u == null && s >= bn) return l;
|
|
1968
|
+
let d = u ?? yn, f = Number.isNaN(d) ? yn : d === Infinity ? e.levels.length : Math.max(0, Math.floor(d));
|
|
1969
|
+
return xn(e.levels, l, f);
|
|
1940
1970
|
}
|
|
1941
1971
|
onMediaResize() {
|
|
1942
1972
|
if (!this.sizeCapManaged) return;
|
|
@@ -1951,7 +1981,7 @@ var Vn = class {
|
|
|
1951
1981
|
return;
|
|
1952
1982
|
}
|
|
1953
1983
|
this.capTimer && clearTimeout(this.capTimer);
|
|
1954
|
-
let t = e > this.sizeCapLevel ?
|
|
1984
|
+
let t = e > this.sizeCapLevel ? _n : vn;
|
|
1955
1985
|
this.capTimer = setTimeout(() => {
|
|
1956
1986
|
this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
|
|
1957
1987
|
}, t);
|
|
@@ -1961,9 +1991,9 @@ var Vn = class {
|
|
|
1961
1991
|
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
1992
|
}
|
|
1963
1993
|
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)
|
|
1994
|
+
this.removeLevelsWhere(e, (e) => Ze(e) !== !0);
|
|
1995
|
+
let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && F(e) !== "avc" && !!F(e)));
|
|
1996
|
+
for (let n of t) Ye(n).then((t) => {
|
|
1967
1997
|
t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
|
|
1968
1998
|
});
|
|
1969
1999
|
}
|
|
@@ -1971,10 +2001,10 @@ var Vn = class {
|
|
|
1971
2001
|
let n = e.levels ?? [], r = [], i = /* @__PURE__ */ new Set();
|
|
1972
2002
|
if (n.forEach((e, n) => {
|
|
1973
2003
|
let a = e.videoCodec;
|
|
1974
|
-
a &&
|
|
2004
|
+
a && F(a) && t(a) && (r.push(n), i.add(a));
|
|
1975
2005
|
}), !r.length) return !1;
|
|
1976
2006
|
let a = [...i].join(", ");
|
|
1977
|
-
if (!n.some((e, t) => r.includes(t) ? !1 : !
|
|
2007
|
+
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
2008
|
for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
|
|
1979
2009
|
return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
|
|
1980
2010
|
}
|
|
@@ -2077,12 +2107,12 @@ var Vn = class {
|
|
|
2077
2107
|
this.lastAdvanceMs = Date.now();
|
|
2078
2108
|
return;
|
|
2079
2109
|
}
|
|
2080
|
-
if (this.loadSuspended) {
|
|
2110
|
+
if (this.loadSuspended || this.offlineHold) {
|
|
2081
2111
|
this.lastAdvanceMs = Date.now();
|
|
2082
2112
|
return;
|
|
2083
2113
|
}
|
|
2084
2114
|
let e = Date.now() - this.lastAdvanceMs;
|
|
2085
|
-
!this.chaseSuspended && e >
|
|
2115
|
+
!this.chaseSuspended && e > nn && this.suspendChasing(), e > $t && this.emitEnded("stalled");
|
|
2086
2116
|
}
|
|
2087
2117
|
resetStarvationWindow() {
|
|
2088
2118
|
this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
|
|
@@ -2093,11 +2123,11 @@ var Vn = class {
|
|
|
2093
2123
|
checkStarvation() {
|
|
2094
2124
|
let e = this.hls, { video: t } = this.deps;
|
|
2095
2125
|
if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended) return;
|
|
2096
|
-
if (typeof document < "u" && document.hidden || this.loadSuspended) {
|
|
2126
|
+
if (typeof document < "u" && document.hidden || this.loadSuspended || this.offlineHold) {
|
|
2097
2127
|
this.resetStarvationWindow();
|
|
2098
2128
|
return;
|
|
2099
2129
|
}
|
|
2100
|
-
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs <
|
|
2130
|
+
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
2131
|
if (this.starvedFrames = c, !a || l) {
|
|
2102
2132
|
(t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
|
|
2103
2133
|
return;
|
|
@@ -2106,12 +2136,12 @@ var Vn = class {
|
|
|
2106
2136
|
this.resetStarvationWindow();
|
|
2107
2137
|
return;
|
|
2108
2138
|
}
|
|
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 >
|
|
2139
|
+
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
2140
|
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
2141
|
return;
|
|
2112
2142
|
}
|
|
2113
|
-
let u = i && this.starvedTicks >=
|
|
2114
|
-
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >=
|
|
2143
|
+
let u = i && this.starvedTicks >= dn, d = !i && this.deadTicks >= hn && this.recentMainFrags.reduce((e, t) => e + t, 0) >= gn;
|
|
2144
|
+
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= fn))) {
|
|
2115
2145
|
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
2146
|
try {
|
|
2117
2147
|
e.stopLoad(), e.startLoad(-1);
|
|
@@ -2122,11 +2152,11 @@ var Vn = class {
|
|
|
2122
2152
|
}
|
|
2123
2153
|
updateCatchUpBand() {
|
|
2124
2154
|
let e = this.hls;
|
|
2125
|
-
if (!e || this.catchUpRate <= 1 || this.chaseSuspended || this.loadSuspended) return;
|
|
2155
|
+
if (!e || this.catchUpRate <= 1 || this.chaseSuspended || this.loadSuspended || this.offlineHold) return;
|
|
2126
2156
|
let t = e.latency, n = e.targetLatency;
|
|
2127
2157
|
if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
|
|
2128
2158
|
let r = t - n;
|
|
2129
|
-
!this.catchUpEngaged && r >
|
|
2159
|
+
!this.catchUpEngaged && r > rn ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= rn && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
|
|
2130
2160
|
let i = this.catchUpEngaged ? this.catchUpRate : 1;
|
|
2131
2161
|
e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
|
|
2132
2162
|
}
|
|
@@ -2139,19 +2169,19 @@ var Vn = class {
|
|
|
2139
2169
|
}), n < 0 ? 0 : n;
|
|
2140
2170
|
}
|
|
2141
2171
|
armFrameDropGrace() {
|
|
2142
|
-
this.fpsGraceTicks > 0 || (this.fpsGraceTicks =
|
|
2172
|
+
this.fpsGraceTicks > 0 || (this.fpsGraceTicks = Tn, this.fpsBadTicks = 0);
|
|
2143
2173
|
}
|
|
2144
2174
|
resetFrameDropWindow() {
|
|
2145
2175
|
this.fpsLastFrames = -1, this.fpsLastDropped = -1, this.fpsBadTicks = 0;
|
|
2146
2176
|
}
|
|
2147
2177
|
checkFrameDrops() {
|
|
2148
2178
|
let e = this.hls, { video: t } = this.deps;
|
|
2149
|
-
if (!e || !this.fpsCapManaged || this.loadSuspended || t.paused || !e.autoLevelEnabled || typeof document < "u" && document.hidden) {
|
|
2179
|
+
if (!e || !this.fpsCapManaged || this.loadSuspended || this.offlineHold || t.paused || !e.autoLevelEnabled || typeof document < "u" && document.hidden) {
|
|
2150
2180
|
this.resetFrameDropWindow();
|
|
2151
2181
|
return;
|
|
2152
2182
|
}
|
|
2153
2183
|
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 <
|
|
2184
|
+
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Cn || o < 0) {
|
|
2155
2185
|
this.fpsBadTicks = 0;
|
|
2156
2186
|
return;
|
|
2157
2187
|
}
|
|
@@ -2159,11 +2189,11 @@ var Vn = class {
|
|
|
2159
2189
|
--this.fpsGraceTicks, this.fpsBadTicks = 0;
|
|
2160
2190
|
return;
|
|
2161
2191
|
}
|
|
2162
|
-
if (o <=
|
|
2192
|
+
if (o <= Sn * a) {
|
|
2163
2193
|
this.fpsBadTicks = 0;
|
|
2164
2194
|
return;
|
|
2165
2195
|
}
|
|
2166
|
-
if (this.fpsBadTicks += 1, this.fpsBadTicks <
|
|
2196
|
+
if (this.fpsBadTicks += 1, this.fpsBadTicks < wn) return;
|
|
2167
2197
|
this.fpsBadTicks = 0;
|
|
2168
2198
|
let s = e.levels, c = s[e.currentLevel];
|
|
2169
2199
|
if (!c) return;
|
|
@@ -2175,27 +2205,27 @@ var Vn = class {
|
|
|
2175
2205
|
}
|
|
2176
2206
|
checkFutileChase() {
|
|
2177
2207
|
let e = this.hls, { video: t } = this.deps;
|
|
2178
|
-
if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended || this.loadSuspended || typeof document < "u" && document.hidden) {
|
|
2208
|
+
if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended || this.loadSuspended || this.offlineHold || typeof document < "u" && document.hidden) {
|
|
2179
2209
|
this.resetChaseWindow();
|
|
2180
2210
|
return;
|
|
2181
2211
|
}
|
|
2182
2212
|
let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
|
|
2183
|
-
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(
|
|
2213
|
+
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(sn, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
|
|
2184
2214
|
this.resetChaseWindow();
|
|
2185
2215
|
return;
|
|
2186
2216
|
}
|
|
2187
|
-
if (this.chaseLatency < 0 || this.chaseLatency - n >=
|
|
2217
|
+
if (this.chaseLatency < 0 || this.chaseLatency - n >= on) {
|
|
2188
2218
|
this.chaseLatency = n, this.chaseTicks = 0;
|
|
2189
2219
|
return;
|
|
2190
2220
|
}
|
|
2191
|
-
if (this.chaseTicks += 1, this.chaseTicks <
|
|
2221
|
+
if (this.chaseTicks += 1, this.chaseTicks < an) return;
|
|
2192
2222
|
this.resetChaseWindow();
|
|
2193
2223
|
let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
|
|
2194
2224
|
if (!(a > 1)) return;
|
|
2195
2225
|
let o = e.targetLatency;
|
|
2196
2226
|
if (typeof o != "number" || !(o > 0)) return;
|
|
2197
2227
|
let s = Math.min(n, a - 1);
|
|
2198
|
-
s < o +
|
|
2228
|
+
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
2229
|
type: "livetargetchange",
|
|
2200
2230
|
change: {
|
|
2201
2231
|
targetSeconds: s,
|
|
@@ -2212,13 +2242,13 @@ var Vn = class {
|
|
|
2212
2242
|
if (!this.holdBackEnabled || this.holdBackPriorChecked || !e || (this.holdBackPriorChecked = !0, this.holdBackApplied > 0 || this.holdBackStepCount > 0)) return;
|
|
2213
2243
|
let t = e.targetLatency;
|
|
2214
2244
|
if (this.holdBackBase < 0 && typeof t == "number" && t > 0 && (this.holdBackBase = t), this.holdBackBase < 0) return;
|
|
2215
|
-
let n =
|
|
2216
|
-
if (!(n >=
|
|
2245
|
+
let n = Bn();
|
|
2246
|
+
if (!(n >= Rn)) return;
|
|
2217
2247
|
let r = typeof t == "number" && t > 0 ? t : this.holdBackBase, i = Math.min(this.holdBackCeiling(e), this.holdBackBase + J);
|
|
2218
2248
|
i > r && (this.holdBackStepCount = 1, this.moveHoldBack(e, r, i, "connection-rtt", `connection rtt ${n} ms`));
|
|
2219
2249
|
}
|
|
2220
2250
|
holdBackCeiling(e) {
|
|
2221
|
-
let t = this.deps.adaptiveHoldBackCeiling, n = typeof t == "number" && Number.isFinite(t) ? t :
|
|
2251
|
+
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
2252
|
return r > 1 ? Math.min(n, r - 1) : n;
|
|
2223
2253
|
}
|
|
2224
2254
|
sampleHoldBack(e) {
|
|
@@ -2227,7 +2257,7 @@ var Vn = class {
|
|
|
2227
2257
|
if (t !== "main" && t !== "audio") return;
|
|
2228
2258
|
let n = e.part ? e.part.duration : this.detectedLowLatency ? 0 : e.frag?.duration;
|
|
2229
2259
|
if (typeof n != "number" || !(n > 0)) return;
|
|
2230
|
-
let r =
|
|
2260
|
+
let r = zn(e)?.loading;
|
|
2231
2261
|
if (!r || !(r.start > 0) || !(r.end > 0)) return;
|
|
2232
2262
|
let i = r.first > r.start ? r.first : r.end, a = Math.max(0, i - r.start) / (n * 1e3);
|
|
2233
2263
|
this.holdBackSamples.push({
|
|
@@ -2238,24 +2268,24 @@ var Vn = class {
|
|
|
2238
2268
|
adaptHoldBack() {
|
|
2239
2269
|
if (!this.holdBackEnabled) return;
|
|
2240
2270
|
let e = this.hls;
|
|
2241
|
-
if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended || this.loadSuspended || typeof document < "u" && document.hidden) {
|
|
2271
|
+
if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended || this.loadSuspended || this.offlineHold || typeof document < "u" && document.hidden) {
|
|
2242
2272
|
this.holdBackSlowTicks = 0, this.holdBackFastSince = 0, this.holdBackSamples = [];
|
|
2243
2273
|
return;
|
|
2244
2274
|
}
|
|
2245
|
-
let t = Date.now(), n = t -
|
|
2275
|
+
let t = Date.now(), n = t - An, r = this.holdBackSamples, i = 0;
|
|
2246
2276
|
for (; i < r.length && r[i].t < n;) i += 1;
|
|
2247
2277
|
i > 0 && r.splice(0, i);
|
|
2248
2278
|
let a = e.targetLatency;
|
|
2249
2279
|
if (typeof a != "number" || !(a > 0)) return;
|
|
2250
2280
|
this.holdBackBase < 0 && (this.holdBackBase = a);
|
|
2251
2281
|
let o = this.holdBackBase, s = this.holdBackCeiling(e);
|
|
2252
|
-
if (r.length <
|
|
2282
|
+
if (r.length < jn) {
|
|
2253
2283
|
this.holdBackSlowTicks = 0;
|
|
2254
2284
|
return;
|
|
2255
2285
|
}
|
|
2256
2286
|
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 <
|
|
2287
|
+
if (l >= Mn && u >= Nn) {
|
|
2288
|
+
if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks < Fn) return;
|
|
2259
2289
|
this.holdBackSlowTicks = 0;
|
|
2260
2290
|
let t = Math.ceil((s - o) / J), n = Math.ceil((a - o) / J - 1e-9);
|
|
2261
2291
|
if (n > this.holdBackStepCount && (this.holdBackStepCount = n), this.holdBackStepCount >= t) return;
|
|
@@ -2265,7 +2295,7 @@ var Vn = class {
|
|
|
2265
2295
|
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
2296
|
return;
|
|
2267
2297
|
}
|
|
2268
|
-
if (this.holdBackSlowTicks = 0, l >=
|
|
2298
|
+
if (this.holdBackSlowTicks = 0, l >= Pn) {
|
|
2269
2299
|
this.holdBackFastSince = 0;
|
|
2270
2300
|
return;
|
|
2271
2301
|
}
|
|
@@ -2273,7 +2303,7 @@ var Vn = class {
|
|
|
2273
2303
|
this.holdBackFastSince = t;
|
|
2274
2304
|
return;
|
|
2275
2305
|
}
|
|
2276
|
-
if (t - this.holdBackFastSince <
|
|
2306
|
+
if (t - this.holdBackFastSince < In || (this.holdBackFastSince = t, this.holdBackStepCount === 0 || a !== this.holdBackApplied)) return;
|
|
2277
2307
|
--this.holdBackStepCount;
|
|
2278
2308
|
let f = Math.max(o, o + this.holdBackStepCount * J);
|
|
2279
2309
|
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 +2346,17 @@ var Vn = class {
|
|
|
2316
2346
|
} catch {}
|
|
2317
2347
|
}
|
|
2318
2348
|
startEstimate() {
|
|
2319
|
-
return this.deps.rememberBandwidth === !1 ?
|
|
2349
|
+
return this.deps.rememberBandwidth === !1 ? Gt : ze() ?? Gt;
|
|
2320
2350
|
}
|
|
2321
2351
|
maybeRememberBandwidth(e) {
|
|
2322
|
-
if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded <
|
|
2352
|
+
if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < Kt) return;
|
|
2323
2353
|
let t = Date.now();
|
|
2324
|
-
if (!e && t - this.bwSavedAt <
|
|
2354
|
+
if (!e && t - this.bwSavedAt < qt) return;
|
|
2325
2355
|
let n = this.hls?.bandwidthEstimate;
|
|
2326
|
-
typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t,
|
|
2356
|
+
typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Be(n));
|
|
2327
2357
|
}
|
|
2328
2358
|
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) {
|
|
2359
|
+
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.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
2360
|
try {
|
|
2331
2361
|
this.hls.destroy();
|
|
2332
2362
|
} catch (e) {
|
|
@@ -2341,7 +2371,7 @@ var Vn = class {
|
|
|
2341
2371
|
scheduleLicenseRetry(t) {
|
|
2342
2372
|
if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
|
|
2343
2373
|
let n = t.response?.code ?? 0;
|
|
2344
|
-
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >=
|
|
2374
|
+
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Xt) return !1;
|
|
2345
2375
|
this.licenseRecoveries += 1;
|
|
2346
2376
|
let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
|
|
2347
2377
|
return this.licenseRetryTimer = setTimeout(() => {
|
|
@@ -2373,7 +2403,11 @@ var Vn = class {
|
|
|
2373
2403
|
return;
|
|
2374
2404
|
}
|
|
2375
2405
|
if (t.type === e.ErrorTypes.NETWORK_ERROR) {
|
|
2376
|
-
if (
|
|
2406
|
+
if (!R() && (t.response?.code ?? 0) === 0) {
|
|
2407
|
+
this.offlineHold = !0, this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null);
|
|
2408
|
+
return;
|
|
2409
|
+
}
|
|
2410
|
+
if (this.networkRecoveries < Yt) {
|
|
2377
2411
|
this.networkRecoveries += 1;
|
|
2378
2412
|
let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
|
|
2379
2413
|
this.networkRetryTimer = setTimeout(() => {
|
|
@@ -2390,7 +2424,7 @@ var Vn = class {
|
|
|
2390
2424
|
return;
|
|
2391
2425
|
}
|
|
2392
2426
|
if (t.type === e.ErrorTypes.MEDIA_ERROR) {
|
|
2393
|
-
if (this.mediaRecoveries <
|
|
2427
|
+
if (this.mediaRecoveries < Jt) {
|
|
2394
2428
|
this.mediaRecoveries += 1, n.recoverMediaError();
|
|
2395
2429
|
return;
|
|
2396
2430
|
}
|
|
@@ -2411,18 +2445,18 @@ var Vn = class {
|
|
|
2411
2445
|
}
|
|
2412
2446
|
}
|
|
2413
2447
|
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);
|
|
2448
|
+
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;
|
|
2449
|
+
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
2450
|
}
|
|
2417
|
-
},
|
|
2451
|
+
}, Wn = 15e3, Gn = 6e5, Kn = 3e5, qn = 100, Y = 1, Jn = 1e3, Yn = 3e4, Xn = 1e3, Zn = {
|
|
2418
2452
|
inline: "PRESENTATION_INLINE",
|
|
2419
2453
|
fullscreen: "PRESENTATION_FULLSCREEN",
|
|
2420
2454
|
pip: "PRESENTATION_PIP"
|
|
2421
|
-
},
|
|
2455
|
+
}, Qn = {
|
|
2422
2456
|
widevine: "KEY_SYSTEM_WIDEVINE",
|
|
2423
2457
|
fairplay: "KEY_SYSTEM_FAIRPLAY",
|
|
2424
2458
|
none: "KEY_SYSTEM_NONE"
|
|
2425
|
-
},
|
|
2459
|
+
}, $n = /* @__PURE__ */ new Set([
|
|
2426
2460
|
"INVALID_URN",
|
|
2427
2461
|
"NOT_FOUND",
|
|
2428
2462
|
"GEO_DENIED",
|
|
@@ -2443,7 +2477,7 @@ var Vn = class {
|
|
|
2443
2477
|
ended: "PLAYER_STATE_ENDED",
|
|
2444
2478
|
error: "PLAYER_STATE_ERROR"
|
|
2445
2479
|
};
|
|
2446
|
-
function
|
|
2480
|
+
function er(e) {
|
|
2447
2481
|
try {
|
|
2448
2482
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
2449
2483
|
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 +2485,8 @@ function Qn(e) {
|
|
|
2451
2485
|
return;
|
|
2452
2486
|
}
|
|
2453
2487
|
}
|
|
2454
|
-
var
|
|
2455
|
-
function
|
|
2488
|
+
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.`;
|
|
2489
|
+
function ir(e) {
|
|
2456
2490
|
if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
|
|
2457
2491
|
let t;
|
|
2458
2492
|
try {
|
|
@@ -2461,19 +2495,19 @@ function nr(e) {
|
|
|
2461
2495
|
} catch {
|
|
2462
2496
|
return;
|
|
2463
2497
|
}
|
|
2464
|
-
if (
|
|
2465
|
-
Z.add(t), _(
|
|
2498
|
+
if (nr.has(t) && !Z.has(t)) {
|
|
2499
|
+
Z.add(t), _(rr(new URL(t).origin));
|
|
2466
2500
|
for (let e of Q) e.noteCspBlocked();
|
|
2467
2501
|
}
|
|
2468
2502
|
}
|
|
2469
|
-
function
|
|
2503
|
+
function ar(e, t) {
|
|
2470
2504
|
return _(t, e), { disabledReason: t };
|
|
2471
2505
|
}
|
|
2472
|
-
function
|
|
2473
|
-
if (n) return t &&
|
|
2506
|
+
function or(e, t, n) {
|
|
2507
|
+
if (n) return t && !tr(t, n) && _(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
|
|
2474
2508
|
if (t) return { endpoint: t };
|
|
2475
|
-
if (t !== void 0) return
|
|
2476
|
-
let r =
|
|
2509
|
+
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).");
|
|
2510
|
+
let r = er(e);
|
|
2477
2511
|
if (r) return { endpoint: r };
|
|
2478
2512
|
let i;
|
|
2479
2513
|
try {
|
|
@@ -2481,9 +2515,9 @@ function ir(e, t, n) {
|
|
|
2481
2515
|
} catch {
|
|
2482
2516
|
i = e;
|
|
2483
2517
|
}
|
|
2484
|
-
return
|
|
2518
|
+
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
2519
|
}
|
|
2486
|
-
var
|
|
2520
|
+
var sr = class {
|
|
2487
2521
|
opts;
|
|
2488
2522
|
url;
|
|
2489
2523
|
cspKey;
|
|
@@ -2565,8 +2599,8 @@ var ar = class {
|
|
|
2565
2599
|
constructor(e) {
|
|
2566
2600
|
this.opts = {
|
|
2567
2601
|
...e,
|
|
2568
|
-
heartbeatMs: e.heartbeatMs ??
|
|
2569
|
-
idleMs: e.idleMs ??
|
|
2602
|
+
heartbeatMs: e.heartbeatMs ?? Wn,
|
|
2603
|
+
idleMs: e.idleMs ?? Gn
|
|
2570
2604
|
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
|
|
2571
2605
|
try {
|
|
2572
2606
|
let e = new URL(this.url);
|
|
@@ -2583,11 +2617,11 @@ var ar = class {
|
|
|
2583
2617
|
sdkVersion: this.opts.sdkVersion,
|
|
2584
2618
|
...this.opts.environment
|
|
2585
2619
|
};
|
|
2586
|
-
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(),
|
|
2620
|
+
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
2621
|
}
|
|
2588
2622
|
checkSuspension(e) {
|
|
2589
2623
|
if (this.endedFlag || !this.opts.idleMs) return !1;
|
|
2590
|
-
let t = Math.max(this.opts.idleMs,
|
|
2624
|
+
let t = Math.max(this.opts.idleMs, Kn);
|
|
2591
2625
|
return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
|
|
2592
2626
|
}
|
|
2593
2627
|
syncIdle(e) {
|
|
@@ -2610,12 +2644,12 @@ var ar = class {
|
|
|
2610
2644
|
let a = {
|
|
2611
2645
|
fromState: X[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2612
2646
|
toState: X[t] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2613
|
-
presentation:
|
|
2647
|
+
presentation: Zn[this.presentation]
|
|
2614
2648
|
}, o = this.causeOf(e, t, i);
|
|
2615
2649
|
o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
2616
2650
|
}
|
|
2617
2651
|
seekInduced(e) {
|
|
2618
|
-
return this.lastSeekMs >= 0 && e - this.lastSeekMs <
|
|
2652
|
+
return this.lastSeekMs >= 0 && e - this.lastSeekMs < Xn;
|
|
2619
2653
|
}
|
|
2620
2654
|
causeOf(e, t, n) {
|
|
2621
2655
|
if (t === "error") return "TRANSITION_CAUSE_ERROR";
|
|
@@ -2689,7 +2723,7 @@ var ar = class {
|
|
|
2689
2723
|
let r = n ?? "";
|
|
2690
2724
|
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
2725
|
if (e === "DRM_CLIENT" || e === "DRM_DEVICE_REVOKED") return "ERROR_STAGE_DRM";
|
|
2692
|
-
if (
|
|
2726
|
+
if ($n.has(e)) return "ERROR_STAGE_RESOLVE";
|
|
2693
2727
|
let i = t ?? "";
|
|
2694
2728
|
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
2729
|
}
|
|
@@ -2743,7 +2777,7 @@ var ar = class {
|
|
|
2743
2777
|
maybeEmitMediaInfo(e) {
|
|
2744
2778
|
if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
|
|
2745
2779
|
let t = {};
|
|
2746
|
-
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem =
|
|
2780
|
+
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
2781
|
let n = JSON.stringify(t);
|
|
2748
2782
|
n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
|
|
2749
2783
|
}
|
|
@@ -2763,7 +2797,7 @@ var ar = class {
|
|
|
2763
2797
|
let c = r?.positionMs ?? 0;
|
|
2764
2798
|
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
2799
|
let l = e !== "END_REASON_ENDED";
|
|
2766
|
-
l && this.lastStallMs > 0 && n - this.lastStallMs <=
|
|
2800
|
+
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
2801
|
let u = r?.decodedFrames ?? this.lastDecoded;
|
|
2768
2802
|
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
2803
|
}
|
|
@@ -2783,13 +2817,13 @@ var ar = class {
|
|
|
2783
2817
|
};
|
|
2784
2818
|
}
|
|
2785
2819
|
noteCspBlocked() {
|
|
2786
|
-
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(
|
|
2820
|
+
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(rr(new URL(this.url).origin)));
|
|
2787
2821
|
}
|
|
2788
2822
|
cspBlocked() {
|
|
2789
2823
|
return !!this.cspKey && Z.has(this.cspKey);
|
|
2790
2824
|
}
|
|
2791
2825
|
enqueue(e) {
|
|
2792
|
-
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length >
|
|
2826
|
+
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > qn;) {
|
|
2793
2827
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
2794
2828
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
2795
2829
|
}
|
|
@@ -2816,7 +2850,7 @@ var ar = class {
|
|
|
2816
2850
|
};
|
|
2817
2851
|
//#endregion
|
|
2818
2852
|
//#region src/core/environment.ts
|
|
2819
|
-
function
|
|
2853
|
+
function cr() {
|
|
2820
2854
|
if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
|
|
2821
2855
|
let e;
|
|
2822
2856
|
try {
|
|
@@ -2841,14 +2875,14 @@ function or() {
|
|
|
2841
2875
|
integration: "INTEGRATION_KIND_IFRAME"
|
|
2842
2876
|
};
|
|
2843
2877
|
}
|
|
2844
|
-
function
|
|
2878
|
+
function lr() {
|
|
2845
2879
|
if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
|
|
2846
2880
|
let e = navigator.userAgentData, t = e?.platform ?? "";
|
|
2847
2881
|
if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
|
|
2848
2882
|
let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
|
|
2849
2883
|
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
2884
|
}
|
|
2851
|
-
function
|
|
2885
|
+
function ur() {
|
|
2852
2886
|
let e = typeof navigator < "u" ? navigator.connection : void 0;
|
|
2853
2887
|
if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
|
|
2854
2888
|
let t = {
|
|
@@ -2867,17 +2901,17 @@ function cr() {
|
|
|
2867
2901
|
}
|
|
2868
2902
|
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
2903
|
}
|
|
2870
|
-
function
|
|
2871
|
-
let t =
|
|
2872
|
-
deviceClass:
|
|
2904
|
+
function dr(e) {
|
|
2905
|
+
let t = cr(), n = {
|
|
2906
|
+
deviceClass: lr(),
|
|
2873
2907
|
integration: t.integration,
|
|
2874
|
-
...
|
|
2908
|
+
...ur()
|
|
2875
2909
|
};
|
|
2876
2910
|
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
2911
|
let r = e.getBoundingClientRect?.();
|
|
2878
2912
|
return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
|
|
2879
2913
|
}
|
|
2880
|
-
async function
|
|
2914
|
+
async function fr() {
|
|
2881
2915
|
let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
|
|
2882
2916
|
if (!e?.getHighEntropyValues) return {};
|
|
2883
2917
|
try {
|
|
@@ -2889,7 +2923,7 @@ async function ur() {
|
|
|
2889
2923
|
}
|
|
2890
2924
|
//#endregion
|
|
2891
2925
|
//#region src/core/version.ts
|
|
2892
|
-
var
|
|
2926
|
+
var pr = "2.25.0", mr = {
|
|
2893
2927
|
accent: "#E1B600",
|
|
2894
2928
|
accentText: "#1B1C23",
|
|
2895
2929
|
background: "#0e0f13",
|
|
@@ -2900,7 +2934,7 @@ var dr = "2.24.0", fr = {
|
|
|
2900
2934
|
border: "rgba(255, 255, 255, 0.1)",
|
|
2901
2935
|
radius: "8px",
|
|
2902
2936
|
fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
|
|
2903
|
-
},
|
|
2937
|
+
}, hr = {
|
|
2904
2938
|
accent: "--havik-accent",
|
|
2905
2939
|
accentText: "--havik-accent-text",
|
|
2906
2940
|
background: "--havik-bg",
|
|
@@ -2912,26 +2946,26 @@ var dr = "2.24.0", fr = {
|
|
|
2912
2946
|
radius: "--havik-radius",
|
|
2913
2947
|
fontFamily: "--havik-font"
|
|
2914
2948
|
};
|
|
2915
|
-
function
|
|
2949
|
+
function gr(e, t) {
|
|
2916
2950
|
let n = {
|
|
2917
|
-
...
|
|
2951
|
+
...mr,
|
|
2918
2952
|
...t
|
|
2919
2953
|
};
|
|
2920
|
-
for (let t of Object.keys(
|
|
2954
|
+
for (let t of Object.keys(hr)) e.style.setProperty(hr[t], n[t]);
|
|
2921
2955
|
n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
|
|
2922
2956
|
}
|
|
2923
2957
|
//#endregion
|
|
2924
2958
|
//#region src/ui/styles.ts
|
|
2925
|
-
var
|
|
2926
|
-
function
|
|
2927
|
-
let n = e.querySelector(`style#${
|
|
2928
|
-
if (n && (!t ||
|
|
2959
|
+
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();
|
|
2960
|
+
function br(e = document, t) {
|
|
2961
|
+
let n = e.querySelector(`style#${_r}`);
|
|
2962
|
+
if (n && (!t || yr.get(n) === t)) return;
|
|
2929
2963
|
let r = e.createElement("style");
|
|
2930
|
-
r.id =
|
|
2964
|
+
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
2965
|
}
|
|
2932
2966
|
//#endregion
|
|
2933
2967
|
//#region src/ui/icons.ts
|
|
2934
|
-
var
|
|
2968
|
+
var xr = {
|
|
2935
2969
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
2936
2970
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
2937
2971
|
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 +2979,11 @@ var yr = {
|
|
|
2945
2979
|
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
2980
|
};
|
|
2947
2981
|
function $(e) {
|
|
2948
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
2982
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${xr[e]}</svg>`;
|
|
2949
2983
|
}
|
|
2950
2984
|
//#endregion
|
|
2951
2985
|
//#region src/ui/controls.ts
|
|
2952
|
-
var
|
|
2986
|
+
var Sr = 3e3, Cr = 250, wr = /* @__PURE__ */ new Set([
|
|
2953
2987
|
"GONE",
|
|
2954
2988
|
"NOT_FOUND",
|
|
2955
2989
|
"GEO_DENIED",
|
|
@@ -2957,15 +2991,15 @@ var br = 3e3, xr = 250, Sr = /* @__PURE__ */ new Set([
|
|
|
2957
2991
|
"UNAUTHORIZED",
|
|
2958
2992
|
"DRM_DEVICE_REVOKED"
|
|
2959
2993
|
]);
|
|
2960
|
-
function
|
|
2994
|
+
function Tr(e) {
|
|
2961
2995
|
let t = "This match isn't available in your country";
|
|
2962
2996
|
return e ? `${t} (${e})` : t;
|
|
2963
2997
|
}
|
|
2964
|
-
var
|
|
2965
|
-
function
|
|
2966
|
-
return new
|
|
2998
|
+
var Er = "This device can't play protected video";
|
|
2999
|
+
function Dr(e) {
|
|
3000
|
+
return new Or(e);
|
|
2967
3001
|
}
|
|
2968
|
-
var
|
|
3002
|
+
var Or = class {
|
|
2969
3003
|
root;
|
|
2970
3004
|
video;
|
|
2971
3005
|
player;
|
|
@@ -3004,6 +3038,7 @@ var Er = class {
|
|
|
3004
3038
|
endedMessage;
|
|
3005
3039
|
interruptedMessage;
|
|
3006
3040
|
errorMessage;
|
|
3041
|
+
offlineMessage;
|
|
3007
3042
|
hideTimer;
|
|
3008
3043
|
tapTimer;
|
|
3009
3044
|
surfacePointerType = "";
|
|
@@ -3013,7 +3048,7 @@ var Er = class {
|
|
|
3013
3048
|
scrubbing = !1;
|
|
3014
3049
|
offFns = [];
|
|
3015
3050
|
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 ??
|
|
3051
|
+
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
3052
|
let t = (e, t, n) => {
|
|
3018
3053
|
let r = this.doc.createElement(e);
|
|
3019
3054
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -3069,7 +3104,7 @@ var Er = class {
|
|
|
3069
3104
|
}), this.on(this.muteBtn, "click", () => this.player.setMuted(!e.muted)), this.on(this.volSlider, "input", () => {
|
|
3070
3105
|
let t = Number(this.volSlider.value);
|
|
3071
3106
|
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) => {
|
|
3107
|
+
}), 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
3108
|
this.lastError = e, this.statusKind = null, this.syncState();
|
|
3074
3109
|
}));
|
|
3075
3110
|
let t = (e) => e.pointerType !== "touch";
|
|
@@ -3099,7 +3134,7 @@ var Er = class {
|
|
|
3099
3134
|
let t = this.surfaceWasHidden;
|
|
3100
3135
|
this.tapTimer = setTimeout(() => {
|
|
3101
3136
|
this.tapTimer = void 0, this.toggleBar(t);
|
|
3102
|
-
},
|
|
3137
|
+
}, Cr);
|
|
3103
3138
|
}
|
|
3104
3139
|
toggleBar(e) {
|
|
3105
3140
|
e ? this.poke() : this.hideIfIdle();
|
|
@@ -3116,10 +3151,14 @@ var Er = class {
|
|
|
3116
3151
|
}
|
|
3117
3152
|
syncStatus(e) {
|
|
3118
3153
|
let t = null;
|
|
3119
|
-
|
|
3154
|
+
if (this.statusOverlays) {
|
|
3155
|
+
let n = this.player.offline && e !== "ended" && e !== "idle", r = !this.hasPlayed && (e === "paused" || e === "waiting");
|
|
3156
|
+
e === "ended" ? t = "ended" : n && !r ? t = "offline" : e === "error" ? t = "error" : e === "waiting" ? t = "waiting" : !this.hasPlayed && (e === "idle" || e === "paused") && (t = "preplay");
|
|
3157
|
+
}
|
|
3158
|
+
this.renderStatus(t);
|
|
3120
3159
|
}
|
|
3121
3160
|
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" ?
|
|
3161
|
+
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
3162
|
}
|
|
3124
3163
|
renderStatus(e) {
|
|
3125
3164
|
let t = this.statusMessageFor(e);
|
|
@@ -3134,7 +3173,7 @@ var Er = class {
|
|
|
3134
3173
|
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
3174
|
} else {
|
|
3136
3175
|
let r = this.doc.createElement("div");
|
|
3137
|
-
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !
|
|
3176
|
+
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !wr.has(this.lastError.code)) {
|
|
3138
3177
|
let e = this.doc.createElement("button");
|
|
3139
3178
|
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
3179
|
}
|
|
@@ -3175,7 +3214,7 @@ var Er = class {
|
|
|
3175
3214
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
3176
3215
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
3177
3216
|
}
|
|
3178
|
-
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${
|
|
3217
|
+
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${kr(this.video.currentTime)} / ${kr(this.video.duration)}`);
|
|
3179
3218
|
}
|
|
3180
3219
|
syncLive() {
|
|
3181
3220
|
let e = this.player.getStats(), t = e.isLive !== !1, n = this.player.state === "ended", r = !t && !this.streamEnded();
|
|
@@ -3225,17 +3264,17 @@ var Er = class {
|
|
|
3225
3264
|
renderQualityMenu() {
|
|
3226
3265
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
3227
3266
|
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(
|
|
3267
|
+
for (let n of e) this.menu.append(this.menuItem(Ar(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
3229
3268
|
}
|
|
3230
3269
|
renderAudioMenu() {
|
|
3231
3270
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
3232
3271
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
3233
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
3272
|
+
for (let t of e) this.menu.append(this.menuItem(jr(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
3234
3273
|
}
|
|
3235
3274
|
renderCcMenu() {
|
|
3236
3275
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
3237
3276
|
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(
|
|
3277
|
+
for (let t of e) this.menu.append(this.menuItem(Mr(t), !1, () => this.player.setTextTrack(t.id)));
|
|
3239
3278
|
}
|
|
3240
3279
|
onTracksChanged() {
|
|
3241
3280
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -3255,14 +3294,14 @@ var Er = class {
|
|
|
3255
3294
|
}
|
|
3256
3295
|
async toggleFullscreen() {
|
|
3257
3296
|
try {
|
|
3258
|
-
|
|
3297
|
+
ye(this.video, this.root) ? await C(this.video, this.root) : await S(this.video, this.root);
|
|
3259
3298
|
} catch {}
|
|
3260
3299
|
}
|
|
3261
3300
|
syncFullscreenSupport() {
|
|
3262
|
-
this.fsSupported =
|
|
3301
|
+
this.fsSupported = x(this.video, this.root), this.fsBtn.style.display = this.fsSupported ? "" : "none";
|
|
3263
3302
|
}
|
|
3264
3303
|
syncFullscreen() {
|
|
3265
|
-
let e =
|
|
3304
|
+
let e = ye(this.video, this.root);
|
|
3266
3305
|
this.setIcon(this.fsBtn, e ? "fullscreenExit" : "fullscreen"), this.fsBtn.setAttribute("aria-label", e ? "Exit fullscreen" : "Fullscreen");
|
|
3267
3306
|
}
|
|
3268
3307
|
poke() {
|
|
@@ -3340,41 +3379,51 @@ var Er = class {
|
|
|
3340
3379
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
3341
3380
|
}
|
|
3342
3381
|
};
|
|
3343
|
-
function
|
|
3382
|
+
function kr(e) {
|
|
3344
3383
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
3345
3384
|
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
3385
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
3347
3386
|
}
|
|
3348
|
-
function
|
|
3387
|
+
function Ar(e) {
|
|
3349
3388
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
3350
3389
|
}
|
|
3351
|
-
function
|
|
3390
|
+
function jr(e) {
|
|
3352
3391
|
return e.name || e.lang || `Track ${e.id}`;
|
|
3353
3392
|
}
|
|
3354
|
-
function
|
|
3393
|
+
function Mr(e) {
|
|
3355
3394
|
return e.name || e.lang || `Track ${e.id}`;
|
|
3356
3395
|
}
|
|
3357
3396
|
//#endregion
|
|
3358
3397
|
//#region src/managed/index.ts
|
|
3359
|
-
var
|
|
3360
|
-
|
|
3398
|
+
var Nr = 6e3, Pr = 45e3, Fr = 2e3, Ir = 3, Lr = 5e3, Rr = 2e3, zr = 48e4, Br = "keySystemLicenseRequestFailed", Vr = /* @__PURE__ */ new Set([
|
|
3399
|
+
"GONE",
|
|
3400
|
+
"NOT_FOUND",
|
|
3401
|
+
"INVALID_URN",
|
|
3402
|
+
"UNAUTHORIZED",
|
|
3403
|
+
"GEO_DENIED",
|
|
3404
|
+
"DRM_DEVICE_REVOKED"
|
|
3405
|
+
]);
|
|
3406
|
+
function Hr(e) {
|
|
3407
|
+
return !Vr.has(e);
|
|
3408
|
+
}
|
|
3409
|
+
function Ur(e) {
|
|
3361
3410
|
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
|
|
3411
|
+
if (e.env !== void 0) return ct(e.env);
|
|
3363
3412
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
|
|
3364
3413
|
return e.baseUrl;
|
|
3365
3414
|
}
|
|
3366
|
-
async function
|
|
3415
|
+
async function Wr(e) {
|
|
3367
3416
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
3368
|
-
let t =
|
|
3417
|
+
let t = Ur(e);
|
|
3369
3418
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
3370
3419
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
3371
|
-
let r = new
|
|
3420
|
+
let r = new Gr({
|
|
3372
3421
|
...e,
|
|
3373
3422
|
baseUrl: t
|
|
3374
3423
|
});
|
|
3375
3424
|
return await r.start(), r;
|
|
3376
3425
|
}
|
|
3377
|
-
var
|
|
3426
|
+
var Gr = class {
|
|
3378
3427
|
opts;
|
|
3379
3428
|
abort = new AbortController();
|
|
3380
3429
|
listeners = {};
|
|
@@ -3409,12 +3458,17 @@ var Vr = class {
|
|
|
3409
3458
|
playRequested = !1;
|
|
3410
3459
|
idleClosed = !1;
|
|
3411
3460
|
pendingStartLoad = !1;
|
|
3461
|
+
connectivity = null;
|
|
3462
|
+
failedWhileOffline = !1;
|
|
3412
3463
|
constructor(e) {
|
|
3413
3464
|
this.opts = e;
|
|
3414
3465
|
}
|
|
3415
3466
|
get state() {
|
|
3416
3467
|
return this._state;
|
|
3417
3468
|
}
|
|
3469
|
+
get offline() {
|
|
3470
|
+
return !R();
|
|
3471
|
+
}
|
|
3418
3472
|
get descriptor() {
|
|
3419
3473
|
return this._descriptor;
|
|
3420
3474
|
}
|
|
@@ -3422,7 +3476,7 @@ var Vr = class {
|
|
|
3422
3476
|
return this._endedReason;
|
|
3423
3477
|
}
|
|
3424
3478
|
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");
|
|
3479
|
+
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
3480
|
let e = ++this.loadGen, t = this.resolveOptions();
|
|
3427
3481
|
try {
|
|
3428
3482
|
let n = await v(t);
|
|
@@ -3435,7 +3489,7 @@ var Vr = class {
|
|
|
3435
3489
|
this.setState("waiting"), this.beginArming(e, t.liveStartsAtMs);
|
|
3436
3490
|
return;
|
|
3437
3491
|
}
|
|
3438
|
-
throw t;
|
|
3492
|
+
throw this.destroy(), t;
|
|
3439
3493
|
}
|
|
3440
3494
|
}
|
|
3441
3495
|
resolveOptions() {
|
|
@@ -3448,7 +3502,7 @@ var Vr = class {
|
|
|
3448
3502
|
};
|
|
3449
3503
|
}
|
|
3450
3504
|
beginArming(e, t, n = !1) {
|
|
3451
|
-
let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ??
|
|
3505
|
+
let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? E(this.opts.baseUrl);
|
|
3452
3506
|
r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
|
|
3453
3507
|
}
|
|
3454
3508
|
beginArmingByPolling(e) {
|
|
@@ -3469,7 +3523,7 @@ var Vr = class {
|
|
|
3469
3523
|
setTimeout(() => {
|
|
3470
3524
|
a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
3471
3525
|
phase: i ? "unavailable" : "tooEarly",
|
|
3472
|
-
retryInMs:
|
|
3526
|
+
retryInMs: Pr,
|
|
3473
3527
|
attempt: 1,
|
|
3474
3528
|
elapsedMs: 0,
|
|
3475
3529
|
...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
|
|
@@ -3508,13 +3562,13 @@ var Vr = class {
|
|
|
3508
3562
|
!a && !p() && h();
|
|
3509
3563
|
}, e);
|
|
3510
3564
|
};
|
|
3511
|
-
_(
|
|
3565
|
+
_(Nr), this.armingSub = T({
|
|
3512
3566
|
eventsBaseUrl: t,
|
|
3513
3567
|
matchUrn: this.opts.matchUrn,
|
|
3514
3568
|
credential: this.opts.credential,
|
|
3515
|
-
onAlive: () => _(
|
|
3569
|
+
onAlive: () => _(Pr),
|
|
3516
3570
|
onState: (e) => {
|
|
3517
|
-
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() *
|
|
3571
|
+
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Fr);
|
|
3518
3572
|
},
|
|
3519
3573
|
onError: () => h()
|
|
3520
3574
|
});
|
|
@@ -3537,7 +3591,7 @@ var Vr = class {
|
|
|
3537
3591
|
let n = await c(this.opts.credential);
|
|
3538
3592
|
if (this.destroyed || t !== this.loadGen) return;
|
|
3539
3593
|
this.setState("loading");
|
|
3540
|
-
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a =
|
|
3594
|
+
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = ht(this.opts.video, (e) => {
|
|
3541
3595
|
this._state !== "ended" && this._state !== "error" && this.setState(e);
|
|
3542
3596
|
});
|
|
3543
3597
|
if (await i.load(), this.destroyed || t !== this.loadGen) {
|
|
@@ -3559,26 +3613,26 @@ var Vr = class {
|
|
|
3559
3613
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
|
|
3560
3614
|
let i = e.analytics?.sid;
|
|
3561
3615
|
if (!i) return;
|
|
3562
|
-
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } =
|
|
3616
|
+
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
3617
|
if (!o) {
|
|
3564
3618
|
s && setTimeout(() => {
|
|
3565
3619
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
|
|
3566
3620
|
}, 0);
|
|
3567
3621
|
return;
|
|
3568
3622
|
}
|
|
3569
|
-
let c = this.opts.video, l = new
|
|
3623
|
+
let c = this.opts.video, l = new sr({
|
|
3570
3624
|
endpoint: o,
|
|
3571
3625
|
sid: i,
|
|
3572
3626
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
3573
|
-
sdkVersion:
|
|
3574
|
-
environment:
|
|
3627
|
+
sdkVersion: pr,
|
|
3628
|
+
environment: dr(c),
|
|
3575
3629
|
idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
|
|
3576
3630
|
onIdle: () => this.onAnalyticsIdle(t),
|
|
3577
3631
|
onBlocked: (e) => setTimeout(() => {
|
|
3578
3632
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
|
|
3579
3633
|
}, 0),
|
|
3580
3634
|
sample: () => {
|
|
3581
|
-
let e = this.engine?.getStats() ??
|
|
3635
|
+
let e = this.engine?.getStats() ?? ut, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
|
|
3582
3636
|
return {
|
|
3583
3637
|
...e,
|
|
3584
3638
|
bufferedMs: Math.round(t * 1e3),
|
|
@@ -3592,7 +3646,7 @@ var Vr = class {
|
|
|
3592
3646
|
let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
|
|
3593
3647
|
c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
|
|
3594
3648
|
c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
|
|
3595
|
-
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()),
|
|
3649
|
+
}, 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
3650
|
}
|
|
3597
3651
|
currentPresentation() {
|
|
3598
3652
|
let e = this.opts.video;
|
|
@@ -3607,7 +3661,7 @@ var Vr = class {
|
|
|
3607
3661
|
video: this.opts.video,
|
|
3608
3662
|
descriptor: e,
|
|
3609
3663
|
credential: t,
|
|
3610
|
-
deviceId:
|
|
3664
|
+
deviceId: k(),
|
|
3611
3665
|
userId: this.opts.userId,
|
|
3612
3666
|
lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
|
|
3613
3667
|
snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
|
|
@@ -3624,9 +3678,9 @@ var Vr = class {
|
|
|
3624
3678
|
freshLicenseUrl: () => this.refreshLicense()
|
|
3625
3679
|
}, o = this.opts.engine ?? "auto";
|
|
3626
3680
|
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 (
|
|
3681
|
+
if (o === "hls") return new Un(a);
|
|
3682
|
+
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);
|
|
3683
|
+
if (Ut()) return new Un(a);
|
|
3630
3684
|
if (V(this.opts.video)) return new U(a);
|
|
3631
3685
|
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
3632
3686
|
}
|
|
@@ -3677,11 +3731,11 @@ var Vr = class {
|
|
|
3677
3731
|
}
|
|
3678
3732
|
startLiveState(e) {
|
|
3679
3733
|
if (this.opts.liveStateEvents === !1) return;
|
|
3680
|
-
let t = this.opts.eventsBaseUrl ??
|
|
3734
|
+
let t = this.opts.eventsBaseUrl ?? E(this.opts.baseUrl);
|
|
3681
3735
|
if (!t) return;
|
|
3682
3736
|
this.closeLiveState();
|
|
3683
3737
|
let i = 0, a = !1;
|
|
3684
|
-
this.liveStateSub =
|
|
3738
|
+
this.liveStateSub = T({
|
|
3685
3739
|
eventsBaseUrl: t,
|
|
3686
3740
|
matchUrn: this.opts.matchUrn,
|
|
3687
3741
|
credential: this.opts.credential,
|
|
@@ -3693,11 +3747,11 @@ var Vr = class {
|
|
|
3693
3747
|
},
|
|
3694
3748
|
onError: (o) => {
|
|
3695
3749
|
if (!(this.destroyed || e !== this.loadGen || a) && !this.endedHandled) {
|
|
3696
|
-
if (o instanceof
|
|
3750
|
+
if (o instanceof w && (o.terminal || o.status === 404)) {
|
|
3697
3751
|
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
3752
|
return;
|
|
3699
3753
|
}
|
|
3700
|
-
i += 1, i >=
|
|
3754
|
+
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
3755
|
}
|
|
3702
3756
|
}
|
|
3703
3757
|
});
|
|
@@ -3705,6 +3759,18 @@ var Vr = class {
|
|
|
3705
3759
|
closeLiveState() {
|
|
3706
3760
|
this.liveStateSub?.close(), this.liveStateSub = null;
|
|
3707
3761
|
}
|
|
3762
|
+
watchConnectivity() {
|
|
3763
|
+
this.connectivity || (this.connectivity = lt(), this.connectivity.onChange((e) => {
|
|
3764
|
+
if (this.destroyed) return;
|
|
3765
|
+
if (!e) {
|
|
3766
|
+
this.emit("offline");
|
|
3767
|
+
return;
|
|
3768
|
+
}
|
|
3769
|
+
if (this.emit("online"), this._state !== "error" || !this._lastError) return;
|
|
3770
|
+
let t = this._lastError.code;
|
|
3771
|
+
Hr(t) && (t === "NETWORK" || this.failedWhileOffline) && this.retry().catch(() => void 0);
|
|
3772
|
+
}));
|
|
3773
|
+
}
|
|
3708
3774
|
watchReturn() {
|
|
3709
3775
|
this.onReturnVisible || typeof document > "u" || this.opts.liveStateEvents !== !1 && (document.visibilityState === "hidden" && (this.hiddenAtMs = Date.now()), this.onReturnVisible = () => {
|
|
3710
3776
|
if (document.visibilityState === "hidden") {
|
|
@@ -3712,7 +3778,7 @@ var Vr = class {
|
|
|
3712
3778
|
return;
|
|
3713
3779
|
}
|
|
3714
3780
|
let e = this.hiddenAtMs;
|
|
3715
|
-
this.hiddenAtMs = null, e != null && Date.now() - e >=
|
|
3781
|
+
this.hiddenAtMs = null, e != null && Date.now() - e >= Lr && this.resyncLiveState();
|
|
3716
3782
|
}, this.onReturnPageShow = (e) => {
|
|
3717
3783
|
e.persisted && this.resyncLiveState();
|
|
3718
3784
|
}, document.addEventListener("visibilitychange", this.onReturnVisible), typeof window < "u" && window.addEventListener("pageshow", this.onReturnPageShow));
|
|
@@ -3744,7 +3810,7 @@ var Vr = class {
|
|
|
3744
3810
|
scheduleRejoin(e) {
|
|
3745
3811
|
this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
|
|
3746
3812
|
this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
|
|
3747
|
-
}, Math.random() *
|
|
3813
|
+
}, Math.random() * Fr));
|
|
3748
3814
|
}
|
|
3749
3815
|
cancelRejoin() {
|
|
3750
3816
|
this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
|
|
@@ -3768,7 +3834,7 @@ var Vr = class {
|
|
|
3768
3834
|
}
|
|
3769
3835
|
t.controls = !1;
|
|
3770
3836
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
3771
|
-
r && r.insertBefore(n, t), n.appendChild(t),
|
|
3837
|
+
r && r.insertBefore(n, t), n.appendChild(t), gr(n, this.opts.theme), this.container = n, this.controlBar = Dr({
|
|
3772
3838
|
root: n,
|
|
3773
3839
|
video: t,
|
|
3774
3840
|
player: this,
|
|
@@ -3778,6 +3844,7 @@ var Vr = class {
|
|
|
3778
3844
|
streamEnded: () => this.streamEnded,
|
|
3779
3845
|
interruptedMessage: this.opts.interruptedMessage,
|
|
3780
3846
|
errorMessage: this.opts.errorMessage,
|
|
3847
|
+
offlineMessage: this.opts.offlineMessage,
|
|
3781
3848
|
cspNonce: this.opts.cspNonce
|
|
3782
3849
|
});
|
|
3783
3850
|
}
|
|
@@ -3806,7 +3873,7 @@ var Vr = class {
|
|
|
3806
3873
|
}
|
|
3807
3874
|
startStats() {
|
|
3808
3875
|
this.stopStats();
|
|
3809
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
3876
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? Rr);
|
|
3810
3877
|
this.statsTimer = setInterval(() => {
|
|
3811
3878
|
if (!this.engine) return;
|
|
3812
3879
|
let e = this.engine.getStats();
|
|
@@ -3817,14 +3884,14 @@ var Vr = class {
|
|
|
3817
3884
|
this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
|
|
3818
3885
|
}
|
|
3819
3886
|
isStaleLicenseDenial(e) {
|
|
3820
|
-
return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !==
|
|
3887
|
+
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
3888
|
}
|
|
3822
3889
|
scheduleLicenseRefresh() {
|
|
3823
3890
|
if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
|
|
3824
3891
|
typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
|
|
3825
3892
|
document.visibilityState !== "visible" || this.destroyed || G(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
|
|
3826
3893
|
}, document.addEventListener("visibilitychange", this.onRefocus));
|
|
3827
|
-
let e = this.opts.licenseRefreshMs ??
|
|
3894
|
+
let e = this.opts.licenseRefreshMs ?? zr;
|
|
3828
3895
|
e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
3829
3896
|
}
|
|
3830
3897
|
stopRefresh() {
|
|
@@ -3881,7 +3948,7 @@ var Vr = class {
|
|
|
3881
3948
|
this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
|
|
3882
3949
|
}
|
|
3883
3950
|
getStats() {
|
|
3884
|
-
return this.engine?.getStats() ??
|
|
3951
|
+
return this.engine?.getStats() ?? ut;
|
|
3885
3952
|
}
|
|
3886
3953
|
getQualityLevels() {
|
|
3887
3954
|
return this.engine?.getQualityLevels() ?? [];
|
|
@@ -3920,13 +3987,13 @@ var Vr = class {
|
|
|
3920
3987
|
e.pictureInPictureElement === this.opts.video && typeof e.exitPictureInPicture == "function" && await e.exitPictureInPicture();
|
|
3921
3988
|
}
|
|
3922
3989
|
async enterFullscreen() {
|
|
3923
|
-
return !this.destroyed &&
|
|
3990
|
+
return !this.destroyed && S(this.opts.video, this.container ?? void 0);
|
|
3924
3991
|
}
|
|
3925
3992
|
async exitFullscreen() {
|
|
3926
|
-
await
|
|
3993
|
+
await C(this.opts.video, this.container ?? void 0);
|
|
3927
3994
|
}
|
|
3928
3995
|
fullscreenSupported() {
|
|
3929
|
-
return !this.destroyed &&
|
|
3996
|
+
return !this.destroyed && x(this.opts.video, this.container ?? void 0);
|
|
3930
3997
|
}
|
|
3931
3998
|
retry() {
|
|
3932
3999
|
return this.reload();
|
|
@@ -3951,13 +4018,13 @@ var Vr = class {
|
|
|
3951
4018
|
return n.add(t), () => n.delete(t);
|
|
3952
4019
|
}
|
|
3953
4020
|
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());
|
|
4021
|
+
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
4022
|
}
|
|
3956
4023
|
clearListeners() {
|
|
3957
4024
|
for (let e of Object.keys(this.listeners)) this.listeners[e]?.clear();
|
|
3958
4025
|
}
|
|
3959
4026
|
fail(e) {
|
|
3960
|
-
this._lastError = e, this.setState("error"), this.analyticsSession?.noteFatal(), this.emit("error", e);
|
|
4027
|
+
this._lastError = e, this.failedWhileOffline = !R(), this.setState("error"), this.analyticsSession?.noteFatal(), this.emit("error", e);
|
|
3961
4028
|
}
|
|
3962
4029
|
setState(e) {
|
|
3963
4030
|
if (e === this._state) return;
|
|
@@ -3989,12 +4056,12 @@ var Vr = class {
|
|
|
3989
4056
|
};
|
|
3990
4057
|
//#endregion
|
|
3991
4058
|
//#region src/embed/protocol.ts
|
|
3992
|
-
function
|
|
4059
|
+
function Kr(e) {
|
|
3993
4060
|
return !!e && typeof e == "object" && typeof e.type == "string" && e.type.startsWith("oddin:");
|
|
3994
4061
|
}
|
|
3995
4062
|
//#endregion
|
|
3996
4063
|
//#region src/embed/host.ts
|
|
3997
|
-
function
|
|
4064
|
+
function qr(e) {
|
|
3998
4065
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
3999
4066
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
4000
4067
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -4003,7 +4070,7 @@ function Ur(e) {
|
|
|
4003
4070
|
let r = document.createElement("iframe");
|
|
4004
4071
|
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
4072
|
let i = /* @__PURE__ */ new Set(), a = (t) => {
|
|
4006
|
-
if (t.source !== r.contentWindow || t.origin !== n || !
|
|
4073
|
+
if (t.source !== r.contentWindow || t.origin !== n || !Kr(t.data)) return;
|
|
4007
4074
|
let a = t.data;
|
|
4008
4075
|
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
4076
|
};
|
|
@@ -4053,15 +4120,15 @@ function Ur(e) {
|
|
|
4053
4120
|
}
|
|
4054
4121
|
//#endregion
|
|
4055
4122
|
//#region src/embed/page.ts
|
|
4056
|
-
var
|
|
4057
|
-
function
|
|
4123
|
+
var Jr = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
4124
|
+
function Yr(e) {
|
|
4058
4125
|
if (typeof e == "boolean") return e;
|
|
4059
4126
|
if (typeof e == "object" && e) {
|
|
4060
4127
|
let t = e.endpoint;
|
|
4061
4128
|
return typeof t == "string" ? { endpoint: t } : {};
|
|
4062
4129
|
}
|
|
4063
4130
|
}
|
|
4064
|
-
function
|
|
4131
|
+
function Xr() {
|
|
4065
4132
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
4066
4133
|
if (e) return {
|
|
4067
4134
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -4071,7 +4138,7 @@ function Kr() {
|
|
|
4071
4138
|
autoplay: e.autoplay ?? !0,
|
|
4072
4139
|
muted: e.muted ?? !0,
|
|
4073
4140
|
waitForLive: e.waitForLive ?? !0,
|
|
4074
|
-
analytics:
|
|
4141
|
+
analytics: Yr(e.analytics)
|
|
4075
4142
|
};
|
|
4076
4143
|
let t = new URLSearchParams(location.search);
|
|
4077
4144
|
return {
|
|
@@ -4084,9 +4151,9 @@ function Kr() {
|
|
|
4084
4151
|
waitForLive: !0
|
|
4085
4152
|
};
|
|
4086
4153
|
}
|
|
4087
|
-
async function
|
|
4088
|
-
let e =
|
|
4089
|
-
|
|
4154
|
+
async function Zr() {
|
|
4155
|
+
let e = Xr();
|
|
4156
|
+
$r();
|
|
4090
4157
|
let t = document.createElement("video");
|
|
4091
4158
|
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
4159
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -4142,12 +4209,12 @@ async function qr() {
|
|
|
4142
4209
|
message: e.message,
|
|
4143
4210
|
...e.country === void 0 ? {} : { country: e.country }
|
|
4144
4211
|
})), e.on("autoplayblocked", () => {
|
|
4145
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
4212
|
+
i({ type: "oddin:autoplayblocked" }), Qr(t, e);
|
|
4146
4213
|
});
|
|
4147
4214
|
}, s = async (r) => {
|
|
4148
4215
|
a?.destroy(), a = null;
|
|
4149
4216
|
try {
|
|
4150
|
-
let n = await
|
|
4217
|
+
let n = await Wr({
|
|
4151
4218
|
video: t,
|
|
4152
4219
|
baseUrl: e.baseUrl,
|
|
4153
4220
|
matchUrn: r,
|
|
@@ -4210,30 +4277,30 @@ async function qr() {
|
|
|
4210
4277
|
a?.retry();
|
|
4211
4278
|
break;
|
|
4212
4279
|
case "oddin:load":
|
|
4213
|
-
typeof e.matchUrn == "string" &&
|
|
4280
|
+
typeof e.matchUrn == "string" && Jr.test(e.matchUrn) && s(e.matchUrn);
|
|
4214
4281
|
break;
|
|
4215
4282
|
case "oddin:destroy": c();
|
|
4216
4283
|
}
|
|
4217
4284
|
}, u = (e) => {
|
|
4218
|
-
r && e.origin === r &&
|
|
4285
|
+
r && e.origin === r && Kr(e.data) && l(e.data);
|
|
4219
4286
|
};
|
|
4220
4287
|
r && window.addEventListener("message", u), window.addEventListener("pagehide", c, { once: !0 }), await s(e.matchUrn), i({
|
|
4221
4288
|
type: "oddin:ready",
|
|
4222
4289
|
protocol: 1
|
|
4223
4290
|
});
|
|
4224
4291
|
}
|
|
4225
|
-
function
|
|
4292
|
+
function Qr(e, t) {
|
|
4226
4293
|
if (document.getElementById("havik-tap")) return;
|
|
4227
4294
|
let n = document.createElement("button");
|
|
4228
4295
|
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
4296
|
n.remove(), t.play();
|
|
4230
4297
|
}), document.body.appendChild(n);
|
|
4231
4298
|
}
|
|
4232
|
-
function
|
|
4299
|
+
function $r() {
|
|
4233
4300
|
let e = document.createElement("style");
|
|
4234
4301
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
4235
4302
|
}
|
|
4236
4303
|
//#endregion
|
|
4237
|
-
export {
|
|
4304
|
+
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, x 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, ye as videoFullscreenActive, Ee as watchStatus };
|
|
4238
4305
|
|
|
4239
4306
|
//# sourceMappingURL=index.js.map
|