@oddin-gg/havik-player 2.0.3 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/havik-player.global.js +2 -2
- package/dist/havik-player.global.js.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -3
- package/dist/index.d.ts +38 -3
- package/dist/index.js +474 -185
- package/dist/index.js.map +1 -1
- package/docs/API.md +30 -30
- package/embed/index.html +1 -1
- package/examples/vanilla.html +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -616,11 +616,15 @@ function Ce(e) {
|
|
|
616
616
|
}
|
|
617
617
|
//#endregion
|
|
618
618
|
//#region src/core/stats.ts
|
|
619
|
-
var
|
|
620
|
-
function
|
|
621
|
-
|
|
619
|
+
var we = { droppedFrames: 0 };
|
|
620
|
+
function F(e) {
|
|
621
|
+
let t = e.getVideoPlaybackQuality?.();
|
|
622
|
+
return {
|
|
623
|
+
dropped: t?.droppedVideoFrames ?? 0,
|
|
624
|
+
decoded: t?.totalVideoFrames ?? 0
|
|
625
|
+
};
|
|
622
626
|
}
|
|
623
|
-
function
|
|
627
|
+
function Te(e, t) {
|
|
624
628
|
let n = [
|
|
625
629
|
["playing", () => t("playing")],
|
|
626
630
|
["waiting", () => t("buffering")],
|
|
@@ -637,7 +641,7 @@ function we(e, t) {
|
|
|
637
641
|
}
|
|
638
642
|
//#endregion
|
|
639
643
|
//#region src/core/engine/native.ts
|
|
640
|
-
function
|
|
644
|
+
function Ee(e) {
|
|
641
645
|
try {
|
|
642
646
|
let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
|
|
643
647
|
return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
|
|
@@ -645,15 +649,15 @@ function Te(e) {
|
|
|
645
649
|
return;
|
|
646
650
|
}
|
|
647
651
|
}
|
|
648
|
-
function
|
|
652
|
+
function I(e) {
|
|
649
653
|
return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
|
|
650
654
|
}
|
|
651
|
-
function
|
|
655
|
+
function L() {
|
|
652
656
|
if (typeof window > "u") return !1;
|
|
653
657
|
let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
|
|
654
658
|
return e || t;
|
|
655
659
|
}
|
|
656
|
-
var
|
|
660
|
+
var R = class {
|
|
657
661
|
name = "native";
|
|
658
662
|
deps;
|
|
659
663
|
onLoaded;
|
|
@@ -663,12 +667,15 @@ var z = class {
|
|
|
663
667
|
keySession = null;
|
|
664
668
|
fairplayArmed = !1;
|
|
665
669
|
fairplayKeyIV;
|
|
670
|
+
loadStarted;
|
|
671
|
+
preloadTouched = !1;
|
|
672
|
+
savedPreload = null;
|
|
666
673
|
constructor(e) {
|
|
667
|
-
this.deps = e;
|
|
674
|
+
this.deps = e, this.loadStarted = e.deferLoad !== !0;
|
|
668
675
|
}
|
|
669
676
|
async load() {
|
|
670
677
|
let { video: e, descriptor: t, emit: r } = this.deps;
|
|
671
|
-
if (t.drmEnabled) {
|
|
678
|
+
if (this.loadStarted || (this.preloadTouched = !0, this.savedPreload = e.getAttribute("preload"), e.preload = "none"), t.drmEnabled) {
|
|
672
679
|
if (!t.drm?.fairplay) {
|
|
673
680
|
r({
|
|
674
681
|
type: "error",
|
|
@@ -679,11 +686,21 @@ var z = class {
|
|
|
679
686
|
}
|
|
680
687
|
this.armFairPlay();
|
|
681
688
|
}
|
|
682
|
-
|
|
689
|
+
let i = !this.loadStarted;
|
|
690
|
+
this.onLoaded = i ? void 0 : () => r({ type: "ready" }), this.onError = () => r({
|
|
683
691
|
type: "error",
|
|
684
692
|
error: new n("INTERNAL", 0, "native HLS playback error"),
|
|
685
693
|
fatal: !0
|
|
686
|
-
}), e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src =
|
|
694
|
+
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = De(t.manifestUrl, t.analytics?.sid), e.load();
|
|
695
|
+
}
|
|
696
|
+
startLoad() {
|
|
697
|
+
this.loadStarted || (this.loadStarted = !0, this.restorePreload());
|
|
698
|
+
}
|
|
699
|
+
restorePreload() {
|
|
700
|
+
if (!this.preloadTouched) return;
|
|
701
|
+
this.preloadTouched = !1;
|
|
702
|
+
let { video: e } = this.deps;
|
|
703
|
+
this.savedPreload === null ? e.removeAttribute("preload") : e.setAttribute("preload", this.savedPreload);
|
|
687
704
|
}
|
|
688
705
|
armFairPlay() {
|
|
689
706
|
let { video: e, descriptor: t, credential: r, deviceId: a, userId: o, emit: s } = this.deps, c = t.drm?.fairplay;
|
|
@@ -696,7 +713,7 @@ var z = class {
|
|
|
696
713
|
});
|
|
697
714
|
this.onEncrypted = (n) => {
|
|
698
715
|
let i = n;
|
|
699
|
-
!i.initData || this.fairplayArmed || (this.fairplayArmed = !0, this.fairplayKeyIV =
|
|
716
|
+
!i.initData || this.fairplayArmed || (this.fairplayArmed = !0, this.fairplayKeyIV = Ee(i.initData), (async () => {
|
|
700
717
|
try {
|
|
701
718
|
let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
|
|
702
719
|
initDataTypes: [i.initDataType],
|
|
@@ -791,8 +808,11 @@ var z = class {
|
|
|
791
808
|
e.seekable.length > 0 && (e.currentTime = e.seekable.end(e.seekable.length - 1));
|
|
792
809
|
}
|
|
793
810
|
getStats() {
|
|
794
|
-
let e = this.deps.video, t =
|
|
795
|
-
|
|
811
|
+
let e = this.deps.video, t = F(e), n = {
|
|
812
|
+
droppedFrames: t.dropped,
|
|
813
|
+
decodedFrames: t.decoded
|
|
814
|
+
};
|
|
815
|
+
return this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity && (n.isLive = !0, e.seekable.length > 0 && (n.atLiveEdge = e.currentTime >= e.seekable.end(e.seekable.length - 1) - 2)), n;
|
|
796
816
|
}
|
|
797
817
|
stop() {
|
|
798
818
|
try {
|
|
@@ -805,35 +825,42 @@ var z = class {
|
|
|
805
825
|
try {
|
|
806
826
|
e.pause();
|
|
807
827
|
} catch {}
|
|
808
|
-
e.removeAttribute("src");
|
|
828
|
+
e.removeAttribute("src"), this.restorePreload();
|
|
809
829
|
try {
|
|
810
830
|
e.load();
|
|
811
831
|
} catch {}
|
|
812
832
|
}
|
|
813
833
|
};
|
|
814
|
-
function
|
|
834
|
+
function De(e, t) {
|
|
815
835
|
return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
|
|
816
836
|
}
|
|
817
837
|
//#endregion
|
|
818
838
|
//#region src/core/engine/hls.ts
|
|
819
|
-
function
|
|
839
|
+
function Oe() {
|
|
820
840
|
return e.isSupported();
|
|
821
841
|
}
|
|
822
|
-
var
|
|
823
|
-
function
|
|
842
|
+
var ke = 3, Ae = 5, je = 3, Me = 3e4, Ne = 12e3, Pe = 3e3, z = 6e3, Fe = 4e3, Ie = 2, Le = 5, Re = 2, ze = 2, Be = 2e3, Ve = 3e4, He = 2, Ue = 9, We = .5, Ge = 64;
|
|
843
|
+
function Ke(e) {
|
|
844
|
+
try {
|
|
845
|
+
return new URL(e).host;
|
|
846
|
+
} catch {
|
|
847
|
+
return "";
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
function qe(e) {
|
|
824
851
|
if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
|
|
825
852
|
delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
|
|
826
853
|
return;
|
|
827
854
|
}
|
|
828
|
-
e.liveSyncDuration ??=
|
|
829
|
-
let t = Math.max(12, e.liveSyncDuration +
|
|
830
|
-
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t),
|
|
855
|
+
e.liveSyncDuration ??= He;
|
|
856
|
+
let t = Math.max(12, e.liveSyncDuration + Ue);
|
|
857
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Je(e, e.liveSyncDuration);
|
|
831
858
|
}
|
|
832
|
-
function
|
|
859
|
+
function Je(e, t) {
|
|
833
860
|
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
834
861
|
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
835
862
|
}
|
|
836
|
-
var
|
|
863
|
+
var B = class {
|
|
837
864
|
name = "hls";
|
|
838
865
|
hls = null;
|
|
839
866
|
deps;
|
|
@@ -843,6 +870,16 @@ var V = class {
|
|
|
843
870
|
playlistBytesLoaded = 0;
|
|
844
871
|
renditionSwitches = 0;
|
|
845
872
|
licenseTimeMs = 0;
|
|
873
|
+
licenseRequested = !1;
|
|
874
|
+
upshifts = 0;
|
|
875
|
+
downshifts = 0;
|
|
876
|
+
lastLevelIndex = -1;
|
|
877
|
+
requestCount = 0;
|
|
878
|
+
requestErrors = 0;
|
|
879
|
+
requestTimesMs = [];
|
|
880
|
+
cdnHost = "";
|
|
881
|
+
ladderHeights;
|
|
882
|
+
ladderTopBitrateKbps = 0;
|
|
846
883
|
mediaRecoveries = 0;
|
|
847
884
|
networkRecoveries = 0;
|
|
848
885
|
licenseRecoveries = 0;
|
|
@@ -872,11 +909,12 @@ var V = class {
|
|
|
872
909
|
sizeCapManaged = !0;
|
|
873
910
|
dprMedia = null;
|
|
874
911
|
onDprChange = null;
|
|
912
|
+
loadStarted;
|
|
875
913
|
constructor(e) {
|
|
876
|
-
this.deps = e, this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl;
|
|
914
|
+
this.deps = e, this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
|
|
877
915
|
}
|
|
878
916
|
async load() {
|
|
879
|
-
let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a =
|
|
917
|
+
let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = I(r) && L(), o = !!e.drm?.widevine?.licenseUrl && !a;
|
|
880
918
|
if (e.drmEnabled && !o) {
|
|
881
919
|
i({
|
|
882
920
|
type: "error",
|
|
@@ -894,6 +932,9 @@ var V = class {
|
|
|
894
932
|
t - r.currentTime > Math.max(n * 3, 8) && (r.currentTime = t);
|
|
895
933
|
}, document.addEventListener("visibilitychange", this.onVisibility)), this.onSeeking = () => this.clampOverSeek(), r.addEventListener("seeking", this.onSeeking), this.sizeCapManaged && typeof ResizeObserver < "u" && (this.capObserver = new ResizeObserver(() => this.onMediaResize()), this.capObserver.observe(r), this.watchDprChanges());
|
|
896
934
|
}
|
|
935
|
+
startLoad() {
|
|
936
|
+
this.loadStarted || (this.loadStarted = !0, this.hls?.startLoad(-1));
|
|
937
|
+
}
|
|
897
938
|
watchDprChanges() {
|
|
898
939
|
if (typeof matchMedia != "function") return;
|
|
899
940
|
this.unwatchDprChanges();
|
|
@@ -913,7 +954,7 @@ var V = class {
|
|
|
913
954
|
let t = e.liveSyncPosition;
|
|
914
955
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
915
956
|
let { video: n } = this.deps;
|
|
916
|
-
n.currentTime <= t +
|
|
957
|
+
n.currentTime <= t + We || (n.currentTime = t);
|
|
917
958
|
}
|
|
918
959
|
startHls() {
|
|
919
960
|
let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
|
|
@@ -927,6 +968,7 @@ var V = class {
|
|
|
927
968
|
maxLiveSyncPlaybackRate: 1.5,
|
|
928
969
|
abrEwmaDefaultEstimate: 1e6,
|
|
929
970
|
capLevelToPlayerSize: !1,
|
|
971
|
+
...this.loadStarted ? {} : { autoStartLoad: !1 },
|
|
930
972
|
...u ? {
|
|
931
973
|
emeEnabled: !0,
|
|
932
974
|
drmSystems: { ...this.licenseUrl ? { "com.widevine.alpha": { licenseUrl: this.licenseUrl } } : {} },
|
|
@@ -937,7 +979,7 @@ var V = class {
|
|
|
937
979
|
audioEncryptionScheme: "cbcs"
|
|
938
980
|
},
|
|
939
981
|
licenseXhrSetup: (e, t) => {
|
|
940
|
-
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);
|
|
982
|
+
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;
|
|
941
983
|
let o = performance.now();
|
|
942
984
|
e.addEventListener("loadend", () => {
|
|
943
985
|
this.licenseTimeMs = Math.max(1, Math.round(performance.now() - o));
|
|
@@ -951,19 +993,28 @@ var V = class {
|
|
|
951
993
|
} } : {},
|
|
952
994
|
...c
|
|
953
995
|
};
|
|
954
|
-
|
|
996
|
+
qe(d), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.loadStarted = d.autoStartLoad !== !1;
|
|
955
997
|
let f = new e(d);
|
|
956
998
|
this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
|
|
957
|
-
this.mediaRecoveries = 0, this.networkRecoveries = 0
|
|
999
|
+
this.mediaRecoveries = 0, this.networkRecoveries = 0;
|
|
1000
|
+
let e = f.levels.map((e) => e.height).filter((e) => !!e);
|
|
1001
|
+
this.ladderHeights = e.length ? [...new Set(e)].sort((e, t) => e - t) : void 0, this.ladderTopBitrateKbps = f.levels.length ? Math.round(Math.max(...f.levels.map((e) => e.bitrate)) / 1e3) : 0, this.applySizeCap(), l({ type: "ready" });
|
|
958
1002
|
}), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
|
|
959
1003
|
t?.frag?.type === "main" && (this.kickPending = !1, this.kickTicks = 0, (this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0 || this.starvationKicks > 0 || this.starvationRebuilds > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
|
|
960
1004
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
|
|
961
|
-
},
|
|
1005
|
+
}, Me)));
|
|
962
1006
|
}), f.on(e.Events.FRAG_LOADING, (e, t) => {
|
|
963
1007
|
t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
|
|
964
1008
|
}), f.on(e.Events.FRAG_LOADED, (e, t) => {
|
|
965
|
-
let n = t?.frag?.stats?.loaded;
|
|
966
|
-
typeof
|
|
1009
|
+
let n = t?.frag?.stats, r = n?.loaded;
|
|
1010
|
+
typeof r == "number" && (this.bytesLoaded += r);
|
|
1011
|
+
let i = n?.loading;
|
|
1012
|
+
i && i.end > 0 && i.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(i.end - i.start))), this.requestTimesMs.length > Ge && this.requestTimesMs.shift());
|
|
1013
|
+
let a = t?.frag?.url;
|
|
1014
|
+
if (a) {
|
|
1015
|
+
let e = Ke(a);
|
|
1016
|
+
e && (this.cdnHost = e);
|
|
1017
|
+
}
|
|
967
1018
|
}), f.on(e.Events.LEVEL_LOADED, (e, t) => {
|
|
968
1019
|
let n = t?.stats?.loaded;
|
|
969
1020
|
if (typeof n == "number" && (this.playlistBytesLoaded += n), this.detectedLowLatency) return;
|
|
@@ -974,8 +1025,10 @@ var V = class {
|
|
|
974
1025
|
}));
|
|
975
1026
|
}), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
|
|
976
1027
|
this.checkEndStale(), this.checkStarvation();
|
|
977
|
-
},
|
|
978
|
-
this.renditionSwitches += 1
|
|
1028
|
+
}, Pe), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
1029
|
+
this.renditionSwitches += 1;
|
|
1030
|
+
let n = this.lastLevelIndex >= 0 ? f.levels[this.lastLevelIndex] : void 0, r = f.levels[t.level];
|
|
1031
|
+
n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
|
|
979
1032
|
type: "qualitychange",
|
|
980
1033
|
index: t.level
|
|
981
1034
|
});
|
|
@@ -1036,7 +1089,7 @@ var V = class {
|
|
|
1036
1089
|
return;
|
|
1037
1090
|
}
|
|
1038
1091
|
this.capTimer && clearTimeout(this.capTimer);
|
|
1039
|
-
let t = e > this.sizeCapLevel ?
|
|
1092
|
+
let t = e > this.sizeCapLevel ? Be : Ve;
|
|
1040
1093
|
this.capTimer = setTimeout(() => {
|
|
1041
1094
|
this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
|
|
1042
1095
|
}, t);
|
|
@@ -1083,20 +1136,28 @@ var V = class {
|
|
|
1083
1136
|
e.widevine && (this.licenseUrl = e.widevine);
|
|
1084
1137
|
}
|
|
1085
1138
|
getStats() {
|
|
1086
|
-
let e = this.hls, t = {
|
|
1087
|
-
droppedFrames:
|
|
1139
|
+
let e = this.hls, t = F(this.deps.video), n = {
|
|
1140
|
+
droppedFrames: t.dropped,
|
|
1141
|
+
decodedFrames: t.decoded,
|
|
1088
1142
|
lowLatency: this.detectedLowLatency,
|
|
1089
1143
|
bytesLoaded: this.bytesLoaded,
|
|
1090
1144
|
playlistBytesLoaded: this.playlistBytesLoaded,
|
|
1091
1145
|
renditionSwitches: this.renditionSwitches,
|
|
1092
|
-
licenseTimeMs: this.licenseTimeMs
|
|
1146
|
+
licenseTimeMs: this.licenseTimeMs,
|
|
1147
|
+
upshifts: this.upshifts,
|
|
1148
|
+
downshifts: this.downshifts,
|
|
1149
|
+
requestCount: this.requestCount,
|
|
1150
|
+
requestErrors: this.requestErrors,
|
|
1151
|
+
requestTimesMs: [...this.requestTimesMs],
|
|
1152
|
+
ladderHeights: this.ladderHeights,
|
|
1153
|
+
ladderTopBitrateKbps: this.ladderTopBitrateKbps || void 0
|
|
1093
1154
|
};
|
|
1094
|
-
if (e) {
|
|
1095
|
-
typeof e.latency == "number" && (
|
|
1096
|
-
let
|
|
1097
|
-
|
|
1155
|
+
if (this.cdnHost && (n.cdnHost = this.cdnHost), this.licenseRequested && (n.keySystem = "widevine", n.drmSecurityLevel = "L3"), e) {
|
|
1156
|
+
n.qualityPinned = !e.autoLevelEnabled, typeof e.latency == "number" && (n.latencySeconds = e.latency), typeof e.targetLatency == "number" && e.targetLatency > 0 && (n.targetLatencySeconds = e.targetLatency), typeof e.bandwidthEstimate == "number" && (n.bandwidthKbps = Math.round(e.bandwidthEstimate / 1e3));
|
|
1157
|
+
let t = e.currentLevel >= 0 ? e.levels[e.currentLevel] : void 0;
|
|
1158
|
+
t && (n.levelHeight = t.height), t?.videoCodec && (n.videoCodec = t.videoCodec), t?.audioCodec && (n.audioCodec = t.audioCodec), t && typeof t.bitrate == "number" && (n.renditionBitrateKbps = Math.round(t.bitrate / 1e3)), typeof t?.details?.live == "boolean" && (n.isLive = t.details.live, typeof e.liveSyncPosition == "number" && (n.atLiveEdge = this.deps.video.currentTime >= e.liveSyncPosition - 1.5));
|
|
1098
1159
|
}
|
|
1099
|
-
return
|
|
1160
|
+
return n;
|
|
1100
1161
|
}
|
|
1101
1162
|
trackEnd(e) {
|
|
1102
1163
|
let t = e.details;
|
|
@@ -1117,7 +1178,7 @@ var V = class {
|
|
|
1117
1178
|
return;
|
|
1118
1179
|
}
|
|
1119
1180
|
let e = Date.now() - this.lastAdvanceMs;
|
|
1120
|
-
!this.chaseSuspended && e >
|
|
1181
|
+
!this.chaseSuspended && e > z && this.suspendChasing(), e > Ne && this.emitEnded("stalled");
|
|
1121
1182
|
}
|
|
1122
1183
|
checkStarvation() {
|
|
1123
1184
|
let e = this.hls, { video: t } = this.deps;
|
|
@@ -1126,17 +1187,17 @@ var V = class {
|
|
|
1126
1187
|
this.starvedTicks = 0;
|
|
1127
1188
|
return;
|
|
1128
1189
|
}
|
|
1129
|
-
let n = this.lastAdvanceMs !== 0 && Date.now() - this.lastAdvanceMs <
|
|
1190
|
+
let n = this.lastAdvanceMs !== 0 && Date.now() - this.lastAdvanceMs < z, r = this.lastFragLoadingMs !== 0 && Date.now() - this.lastFragLoadingMs > Fe;
|
|
1130
1191
|
if (!(t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused && n && r)) {
|
|
1131
1192
|
this.starvedTicks = 0;
|
|
1132
1193
|
return;
|
|
1133
1194
|
}
|
|
1134
|
-
if (this.kickPending && (this.kickTicks += 1), !(++this.starvedTicks <
|
|
1135
|
-
if (this.starvedTicks = 0, this.kickPending && this.kickTicks >=
|
|
1195
|
+
if (this.kickPending && (this.kickTicks += 1), !(++this.starvedTicks < Ie)) {
|
|
1196
|
+
if (this.starvedTicks = 0, this.kickPending && this.kickTicks >= Re && (this.kickPending = !1, this.kickTicks = 0, this.starvationRebuilds < ze)) {
|
|
1136
1197
|
this.starvationRebuilds += 1, 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");
|
|
1137
1198
|
return;
|
|
1138
1199
|
}
|
|
1139
|
-
if (!(this.starvationKicks >=
|
|
1200
|
+
if (!(this.starvationKicks >= Le)) {
|
|
1140
1201
|
this.starvationKicks += 1, this.kickPending = !0, this.kickTicks = 0, console.warn("havik-player: video starved while the live playlist advances (wedged hls.js fragment pipeline) — restarting the load");
|
|
1141
1202
|
try {
|
|
1142
1203
|
e.stopLoad(), e.startLoad(-1);
|
|
@@ -1186,7 +1247,7 @@ var V = class {
|
|
|
1186
1247
|
scheduleLicenseRetry(t) {
|
|
1187
1248
|
if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
|
|
1188
1249
|
let n = t.response?.code ?? 0;
|
|
1189
|
-
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >=
|
|
1250
|
+
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= je) return !1;
|
|
1190
1251
|
this.licenseRecoveries += 1;
|
|
1191
1252
|
let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
|
|
1192
1253
|
return this.licenseRetryTimer = setTimeout(() => {
|
|
@@ -1204,7 +1265,7 @@ var V = class {
|
|
|
1204
1265
|
}
|
|
1205
1266
|
}
|
|
1206
1267
|
onError(t) {
|
|
1207
|
-
if (!t.fatal) return;
|
|
1268
|
+
if (t.type === e.ErrorTypes.NETWORK_ERROR && String(t.details ?? "").startsWith("frag") && (this.requestErrors += 1), !t.fatal) return;
|
|
1208
1269
|
let n = this.hls;
|
|
1209
1270
|
if (n) {
|
|
1210
1271
|
if (this.clearRecoveryReset(), t.type === e.ErrorTypes.KEY_SYSTEM_ERROR) {
|
|
@@ -1212,12 +1273,13 @@ var V = class {
|
|
|
1212
1273
|
this.deps.emit({
|
|
1213
1274
|
type: "error",
|
|
1214
1275
|
error: this.toError(t, "DRM"),
|
|
1215
|
-
fatal: !0
|
|
1276
|
+
fatal: !0,
|
|
1277
|
+
detail: t.details
|
|
1216
1278
|
});
|
|
1217
1279
|
return;
|
|
1218
1280
|
}
|
|
1219
1281
|
if (t.type === e.ErrorTypes.NETWORK_ERROR) {
|
|
1220
|
-
if (this.networkRecoveries <
|
|
1282
|
+
if (this.networkRecoveries < Ae) {
|
|
1221
1283
|
this.networkRecoveries += 1;
|
|
1222
1284
|
let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
|
|
1223
1285
|
this.networkRetryTimer = setTimeout(() => {
|
|
@@ -1228,26 +1290,29 @@ var V = class {
|
|
|
1228
1290
|
this.deps.emit({
|
|
1229
1291
|
type: "error",
|
|
1230
1292
|
error: this.toError(t, "NETWORK"),
|
|
1231
|
-
fatal: !0
|
|
1293
|
+
fatal: !0,
|
|
1294
|
+
detail: t.details
|
|
1232
1295
|
});
|
|
1233
1296
|
return;
|
|
1234
1297
|
}
|
|
1235
1298
|
if (t.type === e.ErrorTypes.MEDIA_ERROR) {
|
|
1236
|
-
if (this.mediaRecoveries <
|
|
1299
|
+
if (this.mediaRecoveries < ke) {
|
|
1237
1300
|
this.mediaRecoveries += 1, n.recoverMediaError();
|
|
1238
1301
|
return;
|
|
1239
1302
|
}
|
|
1240
1303
|
this.deps.emit({
|
|
1241
1304
|
type: "error",
|
|
1242
1305
|
error: this.toError(t),
|
|
1243
|
-
fatal: !0
|
|
1306
|
+
fatal: !0,
|
|
1307
|
+
detail: t.details
|
|
1244
1308
|
});
|
|
1245
1309
|
return;
|
|
1246
1310
|
}
|
|
1247
1311
|
this.deps.emit({
|
|
1248
1312
|
type: "error",
|
|
1249
1313
|
error: this.toError(t),
|
|
1250
|
-
fatal: !0
|
|
1314
|
+
fatal: !0,
|
|
1315
|
+
detail: t.details
|
|
1251
1316
|
});
|
|
1252
1317
|
}
|
|
1253
1318
|
}
|
|
@@ -1255,7 +1320,29 @@ var V = class {
|
|
|
1255
1320
|
let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
|
|
1256
1321
|
return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
|
|
1257
1322
|
}
|
|
1258
|
-
},
|
|
1323
|
+
}, Ye = 15e3, Xe = 100, V = 1, Ze = 1e3, H = 3e4, Qe = {
|
|
1324
|
+
inline: "PRESENTATION_INLINE",
|
|
1325
|
+
fullscreen: "PRESENTATION_FULLSCREEN",
|
|
1326
|
+
pip: "PRESENTATION_PIP"
|
|
1327
|
+
}, $e = {
|
|
1328
|
+
widevine: "KEY_SYSTEM_WIDEVINE",
|
|
1329
|
+
fairplay: "KEY_SYSTEM_FAIRPLAY",
|
|
1330
|
+
none: "KEY_SYSTEM_NONE"
|
|
1331
|
+
};
|
|
1332
|
+
function U(e, t) {
|
|
1333
|
+
return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
|
|
1334
|
+
}
|
|
1335
|
+
var et = /* @__PURE__ */ new Set([
|
|
1336
|
+
"INVALID_URN",
|
|
1337
|
+
"NOT_FOUND",
|
|
1338
|
+
"GONE",
|
|
1339
|
+
"TOO_EARLY",
|
|
1340
|
+
"UNAVAILABLE",
|
|
1341
|
+
"UNAUTHORIZED",
|
|
1342
|
+
"FORBIDDEN",
|
|
1343
|
+
"RATE_LIMITED",
|
|
1344
|
+
"TIMEOUT"
|
|
1345
|
+
]), W = {
|
|
1259
1346
|
idle: "PLAYER_STATE_IDLE",
|
|
1260
1347
|
waiting: "PLAYER_STATE_WAITING",
|
|
1261
1348
|
loading: "PLAYER_STATE_LOADING",
|
|
@@ -1265,7 +1352,7 @@ var V = class {
|
|
|
1265
1352
|
ended: "PLAYER_STATE_ENDED",
|
|
1266
1353
|
error: "PLAYER_STATE_ERROR"
|
|
1267
1354
|
};
|
|
1268
|
-
function
|
|
1355
|
+
function tt(e) {
|
|
1269
1356
|
try {
|
|
1270
1357
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
1271
1358
|
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);
|
|
@@ -1273,7 +1360,7 @@ function Je(e) {
|
|
|
1273
1360
|
return;
|
|
1274
1361
|
}
|
|
1275
1362
|
}
|
|
1276
|
-
var
|
|
1363
|
+
var nt = class {
|
|
1277
1364
|
opts;
|
|
1278
1365
|
url;
|
|
1279
1366
|
now;
|
|
@@ -1297,50 +1384,133 @@ var Ye = class {
|
|
|
1297
1384
|
errorCount = 0;
|
|
1298
1385
|
seekCount = 0;
|
|
1299
1386
|
pauseCount = 0;
|
|
1387
|
+
isPlaying = !1;
|
|
1388
|
+
isHidden = !1;
|
|
1389
|
+
isMuted = !1;
|
|
1390
|
+
activeSinceMs = null;
|
|
1391
|
+
activeTotalMs = 0;
|
|
1392
|
+
mutedSinceMs = null;
|
|
1393
|
+
mutedTotalMs = 0;
|
|
1394
|
+
lastHbMutedMs = 0;
|
|
1395
|
+
volumeChanges = 0;
|
|
1396
|
+
muteChanges = 0;
|
|
1397
|
+
presentation = "inline";
|
|
1398
|
+
presentationSinceMs;
|
|
1399
|
+
fullscreenTotalMs = 0;
|
|
1400
|
+
pipTotalMs = 0;
|
|
1401
|
+
waitingSinceMs = null;
|
|
1402
|
+
waitingTotalMs = 0;
|
|
1403
|
+
firstAudioMs = 0;
|
|
1404
|
+
timeToFirstStallMs = 0;
|
|
1405
|
+
lastStallMs = 0;
|
|
1406
|
+
lastErrorMs = 0;
|
|
1407
|
+
lastSeekMs = 0;
|
|
1408
|
+
lastErrorStage = null;
|
|
1409
|
+
sawFirstBytes = !1;
|
|
1410
|
+
mediaInfoSignature = "";
|
|
1411
|
+
lastUpshifts = 0;
|
|
1412
|
+
lastDownshifts = 0;
|
|
1413
|
+
lastDecoded = 0;
|
|
1414
|
+
lastRequestCount = 0;
|
|
1415
|
+
lastRequestErrors = 0;
|
|
1416
|
+
pendingStart = null;
|
|
1417
|
+
firstFlushTimer = null;
|
|
1300
1418
|
bornMs;
|
|
1301
1419
|
startupTimeMs = 0;
|
|
1302
1420
|
manifestLoadMs = 0;
|
|
1303
1421
|
firstFragLoadMs = 0;
|
|
1304
1422
|
onPagehide = () => this.end("END_REASON_PAGEHIDE");
|
|
1305
1423
|
onVisibility = () => {
|
|
1306
|
-
typeof document > "u" || (document.visibilityState === "hidden" ? this.hiddenSinceMs === null && (this.hiddenSinceMs = this.now()) : this.hiddenSinceMs !== null && (this.hiddenTotalMs += this.now() - this.hiddenSinceMs, this.hiddenSinceMs = null));
|
|
1424
|
+
typeof document > "u" || (document.visibilityState === "hidden" ? (this.hiddenSinceMs === null && (this.hiddenSinceMs = this.now()), this.isHidden = !0) : (this.hiddenSinceMs !== null && (this.hiddenTotalMs += this.now() - this.hiddenSinceMs, this.hiddenSinceMs = null), this.isHidden = !1), this.syncActive());
|
|
1307
1425
|
};
|
|
1308
1426
|
constructor(e) {
|
|
1309
1427
|
this.opts = {
|
|
1310
1428
|
...e,
|
|
1311
|
-
heartbeatMs: e.heartbeatMs ??
|
|
1312
|
-
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`, this.now = e.now ?? (() => Date.now()), this.bornMs = this.now();
|
|
1429
|
+
heartbeatMs: e.heartbeatMs ?? Ye
|
|
1430
|
+
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`, this.now = e.now ?? (() => Date.now()), this.bornMs = this.now(), this.presentationSinceMs = this.bornMs;
|
|
1313
1431
|
}
|
|
1314
1432
|
start() {
|
|
1315
|
-
|
|
1433
|
+
if (this.endedFlag) return;
|
|
1434
|
+
let e = {
|
|
1316
1435
|
player: this.opts.player,
|
|
1317
|
-
sdkVersion: this.opts.sdkVersion
|
|
1318
|
-
|
|
1436
|
+
sdkVersion: this.opts.sdkVersion,
|
|
1437
|
+
...this.opts.environment
|
|
1438
|
+
};
|
|
1439
|
+
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Ze), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), this.onVisibility());
|
|
1319
1440
|
}
|
|
1320
1441
|
noteStateChange(e, t, n, r) {
|
|
1321
1442
|
if (this.endedFlag || e === t) return;
|
|
1322
1443
|
let i = this.now();
|
|
1323
|
-
t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(
|
|
1444
|
+
t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(V, i - this.bornMs)), this.firstAudioMs === 0 && !this.isMuted && (this.firstAudioMs = Math.max(V, i - this.bornMs)), this.isMuted && this.mutedSinceMs === null && (this.mutedSinceMs = i)) : this.playingSinceMs !== null && (this.playingTotalMs += i - this.playingSinceMs, this.playingSinceMs = null, this.mutedSinceMs !== null && (this.mutedTotalMs += i - this.mutedSinceMs, this.mutedSinceMs = null)), this.isPlaying = t === "playing", this.syncActive(), t === "waiting" ? this.waitingSinceMs = i : this.waitingSinceMs !== null && (this.waitingTotalMs += i - this.waitingSinceMs, this.waitingSinceMs = null), t === "buffering" && e === "playing" ? (this.rebufferCount += 1, this.bufferingSinceMs = i, this.lastStallMs = i, this.timeToFirstStallMs === 0 && (this.timeToFirstStallMs = Math.max(V, Math.round(this.playingTotalMs)))) : e === "buffering" && this.bufferingSinceMs !== null && (this.rebufferTotalMs += i - this.bufferingSinceMs, this.bufferingSinceMs = null), t === "paused" && (this.pauseCount += 1);
|
|
1324
1445
|
let a = {
|
|
1325
|
-
fromState:
|
|
1326
|
-
toState:
|
|
1327
|
-
|
|
1328
|
-
|
|
1446
|
+
fromState: W[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
1447
|
+
toState: W[t] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
1448
|
+
presentation: Qe[this.presentation]
|
|
1449
|
+
}, o = this.causeOf(e, t, i);
|
|
1450
|
+
o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
1451
|
+
}
|
|
1452
|
+
causeOf(e, t, n) {
|
|
1453
|
+
if (t === "error") return "TRANSITION_CAUSE_ERROR";
|
|
1454
|
+
if (t === "buffering") return n - this.lastSeekMs < 1e3 ? "TRANSITION_CAUSE_SEEK" : "TRANSITION_CAUSE_NETWORK_STALL";
|
|
1455
|
+
if (t === "paused" || t === "playing" && e === "paused") return "TRANSITION_CAUSE_USER";
|
|
1456
|
+
}
|
|
1457
|
+
syncActive() {
|
|
1458
|
+
let e = this.isPlaying && !this.isHidden && !this.isMuted;
|
|
1459
|
+
e && this.activeSinceMs === null ? this.activeSinceMs = this.now() : !e && this.activeSinceMs !== null && (this.activeTotalMs += this.now() - this.activeSinceMs, this.activeSinceMs = null);
|
|
1460
|
+
}
|
|
1461
|
+
closePresentation() {
|
|
1462
|
+
let e = this.now(), t = e - this.presentationSinceMs;
|
|
1463
|
+
this.presentation === "fullscreen" ? this.fullscreenTotalMs += t : this.presentation === "pip" && (this.pipTotalMs += t), this.presentationSinceMs = e;
|
|
1464
|
+
}
|
|
1465
|
+
noteAutoplay(e) {
|
|
1466
|
+
this.pendingStart && (this.pendingStart.autoplay = e);
|
|
1467
|
+
}
|
|
1468
|
+
noteEnvironment(e) {
|
|
1469
|
+
this.pendingStart && Object.assign(this.pendingStart, e);
|
|
1470
|
+
}
|
|
1471
|
+
seedVolume(e, t) {
|
|
1472
|
+
this.endedFlag || (this.isMuted = e || t === 0, this.isMuted && this.isPlaying && this.mutedSinceMs === null && (this.mutedSinceMs = this.now()), this.syncActive());
|
|
1473
|
+
}
|
|
1474
|
+
noteVolume(e, t) {
|
|
1475
|
+
if (this.endedFlag) return;
|
|
1476
|
+
let n = e || t === 0;
|
|
1477
|
+
if (n === this.isMuted) {
|
|
1478
|
+
this.volumeChanges += 1;
|
|
1479
|
+
return;
|
|
1480
|
+
}
|
|
1481
|
+
this.muteChanges += 1;
|
|
1482
|
+
let r = this.now();
|
|
1483
|
+
n ? this.isPlaying && this.mutedSinceMs === null && (this.mutedSinceMs = r) : (this.mutedSinceMs !== null && (this.mutedTotalMs += r - this.mutedSinceMs, this.mutedSinceMs = null), this.firstAudioMs === 0 && this.isPlaying && (this.firstAudioMs = Math.max(V, r - this.bornMs))), this.isMuted = n, this.syncActive();
|
|
1484
|
+
}
|
|
1485
|
+
notePresentation(e) {
|
|
1486
|
+
this.endedFlag || e === this.presentation || (this.closePresentation(), this.presentation = e);
|
|
1329
1487
|
}
|
|
1330
1488
|
noteReady() {
|
|
1331
|
-
this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(
|
|
1489
|
+
this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(V, this.now() - this.bornMs));
|
|
1332
1490
|
}
|
|
1333
1491
|
noteFirstBytes() {
|
|
1334
|
-
this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(
|
|
1492
|
+
this.sawFirstBytes = !0, this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(V, this.now() - this.bornMs));
|
|
1335
1493
|
}
|
|
1336
1494
|
noteSeek() {
|
|
1337
|
-
this.endedFlag || (this.seekCount += 1);
|
|
1495
|
+
this.endedFlag || (this.seekCount += 1, this.lastSeekMs = this.now());
|
|
1338
1496
|
}
|
|
1339
|
-
noteError(e, t, n, r, i) {
|
|
1497
|
+
noteError(e, t, n, r, i, a) {
|
|
1340
1498
|
if (this.endedFlag) return;
|
|
1341
|
-
this.errorCount += 1;
|
|
1342
|
-
let
|
|
1343
|
-
t && (
|
|
1499
|
+
this.errorCount += 1, this.lastErrorMs = this.now();
|
|
1500
|
+
let o = { code: e };
|
|
1501
|
+
t && (o.detail = t), n && (o.fatal = !0), r > 0 && (o.httpStatus = r), i > 0 && (o.positionMs = Math.round(i));
|
|
1502
|
+
let s = this.stageOf(e, t, a);
|
|
1503
|
+
o.stage = s, this.lastErrorStage = s;
|
|
1504
|
+
let c = this.safeSample()?.cdnHost;
|
|
1505
|
+
c && (o.cdnHost = c), this.enqueue({ error: o }), this.flush();
|
|
1506
|
+
}
|
|
1507
|
+
stageOf(e, t, n) {
|
|
1508
|
+
let r = n ?? "";
|
|
1509
|
+
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";
|
|
1510
|
+
if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
|
|
1511
|
+
if (et.has(e)) return "ERROR_STAGE_RESOLVE";
|
|
1512
|
+
let i = t ?? "";
|
|
1513
|
+
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";
|
|
1344
1514
|
}
|
|
1345
1515
|
noteEnded() {
|
|
1346
1516
|
this.end("END_REASON_ENDED");
|
|
@@ -1364,25 +1534,51 @@ var Ye = class {
|
|
|
1364
1534
|
let s = e.droppedFrames ?? 0;
|
|
1365
1535
|
s > this.lastDropped && (i.droppedFramesDelta = s - this.lastDropped), this.lastDropped = s;
|
|
1366
1536
|
let c = e.renditionSwitches ?? 0;
|
|
1367
|
-
c > this.lastSwitches && (i.renditionSwitchesDelta = c - this.lastSwitches), this.lastSwitches = c, n > this.lastHbPlayingMs && (i.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (i.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, typeof e.latencySeconds == "number" && (i.latencyMs = Math.round(e.latencySeconds * 1e3)), typeof e.targetLatencySeconds == "number" && (i.targetLatencyMs = Math.round(e.targetLatencySeconds * 1e3)), typeof e.bandwidthKbps == "number" && (i.bandwidthEstKbps = e.bandwidthKbps), typeof e.levelHeight == "number" && (i.renditionHeight = e.levelHeight), typeof e.renditionBitrateKbps == "number" && (i.renditionBitrateKbps = e.renditionBitrateKbps), e.atLiveEdge === !0 && (i.atLiveEdge = !0);
|
|
1368
|
-
let l = this.
|
|
1369
|
-
|
|
1537
|
+
c > this.lastSwitches && (i.renditionSwitchesDelta = c - this.lastSwitches), this.lastSwitches = c, n > this.lastHbPlayingMs && (i.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (i.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, typeof e.latencySeconds == "number" && (i.latencyMs = Math.round(e.latencySeconds * 1e3)), typeof e.targetLatencySeconds == "number" && (i.targetLatencyMs = Math.round(e.targetLatencySeconds * 1e3)), typeof e.bandwidthKbps == "number" && (i.bandwidthEstKbps = e.bandwidthKbps), typeof e.levelHeight == "number" && (i.renditionHeight = e.levelHeight), typeof e.renditionBitrateKbps == "number" && (i.renditionBitrateKbps = e.renditionBitrateKbps), e.atLiveEdge === !0 && (i.atLiveEdge = !0), typeof e.bufferedMs == "number" && e.bufferedMs > 0 && (i.bufferedMs = Math.round(e.bufferedMs)), i.playerState = W[e.state] ?? "PLAYER_STATE_UNSPECIFIED";
|
|
1538
|
+
let l = this.mutedTotalMs;
|
|
1539
|
+
this.mutedSinceMs !== null && (l += t - this.mutedSinceMs), l > this.lastHbMutedMs && (i.mutedMsDelta = Math.round(l - this.lastHbMutedMs)), this.lastHbMutedMs = l;
|
|
1540
|
+
let u = e.upshifts ?? 0;
|
|
1541
|
+
u > this.lastUpshifts && (i.upshiftsDelta = u - this.lastUpshifts), this.lastUpshifts = u;
|
|
1542
|
+
let d = e.downshifts ?? 0;
|
|
1543
|
+
d > this.lastDownshifts && (i.downshiftsDelta = d - this.lastDownshifts), this.lastDownshifts = d;
|
|
1544
|
+
let f = e.decodedFrames ?? 0;
|
|
1545
|
+
f > this.lastDecoded && (i.decodedFramesDelta = f - this.lastDecoded), this.lastDecoded = f;
|
|
1546
|
+
let p = e.requestErrors ?? 0;
|
|
1547
|
+
p > this.lastRequestErrors && (i.requestErrorsDelta = p - this.lastRequestErrors), this.lastRequestErrors = p;
|
|
1548
|
+
let m = e.requestCount ?? 0, h = m - this.lastRequestCount;
|
|
1549
|
+
if (this.lastRequestCount = m, h > 0) {
|
|
1550
|
+
i.requestCountDelta = h;
|
|
1551
|
+
let t = e.requestTimesMs ?? [], n = t.slice(Math.max(0, t.length - h)).sort((e, t) => e - t);
|
|
1552
|
+
n.length > 0 && (i.requestTimeP50Ms = U(n, 50), i.requestTimeP95Ms = U(n, 95));
|
|
1553
|
+
}
|
|
1554
|
+
typeof e.latencySeconds == "number" && typeof e.targetLatencySeconds == "number" && (i.driftMs = Math.round((e.latencySeconds - e.targetLatencySeconds) * 1e3)), typeof e.playbackRate == "number" && e.playbackRate > 0 && (i.playbackRate = e.playbackRate), e.qualityPinned === !0 && (i.qualityPinned = !0), e.cdnHost && (i.cdnHost = e.cdnHost), this.maybeEmitMediaInfo(e), this.enqueue({ heartbeat: i }), this.flush(), a > 0 && this.noteFirstBytes();
|
|
1370
1555
|
}
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1556
|
+
maybeEmitMediaInfo(e) {
|
|
1557
|
+
if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
|
|
1558
|
+
let t = {};
|
|
1559
|
+
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = $e[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);
|
|
1560
|
+
let n = JSON.stringify(t);
|
|
1561
|
+
n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
|
|
1374
1562
|
}
|
|
1375
1563
|
end(e) {
|
|
1376
1564
|
if (this.endedFlag) return;
|
|
1377
1565
|
this.endedFlag = !0;
|
|
1378
1566
|
let t = this.now();
|
|
1379
|
-
this.playingSinceMs !== null && (this.playingTotalMs += t - this.playingSinceMs, this.playingSinceMs = null), this.hiddenSinceMs !== null && (this.hiddenTotalMs += t - this.hiddenSinceMs, this.hiddenSinceMs = null), this.bufferingSinceMs !== null && (this.rebufferTotalMs += t - this.bufferingSinceMs, this.bufferingSinceMs = null), this.timer &&= (clearInterval(this.timer), null), typeof window < "u" && window.removeEventListener("pagehide", this.onPagehide), typeof document < "u" && document.removeEventListener("visibilitychange", this.onVisibility);
|
|
1380
|
-
let n = this.safeSample()
|
|
1567
|
+
this.playingSinceMs !== null && (this.playingTotalMs += t - this.playingSinceMs, this.playingSinceMs = null), this.hiddenSinceMs !== null && (this.hiddenTotalMs += t - this.hiddenSinceMs, this.hiddenSinceMs = null), this.bufferingSinceMs !== null && (this.rebufferTotalMs += t - this.bufferingSinceMs, this.bufferingSinceMs = null), this.mutedSinceMs !== null && (this.mutedTotalMs += t - this.mutedSinceMs, this.mutedSinceMs = null), this.waitingSinceMs !== null && (this.waitingTotalMs += t - this.waitingSinceMs, this.waitingSinceMs = null), this.isPlaying = !1, this.syncActive(), this.closePresentation(), this.firstFlushTimer &&= (clearTimeout(this.firstFlushTimer), null), this.timer &&= (clearInterval(this.timer), null), typeof window < "u" && window.removeEventListener("pagehide", this.onPagehide), typeof document < "u" && document.removeEventListener("visibilitychange", this.onVisibility);
|
|
1568
|
+
let n = this.safeSample();
|
|
1569
|
+
n && this.maybeEmitMediaInfo(n);
|
|
1570
|
+
let r = { reason: e }, i = n?.bytesLoaded ?? this.lastBytes;
|
|
1381
1571
|
i > 0 && (r.bytesDownloadedTotal = i), this.playingTotalMs > 0 && (r.watchTimeMs = Math.round(this.playingTotalMs)), this.rebufferCount > 0 && (r.rebufferCount = this.rebufferCount), this.rebufferTotalMs > 0 && (r.rebufferTimeMs = Math.round(this.rebufferTotalMs)), this.startupTimeMs > 0 && (r.startupTimeMs = Math.round(this.startupTimeMs)), this.manifestLoadMs > 0 && (r.manifestLoadMs = Math.round(this.manifestLoadMs)), this.firstFragLoadMs > 0 && (r.firstFragLoadMs = Math.round(this.firstFragLoadMs));
|
|
1382
1572
|
let a = n?.licenseTimeMs ?? 0;
|
|
1383
1573
|
a > 0 && (r.licenseTimeMs = Math.round(a));
|
|
1384
1574
|
let o = n?.droppedFrames ?? this.lastDropped;
|
|
1385
|
-
o > 0 && (r.droppedFramesTotal = o), this.errorCount > 0 && (r.errorCount = this.errorCount), this.hiddenTotalMs > 0 && (r.hiddenTimeMs = Math.round(this.hiddenTotalMs)), this.seekCount > 0 && (r.seekCount = this.seekCount), this.pauseCount > 0 && (r.pauseCount = this.pauseCount), this.
|
|
1575
|
+
o > 0 && (r.droppedFramesTotal = o), this.errorCount > 0 && (r.errorCount = this.errorCount), this.hiddenTotalMs > 0 && (r.hiddenTimeMs = Math.round(this.hiddenTotalMs)), this.seekCount > 0 && (r.seekCount = this.seekCount), this.pauseCount > 0 && (r.pauseCount = this.pauseCount), this.firstAudioMs > 0 && (r.firstAudioMs = Math.round(this.firstAudioMs)), this.waitingTotalMs > 0 && (r.waitingForLiveMs = Math.round(this.waitingTotalMs)), this.timeToFirstStallMs > 0 && (r.timeToFirstStallMs = Math.round(this.timeToFirstStallMs));
|
|
1576
|
+
let s = n?.positionMs ?? 0;
|
|
1577
|
+
s > 0 && (r.exitPositionMs = Math.round(s)), this.activeTotalMs > 0 && (r.activeWatchTimeMs = Math.round(this.activeTotalMs)), this.mutedTotalMs > 0 && (r.mutedTimeMs = Math.round(this.mutedTotalMs));
|
|
1578
|
+
let c = e !== "END_REASON_ENDED";
|
|
1579
|
+
c && this.lastStallMs > 0 && t - this.lastStallMs <= H && (r.abandonAfterStallMs = Math.max(V, Math.round(t - this.lastStallMs))), c && this.lastErrorMs > 0 && t - this.lastErrorMs <= H && (r.abandonAfterErrorMs = Math.max(V, Math.round(t - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (r.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (r.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (r.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (r.muteChanges = this.muteChanges);
|
|
1580
|
+
let l = n?.decodedFrames ?? this.lastDecoded;
|
|
1581
|
+
l > 0 && (r.decodedFramesTotal = l), this.startupTimeMs === 0 && (r.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: r })), this.flush(e === "END_REASON_PAGEHIDE");
|
|
1386
1582
|
}
|
|
1387
1583
|
safeSample() {
|
|
1388
1584
|
try {
|
|
@@ -1400,13 +1596,13 @@ var Ye = class {
|
|
|
1400
1596
|
};
|
|
1401
1597
|
}
|
|
1402
1598
|
enqueue(e) {
|
|
1403
|
-
for (this.pending.push(this.wrap(e)); this.pending.length >
|
|
1599
|
+
for (this.pending.push(this.wrap(e)); this.pending.length > Xe;) {
|
|
1404
1600
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
1405
1601
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
1406
1602
|
}
|
|
1407
1603
|
}
|
|
1408
1604
|
flush(e = !1) {
|
|
1409
|
-
if (this.pending.length === 0) return;
|
|
1605
|
+
if (this.firstFlushTimer &&= (clearTimeout(this.firstFlushTimer), null), this.pendingStart = null, this.pending.length === 0) return;
|
|
1410
1606
|
let t = JSON.stringify({ beacons: this.pending });
|
|
1411
1607
|
if (this.pending = [], e) {
|
|
1412
1608
|
let e = this.opts.sendBeacon ?? (typeof navigator < "u" && navigator.sendBeacon ? navigator.sendBeacon.bind(navigator) : void 0);
|
|
@@ -1422,7 +1618,74 @@ var Ye = class {
|
|
|
1422
1618
|
keepalive: !0
|
|
1423
1619
|
}).catch(() => {});
|
|
1424
1620
|
}
|
|
1425
|
-
}
|
|
1621
|
+
};
|
|
1622
|
+
//#endregion
|
|
1623
|
+
//#region src/core/environment.ts
|
|
1624
|
+
function rt() {
|
|
1625
|
+
if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
|
|
1626
|
+
let e;
|
|
1627
|
+
try {
|
|
1628
|
+
e = window.top !== window.self;
|
|
1629
|
+
} catch {
|
|
1630
|
+
e = !0;
|
|
1631
|
+
}
|
|
1632
|
+
let t = window.location?.origin;
|
|
1633
|
+
if (!e) return {
|
|
1634
|
+
host: t && t !== "null" ? t : void 0,
|
|
1635
|
+
integration: "INTEGRATION_KIND_SDK"
|
|
1636
|
+
};
|
|
1637
|
+
let n;
|
|
1638
|
+
try {
|
|
1639
|
+
let e = window.location.ancestorOrigins;
|
|
1640
|
+
e && e.length > 0 && (n = e[e.length - 1] ?? void 0), !n && typeof document < "u" && document.referrer && (n = new URL(document.referrer).origin);
|
|
1641
|
+
} catch {
|
|
1642
|
+
n = void 0;
|
|
1643
|
+
}
|
|
1644
|
+
return n === "null" && (n = void 0), {
|
|
1645
|
+
host: n,
|
|
1646
|
+
integration: "INTEGRATION_KIND_IFRAME"
|
|
1647
|
+
};
|
|
1648
|
+
}
|
|
1649
|
+
function it() {
|
|
1650
|
+
if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
|
|
1651
|
+
let e = navigator.userAgentData, t = e?.platform ?? "";
|
|
1652
|
+
if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
|
|
1653
|
+
let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
|
|
1654
|
+
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";
|
|
1655
|
+
}
|
|
1656
|
+
function at() {
|
|
1657
|
+
let e = typeof navigator < "u" ? navigator.connection : void 0;
|
|
1658
|
+
if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
|
|
1659
|
+
let t = { connectionType: e.type ? {
|
|
1660
|
+
wifi: "CONNECTION_TYPE_WIFI",
|
|
1661
|
+
cellular: "CONNECTION_TYPE_CELLULAR",
|
|
1662
|
+
ethernet: "CONNECTION_TYPE_ETHERNET"
|
|
1663
|
+
}[e.type] ?? "CONNECTION_TYPE_OTHER" : "CONNECTION_TYPE_UNKNOWN" };
|
|
1664
|
+
return typeof e.downlink == "number" && e.downlink > 0 && (t.downlinkKbps = Math.round(e.downlink * 1e3)), e.saveData && (t.saveData = !0), t;
|
|
1665
|
+
}
|
|
1666
|
+
function ot(e) {
|
|
1667
|
+
let t = rt(), n = {
|
|
1668
|
+
deviceClass: it(),
|
|
1669
|
+
integration: t.integration,
|
|
1670
|
+
...at()
|
|
1671
|
+
};
|
|
1672
|
+
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);
|
|
1673
|
+
let r = e.getBoundingClientRect?.();
|
|
1674
|
+
return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
|
|
1675
|
+
}
|
|
1676
|
+
async function st() {
|
|
1677
|
+
let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
|
|
1678
|
+
if (!e?.getHighEntropyValues) return {};
|
|
1679
|
+
try {
|
|
1680
|
+
let t = await e.getHighEntropyValues(["model", "platformVersion"]), n = {};
|
|
1681
|
+
return t.model && (n.deviceModel = t.model), t.platformVersion && (n.osVersion = t.platformVersion), n;
|
|
1682
|
+
} catch {
|
|
1683
|
+
return {};
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
//#endregion
|
|
1687
|
+
//#region src/core/version.ts
|
|
1688
|
+
var ct = "2.1.0", G = {
|
|
1426
1689
|
accent: "#E1B600",
|
|
1427
1690
|
accentText: "#1B1C23",
|
|
1428
1691
|
background: "#0e0f13",
|
|
@@ -1433,7 +1696,7 @@ var Ye = class {
|
|
|
1433
1696
|
border: "rgba(255, 255, 255, 0.1)",
|
|
1434
1697
|
radius: "8px",
|
|
1435
1698
|
fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
|
|
1436
|
-
},
|
|
1699
|
+
}, K = {
|
|
1437
1700
|
accent: "--havik-accent",
|
|
1438
1701
|
accentText: "--havik-accent-text",
|
|
1439
1702
|
background: "--havik-bg",
|
|
@@ -1445,25 +1708,25 @@ var Ye = class {
|
|
|
1445
1708
|
radius: "--havik-radius",
|
|
1446
1709
|
fontFamily: "--havik-font"
|
|
1447
1710
|
};
|
|
1448
|
-
function
|
|
1711
|
+
function q(e, t) {
|
|
1449
1712
|
let n = {
|
|
1450
|
-
...
|
|
1713
|
+
...G,
|
|
1451
1714
|
...t
|
|
1452
1715
|
};
|
|
1453
|
-
for (let t of Object.keys(
|
|
1716
|
+
for (let t of Object.keys(K)) e.style.setProperty(K[t], n[t]);
|
|
1454
1717
|
n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
|
|
1455
1718
|
}
|
|
1456
1719
|
//#endregion
|
|
1457
1720
|
//#region src/ui/styles.ts
|
|
1458
|
-
var
|
|
1459
|
-
function
|
|
1460
|
-
if (e.getElementById(
|
|
1721
|
+
var J = "havik-player-styles", lt = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n.havik-spinner{width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n";
|
|
1722
|
+
function ut(e = document) {
|
|
1723
|
+
if (e.getElementById(J)) return;
|
|
1461
1724
|
let t = e.createElement("style");
|
|
1462
|
-
t.id =
|
|
1725
|
+
t.id = J, t.textContent = lt, e.head.appendChild(t);
|
|
1463
1726
|
}
|
|
1464
1727
|
//#endregion
|
|
1465
1728
|
//#region src/ui/icons.ts
|
|
1466
|
-
var
|
|
1729
|
+
var dt = {
|
|
1467
1730
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
1468
1731
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
1469
1732
|
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\"/>",
|
|
@@ -1476,21 +1739,21 @@ var $e = {
|
|
|
1476
1739
|
liveDot: "<circle cx=\"12\" cy=\"12\" r=\"6\"/>",
|
|
1477
1740
|
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\"/>"
|
|
1478
1741
|
};
|
|
1479
|
-
function
|
|
1480
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
1742
|
+
function Y(e) {
|
|
1743
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${dt[e]}</svg>`;
|
|
1481
1744
|
}
|
|
1482
1745
|
//#endregion
|
|
1483
1746
|
//#region src/ui/controls.ts
|
|
1484
|
-
var
|
|
1747
|
+
var ft = 3e3, pt = /* @__PURE__ */ new Set([
|
|
1485
1748
|
"GONE",
|
|
1486
1749
|
"NOT_FOUND",
|
|
1487
1750
|
"INVALID_URN",
|
|
1488
1751
|
"UNAUTHORIZED"
|
|
1489
1752
|
]);
|
|
1490
|
-
function
|
|
1491
|
-
return new
|
|
1753
|
+
function mt(e) {
|
|
1754
|
+
return new ht(e);
|
|
1492
1755
|
}
|
|
1493
|
-
var
|
|
1756
|
+
var ht = class {
|
|
1494
1757
|
root;
|
|
1495
1758
|
video;
|
|
1496
1759
|
player;
|
|
@@ -1532,7 +1795,7 @@ var rt = class {
|
|
|
1532
1795
|
scrubbing = !1;
|
|
1533
1796
|
offFns = [];
|
|
1534
1797
|
constructor(e) {
|
|
1535
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
1798
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? ft, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, ut(this.doc), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
|
|
1536
1799
|
let t = (e, t, n) => {
|
|
1537
1800
|
let r = this.doc.createElement(e);
|
|
1538
1801
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -1543,12 +1806,12 @@ var rt = class {
|
|
|
1543
1806
|
"aria-label": r,
|
|
1544
1807
|
title: r
|
|
1545
1808
|
});
|
|
1546
|
-
return i.innerHTML =
|
|
1809
|
+
return i.innerHTML = Y(n), i;
|
|
1547
1810
|
};
|
|
1548
1811
|
this.overlay = t("div", "havik-overlay"), this.center = t("button", "havik-center", {
|
|
1549
1812
|
type: "button",
|
|
1550
1813
|
"aria-label": "Play"
|
|
1551
|
-
}), this.center.innerHTML =
|
|
1814
|
+
}), this.center.innerHTML = Y("play"), this.spinner = t("div", "havik-spinner"), this.spinner.style.display = "none", this.overlay.append(this.center, this.spinner), this.gradient = t("div", "havik-gradient"), this.bar = t("div", "havik-bar"), this.seek = t("div", "havik-seek", {
|
|
1552
1815
|
role: "slider",
|
|
1553
1816
|
"aria-label": "Seek",
|
|
1554
1817
|
"aria-valuemin": "0",
|
|
@@ -1566,7 +1829,7 @@ var rt = class {
|
|
|
1566
1829
|
"aria-label": "Volume"
|
|
1567
1830
|
});
|
|
1568
1831
|
let a = t("div", "havik-vol");
|
|
1569
|
-
a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML =
|
|
1832
|
+
a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML = Y("liveDot");
|
|
1570
1833
|
let o = this.doc.createElement("span");
|
|
1571
1834
|
o.textContent = "LIVE", this.liveGo = t("button", "havik-live__go", { type: "button" }), this.liveGo.textContent = "Go live", this.live.append(o, this.liveGo), this.time = t("div", "havik-time"), this.time.textContent = "0:00", this.time.style.display = "none";
|
|
1572
1835
|
let s = t("div", "havik-spacer");
|
|
@@ -1620,12 +1883,12 @@ var rt = class {
|
|
|
1620
1883
|
}
|
|
1621
1884
|
if (e === "preplay") {
|
|
1622
1885
|
let e = this.doc.createElement("button");
|
|
1623
|
-
e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML =
|
|
1886
|
+
e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = Y("play"), e.addEventListener("click", () => void this.player.play()), n.append(e);
|
|
1624
1887
|
} else {
|
|
1625
1888
|
let r = this.doc.createElement("div");
|
|
1626
|
-
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !
|
|
1889
|
+
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !pt.has(this.lastError.code)) {
|
|
1627
1890
|
let e = this.doc.createElement("button");
|
|
1628
|
-
e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${
|
|
1891
|
+
e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${Y("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), n.append(e);
|
|
1629
1892
|
}
|
|
1630
1893
|
}
|
|
1631
1894
|
this.root.append(n), this.statusBox = n, this.show();
|
|
@@ -1664,7 +1927,7 @@ var rt = class {
|
|
|
1664
1927
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
1665
1928
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
1666
1929
|
}
|
|
1667
|
-
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${
|
|
1930
|
+
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${X(this.video.currentTime)} / ${X(this.video.duration)}`);
|
|
1668
1931
|
}
|
|
1669
1932
|
syncLive() {
|
|
1670
1933
|
let e = this.player.getStats(), t = e.isLive !== !1;
|
|
@@ -1714,17 +1977,17 @@ var rt = class {
|
|
|
1714
1977
|
renderQualityMenu() {
|
|
1715
1978
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
1716
1979
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
1717
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
1980
|
+
for (let n of e) this.menu.append(this.menuItem(gt(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
1718
1981
|
}
|
|
1719
1982
|
renderAudioMenu() {
|
|
1720
1983
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
1721
1984
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
1722
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
1985
|
+
for (let t of e) this.menu.append(this.menuItem(_t(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
1723
1986
|
}
|
|
1724
1987
|
renderCcMenu() {
|
|
1725
1988
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
1726
1989
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
1727
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
1990
|
+
for (let t of e) this.menu.append(this.menuItem(vt(t), !1, () => this.player.setTextTrack(t.id)));
|
|
1728
1991
|
}
|
|
1729
1992
|
onTracksChanged() {
|
|
1730
1993
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -1807,7 +2070,7 @@ var rt = class {
|
|
|
1807
2070
|
}
|
|
1808
2071
|
}
|
|
1809
2072
|
setIcon(e, t) {
|
|
1810
|
-
e.innerHTML =
|
|
2073
|
+
e.innerHTML = Y(t);
|
|
1811
2074
|
}
|
|
1812
2075
|
destroy() {
|
|
1813
2076
|
this.hideTimer && clearTimeout(this.hideTimer);
|
|
@@ -1824,32 +2087,32 @@ var rt = class {
|
|
|
1824
2087
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
1825
2088
|
}
|
|
1826
2089
|
};
|
|
1827
|
-
function
|
|
2090
|
+
function X(e) {
|
|
1828
2091
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
1829
2092
|
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");
|
|
1830
2093
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
1831
2094
|
}
|
|
1832
|
-
function
|
|
2095
|
+
function gt(e) {
|
|
1833
2096
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
1834
2097
|
}
|
|
1835
|
-
function
|
|
2098
|
+
function _t(e) {
|
|
1836
2099
|
return e.name || e.lang || `Track ${e.id}`;
|
|
1837
2100
|
}
|
|
1838
|
-
function
|
|
2101
|
+
function vt(e) {
|
|
1839
2102
|
return e.name || e.lang || `Track ${e.id}`;
|
|
1840
2103
|
}
|
|
1841
2104
|
//#endregion
|
|
1842
2105
|
//#region src/managed/index.ts
|
|
1843
|
-
var
|
|
1844
|
-
async function
|
|
2106
|
+
var yt = 6e3, Z = 45e3, Q = 2e3, bt = 3, xt = 2e3, St = 48e4;
|
|
2107
|
+
async function Ct(e) {
|
|
1845
2108
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
1846
2109
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: baseUrl is required");
|
|
1847
2110
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
1848
2111
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
1849
|
-
let t = new
|
|
2112
|
+
let t = new wt(e);
|
|
1850
2113
|
return await t.start(), t;
|
|
1851
2114
|
}
|
|
1852
|
-
var
|
|
2115
|
+
var wt = class {
|
|
1853
2116
|
opts;
|
|
1854
2117
|
abort = new AbortController();
|
|
1855
2118
|
listeners = {};
|
|
@@ -1873,7 +2136,9 @@ var dt = class {
|
|
|
1873
2136
|
armFallbackCtrl = null;
|
|
1874
2137
|
_lastError = null;
|
|
1875
2138
|
analyticsSession = null;
|
|
1876
|
-
|
|
2139
|
+
detachMediaListeners;
|
|
2140
|
+
playRequested = !1;
|
|
2141
|
+
pendingStartLoad = !1;
|
|
1877
2142
|
constructor(e) {
|
|
1878
2143
|
this.opts = e;
|
|
1879
2144
|
}
|
|
@@ -1934,7 +2199,7 @@ var dt = class {
|
|
|
1934
2199
|
setTimeout(() => {
|
|
1935
2200
|
a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
1936
2201
|
phase: i ? "unavailable" : "tooEarly",
|
|
1937
|
-
retryInMs:
|
|
2202
|
+
retryInMs: Z,
|
|
1938
2203
|
attempt: 1,
|
|
1939
2204
|
elapsedMs: 0,
|
|
1940
2205
|
...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
|
|
@@ -1973,13 +2238,13 @@ var dt = class {
|
|
|
1973
2238
|
!a && !p() && h();
|
|
1974
2239
|
}, e);
|
|
1975
2240
|
};
|
|
1976
|
-
_(
|
|
2241
|
+
_(yt), this.armingSub = D({
|
|
1977
2242
|
eventsBaseUrl: t,
|
|
1978
2243
|
matchUrn: this.opts.matchUrn,
|
|
1979
2244
|
credential: this.opts.credential,
|
|
1980
|
-
onAlive: () => _(
|
|
2245
|
+
onAlive: () => _(Z),
|
|
1981
2246
|
onState: (e) => {
|
|
1982
|
-
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() *
|
|
2247
|
+
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Q);
|
|
1983
2248
|
},
|
|
1984
2249
|
onError: () => h()
|
|
1985
2250
|
});
|
|
@@ -2002,49 +2267,61 @@ var dt = class {
|
|
|
2002
2267
|
let n = await s(this.opts.credential);
|
|
2003
2268
|
if (this.destroyed || t !== this.loadGen) return;
|
|
2004
2269
|
this.setState("loading");
|
|
2005
|
-
let r = this.createEngine(e, n),
|
|
2270
|
+
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = Te(this.opts.video, (e) => {
|
|
2006
2271
|
this._state !== "ended" && this._state !== "error" && this.setState(e);
|
|
2007
2272
|
});
|
|
2008
|
-
if (await
|
|
2009
|
-
|
|
2273
|
+
if (await i.load(), this.destroyed || t !== this.loadGen) {
|
|
2274
|
+
a(), i.destroy();
|
|
2010
2275
|
return;
|
|
2011
2276
|
}
|
|
2012
2277
|
if (this._state === "error") {
|
|
2013
|
-
|
|
2278
|
+
a(), i.destroy();
|
|
2014
2279
|
return;
|
|
2015
2280
|
}
|
|
2016
|
-
this.engine =
|
|
2281
|
+
this.engine = i, this.detachMedia = a, this.opts.maxBitrate != null && i.setMaxBitrate(this.opts.maxBitrate), this.startStats(), this.scheduleLicenseRefresh(), this.startLiveState(t), this.startAnalytics(e, i, n.apiKey), r && (this.pendingStartLoad = !0, this.setState("paused"), i.name === "native" && setTimeout(() => {
|
|
2282
|
+
this.destroyed || t !== this.loadGen || this.engine !== i || (this.analyticsSession?.noteReady(), this.emit("ready"));
|
|
2283
|
+
}, 0));
|
|
2017
2284
|
}
|
|
2018
2285
|
startAnalytics(e, t, n) {
|
|
2019
|
-
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.
|
|
2286
|
+
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
|
|
2020
2287
|
let r = e.analytics?.sid;
|
|
2021
2288
|
if (!r) return;
|
|
2022
|
-
let i = (typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0) ??
|
|
2289
|
+
let i = (typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0) ?? tt(this.opts.baseUrl);
|
|
2023
2290
|
if (!i) return;
|
|
2024
|
-
let a = this.opts.video, o = new
|
|
2291
|
+
let a = this.opts.video, o = new nt({
|
|
2025
2292
|
endpoint: i,
|
|
2026
2293
|
sid: r,
|
|
2027
2294
|
apiKey: n,
|
|
2028
2295
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
2029
|
-
sdkVersion:
|
|
2296
|
+
sdkVersion: ct,
|
|
2297
|
+
environment: ot(a),
|
|
2030
2298
|
sample: () => {
|
|
2031
|
-
let e = this.engine?.getStats() ??
|
|
2299
|
+
let e = this.engine?.getStats() ?? we, t = a.buffered.length ? Math.max(0, a.buffered.end(a.buffered.length - 1) - a.currentTime) : 0;
|
|
2032
2300
|
return {
|
|
2033
2301
|
...e,
|
|
2034
2302
|
bufferedMs: Math.round(t * 1e3),
|
|
2035
2303
|
state: this._state,
|
|
2036
|
-
positionMs: Math.round(a.currentTime * 1e3)
|
|
2304
|
+
positionMs: Math.round(a.currentTime * 1e3),
|
|
2305
|
+
playbackRate: a.playbackRate
|
|
2037
2306
|
};
|
|
2038
2307
|
}
|
|
2039
2308
|
});
|
|
2040
2309
|
this.analyticsSession = o;
|
|
2041
|
-
let s = () => o.noteSeek();
|
|
2042
|
-
a.addEventListener("seeking", s),
|
|
2310
|
+
let s = () => o.noteSeek(), c = () => o.noteVolume(a.muted, a.volume);
|
|
2311
|
+
a.addEventListener("seeking", s), a.addEventListener("volumechange", c), this.detachMediaListeners = () => {
|
|
2312
|
+
a.removeEventListener("seeking", s), a.removeEventListener("volumechange", c);
|
|
2313
|
+
}, o.start(), o.seedVolume(a.muted, a.volume), o.notePresentation(this.currentPresentation()), st().then((e) => o.noteEnvironment(e)), this.opts.autoplay === !1 && o.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
|
|
2043
2314
|
}
|
|
2044
|
-
|
|
2045
|
-
let
|
|
2046
|
-
|
|
2047
|
-
let
|
|
2315
|
+
currentPresentation() {
|
|
2316
|
+
let e = this.opts.video;
|
|
2317
|
+
if (typeof document < "u" && document.pictureInPictureElement === e) return "pip";
|
|
2318
|
+
let t = typeof document < "u" ? document.fullscreenElement : null;
|
|
2319
|
+
return e.webkitDisplayingFullscreen === !0 || t && (t === e || t.contains(e)) ? "fullscreen" : "inline";
|
|
2320
|
+
}
|
|
2321
|
+
createEngine(e, t, r = !1) {
|
|
2322
|
+
let i = { ...this.opts.hlsConfig };
|
|
2323
|
+
this.opts.startLevel != null && (i.startLevel = this.opts.startLevel), this.opts.liveLatencyTarget != null && (i.liveSyncDuration = this.opts.liveLatencyTarget);
|
|
2324
|
+
let a = {
|
|
2048
2325
|
video: this.opts.video,
|
|
2049
2326
|
descriptor: e,
|
|
2050
2327
|
credential: t,
|
|
@@ -2053,20 +2330,21 @@ var dt = class {
|
|
|
2053
2330
|
lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
|
|
2054
2331
|
snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
|
|
2055
2332
|
debug: this.opts.debug,
|
|
2056
|
-
|
|
2333
|
+
deferLoad: r,
|
|
2334
|
+
hlsConfig: i,
|
|
2057
2335
|
emit: (e) => this.onEngineEvent(e)
|
|
2058
|
-
},
|
|
2059
|
-
if (
|
|
2060
|
-
if (
|
|
2061
|
-
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl &&
|
|
2062
|
-
if (
|
|
2063
|
-
if (
|
|
2336
|
+
}, o = this.opts.engine ?? "auto";
|
|
2337
|
+
if (o === "native") return new R(a);
|
|
2338
|
+
if (o === "hls") return new B(a);
|
|
2339
|
+
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && I(this.opts.video) && L()) return new R(a);
|
|
2340
|
+
if (Oe()) return new B(a);
|
|
2341
|
+
if (I(this.opts.video)) return new R(a);
|
|
2064
2342
|
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
2065
2343
|
}
|
|
2066
2344
|
onEngineEvent(e) {
|
|
2067
2345
|
if (!this.destroyed) switch (e.type) {
|
|
2068
2346
|
case "ready":
|
|
2069
|
-
this.analyticsSession?.noteReady(), this.emit("ready"), this.opts.autoplay !== !1 && this.play();
|
|
2347
|
+
this.analyticsSession?.noteReady(), this.emit("ready"), (this.opts.autoplay !== !1 || this.playRequested) && this.play();
|
|
2070
2348
|
break;
|
|
2071
2349
|
case "lowLatencyDetected":
|
|
2072
2350
|
this._descriptor && (this._descriptor.isLowLatency = e.value);
|
|
@@ -2083,7 +2361,7 @@ var dt = class {
|
|
|
2083
2361
|
case "ended":
|
|
2084
2362
|
this.onStreamEnded();
|
|
2085
2363
|
break;
|
|
2086
|
-
case "error": this.analyticsSession?.noteError(e.error.code, e.error.message, e.fatal, e.error.httpStatus ?? 0, Math.round(this.opts.video.currentTime * 1e3)), e.fatal ? this.fail(e.error) : this.emit("warning", e.error);
|
|
2364
|
+
case "error": this.analyticsSession?.noteError(e.error.code, e.error.message, e.fatal, e.error.httpStatus ?? 0, Math.round(this.opts.video.currentTime * 1e3), e.detail), e.fatal ? this.fail(e.error) : this.emit("warning", e.error);
|
|
2087
2365
|
}
|
|
2088
2366
|
}
|
|
2089
2367
|
startLiveState(e) {
|
|
@@ -2103,7 +2381,7 @@ var dt = class {
|
|
|
2103
2381
|
r = 0, i = !1;
|
|
2104
2382
|
},
|
|
2105
2383
|
onError: () => {
|
|
2106
|
-
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >=
|
|
2384
|
+
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= bt && (i = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${r} attempts — end-of-stream detection degraded to the HLS staleness watchdog. Check the events host, the api-key's allowed origins, and CSP connect-src.`))));
|
|
2107
2385
|
}
|
|
2108
2386
|
});
|
|
2109
2387
|
}
|
|
@@ -2116,7 +2394,7 @@ var dt = class {
|
|
|
2116
2394
|
t === "match_ended" && this._endedReason !== "match_ended" && (this._endedReason = t, this.emit("ended", t));
|
|
2117
2395
|
return;
|
|
2118
2396
|
}
|
|
2119
|
-
this.endedHandled = !0, this._endedReason = t ?? null, this.stopRefresh(), this.engine?.stop(), this.setState("ended");
|
|
2397
|
+
this.endedHandled = !0, this._endedReason = t ?? null, this.stopRefresh(), this.pendingStartLoad = !1, this.engine?.stop(), this.setState("ended");
|
|
2120
2398
|
}
|
|
2121
2399
|
}
|
|
2122
2400
|
rejoinEnabled() {
|
|
@@ -2125,7 +2403,7 @@ var dt = class {
|
|
|
2125
2403
|
scheduleRejoin(e) {
|
|
2126
2404
|
!this.rejoinEnabled() || this.rejoinTimer || (this.rejoinTimer = setTimeout(() => {
|
|
2127
2405
|
this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
|
|
2128
|
-
}, Math.random() *
|
|
2406
|
+
}, Math.random() * Q));
|
|
2129
2407
|
}
|
|
2130
2408
|
cancelRejoin() {
|
|
2131
2409
|
this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
|
|
@@ -2135,7 +2413,7 @@ var dt = class {
|
|
|
2135
2413
|
this.teardownPlayback(), this.setState("waiting"), this.beginArming(e, void 0, !0);
|
|
2136
2414
|
}
|
|
2137
2415
|
teardownPlayback() {
|
|
2138
|
-
this.stopStats(), this.stopRefresh(), this.cancelRejoin(), this.closeArming(), this.closeLiveState(), this.detachMedia?.(), this.engine?.destroy(), this.engine = null;
|
|
2416
|
+
this.stopStats(), this.stopRefresh(), this.cancelRejoin(), this.closeArming(), this.closeLiveState(), this.detachMedia?.(), this.engine?.destroy(), this.engine = null, this.pendingStartLoad = !1;
|
|
2139
2417
|
}
|
|
2140
2418
|
mountControls() {
|
|
2141
2419
|
let e = this.opts.controls ?? "custom", t = this.opts.video;
|
|
@@ -2149,7 +2427,7 @@ var dt = class {
|
|
|
2149
2427
|
}
|
|
2150
2428
|
t.controls = !1;
|
|
2151
2429
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
2152
|
-
r && r.insertBefore(n, t), n.appendChild(t),
|
|
2430
|
+
r && r.insertBefore(n, t), n.appendChild(t), q(n, this.opts.theme), this.container = n, this.controlBar = mt({
|
|
2153
2431
|
root: n,
|
|
2154
2432
|
video: t,
|
|
2155
2433
|
player: this,
|
|
@@ -2166,14 +2444,20 @@ var dt = class {
|
|
|
2166
2444
|
e && (e.parentNode ? (e.parentNode.insertBefore(this.opts.video, e), e.remove()) : this.opts.video.parentNode === e && e.removeChild(this.opts.video)), this.container = null;
|
|
2167
2445
|
}
|
|
2168
2446
|
attachPipListeners() {
|
|
2169
|
-
let e = this.opts.video, t = () => this.
|
|
2170
|
-
|
|
2171
|
-
|
|
2447
|
+
let e = this.opts.video, t = () => this.analyticsSession?.notePresentation(this.currentPresentation()), n = () => {
|
|
2448
|
+
t(), this.emit("pipchange", !0);
|
|
2449
|
+
}, r = () => {
|
|
2450
|
+
t(), this.emit("pipchange", !1);
|
|
2451
|
+
};
|
|
2452
|
+
e.addEventListener("enterpictureinpicture", n), e.addEventListener("leavepictureinpicture", r);
|
|
2453
|
+
let i = typeof document < "u" ? document : void 0;
|
|
2454
|
+
i?.addEventListener("fullscreenchange", t), i?.addEventListener("webkitfullscreenchange", t), this.detachPip = () => {
|
|
2455
|
+
e.removeEventListener("enterpictureinpicture", n), e.removeEventListener("leavepictureinpicture", r), i?.removeEventListener("fullscreenchange", t), i?.removeEventListener("webkitfullscreenchange", t);
|
|
2172
2456
|
};
|
|
2173
2457
|
}
|
|
2174
2458
|
startStats() {
|
|
2175
2459
|
this.stopStats();
|
|
2176
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
2460
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? xt);
|
|
2177
2461
|
this.statsTimer = setInterval(() => {
|
|
2178
2462
|
if (!this.engine) return;
|
|
2179
2463
|
let e = this.engine.getStats();
|
|
@@ -2185,7 +2469,7 @@ var dt = class {
|
|
|
2185
2469
|
}
|
|
2186
2470
|
scheduleLicenseRefresh() {
|
|
2187
2471
|
this.stopRefresh();
|
|
2188
|
-
let e = this.opts.licenseRefreshMs ??
|
|
2472
|
+
let e = this.opts.licenseRefreshMs ?? St;
|
|
2189
2473
|
!e || !this._descriptor?.drmEnabled || (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
2190
2474
|
}
|
|
2191
2475
|
stopRefresh() {
|
|
@@ -2206,10 +2490,15 @@ var dt = class {
|
|
|
2206
2490
|
}
|
|
2207
2491
|
}
|
|
2208
2492
|
async play() {
|
|
2209
|
-
if (
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2493
|
+
if (this.destroyed) return;
|
|
2494
|
+
let e = !this.playRequested;
|
|
2495
|
+
this.playRequested = !0;
|
|
2496
|
+
let t = this.pendingStartLoad && this._state !== "ended" && this._state !== "error";
|
|
2497
|
+
t && (this.pendingStartLoad = !1, this.setState("loading"), this.engine?.startLoad());
|
|
2498
|
+
try {
|
|
2499
|
+
await this.opts.video.play(), e && this.analyticsSession?.noteAutoplay(this.opts.video.muted ? "AUTOPLAY_RESULT_ALLOWED_MUTED" : "AUTOPLAY_RESULT_ALLOWED");
|
|
2500
|
+
} catch (n) {
|
|
2501
|
+
n instanceof DOMException && n.name === "NotAllowedError" && (this.analyticsSession?.noteAutoplay("AUTOPLAY_RESULT_BLOCKED"), e && (this.playRequested = !1), t && !this.destroyed && this._state === "loading" && this.setState("paused"), this.emit("autoplayblocked"));
|
|
2213
2502
|
}
|
|
2214
2503
|
}
|
|
2215
2504
|
pause() {
|
|
@@ -2222,7 +2511,7 @@ var dt = class {
|
|
|
2222
2511
|
this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
|
|
2223
2512
|
}
|
|
2224
2513
|
getStats() {
|
|
2225
|
-
return this.engine?.getStats() ??
|
|
2514
|
+
return this.engine?.getStats() ?? we;
|
|
2226
2515
|
}
|
|
2227
2516
|
getQualityLevels() {
|
|
2228
2517
|
return this.engine?.getQualityLevels() ?? [];
|
|
@@ -2289,7 +2578,7 @@ var dt = class {
|
|
|
2289
2578
|
return n.add(t), () => n.delete(t);
|
|
2290
2579
|
}
|
|
2291
2580
|
destroy() {
|
|
2292
|
-
this.destroyed || (this.destroyed = !0, this.loadGen += 1, this.abort.abort(), this.stopStats(), this.stopRefresh(), this.unmountControls(), this.cancelRejoin(), this.closeArming(), this.closeLiveState(), this.detachMedia?.(), this.detachPip?.(), this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.
|
|
2581
|
+
this.destroyed || (this.destroyed = !0, this.loadGen += 1, this.abort.abort(), this.stopStats(), this.stopRefresh(), this.unmountControls(), this.cancelRejoin(), this.closeArming(), this.closeLiveState(), this.detachMedia?.(), this.detachPip?.(), this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.engine?.destroy(), this.engine = null, this.setState("idle"), this.clearListeners());
|
|
2293
2582
|
}
|
|
2294
2583
|
clearListeners() {
|
|
2295
2584
|
for (let e of Object.keys(this.listeners)) this.listeners[e]?.clear();
|
|
@@ -2332,7 +2621,7 @@ function $(e) {
|
|
|
2332
2621
|
}
|
|
2333
2622
|
//#endregion
|
|
2334
2623
|
//#region src/embed/host.ts
|
|
2335
|
-
function
|
|
2624
|
+
function Tt(e) {
|
|
2336
2625
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
2337
2626
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
2338
2627
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -2391,8 +2680,8 @@ function ft(e) {
|
|
|
2391
2680
|
}
|
|
2392
2681
|
//#endregion
|
|
2393
2682
|
//#region src/embed/page.ts
|
|
2394
|
-
var
|
|
2395
|
-
function
|
|
2683
|
+
var Et = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
2684
|
+
function Dt() {
|
|
2396
2685
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
2397
2686
|
if (e) return {
|
|
2398
2687
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -2414,9 +2703,9 @@ function mt() {
|
|
|
2414
2703
|
waitForLive: !0
|
|
2415
2704
|
};
|
|
2416
2705
|
}
|
|
2417
|
-
async function
|
|
2418
|
-
let e =
|
|
2419
|
-
|
|
2706
|
+
async function Ot() {
|
|
2707
|
+
let e = Dt();
|
|
2708
|
+
At();
|
|
2420
2709
|
let t = document.createElement("video");
|
|
2421
2710
|
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);
|
|
2422
2711
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -2471,12 +2760,12 @@ async function ht() {
|
|
|
2471
2760
|
code: e.code,
|
|
2472
2761
|
message: e.message
|
|
2473
2762
|
})), e.on("autoplayblocked", () => {
|
|
2474
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
2763
|
+
i({ type: "oddin:autoplayblocked" }), kt(t, e);
|
|
2475
2764
|
});
|
|
2476
2765
|
}, s = async (r) => {
|
|
2477
2766
|
a?.destroy(), a = null;
|
|
2478
2767
|
try {
|
|
2479
|
-
let n = await
|
|
2768
|
+
let n = await Ct({
|
|
2480
2769
|
video: t,
|
|
2481
2770
|
baseUrl: e.baseUrl,
|
|
2482
2771
|
matchUrn: r,
|
|
@@ -2537,7 +2826,7 @@ async function ht() {
|
|
|
2537
2826
|
a?.retry();
|
|
2538
2827
|
break;
|
|
2539
2828
|
case "oddin:load":
|
|
2540
|
-
typeof e.matchUrn == "string" &&
|
|
2829
|
+
typeof e.matchUrn == "string" && Et.test(e.matchUrn) && s(e.matchUrn);
|
|
2541
2830
|
break;
|
|
2542
2831
|
case "oddin:destroy": c();
|
|
2543
2832
|
}
|
|
@@ -2549,18 +2838,18 @@ async function ht() {
|
|
|
2549
2838
|
protocol: 1
|
|
2550
2839
|
});
|
|
2551
2840
|
}
|
|
2552
|
-
function
|
|
2841
|
+
function kt(e, t) {
|
|
2553
2842
|
if (document.getElementById("havik-tap")) return;
|
|
2554
2843
|
let n = document.createElement("button");
|
|
2555
2844
|
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", () => {
|
|
2556
2845
|
n.remove(), t.play();
|
|
2557
2846
|
}), document.body.appendChild(n);
|
|
2558
2847
|
}
|
|
2559
|
-
function
|
|
2848
|
+
function At() {
|
|
2560
2849
|
let e = document.createElement("style");
|
|
2561
2850
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
2562
2851
|
}
|
|
2563
2852
|
//#endregion
|
|
2564
|
-
export {
|
|
2853
|
+
export { G as ODDIN_THEME, n as PlaybackError, q as applyTheme, Ot as bootEmbed, he as clearDeviceId, Ct as createPlayer, O as deriveEventsBaseUrl, xe as detectDrmSupport, T as enterVideoFullscreen, E as exitVideoFullscreen, le as fetchCatalog, de as fetchTournament, pe as flattenMatches, j as getDeviceId, Ce as isLowLatencyManifest, $ as isOddinMessage, _e as licenseRequestHeaders, Tt as mountEmbed, v as pollToLive, b as resolveStream, D as subscribeLiveState, w as videoFullscreenActive, me as watchStatus };
|
|
2565
2854
|
|
|
2566
2855
|
//# sourceMappingURL=index.js.map
|