@oddin-gg/havik-player 2.16.4 → 2.16.6
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.js +314 -260
- package/dist/index.js.map +1 -1
- package/docs/API.md +15 -1
- package/embed/index.html +1 -1
- package/examples/vanilla.html +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -174,7 +174,7 @@ function ue(e, t) {
|
|
|
174
174
|
t?.addEventListener("abort", a, { once: !0 });
|
|
175
175
|
});
|
|
176
176
|
}
|
|
177
|
-
async function
|
|
177
|
+
async function v(e, t, r) {
|
|
178
178
|
let i = ae(t), a = Date.now(), s = i.timeoutMs == null ? Infinity : a + i.timeoutMs, c = 0, l;
|
|
179
179
|
for (;;) {
|
|
180
180
|
if (r?.aborted) throw new n("ABORTED", 0, "wait-for-live aborted");
|
|
@@ -200,21 +200,21 @@ async function de(e, t, r) {
|
|
|
200
200
|
}
|
|
201
201
|
//#endregion
|
|
202
202
|
//#region src/core/resolve.ts
|
|
203
|
-
async function
|
|
203
|
+
async function y(e) {
|
|
204
204
|
if (!e.matchUrn || typeof e.matchUrn != "string") throw new n("INVALID_URN", 0, "resolveStream: a non-empty matchUrn is required");
|
|
205
205
|
let t = await p(d(e.baseUrl, `/v1/playback/${encodeURIComponent(e.matchUrn)}`), {
|
|
206
206
|
credential: e.credential,
|
|
207
207
|
signal: e.signal,
|
|
208
208
|
apiHeaders: e.apiHeaders
|
|
209
209
|
});
|
|
210
|
-
if (!t.ok) throw await
|
|
211
|
-
return
|
|
210
|
+
if (!t.ok) throw await de(t);
|
|
211
|
+
return me(await t.json(), e.matchUrn);
|
|
212
212
|
}
|
|
213
|
-
function
|
|
214
|
-
let t = () =>
|
|
215
|
-
return e.waitForLive ?
|
|
213
|
+
function b(e) {
|
|
214
|
+
let t = () => y(e);
|
|
215
|
+
return e.waitForLive ? v(t, e.waitForLive, e.signal) : t();
|
|
216
216
|
}
|
|
217
|
-
async function
|
|
217
|
+
async function de(e) {
|
|
218
218
|
let t = f(e.headers.get("retry-after")), i = e.headers.get("x-request-id") ?? e.headers.get("x-amzn-requestid") ?? void 0, a = e.statusText || `HTTP ${e.status}`, o, s;
|
|
219
219
|
try {
|
|
220
220
|
let t = await e.json();
|
|
@@ -230,7 +230,7 @@ async function fe(e) {
|
|
|
230
230
|
liveStartsAtMs: s
|
|
231
231
|
});
|
|
232
232
|
}
|
|
233
|
-
var
|
|
233
|
+
var fe = /* @__PURE__ */ new Set([
|
|
234
234
|
"matchUrn",
|
|
235
235
|
"protocol",
|
|
236
236
|
"drmEnabled",
|
|
@@ -241,7 +241,7 @@ var pe = /* @__PURE__ */ new Set([
|
|
|
241
241
|
"expiresAt",
|
|
242
242
|
"analytics"
|
|
243
243
|
]);
|
|
244
|
-
function
|
|
244
|
+
function x(e, t) {
|
|
245
245
|
let r;
|
|
246
246
|
try {
|
|
247
247
|
r = new URL(t);
|
|
@@ -251,7 +251,7 @@ function b(e, t) {
|
|
|
251
251
|
if (r.protocol !== "https:" && r.protocol !== "http:") throw new n("INTERNAL", 0, `playback ${e} has a disallowed scheme: ${r.protocol}`);
|
|
252
252
|
return t;
|
|
253
253
|
}
|
|
254
|
-
function
|
|
254
|
+
function pe(e) {
|
|
255
255
|
if (e !== void 0) {
|
|
256
256
|
if (typeof e == "string" && !e.endsWith("/")) try {
|
|
257
257
|
let t = new URL(e);
|
|
@@ -260,41 +260,41 @@ function me(e) {
|
|
|
260
260
|
g(`server analytics.endpoint ${JSON.stringify(e)} ignored: not a bare https origin.`);
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
|
-
function
|
|
263
|
+
function me(e, t) {
|
|
264
264
|
if (!e.manifestUrl) throw new n("INTERNAL", 0, "playback response is missing manifestUrl");
|
|
265
265
|
let r = e.drmEnabled ?? !!e.drm, i = {
|
|
266
266
|
matchUrn: e.matchUrn ?? t,
|
|
267
267
|
protocol: "hls",
|
|
268
268
|
drmEnabled: r,
|
|
269
|
-
manifestUrl:
|
|
269
|
+
manifestUrl: x("manifestUrl", e.manifestUrl),
|
|
270
270
|
serverTime: e.serverTime ?? ""
|
|
271
271
|
};
|
|
272
272
|
if (e.liveStartsAt && (i.liveStartsAt = e.liveStartsAt), typeof e.analytics?.sid == "string" && e.analytics.sid) {
|
|
273
273
|
i.analytics = { sid: e.analytics.sid };
|
|
274
|
-
let t =
|
|
274
|
+
let t = pe(e.analytics.endpoint);
|
|
275
275
|
t && (i.analytics.endpoint = t);
|
|
276
276
|
}
|
|
277
277
|
if (r && e.drm) {
|
|
278
278
|
let t = {};
|
|
279
|
-
e.drm.widevine?.licenseUrl && (t.widevine = { licenseUrl:
|
|
280
|
-
licenseUrl:
|
|
281
|
-
certificateUrl:
|
|
279
|
+
e.drm.widevine?.licenseUrl && (t.widevine = { licenseUrl: x("widevine licenseUrl", e.drm.widevine.licenseUrl) }), e.drm.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && (t.fairplay = {
|
|
280
|
+
licenseUrl: x("fairplay licenseUrl", e.drm.fairplay.licenseUrl),
|
|
281
|
+
certificateUrl: x("fairplay certificateUrl", e.drm.fairplay.certificateUrl)
|
|
282
282
|
}), (t.widevine || t.fairplay) && (i.drm = t);
|
|
283
283
|
}
|
|
284
284
|
let a = {};
|
|
285
|
-
for (let [t, n] of Object.entries(e))
|
|
285
|
+
for (let [t, n] of Object.entries(e)) fe.has(t) || (a[t] = n);
|
|
286
286
|
return Object.keys(a).length > 0 && (i.extensions = a), i;
|
|
287
287
|
}
|
|
288
288
|
//#endregion
|
|
289
289
|
//#region src/core/fullscreen.ts
|
|
290
|
-
function
|
|
290
|
+
function he(e) {
|
|
291
291
|
return e.ownerDocument ?? document;
|
|
292
292
|
}
|
|
293
|
-
function
|
|
293
|
+
function ge(e) {
|
|
294
294
|
return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
|
|
295
295
|
}
|
|
296
296
|
function S(e, t) {
|
|
297
|
-
let n =
|
|
297
|
+
let n = ge(he(e));
|
|
298
298
|
return n != null && (n === e || t != null && n === t) || e.webkitDisplayingFullscreen === !0;
|
|
299
299
|
}
|
|
300
300
|
async function C(e, t) {
|
|
@@ -310,7 +310,7 @@ async function w(e, t) {
|
|
|
310
310
|
n.webkitExitFullscreen?.();
|
|
311
311
|
return;
|
|
312
312
|
}
|
|
313
|
-
let r =
|
|
313
|
+
let r = he(e), i = ge(r);
|
|
314
314
|
i != null && (i === e || t != null && i === t) && (typeof r.exitFullscreen == "function" ? await r.exitFullscreen() : r.webkitExitFullscreen?.());
|
|
315
315
|
}
|
|
316
316
|
//#endregion
|
|
@@ -671,14 +671,14 @@ function I(e) {
|
|
|
671
671
|
function L(e) {
|
|
672
672
|
return (e ?? "").trim().toLowerCase();
|
|
673
673
|
}
|
|
674
|
-
var
|
|
674
|
+
var R = {
|
|
675
675
|
hevc: "hvc1.1.6.L93.90",
|
|
676
676
|
dv: "dvh1.05.06",
|
|
677
677
|
av1: "av01.0.05M.08",
|
|
678
678
|
vp9: "vp09.00.10.08"
|
|
679
|
-
},
|
|
680
|
-
function
|
|
681
|
-
let t = L(e), n =
|
|
679
|
+
}, z = /* @__PURE__ */ new Map(), B = /* @__PURE__ */ new Map();
|
|
680
|
+
function je(e) {
|
|
681
|
+
let t = L(e), n = z.get(t);
|
|
682
682
|
if (n) return n;
|
|
683
683
|
let r = {
|
|
684
684
|
initDataTypes: ["cenc"],
|
|
@@ -696,23 +696,23 @@ function Ne(e) {
|
|
|
696
696
|
} catch {
|
|
697
697
|
return !1;
|
|
698
698
|
}
|
|
699
|
-
})().then((e) => (
|
|
700
|
-
return
|
|
699
|
+
})().then((e) => (B.set(t, e), e));
|
|
700
|
+
return z.set(t, i), i;
|
|
701
701
|
}
|
|
702
|
-
function
|
|
703
|
-
if (j()) for (let e of Object.values(
|
|
702
|
+
function Me() {
|
|
703
|
+
if (j()) for (let e of Object.values(R)) je(e);
|
|
704
704
|
}
|
|
705
|
-
function
|
|
705
|
+
function Ne(e) {
|
|
706
706
|
let t = I(e);
|
|
707
|
-
if (t) return t === "avc" ? !0 :
|
|
707
|
+
if (t) return t === "avc" ? !0 : B.get(L(e)) ?? B.get(L(R[t]));
|
|
708
708
|
}
|
|
709
709
|
//#endregion
|
|
710
710
|
//#region src/core/drm/support.ts
|
|
711
|
-
var
|
|
711
|
+
var Pe = 5e3, Fe = "video/mp4; codecs=\"avc1.42E01E\"", Ie = "audio/mp4; codecs=\"mp4a.40.2\"", Le = {
|
|
712
712
|
widevine: ["com.widevine.alpha"],
|
|
713
713
|
fairplay: ["com.apple.fps"]
|
|
714
714
|
};
|
|
715
|
-
function
|
|
715
|
+
function Re(e) {
|
|
716
716
|
return e === "fairplay" ? [{
|
|
717
717
|
initDataTypes: [
|
|
718
718
|
"sinf",
|
|
@@ -720,30 +720,30 @@ function Be(e) {
|
|
|
720
720
|
"cenc"
|
|
721
721
|
],
|
|
722
722
|
videoCapabilities: [{
|
|
723
|
-
contentType:
|
|
723
|
+
contentType: Fe,
|
|
724
724
|
robustness: "",
|
|
725
725
|
encryptionScheme: "cbcs"
|
|
726
726
|
}],
|
|
727
727
|
audioCapabilities: [{
|
|
728
|
-
contentType:
|
|
728
|
+
contentType: Ie,
|
|
729
729
|
robustness: "",
|
|
730
730
|
encryptionScheme: "cbcs"
|
|
731
731
|
}]
|
|
732
732
|
}] : N("com.widevine.alpha", [{
|
|
733
733
|
initDataTypes: ["cenc"],
|
|
734
734
|
videoCapabilities: [{
|
|
735
|
-
contentType:
|
|
735
|
+
contentType: Fe,
|
|
736
736
|
robustness: F.video,
|
|
737
737
|
encryptionScheme: F.scheme
|
|
738
738
|
}],
|
|
739
739
|
audioCapabilities: [{
|
|
740
|
-
contentType:
|
|
740
|
+
contentType: Ie,
|
|
741
741
|
robustness: F.audio,
|
|
742
742
|
encryptionScheme: F.scheme
|
|
743
743
|
}]
|
|
744
744
|
}]);
|
|
745
745
|
}
|
|
746
|
-
function
|
|
746
|
+
function ze(e, t) {
|
|
747
747
|
return new Promise((n, r) => {
|
|
748
748
|
let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
|
|
749
749
|
e.then((e) => {
|
|
@@ -753,8 +753,8 @@ function Ve(e, t) {
|
|
|
753
753
|
});
|
|
754
754
|
});
|
|
755
755
|
}
|
|
756
|
-
async function
|
|
757
|
-
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ??
|
|
756
|
+
async function Be(e = {}) {
|
|
757
|
+
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Pe, r = {};
|
|
758
758
|
if (typeof window < "u" && window.isSecureContext === !1) return {
|
|
759
759
|
verdict: "insecure-context",
|
|
760
760
|
detail: r
|
|
@@ -766,7 +766,7 @@ async function He(e = {}) {
|
|
|
766
766
|
};
|
|
767
767
|
let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
|
|
768
768
|
for (let e of t) {
|
|
769
|
-
let t =
|
|
769
|
+
let t = Le[e];
|
|
770
770
|
if (!t) {
|
|
771
771
|
r[e] = "unknown system";
|
|
772
772
|
continue;
|
|
@@ -777,7 +777,7 @@ async function He(e = {}) {
|
|
|
777
777
|
break;
|
|
778
778
|
}
|
|
779
779
|
try {
|
|
780
|
-
return await
|
|
780
|
+
return await ze((await ze(i(n, Re(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
|
|
781
781
|
verdict: "supported",
|
|
782
782
|
system: e,
|
|
783
783
|
detail: r
|
|
@@ -801,25 +801,25 @@ async function He(e = {}) {
|
|
|
801
801
|
}
|
|
802
802
|
//#endregion
|
|
803
803
|
//#region src/core/manifest.ts
|
|
804
|
-
var
|
|
805
|
-
function
|
|
806
|
-
return
|
|
804
|
+
var Ve = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
|
|
805
|
+
function He(e) {
|
|
806
|
+
return Ve.test(e);
|
|
807
807
|
}
|
|
808
808
|
//#endregion
|
|
809
809
|
//#region src/core/env.ts
|
|
810
|
-
var
|
|
810
|
+
var Ue = {
|
|
811
811
|
integration: "https://feed-dev.oddin-video.gg",
|
|
812
812
|
production: "https://feed.oddin-video.gg"
|
|
813
813
|
};
|
|
814
|
-
function
|
|
815
|
-
let t = Object.prototype.hasOwnProperty.call(
|
|
814
|
+
function We(e) {
|
|
815
|
+
let t = Object.prototype.hasOwnProperty.call(Ue, e) ? Ue[e] : void 0;
|
|
816
816
|
if (!t) throw new n("INTERNAL", 0, `unknown env ${JSON.stringify(e)} — expected 'integration' or 'production'`);
|
|
817
817
|
return t;
|
|
818
818
|
}
|
|
819
819
|
//#endregion
|
|
820
820
|
//#region src/core/stats.ts
|
|
821
|
-
var
|
|
822
|
-
function
|
|
821
|
+
var Ge = { droppedFrames: 0 };
|
|
822
|
+
function Ke(e) {
|
|
823
823
|
try {
|
|
824
824
|
return new URL(e).host;
|
|
825
825
|
} catch {
|
|
@@ -831,7 +831,7 @@ function Je(e) {
|
|
|
831
831
|
if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
|
|
832
832
|
let t = "", n = -1, r = performance.getEntriesByType("resource");
|
|
833
833
|
for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || qe.test(i.name)) && i.startTime >= n) {
|
|
834
|
-
let e =
|
|
834
|
+
let e = Ke(i.name);
|
|
835
835
|
e && (t = e, n = i.startTime);
|
|
836
836
|
}
|
|
837
837
|
return t;
|
|
@@ -843,7 +843,7 @@ function V(e) {
|
|
|
843
843
|
totalFrames: t?.totalVideoFrames ?? 0
|
|
844
844
|
};
|
|
845
845
|
}
|
|
846
|
-
var
|
|
846
|
+
var Ye = class {
|
|
847
847
|
video;
|
|
848
848
|
baseFrames = 0;
|
|
849
849
|
baseDropped = 0;
|
|
@@ -866,7 +866,7 @@ var H = class {
|
|
|
866
866
|
};
|
|
867
867
|
}
|
|
868
868
|
};
|
|
869
|
-
function
|
|
869
|
+
function Xe(e, t) {
|
|
870
870
|
let n = [
|
|
871
871
|
["playing", () => t("playing")],
|
|
872
872
|
["waiting", () => t("buffering")],
|
|
@@ -883,8 +883,8 @@ function Ye(e, t) {
|
|
|
883
883
|
}
|
|
884
884
|
//#endregion
|
|
885
885
|
//#region src/core/engine/native.ts
|
|
886
|
-
var
|
|
887
|
-
function
|
|
886
|
+
var Ze = 2e3, Qe = 3, H = 500, $e = 6e3, et = .25;
|
|
887
|
+
function tt(e) {
|
|
888
888
|
try {
|
|
889
889
|
let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
|
|
890
890
|
return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
|
|
@@ -892,20 +892,20 @@ function et(e) {
|
|
|
892
892
|
return;
|
|
893
893
|
}
|
|
894
894
|
}
|
|
895
|
-
function
|
|
895
|
+
function U(e) {
|
|
896
896
|
return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
|
|
897
897
|
}
|
|
898
|
-
function
|
|
898
|
+
function W() {
|
|
899
899
|
if (typeof window > "u") return !1;
|
|
900
900
|
let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
|
|
901
901
|
return e || t;
|
|
902
902
|
}
|
|
903
|
-
function
|
|
904
|
-
if (typeof navigator > "u" || !
|
|
903
|
+
function nt() {
|
|
904
|
+
if (typeof navigator > "u" || !W()) return !1;
|
|
905
905
|
let e = navigator.userAgent ?? "";
|
|
906
906
|
return /iPhone|iPad|iPod/.test(e) ? !0 : /Macintosh/.test(e) && typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1;
|
|
907
907
|
}
|
|
908
|
-
var
|
|
908
|
+
var G = class {
|
|
909
909
|
name = "native";
|
|
910
910
|
deps;
|
|
911
911
|
onLoaded;
|
|
@@ -927,7 +927,7 @@ var K = class {
|
|
|
927
927
|
frameCounter;
|
|
928
928
|
detachFrames = null;
|
|
929
929
|
constructor(e) {
|
|
930
|
-
this.deps = e, this.frameCounter = new
|
|
930
|
+
this.deps = e, this.frameCounter = new Ye(e.video), this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
|
|
931
931
|
}
|
|
932
932
|
async load() {
|
|
933
933
|
this.detachFrames ??= this.frameCounter.attach();
|
|
@@ -948,7 +948,7 @@ var K = class {
|
|
|
948
948
|
type: "error",
|
|
949
949
|
error: new n("INTERNAL", 0, "native HLS playback error"),
|
|
950
950
|
fatal: !0
|
|
951
|
-
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src =
|
|
951
|
+
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = rt(t.manifestUrl, t.analytics?.sid), e.load();
|
|
952
952
|
}
|
|
953
953
|
startLoad() {
|
|
954
954
|
this.loadStarted || (this.loadStarted = !0, this.restorePreload());
|
|
@@ -970,7 +970,7 @@ var K = class {
|
|
|
970
970
|
});
|
|
971
971
|
this.onEncrypted = (n) => {
|
|
972
972
|
let i = n;
|
|
973
|
-
i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV =
|
|
973
|
+
i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = tt(i.initData), (async () => {
|
|
974
974
|
try {
|
|
975
975
|
let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
|
|
976
976
|
initDataTypes: [i.initDataType],
|
|
@@ -1092,7 +1092,7 @@ var K = class {
|
|
|
1092
1092
|
return;
|
|
1093
1093
|
}
|
|
1094
1094
|
let t = this.hiddenSince;
|
|
1095
|
-
this.hiddenSince = null, t != null && e - t >=
|
|
1095
|
+
this.hiddenSince = null, t != null && e - t >= Ze && this.armRefocus();
|
|
1096
1096
|
}, this.onPageShow = (e) => {
|
|
1097
1097
|
e.persisted && this.armRefocus();
|
|
1098
1098
|
}, document.addEventListener("visibilitychange", this.onVisibility), typeof window < "u" && window.addEventListener("pageshow", this.onPageShow));
|
|
@@ -1101,15 +1101,15 @@ var K = class {
|
|
|
1101
1101
|
if (this.cancelRefocus(), Number.isFinite(this.deps.video.duration)) return;
|
|
1102
1102
|
let e = this.liveEnd(), t = () => typeof performance < "u" ? performance.now() : Date.now(), n = t(), r = 0, i = () => {
|
|
1103
1103
|
if (this.refocusTimer = null, Number.isFinite(this.deps.video.duration)) return;
|
|
1104
|
-
r +=
|
|
1105
|
-
let a = this.liveEnd(), o = a != null && (e == null || a >= e +
|
|
1104
|
+
r += H;
|
|
1105
|
+
let a = this.liveEnd(), o = a != null && (e == null || a >= e + et), s = Math.max(r, t() - n) >= $e;
|
|
1106
1106
|
if (o || s && a != null) {
|
|
1107
1107
|
this.snapToLive();
|
|
1108
1108
|
return;
|
|
1109
1109
|
}
|
|
1110
|
-
this.refocusTimer = setTimeout(i,
|
|
1110
|
+
this.refocusTimer = setTimeout(i, H);
|
|
1111
1111
|
};
|
|
1112
|
-
this.refocusTimer = setTimeout(i,
|
|
1112
|
+
this.refocusTimer = setTimeout(i, H);
|
|
1113
1113
|
}
|
|
1114
1114
|
cancelRefocus() {
|
|
1115
1115
|
this.refocusTimer != null && clearTimeout(this.refocusTimer), this.refocusTimer = null;
|
|
@@ -1123,7 +1123,7 @@ var K = class {
|
|
|
1123
1123
|
snapToLive() {
|
|
1124
1124
|
let e = this.deps.video, t = this.liveEnd();
|
|
1125
1125
|
if (t == null) return;
|
|
1126
|
-
let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t -
|
|
1126
|
+
let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t - Qe, r);
|
|
1127
1127
|
try {
|
|
1128
1128
|
e.currentTime = i;
|
|
1129
1129
|
} catch {}
|
|
@@ -1141,13 +1141,25 @@ var K = class {
|
|
|
1141
1141
|
} catch {}
|
|
1142
1142
|
}
|
|
1143
1143
|
};
|
|
1144
|
-
function
|
|
1144
|
+
function rt(e, t) {
|
|
1145
1145
|
return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
|
|
1146
1146
|
}
|
|
1147
1147
|
//#endregion
|
|
1148
|
+
//#region src/core/drm/signedUrl.ts
|
|
1149
|
+
function K(e, t = Date.now()) {
|
|
1150
|
+
if (!e) return !1;
|
|
1151
|
+
let n;
|
|
1152
|
+
try {
|
|
1153
|
+
n = new URL(e).searchParams.get("exp");
|
|
1154
|
+
} catch {
|
|
1155
|
+
return !1;
|
|
1156
|
+
}
|
|
1157
|
+
return !n || !/^\d+$/.test(n) ? !1 : Number(n) * 1e3 <= t;
|
|
1158
|
+
}
|
|
1159
|
+
//#endregion
|
|
1148
1160
|
//#region src/core/engine/prefetch.ts
|
|
1149
|
-
var
|
|
1150
|
-
function
|
|
1161
|
+
var it = 15e3, at = 5e3, ot = 6;
|
|
1162
|
+
function st(e) {
|
|
1151
1163
|
try {
|
|
1152
1164
|
let t = new URL(e);
|
|
1153
1165
|
return t.searchParams.delete("CMCD"), t.toString();
|
|
@@ -1155,7 +1167,7 @@ function ot(e) {
|
|
|
1155
1167
|
return e;
|
|
1156
1168
|
}
|
|
1157
1169
|
}
|
|
1158
|
-
var
|
|
1170
|
+
var ct = class {
|
|
1159
1171
|
cmcd;
|
|
1160
1172
|
entries = /* @__PURE__ */ new Map();
|
|
1161
1173
|
keyed = /* @__PURE__ */ new Set();
|
|
@@ -1178,10 +1190,10 @@ var st = class {
|
|
|
1178
1190
|
}
|
|
1179
1191
|
prefetch(e, t, n) {
|
|
1180
1192
|
if (!this.isActive(t)) return;
|
|
1181
|
-
let r =
|
|
1193
|
+
let r = st(e);
|
|
1182
1194
|
if (this.entries.has(r)) return;
|
|
1183
1195
|
let i = this.perTrack.get(t) ?? 0;
|
|
1184
|
-
if (i >=
|
|
1196
|
+
if (i >= ot) return;
|
|
1185
1197
|
this.perTrack.set(t, i + 1);
|
|
1186
1198
|
let a = new AbortController(), o = {
|
|
1187
1199
|
started: performance.now(),
|
|
@@ -1195,10 +1207,10 @@ var st = class {
|
|
|
1195
1207
|
signal: a.signal
|
|
1196
1208
|
}).then(async (e) => (o.first = performance.now(), e.ok ? e.arrayBuffer() : null)).catch(() => null), this.entries.set(r, o), this.stats.started += 1, setTimeout(() => {
|
|
1197
1209
|
this.entries.get(r) === o && (this.entries.delete(r), a.abort(), this.stats.expired += 1);
|
|
1198
|
-
},
|
|
1210
|
+
}, it);
|
|
1199
1211
|
}
|
|
1200
1212
|
take(e) {
|
|
1201
|
-
let t =
|
|
1213
|
+
let t = st(e), n = this.entries.get(t);
|
|
1202
1214
|
return n && this.entries.delete(t), n;
|
|
1203
1215
|
}
|
|
1204
1216
|
destroy() {
|
|
@@ -1218,13 +1230,13 @@ var st = class {
|
|
|
1218
1230
|
}
|
|
1219
1231
|
}
|
|
1220
1232
|
};
|
|
1221
|
-
function
|
|
1233
|
+
function lt(t) {
|
|
1222
1234
|
let n = e.DefaultConfig?.loader;
|
|
1223
1235
|
if (typeof n != "function") return;
|
|
1224
1236
|
class r extends n {
|
|
1225
1237
|
served = !1;
|
|
1226
1238
|
cancelled = !1;
|
|
1227
|
-
stats =
|
|
1239
|
+
stats = ut();
|
|
1228
1240
|
load(e, n, r) {
|
|
1229
1241
|
let i = e.rangeEnd ? void 0 : t.take(e.url);
|
|
1230
1242
|
if (!i) {
|
|
@@ -1232,7 +1244,7 @@ function ct(t) {
|
|
|
1232
1244
|
return;
|
|
1233
1245
|
}
|
|
1234
1246
|
this.served = !0;
|
|
1235
|
-
let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs ||
|
|
1247
|
+
let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || at, s = setTimeout(() => {
|
|
1236
1248
|
!this.cancelled && this.served && (i.abort.abort(), t.stats.failed += 1, this.served = !1, super.load(e, n, r));
|
|
1237
1249
|
}, o);
|
|
1238
1250
|
i.bytes.then((o) => {
|
|
@@ -1259,7 +1271,7 @@ function ct(t) {
|
|
|
1259
1271
|
}
|
|
1260
1272
|
return r;
|
|
1261
1273
|
}
|
|
1262
|
-
function
|
|
1274
|
+
function ut() {
|
|
1263
1275
|
return {
|
|
1264
1276
|
aborted: !1,
|
|
1265
1277
|
loaded: 0,
|
|
@@ -1283,10 +1295,10 @@ function lt() {
|
|
|
1283
1295
|
}
|
|
1284
1296
|
};
|
|
1285
1297
|
}
|
|
1286
|
-
function
|
|
1298
|
+
function dt(e) {
|
|
1287
1299
|
return e === "audio" ? "audio" : "main";
|
|
1288
1300
|
}
|
|
1289
|
-
function
|
|
1301
|
+
function ft(e, t) {
|
|
1290
1302
|
let n = [];
|
|
1291
1303
|
t.initSegment?.url && !t.initSegment.data && n.push({
|
|
1292
1304
|
url: t.initSegment.url,
|
|
@@ -1305,24 +1317,24 @@ function dt(e, t) {
|
|
|
1305
1317
|
}
|
|
1306
1318
|
//#endregion
|
|
1307
1319
|
//#region src/core/engine/hls.ts
|
|
1308
|
-
function
|
|
1320
|
+
function pt() {
|
|
1309
1321
|
return e.isSupported();
|
|
1310
1322
|
}
|
|
1311
|
-
var
|
|
1312
|
-
function
|
|
1323
|
+
var mt = 3, ht = 5, gt = 3, _t = 1e4, vt = 3e4, yt = 12e3, bt = 3e3, xt = 6e3, St = .5, Ct = 3, wt = .5, Tt = 1.1, Et = .25, Dt = 5e3, Ot = 4e3, kt = 2, At = 5, jt = 2, Mt = 2, Nt = 4, Pt = 4, Ft = 2e3, It = 3e4, Lt = .2, Rt = 30, zt = 2, Bt = 2, Vt = 9, Ht = .5, Ut = 64;
|
|
1324
|
+
function Wt(e) {
|
|
1313
1325
|
if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
|
|
1314
1326
|
delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
|
|
1315
1327
|
return;
|
|
1316
1328
|
}
|
|
1317
|
-
e.liveSyncDuration ??=
|
|
1318
|
-
let t = Math.max(12, e.liveSyncDuration +
|
|
1319
|
-
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t),
|
|
1329
|
+
e.liveSyncDuration ??= Bt;
|
|
1330
|
+
let t = Math.max(12, e.liveSyncDuration + Vt);
|
|
1331
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Gt(e, e.liveSyncDuration);
|
|
1320
1332
|
}
|
|
1321
|
-
function
|
|
1333
|
+
function Gt(e, t) {
|
|
1322
1334
|
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
1323
1335
|
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
1324
1336
|
}
|
|
1325
|
-
var
|
|
1337
|
+
var Kt = class {
|
|
1326
1338
|
name = "hls";
|
|
1327
1339
|
hls = null;
|
|
1328
1340
|
deps;
|
|
@@ -1402,11 +1414,11 @@ var Wt = class {
|
|
|
1402
1414
|
frameCounter;
|
|
1403
1415
|
detachFrames = null;
|
|
1404
1416
|
constructor(e) {
|
|
1405
|
-
this.deps = e, this.frameCounter = new
|
|
1417
|
+
this.deps = e, this.frameCounter = new Ye(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
|
|
1406
1418
|
}
|
|
1407
1419
|
async load() {
|
|
1408
1420
|
this.detachFrames ??= this.frameCounter.attach();
|
|
1409
|
-
let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a =
|
|
1421
|
+
let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = U(r) && W(), o = !!e.drm?.widevine?.licenseUrl && !a;
|
|
1410
1422
|
if (e.drmEnabled && !o) {
|
|
1411
1423
|
i({
|
|
1412
1424
|
type: "error",
|
|
@@ -1415,7 +1427,7 @@ var Wt = class {
|
|
|
1415
1427
|
});
|
|
1416
1428
|
return;
|
|
1417
1429
|
}
|
|
1418
|
-
e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ae(r),
|
|
1430
|
+
e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ae(r), Me()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
|
|
1419
1431
|
let e = this.hls;
|
|
1420
1432
|
if (document.visibilityState !== "visible" || !e) return;
|
|
1421
1433
|
let t = e.liveSyncPosition;
|
|
@@ -1438,7 +1450,7 @@ var Wt = class {
|
|
|
1438
1450
|
}
|
|
1439
1451
|
this.loadSuspended = !0;
|
|
1440
1452
|
}
|
|
1441
|
-
},
|
|
1453
|
+
}, Dt));
|
|
1442
1454
|
}
|
|
1443
1455
|
resumeLoading() {
|
|
1444
1456
|
if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
|
|
@@ -1470,7 +1482,7 @@ var Wt = class {
|
|
|
1470
1482
|
let t = e.liveSyncPosition;
|
|
1471
1483
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
1472
1484
|
let { video: n } = this.deps;
|
|
1473
|
-
n.currentTime <= t +
|
|
1485
|
+
n.currentTime <= t + Ht || (n.currentTime = t);
|
|
1474
1486
|
}
|
|
1475
1487
|
startHls() {
|
|
1476
1488
|
let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
|
|
@@ -1496,10 +1508,21 @@ var Wt = class {
|
|
|
1496
1508
|
},
|
|
1497
1509
|
...j() ? { requestMediaKeySystemAccessFunc: P(t) } : {},
|
|
1498
1510
|
licenseXhrSetup: (e, t) => {
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1511
|
+
let o = performance.now(), s = () => {
|
|
1512
|
+
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", () => {
|
|
1513
|
+
this.licenseTimeMs === 0 && (this.licenseTimeMs = Math.max(1, Math.round(performance.now() - o)));
|
|
1514
|
+
});
|
|
1515
|
+
}, { freshLicenseUrl: c } = this.deps;
|
|
1516
|
+
if (!c || !K(this.licenseUrl)) {
|
|
1517
|
+
s();
|
|
1518
|
+
return;
|
|
1519
|
+
}
|
|
1520
|
+
let l = this.hls, u, d = new Promise((e) => {
|
|
1521
|
+
u = setTimeout(() => e(void 0), _t);
|
|
1522
|
+
});
|
|
1523
|
+
return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
|
|
1524
|
+
if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
|
|
1525
|
+
e && (this.licenseUrl = e), s();
|
|
1503
1526
|
});
|
|
1504
1527
|
}
|
|
1505
1528
|
} : {},
|
|
@@ -1511,20 +1534,20 @@ var Wt = class {
|
|
|
1511
1534
|
...c
|
|
1512
1535
|
};
|
|
1513
1536
|
if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !d.fLoader) {
|
|
1514
|
-
let e = new
|
|
1537
|
+
let e = new ct({
|
|
1515
1538
|
sessionId: n.analytics?.sid,
|
|
1516
1539
|
contentId: n.matchUrn
|
|
1517
|
-
}), t =
|
|
1540
|
+
}), t = lt(e);
|
|
1518
1541
|
t && (this.prefetch = e, d.fLoader = t);
|
|
1519
1542
|
}
|
|
1520
|
-
|
|
1543
|
+
Wt(d), this.catchUpRate = typeof d.maxLiveSyncPlaybackRate == "number" ? d.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (d.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = d.autoStartLoad !== !1;
|
|
1521
1544
|
let f = new e(d);
|
|
1522
1545
|
if (this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
|
|
1523
1546
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(f), this.measureLadder(f), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
|
|
1524
1547
|
}), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
|
|
1525
1548
|
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(() => {
|
|
1526
1549
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
|
|
1527
|
-
},
|
|
1550
|
+
}, vt)));
|
|
1528
1551
|
}), f.on(e.Events.FRAG_LOADING, (e, t) => {
|
|
1529
1552
|
t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
|
|
1530
1553
|
}), f.on(e.Events.FRAG_LOADED, (e, t) => {
|
|
@@ -1532,10 +1555,10 @@ var Wt = class {
|
|
|
1532
1555
|
let n = t?.frag?.stats, r = n?.loaded;
|
|
1533
1556
|
typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
|
|
1534
1557
|
let i = n?.loading;
|
|
1535
|
-
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 >
|
|
1558
|
+
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 > Ut && this.requestTimesMs.shift());
|
|
1536
1559
|
let a = t?.frag?.url;
|
|
1537
1560
|
if (a) {
|
|
1538
|
-
let e =
|
|
1561
|
+
let e = Ke(a);
|
|
1539
1562
|
e && (this.cdnHost = e);
|
|
1540
1563
|
}
|
|
1541
1564
|
}), f.on(e.Events.LEVEL_LOADED, (e, t) => {
|
|
@@ -1549,15 +1572,15 @@ var Wt = class {
|
|
|
1549
1572
|
}), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
|
|
1550
1573
|
let t = this.prefetch;
|
|
1551
1574
|
f.on(e.Events.KEY_LOADING, (e, n) => {
|
|
1552
|
-
let r = n?.frag, i =
|
|
1553
|
-
if (r && t.isActive(i)) for (let e of
|
|
1554
|
-
}), f.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(
|
|
1575
|
+
let r = n?.frag, i = dt(r?.type);
|
|
1576
|
+
if (r && t.isActive(i)) for (let e of ft(f, r)) t.prefetch(e.url, i, e.kind);
|
|
1577
|
+
}), f.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(dt(n?.frag?.type)));
|
|
1555
1578
|
}
|
|
1556
1579
|
f.on(e.Events.KEY_LOADED, () => {
|
|
1557
1580
|
u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
|
|
1558
1581
|
}), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
|
|
1559
1582
|
this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.checkFrameDrops();
|
|
1560
|
-
},
|
|
1583
|
+
}, bt), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
1561
1584
|
this.renditionSwitches += 1;
|
|
1562
1585
|
let n = this.lastLevelIndex >= 0 ? f.levels[this.lastLevelIndex] : void 0, r = f.levels[t.level];
|
|
1563
1586
|
n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
|
|
@@ -1621,7 +1644,7 @@ var Wt = class {
|
|
|
1621
1644
|
return;
|
|
1622
1645
|
}
|
|
1623
1646
|
this.capTimer && clearTimeout(this.capTimer);
|
|
1624
|
-
let t = e > this.sizeCapLevel ?
|
|
1647
|
+
let t = e > this.sizeCapLevel ? Ft : It;
|
|
1625
1648
|
this.capTimer = setTimeout(() => {
|
|
1626
1649
|
this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
|
|
1627
1650
|
}, t);
|
|
@@ -1631,9 +1654,9 @@ var Wt = class {
|
|
|
1631
1654
|
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;
|
|
1632
1655
|
}
|
|
1633
1656
|
dropLevelsWidevineCannotPlay(e) {
|
|
1634
|
-
this.removeLevelsWhere(e, (e) =>
|
|
1657
|
+
this.removeLevelsWhere(e, (e) => Ne(e) !== !0);
|
|
1635
1658
|
let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && I(e) !== "avc" && !!I(e)));
|
|
1636
|
-
for (let n of t)
|
|
1659
|
+
for (let n of t) je(n).then((t) => {
|
|
1637
1660
|
t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
|
|
1638
1661
|
});
|
|
1639
1662
|
}
|
|
@@ -1644,7 +1667,7 @@ var Wt = class {
|
|
|
1644
1667
|
a && I(a) && t(a) && (r.push(n), i.add(a));
|
|
1645
1668
|
}), !r.length) return !1;
|
|
1646
1669
|
let a = [...i].join(", ");
|
|
1647
|
-
if (!n.some((e, t) => r.includes(t) ? !1 : !I(e.videoCodec) ||
|
|
1670
|
+
if (!n.some((e, t) => r.includes(t) ? !1 : !I(e.videoCodec) || Ne(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
|
|
1648
1671
|
for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
|
|
1649
1672
|
return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
|
|
1650
1673
|
}
|
|
@@ -1742,7 +1765,7 @@ var Wt = class {
|
|
|
1742
1765
|
return;
|
|
1743
1766
|
}
|
|
1744
1767
|
let e = Date.now() - this.lastAdvanceMs;
|
|
1745
|
-
!this.chaseSuspended && e >
|
|
1768
|
+
!this.chaseSuspended && e > xt && this.suspendChasing(), e > yt && this.emitEnded("stalled");
|
|
1746
1769
|
}
|
|
1747
1770
|
resetStarvationWindow() {
|
|
1748
1771
|
this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
|
|
@@ -1757,7 +1780,7 @@ var Wt = class {
|
|
|
1757
1780
|
this.resetStarvationWindow();
|
|
1758
1781
|
return;
|
|
1759
1782
|
}
|
|
1760
|
-
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs <
|
|
1783
|
+
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < xt, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > Ot, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = V(t), c = o - s, l = c !== this.starvedFrames;
|
|
1761
1784
|
if (this.starvedFrames = c, !a || l) {
|
|
1762
1785
|
(t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
|
|
1763
1786
|
return;
|
|
@@ -1766,12 +1789,12 @@ var Wt = class {
|
|
|
1766
1789
|
this.resetStarvationWindow();
|
|
1767
1790
|
return;
|
|
1768
1791
|
}
|
|
1769
|
-
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 >
|
|
1792
|
+
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 > Nt && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= jt && (this.clearKick(), this.starvationRebuilds < Mt)) {
|
|
1770
1793
|
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");
|
|
1771
1794
|
return;
|
|
1772
1795
|
}
|
|
1773
|
-
let u = i && this.starvedTicks >=
|
|
1774
|
-
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >=
|
|
1796
|
+
let u = i && this.starvedTicks >= kt, d = !i && this.deadTicks >= Nt && this.recentMainFrags.reduce((e, t) => e + t, 0) >= Pt;
|
|
1797
|
+
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= At))) {
|
|
1775
1798
|
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");
|
|
1776
1799
|
try {
|
|
1777
1800
|
e.stopLoad(), e.startLoad(-1);
|
|
@@ -1786,7 +1809,7 @@ var Wt = class {
|
|
|
1786
1809
|
let t = e.latency, n = e.targetLatency;
|
|
1787
1810
|
if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
|
|
1788
1811
|
let r = t - n;
|
|
1789
|
-
!this.catchUpEngaged && r >
|
|
1812
|
+
!this.catchUpEngaged && r > St ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= St && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
|
|
1790
1813
|
let i = this.catchUpEngaged ? this.catchUpRate : 1;
|
|
1791
1814
|
e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
|
|
1792
1815
|
}
|
|
@@ -1808,15 +1831,15 @@ var Wt = class {
|
|
|
1808
1831
|
return;
|
|
1809
1832
|
}
|
|
1810
1833
|
let { totalFrames: n, dropped: r } = V(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
|
|
1811
|
-
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a <
|
|
1834
|
+
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Rt || o < 0) {
|
|
1812
1835
|
this.fpsBadTicks = 0;
|
|
1813
1836
|
return;
|
|
1814
1837
|
}
|
|
1815
|
-
if (o <=
|
|
1838
|
+
if (o <= Lt * a) {
|
|
1816
1839
|
this.fpsBadTicks = 0;
|
|
1817
1840
|
return;
|
|
1818
1841
|
}
|
|
1819
|
-
if (this.fpsBadTicks += 1, this.fpsBadTicks <
|
|
1842
|
+
if (this.fpsBadTicks += 1, this.fpsBadTicks < zt) return;
|
|
1820
1843
|
this.fpsBadTicks = 0;
|
|
1821
1844
|
let s = e.levels, c = s[e.currentLevel];
|
|
1822
1845
|
if (!c) return;
|
|
@@ -1833,20 +1856,20 @@ var Wt = class {
|
|
|
1833
1856
|
return;
|
|
1834
1857
|
}
|
|
1835
1858
|
let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
|
|
1836
|
-
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(
|
|
1859
|
+
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(Tt, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
|
|
1837
1860
|
this.resetChaseWindow();
|
|
1838
1861
|
return;
|
|
1839
1862
|
}
|
|
1840
|
-
if (this.chaseLatency < 0 || this.chaseLatency - n >=
|
|
1863
|
+
if (this.chaseLatency < 0 || this.chaseLatency - n >= wt) {
|
|
1841
1864
|
this.chaseLatency = n, this.chaseTicks = 0;
|
|
1842
1865
|
return;
|
|
1843
1866
|
}
|
|
1844
|
-
if (this.chaseTicks += 1, this.chaseTicks <
|
|
1867
|
+
if (this.chaseTicks += 1, this.chaseTicks < Ct) return;
|
|
1845
1868
|
this.resetChaseWindow();
|
|
1846
1869
|
let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
|
|
1847
1870
|
if (!(a > 1)) return;
|
|
1848
1871
|
let o = typeof e.targetLatency == "number" ? e.targetLatency : 0, s = Math.min(n, a - 1);
|
|
1849
|
-
s < o +
|
|
1872
|
+
s < o + Et || (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);
|
|
1850
1873
|
}
|
|
1851
1874
|
suspendChasing() {
|
|
1852
1875
|
let e = this.hls;
|
|
@@ -1891,7 +1914,7 @@ var Wt = class {
|
|
|
1891
1914
|
scheduleLicenseRetry(t) {
|
|
1892
1915
|
if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
|
|
1893
1916
|
let n = t.response?.code ?? 0;
|
|
1894
|
-
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >=
|
|
1917
|
+
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= gt) return !1;
|
|
1895
1918
|
this.licenseRecoveries += 1;
|
|
1896
1919
|
let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
|
|
1897
1920
|
return this.licenseRetryTimer = setTimeout(() => {
|
|
@@ -1923,7 +1946,7 @@ var Wt = class {
|
|
|
1923
1946
|
return;
|
|
1924
1947
|
}
|
|
1925
1948
|
if (t.type === e.ErrorTypes.NETWORK_ERROR) {
|
|
1926
|
-
if (this.networkRecoveries <
|
|
1949
|
+
if (this.networkRecoveries < ht) {
|
|
1927
1950
|
this.networkRecoveries += 1;
|
|
1928
1951
|
let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
|
|
1929
1952
|
this.networkRetryTimer = setTimeout(() => {
|
|
@@ -1940,7 +1963,7 @@ var Wt = class {
|
|
|
1940
1963
|
return;
|
|
1941
1964
|
}
|
|
1942
1965
|
if (t.type === e.ErrorTypes.MEDIA_ERROR) {
|
|
1943
|
-
if (this.mediaRecoveries <
|
|
1966
|
+
if (this.mediaRecoveries < mt) {
|
|
1944
1967
|
this.mediaRecoveries += 1, n.recoverMediaError();
|
|
1945
1968
|
return;
|
|
1946
1969
|
}
|
|
@@ -1964,19 +1987,19 @@ var Wt = class {
|
|
|
1964
1987
|
let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
|
|
1965
1988
|
return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
|
|
1966
1989
|
}
|
|
1967
|
-
},
|
|
1990
|
+
}, qt = 15e3, Jt = 6e5, Yt = 3e5, Xt = 100, q = 1, Zt = 1e3, Qt = 3e4, $t = 1e3, en = {
|
|
1968
1991
|
inline: "PRESENTATION_INLINE",
|
|
1969
1992
|
fullscreen: "PRESENTATION_FULLSCREEN",
|
|
1970
1993
|
pip: "PRESENTATION_PIP"
|
|
1971
|
-
},
|
|
1994
|
+
}, tn = {
|
|
1972
1995
|
widevine: "KEY_SYSTEM_WIDEVINE",
|
|
1973
1996
|
fairplay: "KEY_SYSTEM_FAIRPLAY",
|
|
1974
1997
|
none: "KEY_SYSTEM_NONE"
|
|
1975
1998
|
};
|
|
1976
|
-
function
|
|
1999
|
+
function nn(e, t) {
|
|
1977
2000
|
return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
|
|
1978
2001
|
}
|
|
1979
|
-
var
|
|
2002
|
+
var rn = /* @__PURE__ */ new Set([
|
|
1980
2003
|
"INVALID_URN",
|
|
1981
2004
|
"NOT_FOUND",
|
|
1982
2005
|
"GONE",
|
|
@@ -1996,7 +2019,7 @@ var tn = /* @__PURE__ */ new Set([
|
|
|
1996
2019
|
ended: "PLAYER_STATE_ENDED",
|
|
1997
2020
|
error: "PLAYER_STATE_ERROR"
|
|
1998
2021
|
};
|
|
1999
|
-
function
|
|
2022
|
+
function an(e) {
|
|
2000
2023
|
try {
|
|
2001
2024
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
2002
2025
|
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);
|
|
@@ -2004,8 +2027,8 @@ function nn(e) {
|
|
|
2004
2027
|
return;
|
|
2005
2028
|
}
|
|
2006
2029
|
}
|
|
2007
|
-
var
|
|
2008
|
-
function
|
|
2030
|
+
var on = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), sn = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), cn = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
|
|
2031
|
+
function ln(e) {
|
|
2009
2032
|
if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
|
|
2010
2033
|
let t;
|
|
2011
2034
|
try {
|
|
@@ -2014,19 +2037,19 @@ function sn(e) {
|
|
|
2014
2037
|
} catch {
|
|
2015
2038
|
return;
|
|
2016
2039
|
}
|
|
2017
|
-
if (
|
|
2018
|
-
Y.add(t), g(
|
|
2040
|
+
if (sn.has(t) && !Y.has(t)) {
|
|
2041
|
+
Y.add(t), g(cn(new URL(t).origin));
|
|
2019
2042
|
for (let e of X) e.noteCspBlocked();
|
|
2020
2043
|
}
|
|
2021
2044
|
}
|
|
2022
|
-
function
|
|
2045
|
+
function un(e, t) {
|
|
2023
2046
|
return g(t, e), { disabledReason: t };
|
|
2024
2047
|
}
|
|
2025
|
-
function
|
|
2026
|
-
if (n) return t && !
|
|
2048
|
+
function dn(e, t, n) {
|
|
2049
|
+
if (n) return t && !on(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
|
|
2027
2050
|
if (t) return { endpoint: t };
|
|
2028
|
-
if (t !== void 0) return
|
|
2029
|
-
let r =
|
|
2051
|
+
if (t !== void 0) return un("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).");
|
|
2052
|
+
let r = an(e);
|
|
2030
2053
|
if (r) return { endpoint: r };
|
|
2031
2054
|
let i;
|
|
2032
2055
|
try {
|
|
@@ -2034,9 +2057,9 @@ function ln(e, t, n) {
|
|
|
2034
2057
|
} catch {
|
|
2035
2058
|
i = e;
|
|
2036
2059
|
}
|
|
2037
|
-
return
|
|
2060
|
+
return un(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).`);
|
|
2038
2061
|
}
|
|
2039
|
-
var
|
|
2062
|
+
var fn = class {
|
|
2040
2063
|
opts;
|
|
2041
2064
|
url;
|
|
2042
2065
|
cspKey;
|
|
@@ -2118,8 +2141,8 @@ var un = class {
|
|
|
2118
2141
|
constructor(e) {
|
|
2119
2142
|
this.opts = {
|
|
2120
2143
|
...e,
|
|
2121
|
-
heartbeatMs: e.heartbeatMs ??
|
|
2122
|
-
idleMs: e.idleMs ??
|
|
2144
|
+
heartbeatMs: e.heartbeatMs ?? qt,
|
|
2145
|
+
idleMs: e.idleMs ?? Jt
|
|
2123
2146
|
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
|
|
2124
2147
|
try {
|
|
2125
2148
|
let e = new URL(this.url);
|
|
@@ -2136,11 +2159,11 @@ var un = class {
|
|
|
2136
2159
|
sdkVersion: this.opts.sdkVersion,
|
|
2137
2160
|
...this.opts.environment
|
|
2138
2161
|
};
|
|
2139
|
-
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(),
|
|
2162
|
+
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Zt), 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 && sn.add(this.cspKey), document.addEventListener("securitypolicyviolation", ln), X.add(this), this.noteCspBlocked(), this.onVisibility());
|
|
2140
2163
|
}
|
|
2141
2164
|
checkSuspension(e) {
|
|
2142
2165
|
if (this.endedFlag || !this.opts.idleMs) return !1;
|
|
2143
|
-
let t = Math.max(this.opts.idleMs,
|
|
2166
|
+
let t = Math.max(this.opts.idleMs, Yt);
|
|
2144
2167
|
return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
|
|
2145
2168
|
}
|
|
2146
2169
|
syncIdle(e) {
|
|
@@ -2163,12 +2186,12 @@ var un = class {
|
|
|
2163
2186
|
let a = {
|
|
2164
2187
|
fromState: J[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2165
2188
|
toState: J[t] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2166
|
-
presentation:
|
|
2189
|
+
presentation: en[this.presentation]
|
|
2167
2190
|
}, o = this.causeOf(e, t, i);
|
|
2168
2191
|
o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
2169
2192
|
}
|
|
2170
2193
|
seekInduced(e) {
|
|
2171
|
-
return this.lastSeekMs >= 0 && e - this.lastSeekMs <
|
|
2194
|
+
return this.lastSeekMs >= 0 && e - this.lastSeekMs < $t;
|
|
2172
2195
|
}
|
|
2173
2196
|
causeOf(e, t, n) {
|
|
2174
2197
|
if (t === "error") return "TRANSITION_CAUSE_ERROR";
|
|
@@ -2242,7 +2265,7 @@ var un = class {
|
|
|
2242
2265
|
let r = n ?? "";
|
|
2243
2266
|
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";
|
|
2244
2267
|
if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
|
|
2245
|
-
if (
|
|
2268
|
+
if (rn.has(e)) return "ERROR_STAGE_RESOLVE";
|
|
2246
2269
|
let i = t ?? "";
|
|
2247
2270
|
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";
|
|
2248
2271
|
}
|
|
@@ -2289,14 +2312,14 @@ var un = class {
|
|
|
2289
2312
|
if (this.lastRequestCount = g, _ > 0) {
|
|
2290
2313
|
o.requestCountDelta = _;
|
|
2291
2314
|
let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
|
|
2292
|
-
n.length > 0 && (o.requestTimeP50Ms =
|
|
2315
|
+
n.length > 0 && (o.requestTimeP50Ms = nn(n, 50), o.requestTimeP95Ms = nn(n, 95));
|
|
2293
2316
|
}
|
|
2294
2317
|
typeof t.latencySeconds == "number" && typeof t.targetLatencySeconds == "number" && (o.driftMs = Math.round((t.latencySeconds - t.targetLatencySeconds) * 1e3)), typeof t.playbackRate == "number" && t.playbackRate > 0 && (o.playbackRate = t.playbackRate), t.qualityPinned === !0 && (o.qualityPinned = !0), t.cdnHost && (o.cdnHost = t.cdnHost), this.maybeEmitMediaInfo(t), this.enqueue({ heartbeat: o }), this.flush(), s > 0 && this.noteFirstBytes();
|
|
2295
2318
|
}
|
|
2296
2319
|
maybeEmitMediaInfo(e) {
|
|
2297
2320
|
if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
|
|
2298
2321
|
let t = {};
|
|
2299
|
-
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem =
|
|
2322
|
+
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = tn[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);
|
|
2300
2323
|
let n = JSON.stringify(t);
|
|
2301
2324
|
n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
|
|
2302
2325
|
}
|
|
@@ -2316,7 +2339,7 @@ var un = class {
|
|
|
2316
2339
|
let c = r?.positionMs ?? 0;
|
|
2317
2340
|
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));
|
|
2318
2341
|
let l = e !== "END_REASON_ENDED";
|
|
2319
|
-
l && this.lastStallMs > 0 && n - this.lastStallMs <=
|
|
2342
|
+
l && this.lastStallMs > 0 && n - this.lastStallMs <= Qt && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Qt && (i.abandonAfterErrorMs = Math.max(q, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
|
|
2320
2343
|
let u = r?.decodedFrames ?? this.lastDecoded;
|
|
2321
2344
|
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");
|
|
2322
2345
|
}
|
|
@@ -2336,13 +2359,13 @@ var un = class {
|
|
|
2336
2359
|
};
|
|
2337
2360
|
}
|
|
2338
2361
|
noteCspBlocked() {
|
|
2339
|
-
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(
|
|
2362
|
+
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(cn(new URL(this.url).origin)));
|
|
2340
2363
|
}
|
|
2341
2364
|
cspBlocked() {
|
|
2342
2365
|
return !!this.cspKey && Y.has(this.cspKey);
|
|
2343
2366
|
}
|
|
2344
2367
|
enqueue(e) {
|
|
2345
|
-
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length >
|
|
2368
|
+
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Xt;) {
|
|
2346
2369
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
2347
2370
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
2348
2371
|
}
|
|
@@ -2369,7 +2392,7 @@ var un = class {
|
|
|
2369
2392
|
};
|
|
2370
2393
|
//#endregion
|
|
2371
2394
|
//#region src/core/environment.ts
|
|
2372
|
-
function
|
|
2395
|
+
function pn() {
|
|
2373
2396
|
if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
|
|
2374
2397
|
let e;
|
|
2375
2398
|
try {
|
|
@@ -2394,14 +2417,14 @@ function dn() {
|
|
|
2394
2417
|
integration: "INTEGRATION_KIND_IFRAME"
|
|
2395
2418
|
};
|
|
2396
2419
|
}
|
|
2397
|
-
function
|
|
2420
|
+
function mn() {
|
|
2398
2421
|
if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
|
|
2399
2422
|
let e = navigator.userAgentData, t = e?.platform ?? "";
|
|
2400
2423
|
if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
|
|
2401
2424
|
let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
|
|
2402
2425
|
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";
|
|
2403
2426
|
}
|
|
2404
|
-
function
|
|
2427
|
+
function hn() {
|
|
2405
2428
|
let e = typeof navigator < "u" ? navigator.connection : void 0;
|
|
2406
2429
|
if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
|
|
2407
2430
|
let t = {
|
|
@@ -2420,17 +2443,17 @@ function pn() {
|
|
|
2420
2443
|
}
|
|
2421
2444
|
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;
|
|
2422
2445
|
}
|
|
2423
|
-
function
|
|
2424
|
-
let t =
|
|
2425
|
-
deviceClass:
|
|
2446
|
+
function gn(e) {
|
|
2447
|
+
let t = pn(), n = {
|
|
2448
|
+
deviceClass: mn(),
|
|
2426
2449
|
integration: t.integration,
|
|
2427
|
-
...
|
|
2450
|
+
...hn()
|
|
2428
2451
|
};
|
|
2429
2452
|
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);
|
|
2430
2453
|
let r = e.getBoundingClientRect?.();
|
|
2431
2454
|
return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
|
|
2432
2455
|
}
|
|
2433
|
-
async function
|
|
2456
|
+
async function _n() {
|
|
2434
2457
|
let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
|
|
2435
2458
|
if (!e?.getHighEntropyValues) return {};
|
|
2436
2459
|
try {
|
|
@@ -2442,7 +2465,7 @@ async function hn() {
|
|
|
2442
2465
|
}
|
|
2443
2466
|
//#endregion
|
|
2444
2467
|
//#region src/core/version.ts
|
|
2445
|
-
var
|
|
2468
|
+
var vn = "2.16.6", yn = {
|
|
2446
2469
|
accent: "#E1B600",
|
|
2447
2470
|
accentText: "#1B1C23",
|
|
2448
2471
|
background: "#0e0f13",
|
|
@@ -2453,7 +2476,7 @@ var gn = "2.16.4", _n = {
|
|
|
2453
2476
|
border: "rgba(255, 255, 255, 0.1)",
|
|
2454
2477
|
radius: "8px",
|
|
2455
2478
|
fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
|
|
2456
|
-
},
|
|
2479
|
+
}, bn = {
|
|
2457
2480
|
accent: "--havik-accent",
|
|
2458
2481
|
accentText: "--havik-accent-text",
|
|
2459
2482
|
background: "--havik-bg",
|
|
@@ -2465,26 +2488,26 @@ var gn = "2.16.4", _n = {
|
|
|
2465
2488
|
radius: "--havik-radius",
|
|
2466
2489
|
fontFamily: "--havik-font"
|
|
2467
2490
|
};
|
|
2468
|
-
function
|
|
2491
|
+
function xn(e, t) {
|
|
2469
2492
|
let n = {
|
|
2470
|
-
...
|
|
2493
|
+
...yn,
|
|
2471
2494
|
...t
|
|
2472
2495
|
};
|
|
2473
|
-
for (let t of Object.keys(
|
|
2496
|
+
for (let t of Object.keys(bn)) e.style.setProperty(bn[t], n[t]);
|
|
2474
2497
|
n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
|
|
2475
2498
|
}
|
|
2476
2499
|
//#endregion
|
|
2477
2500
|
//#region src/ui/styles.ts
|
|
2478
|
-
var
|
|
2479
|
-
function
|
|
2480
|
-
let n = e.querySelector(`style#${
|
|
2481
|
-
if (n && (!t ||
|
|
2501
|
+
var Sn = "havik-player-styles", Cn = "\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", Z = /* @__PURE__ */ new WeakMap();
|
|
2502
|
+
function wn(e = document, t) {
|
|
2503
|
+
let n = e.querySelector(`style#${Sn}`);
|
|
2504
|
+
if (n && (!t || Z.get(n) === t)) return;
|
|
2482
2505
|
let r = e.createElement("style");
|
|
2483
|
-
r.id =
|
|
2506
|
+
r.id = Sn, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = Cn, Z.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
|
|
2484
2507
|
}
|
|
2485
2508
|
//#endregion
|
|
2486
2509
|
//#region src/ui/icons.ts
|
|
2487
|
-
var
|
|
2510
|
+
var Tn = {
|
|
2488
2511
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
2489
2512
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
2490
2513
|
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\"/>",
|
|
@@ -2498,20 +2521,20 @@ var Cn = {
|
|
|
2498
2521
|
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\"/>"
|
|
2499
2522
|
};
|
|
2500
2523
|
function Q(e) {
|
|
2501
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
2524
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Tn[e]}</svg>`;
|
|
2502
2525
|
}
|
|
2503
2526
|
//#endregion
|
|
2504
2527
|
//#region src/ui/controls.ts
|
|
2505
|
-
var
|
|
2528
|
+
var En = 3e3, Dn = 250, On = /* @__PURE__ */ new Set([
|
|
2506
2529
|
"GONE",
|
|
2507
2530
|
"NOT_FOUND",
|
|
2508
2531
|
"INVALID_URN",
|
|
2509
2532
|
"UNAUTHORIZED"
|
|
2510
2533
|
]);
|
|
2511
|
-
function
|
|
2512
|
-
return new
|
|
2534
|
+
function kn(e) {
|
|
2535
|
+
return new An(e);
|
|
2513
2536
|
}
|
|
2514
|
-
var
|
|
2537
|
+
var An = class {
|
|
2515
2538
|
root;
|
|
2516
2539
|
video;
|
|
2517
2540
|
player;
|
|
@@ -2557,7 +2580,7 @@ var On = class {
|
|
|
2557
2580
|
scrubbing = !1;
|
|
2558
2581
|
offFns = [];
|
|
2559
2582
|
constructor(e) {
|
|
2560
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
2583
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? En, 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, wn(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");
|
|
2561
2584
|
let t = (e, t, n) => {
|
|
2562
2585
|
let r = this.doc.createElement(e);
|
|
2563
2586
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -2643,7 +2666,7 @@ var On = class {
|
|
|
2643
2666
|
let t = this.surfaceWasHidden;
|
|
2644
2667
|
this.tapTimer = setTimeout(() => {
|
|
2645
2668
|
this.tapTimer = void 0, this.toggleBar(t);
|
|
2646
|
-
},
|
|
2669
|
+
}, Dn);
|
|
2647
2670
|
}
|
|
2648
2671
|
toggleBar(e) {
|
|
2649
2672
|
e ? this.poke() : this.hideIfIdle();
|
|
@@ -2678,7 +2701,7 @@ var On = class {
|
|
|
2678
2701
|
e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = Q("play"), e.addEventListener("click", () => void this.player.play()), n.append(e);
|
|
2679
2702
|
} else {
|
|
2680
2703
|
let r = this.doc.createElement("div");
|
|
2681
|
-
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !
|
|
2704
|
+
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !On.has(this.lastError.code)) {
|
|
2682
2705
|
let e = this.doc.createElement("button");
|
|
2683
2706
|
e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${Q("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), n.append(e);
|
|
2684
2707
|
}
|
|
@@ -2719,7 +2742,7 @@ var On = class {
|
|
|
2719
2742
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
2720
2743
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
2721
2744
|
}
|
|
2722
|
-
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${
|
|
2745
|
+
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${jn(this.video.currentTime)} / ${jn(this.video.duration)}`);
|
|
2723
2746
|
}
|
|
2724
2747
|
syncLive() {
|
|
2725
2748
|
let e = this.player.getStats(), t = e.isLive !== !1;
|
|
@@ -2769,17 +2792,17 @@ var On = class {
|
|
|
2769
2792
|
renderQualityMenu() {
|
|
2770
2793
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
2771
2794
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
2772
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
2795
|
+
for (let n of e) this.menu.append(this.menuItem(Mn(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
2773
2796
|
}
|
|
2774
2797
|
renderAudioMenu() {
|
|
2775
2798
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
2776
2799
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
2777
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2800
|
+
for (let t of e) this.menu.append(this.menuItem(Nn(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
2778
2801
|
}
|
|
2779
2802
|
renderCcMenu() {
|
|
2780
2803
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
2781
2804
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
2782
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2805
|
+
for (let t of e) this.menu.append(this.menuItem(Pn(t), !1, () => this.player.setTextTrack(t.id)));
|
|
2783
2806
|
}
|
|
2784
2807
|
onTracksChanged() {
|
|
2785
2808
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -2880,41 +2903,41 @@ var On = class {
|
|
|
2880
2903
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
2881
2904
|
}
|
|
2882
2905
|
};
|
|
2883
|
-
function
|
|
2906
|
+
function jn(e) {
|
|
2884
2907
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
2885
2908
|
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");
|
|
2886
2909
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
2887
2910
|
}
|
|
2888
|
-
function
|
|
2911
|
+
function Mn(e) {
|
|
2889
2912
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
2890
2913
|
}
|
|
2891
|
-
function
|
|
2914
|
+
function Nn(e) {
|
|
2892
2915
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2893
2916
|
}
|
|
2894
|
-
function
|
|
2917
|
+
function Pn(e) {
|
|
2895
2918
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2896
2919
|
}
|
|
2897
2920
|
//#endregion
|
|
2898
2921
|
//#region src/managed/index.ts
|
|
2899
|
-
var
|
|
2900
|
-
function
|
|
2922
|
+
var Fn = 6e3, In = 45e3, Ln = 2e3, Rn = 3, zn = 2e3, Bn = 48e4, Vn = "keySystemLicenseRequestFailed";
|
|
2923
|
+
function Hn(e) {
|
|
2901
2924
|
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)})`);
|
|
2902
|
-
if (e.env !== void 0) return
|
|
2925
|
+
if (e.env !== void 0) return We(e.env);
|
|
2903
2926
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
|
|
2904
2927
|
return e.baseUrl;
|
|
2905
2928
|
}
|
|
2906
|
-
async function
|
|
2929
|
+
async function Un(e) {
|
|
2907
2930
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
2908
|
-
let t =
|
|
2931
|
+
let t = Hn(e);
|
|
2909
2932
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
2910
2933
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
2911
|
-
let r = new
|
|
2934
|
+
let r = new Wn({
|
|
2912
2935
|
...e,
|
|
2913
2936
|
baseUrl: t
|
|
2914
2937
|
});
|
|
2915
2938
|
return await r.start(), r;
|
|
2916
2939
|
}
|
|
2917
|
-
var
|
|
2940
|
+
var Wn = class {
|
|
2918
2941
|
opts;
|
|
2919
2942
|
abort = new AbortController();
|
|
2920
2943
|
listeners = {};
|
|
@@ -2925,6 +2948,9 @@ var Vn = class {
|
|
|
2925
2948
|
detachPip;
|
|
2926
2949
|
statsTimer;
|
|
2927
2950
|
refreshTimer;
|
|
2951
|
+
refreshInFlight;
|
|
2952
|
+
onRefocus;
|
|
2953
|
+
staleLicenseReloaded = !1;
|
|
2928
2954
|
_state = "idle";
|
|
2929
2955
|
_descriptor = null;
|
|
2930
2956
|
destroyed = !1;
|
|
@@ -2958,7 +2984,7 @@ var Vn = class {
|
|
|
2958
2984
|
this.opts.muted && (this.opts.video.muted = !0), this.opts.poster && (this.opts.video.poster = this.opts.poster), this.mountControls(), this.attachPipListeners(), this.setState("loading");
|
|
2959
2985
|
let e = ++this.loadGen, t = this.resolveOptions();
|
|
2960
2986
|
try {
|
|
2961
|
-
let n = await
|
|
2987
|
+
let n = await y(t);
|
|
2962
2988
|
if (await this.onResolved(n, e), e === this.loadGen && this._state === "error" && this._lastError) {
|
|
2963
2989
|
let e = this._lastError;
|
|
2964
2990
|
throw this.destroy(), e;
|
|
@@ -2985,7 +3011,7 @@ var Vn = class {
|
|
|
2985
3011
|
r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
|
|
2986
3012
|
}
|
|
2987
3013
|
beginArmingByPolling(e) {
|
|
2988
|
-
|
|
3014
|
+
b({
|
|
2989
3015
|
...this.resolveOptions(),
|
|
2990
3016
|
signal: this.abort.signal,
|
|
2991
3017
|
waitForLive: this.buildWaitConfig(e)
|
|
@@ -3002,7 +3028,7 @@ var Vn = class {
|
|
|
3002
3028
|
setTimeout(() => {
|
|
3003
3029
|
a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
3004
3030
|
phase: i ? "unavailable" : "tooEarly",
|
|
3005
|
-
retryInMs:
|
|
3031
|
+
retryInMs: In,
|
|
3006
3032
|
attempt: 1,
|
|
3007
3033
|
elapsedMs: 0,
|
|
3008
3034
|
...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
|
|
@@ -3019,7 +3045,7 @@ var Vn = class {
|
|
|
3019
3045
|
}
|
|
3020
3046
|
}
|
|
3021
3047
|
}, h = () => {
|
|
3022
|
-
a || s || p() || (s = !0,
|
|
3048
|
+
a || s || p() || (s = !0, b({
|
|
3023
3049
|
...this.resolveOptions(),
|
|
3024
3050
|
signal: c.signal,
|
|
3025
3051
|
waitForLive: this.buildWaitConfig(e)
|
|
@@ -3027,7 +3053,7 @@ var Vn = class {
|
|
|
3027
3053
|
a || p() || c.signal.aborted || (a = !0, this.closeArming(), this.fail(e instanceof n ? e : new n("INTERNAL", 0, String(e))));
|
|
3028
3054
|
}));
|
|
3029
3055
|
}, g = () => {
|
|
3030
|
-
a || p() ||
|
|
3056
|
+
a || p() || y(this.resolveOptions()).then((e) => m(e)).catch((e) => {
|
|
3031
3057
|
if (!(a || p())) {
|
|
3032
3058
|
if (e instanceof n && o(e.code)) {
|
|
3033
3059
|
h();
|
|
@@ -3041,13 +3067,13 @@ var Vn = class {
|
|
|
3041
3067
|
!a && !p() && h();
|
|
3042
3068
|
}, e);
|
|
3043
3069
|
};
|
|
3044
|
-
_(
|
|
3070
|
+
_(Fn), this.armingSub = T({
|
|
3045
3071
|
eventsBaseUrl: t,
|
|
3046
3072
|
matchUrn: this.opts.matchUrn,
|
|
3047
3073
|
credential: this.opts.credential,
|
|
3048
|
-
onAlive: () => _(
|
|
3074
|
+
onAlive: () => _(In),
|
|
3049
3075
|
onState: (e) => {
|
|
3050
|
-
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() *
|
|
3076
|
+
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Ln);
|
|
3051
3077
|
},
|
|
3052
3078
|
onError: () => h()
|
|
3053
3079
|
});
|
|
@@ -3070,7 +3096,7 @@ var Vn = class {
|
|
|
3070
3096
|
let n = await s(this.opts.credential);
|
|
3071
3097
|
if (this.destroyed || t !== this.loadGen) return;
|
|
3072
3098
|
this.setState("loading");
|
|
3073
|
-
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a =
|
|
3099
|
+
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = Xe(this.opts.video, (e) => {
|
|
3074
3100
|
this._state !== "ended" && this._state !== "error" && this.setState(e);
|
|
3075
3101
|
});
|
|
3076
3102
|
if (await i.load(), this.destroyed || t !== this.loadGen) {
|
|
@@ -3092,26 +3118,26 @@ var Vn = class {
|
|
|
3092
3118
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
|
|
3093
3119
|
let i = e.analytics?.sid;
|
|
3094
3120
|
if (!i) return;
|
|
3095
|
-
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } =
|
|
3121
|
+
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = dn(this.opts.baseUrl, a, e.analytics?.endpoint);
|
|
3096
3122
|
if (!o) {
|
|
3097
3123
|
s && setTimeout(() => {
|
|
3098
3124
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
|
|
3099
3125
|
}, 0);
|
|
3100
3126
|
return;
|
|
3101
3127
|
}
|
|
3102
|
-
let c = this.opts.video, l = new
|
|
3128
|
+
let c = this.opts.video, l = new fn({
|
|
3103
3129
|
endpoint: o,
|
|
3104
3130
|
sid: i,
|
|
3105
3131
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
3106
|
-
sdkVersion:
|
|
3107
|
-
environment:
|
|
3132
|
+
sdkVersion: vn,
|
|
3133
|
+
environment: gn(c),
|
|
3108
3134
|
idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
|
|
3109
3135
|
onIdle: () => this.onAnalyticsIdle(t),
|
|
3110
3136
|
onBlocked: (e) => setTimeout(() => {
|
|
3111
3137
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
|
|
3112
3138
|
}, 0),
|
|
3113
3139
|
sample: () => {
|
|
3114
|
-
let e = this.engine?.getStats() ??
|
|
3140
|
+
let e = this.engine?.getStats() ?? Ge, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
|
|
3115
3141
|
return {
|
|
3116
3142
|
...e,
|
|
3117
3143
|
bufferedMs: Math.round(t * 1e3),
|
|
@@ -3125,7 +3151,7 @@ var Vn = class {
|
|
|
3125
3151
|
let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
|
|
3126
3152
|
c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
|
|
3127
3153
|
c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
|
|
3128
|
-
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()),
|
|
3154
|
+
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), _n().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
|
|
3129
3155
|
}
|
|
3130
3156
|
currentPresentation() {
|
|
3131
3157
|
let e = this.opts.video;
|
|
@@ -3148,13 +3174,14 @@ var Vn = class {
|
|
|
3148
3174
|
debug: this.opts.debug,
|
|
3149
3175
|
deferLoad: r,
|
|
3150
3176
|
hlsConfig: i,
|
|
3151
|
-
emit: (e) => this.onEngineEvent(e)
|
|
3177
|
+
emit: (e) => this.onEngineEvent(e),
|
|
3178
|
+
freshLicenseUrl: () => this.refreshLicense()
|
|
3152
3179
|
}, o = this.opts.engine ?? "auto";
|
|
3153
|
-
if (o === "native") return new
|
|
3154
|
-
if (o === "hls") return new
|
|
3155
|
-
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl &&
|
|
3156
|
-
if (
|
|
3157
|
-
if (
|
|
3180
|
+
if (o === "native") return new G(a);
|
|
3181
|
+
if (o === "hls") return new Kt(a);
|
|
3182
|
+
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && U(this.opts.video) && W() || !e.drmEnabled && nt() && U(this.opts.video)) return new G(a);
|
|
3183
|
+
if (pt()) return new Kt(a);
|
|
3184
|
+
if (U(this.opts.video)) return new G(a);
|
|
3158
3185
|
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
3159
3186
|
}
|
|
3160
3187
|
onEngineEvent(e) {
|
|
@@ -3166,7 +3193,7 @@ var Vn = class {
|
|
|
3166
3193
|
this.analyticsSession?.noteFirstBytes();
|
|
3167
3194
|
break;
|
|
3168
3195
|
case "drmReady":
|
|
3169
|
-
this.analyticsSession?.noteDrmReady();
|
|
3196
|
+
this.analyticsSession?.noteDrmReady(), this.staleLicenseReloaded = !1;
|
|
3170
3197
|
break;
|
|
3171
3198
|
case "ready":
|
|
3172
3199
|
this.analyticsSession?.noteReady(), this.emit("ready"), (this.opts.autoplay !== !1 || this.playRequested) && this.play();
|
|
@@ -3186,7 +3213,17 @@ var Vn = class {
|
|
|
3186
3213
|
case "ended":
|
|
3187
3214
|
this.onStreamEnded();
|
|
3188
3215
|
break;
|
|
3189
|
-
case "error":
|
|
3216
|
+
case "error": {
|
|
3217
|
+
let t = e.fatal && this.isStaleLicenseDenial(e);
|
|
3218
|
+
if (this.analyticsSession?.noteError(e.error.code, e.error.message, e.fatal && !t, e.error.httpStatus ?? 0, Math.round(this.opts.video.currentTime * 1e3), e.detail), t) {
|
|
3219
|
+
this.staleLicenseReloaded = !0;
|
|
3220
|
+
let t = this.loadGen;
|
|
3221
|
+
this.emit("warning", e.error), Promise.resolve().then(() => {
|
|
3222
|
+
if (!(this.destroyed || t !== this.loadGen) && this._state !== "error" && this._state !== "ended") return this.reload().catch(() => void 0);
|
|
3223
|
+
});
|
|
3224
|
+
} else e.fatal ? this.fail(e.error) : this.emit("warning", e.error);
|
|
3225
|
+
break;
|
|
3226
|
+
}
|
|
3190
3227
|
}
|
|
3191
3228
|
}
|
|
3192
3229
|
startLiveState(e) {
|
|
@@ -3206,7 +3243,7 @@ var Vn = class {
|
|
|
3206
3243
|
r = 0, i = !1;
|
|
3207
3244
|
},
|
|
3208
3245
|
onError: () => {
|
|
3209
|
-
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >=
|
|
3246
|
+
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= Rn && (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.`))));
|
|
3210
3247
|
}
|
|
3211
3248
|
});
|
|
3212
3249
|
}
|
|
@@ -3228,7 +3265,7 @@ var Vn = class {
|
|
|
3228
3265
|
scheduleRejoin(e) {
|
|
3229
3266
|
this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
|
|
3230
3267
|
this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
|
|
3231
|
-
}, Math.random() *
|
|
3268
|
+
}, Math.random() * Ln));
|
|
3232
3269
|
}
|
|
3233
3270
|
cancelRejoin() {
|
|
3234
3271
|
this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
|
|
@@ -3252,7 +3289,7 @@ var Vn = class {
|
|
|
3252
3289
|
}
|
|
3253
3290
|
t.controls = !1;
|
|
3254
3291
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
3255
|
-
r && r.insertBefore(n, t), n.appendChild(t),
|
|
3292
|
+
r && r.insertBefore(n, t), n.appendChild(t), xn(n, this.opts.theme), this.container = n, this.controlBar = kn({
|
|
3256
3293
|
root: n,
|
|
3257
3294
|
video: t,
|
|
3258
3295
|
player: this,
|
|
@@ -3283,7 +3320,7 @@ var Vn = class {
|
|
|
3283
3320
|
}
|
|
3284
3321
|
startStats() {
|
|
3285
3322
|
this.stopStats();
|
|
3286
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
3323
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? zn);
|
|
3287
3324
|
this.statsTimer = setInterval(() => {
|
|
3288
3325
|
if (!this.engine) return;
|
|
3289
3326
|
let e = this.engine.getStats();
|
|
@@ -3293,27 +3330,44 @@ var Vn = class {
|
|
|
3293
3330
|
stopStats() {
|
|
3294
3331
|
this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
|
|
3295
3332
|
}
|
|
3333
|
+
isStaleLicenseDenial(e) {
|
|
3334
|
+
return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== Vn || e.error.httpStatus !== 403 ? !1 : K(this._descriptor?.drm?.widevine?.licenseUrl);
|
|
3335
|
+
}
|
|
3296
3336
|
scheduleLicenseRefresh() {
|
|
3297
|
-
this.stopRefresh();
|
|
3298
|
-
|
|
3299
|
-
|
|
3337
|
+
if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
|
|
3338
|
+
typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
|
|
3339
|
+
document.visibilityState !== "visible" || this.destroyed || K(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
|
|
3340
|
+
}, document.addEventListener("visibilitychange", this.onRefocus));
|
|
3341
|
+
let e = this.opts.licenseRefreshMs ?? Bn;
|
|
3342
|
+
e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
3300
3343
|
}
|
|
3301
3344
|
stopRefresh() {
|
|
3302
|
-
this.refreshTimer && clearInterval(this.refreshTimer), this.refreshTimer = void 0;
|
|
3345
|
+
this.refreshTimer && clearInterval(this.refreshTimer), this.refreshTimer = void 0, this.onRefocus && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onRefocus), this.onRefocus = void 0);
|
|
3303
3346
|
}
|
|
3304
|
-
|
|
3347
|
+
refreshLicense() {
|
|
3305
3348
|
let e = this.engine;
|
|
3306
|
-
if (
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3349
|
+
if (this.destroyed || !e) return Promise.resolve(void 0);
|
|
3350
|
+
if (this.refreshInFlight?.engine === e) return this.refreshInFlight.promise;
|
|
3351
|
+
let t = (async () => {
|
|
3352
|
+
try {
|
|
3353
|
+
let t = await y(this.resolveOptions());
|
|
3354
|
+
if (this.destroyed || this.engine !== e) return;
|
|
3355
|
+
let n = t.drm?.widevine?.licenseUrl, r = t.drm?.fairplay?.licenseUrl;
|
|
3356
|
+
return (n || r) && (e.setLicenseUrls({
|
|
3357
|
+
widevine: n,
|
|
3358
|
+
fairplay: r
|
|
3359
|
+
}), this._descriptor = t), n;
|
|
3360
|
+
} catch (e) {
|
|
3361
|
+
e instanceof n && !o(e.code) && (this.stopRefresh(), this.destroyed || this.emit("warning", e));
|
|
3362
|
+
return;
|
|
3363
|
+
} finally {
|
|
3364
|
+
this.refreshInFlight?.promise === t && (this.refreshInFlight = void 0);
|
|
3365
|
+
}
|
|
3366
|
+
})();
|
|
3367
|
+
return this.refreshInFlight = {
|
|
3368
|
+
engine: e,
|
|
3369
|
+
promise: t
|
|
3370
|
+
}, t;
|
|
3317
3371
|
}
|
|
3318
3372
|
async play() {
|
|
3319
3373
|
if (this.destroyed) return;
|
|
@@ -3340,7 +3394,7 @@ var Vn = class {
|
|
|
3340
3394
|
this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
|
|
3341
3395
|
}
|
|
3342
3396
|
getStats() {
|
|
3343
|
-
return this.engine?.getStats() ??
|
|
3397
|
+
return this.engine?.getStats() ?? Ge;
|
|
3344
3398
|
}
|
|
3345
3399
|
getQualityLevels() {
|
|
3346
3400
|
return this.engine?.getQualityLevels() ?? [];
|
|
@@ -3392,7 +3446,7 @@ var Vn = class {
|
|
|
3392
3446
|
let e = ++this.loadGen;
|
|
3393
3447
|
this.teardownPlayback();
|
|
3394
3448
|
try {
|
|
3395
|
-
let t = await
|
|
3449
|
+
let t = await b({
|
|
3396
3450
|
...this.resolveOptions(),
|
|
3397
3451
|
waitForLive: this.opts.waitForLive ? this.buildWaitConfig(e) : void 0
|
|
3398
3452
|
});
|
|
@@ -3450,7 +3504,7 @@ function $(e) {
|
|
|
3450
3504
|
}
|
|
3451
3505
|
//#endregion
|
|
3452
3506
|
//#region src/embed/host.ts
|
|
3453
|
-
function
|
|
3507
|
+
function Gn(e) {
|
|
3454
3508
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
3455
3509
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
3456
3510
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -3509,15 +3563,15 @@ function Hn(e) {
|
|
|
3509
3563
|
}
|
|
3510
3564
|
//#endregion
|
|
3511
3565
|
//#region src/embed/page.ts
|
|
3512
|
-
var
|
|
3513
|
-
function
|
|
3566
|
+
var Kn = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
3567
|
+
function qn(e) {
|
|
3514
3568
|
if (typeof e == "boolean") return e;
|
|
3515
3569
|
if (typeof e == "object" && e) {
|
|
3516
3570
|
let t = e.endpoint;
|
|
3517
3571
|
return typeof t == "string" ? { endpoint: t } : {};
|
|
3518
3572
|
}
|
|
3519
3573
|
}
|
|
3520
|
-
function
|
|
3574
|
+
function Jn() {
|
|
3521
3575
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
3522
3576
|
if (e) return {
|
|
3523
3577
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -3527,7 +3581,7 @@ function Gn() {
|
|
|
3527
3581
|
autoplay: e.autoplay ?? !0,
|
|
3528
3582
|
muted: e.muted ?? !0,
|
|
3529
3583
|
waitForLive: e.waitForLive ?? !0,
|
|
3530
|
-
analytics:
|
|
3584
|
+
analytics: qn(e.analytics)
|
|
3531
3585
|
};
|
|
3532
3586
|
let t = new URLSearchParams(location.search);
|
|
3533
3587
|
return {
|
|
@@ -3540,9 +3594,9 @@ function Gn() {
|
|
|
3540
3594
|
waitForLive: !0
|
|
3541
3595
|
};
|
|
3542
3596
|
}
|
|
3543
|
-
async function
|
|
3544
|
-
let e =
|
|
3545
|
-
|
|
3597
|
+
async function Yn() {
|
|
3598
|
+
let e = Jn();
|
|
3599
|
+
Zn();
|
|
3546
3600
|
let t = document.createElement("video");
|
|
3547
3601
|
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);
|
|
3548
3602
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -3597,12 +3651,12 @@ async function Kn() {
|
|
|
3597
3651
|
code: e.code,
|
|
3598
3652
|
message: e.message
|
|
3599
3653
|
})), e.on("autoplayblocked", () => {
|
|
3600
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
3654
|
+
i({ type: "oddin:autoplayblocked" }), Xn(t, e);
|
|
3601
3655
|
});
|
|
3602
3656
|
}, s = async (r) => {
|
|
3603
3657
|
a?.destroy(), a = null;
|
|
3604
3658
|
try {
|
|
3605
|
-
let n = await
|
|
3659
|
+
let n = await Un({
|
|
3606
3660
|
video: t,
|
|
3607
3661
|
baseUrl: e.baseUrl,
|
|
3608
3662
|
matchUrn: r,
|
|
@@ -3664,7 +3718,7 @@ async function Kn() {
|
|
|
3664
3718
|
a?.retry();
|
|
3665
3719
|
break;
|
|
3666
3720
|
case "oddin:load":
|
|
3667
|
-
typeof e.matchUrn == "string" &&
|
|
3721
|
+
typeof e.matchUrn == "string" && Kn.test(e.matchUrn) && s(e.matchUrn);
|
|
3668
3722
|
break;
|
|
3669
3723
|
case "oddin:destroy": c();
|
|
3670
3724
|
}
|
|
@@ -3676,18 +3730,18 @@ async function Kn() {
|
|
|
3676
3730
|
protocol: 1
|
|
3677
3731
|
});
|
|
3678
3732
|
}
|
|
3679
|
-
function
|
|
3733
|
+
function Xn(e, t) {
|
|
3680
3734
|
if (document.getElementById("havik-tap")) return;
|
|
3681
3735
|
let n = document.createElement("button");
|
|
3682
3736
|
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", () => {
|
|
3683
3737
|
n.remove(), t.play();
|
|
3684
3738
|
}), document.body.appendChild(n);
|
|
3685
3739
|
}
|
|
3686
|
-
function
|
|
3740
|
+
function Zn() {
|
|
3687
3741
|
let e = document.createElement("style");
|
|
3688
3742
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
3689
3743
|
}
|
|
3690
3744
|
//#endregion
|
|
3691
|
-
export {
|
|
3745
|
+
export { yn as ODDIN_THEME, n as PlaybackError, xn as applyTheme, We as baseUrlForEnv, Yn as bootEmbed, Te as clearDeviceId, Un as createPlayer, E as deriveEventsBaseUrl, Be as detectDrmSupport, C as enterVideoFullscreen, w as exitVideoFullscreen, _e as fetchCatalog, ye as fetchTournament, xe as flattenMatches, k as getDeviceId, He as isLowLatencyManifest, $ as isOddinMessage, De as licenseRequestHeaders, Gn as mountEmbed, v as pollToLive, b as resolveStream, T as subscribeLiveState, S as videoFullscreenActive, Ce as watchStatus };
|
|
3692
3746
|
|
|
3693
3747
|
//# sourceMappingURL=index.js.map
|