@oddin-gg/havik-player 2.15.1 → 2.15.3
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 +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +244 -199
- package/dist/index.js.map +1 -1
- package/docs/API.md +21 -6
- 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 V(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 je() {
|
|
703
|
+
if (j()) for (let e of Object.values(R)) V(e);
|
|
704
704
|
}
|
|
705
|
-
function
|
|
705
|
+
function H(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 Me = 5e3, U = "video/mp4; codecs=\"avc1.42E01E\"", Ne = "audio/mp4; codecs=\"mp4a.40.2\"", Pe = {
|
|
712
712
|
widevine: ["com.widevine.alpha"],
|
|
713
713
|
fairplay: ["com.apple.fps"]
|
|
714
714
|
};
|
|
715
|
-
function
|
|
715
|
+
function Fe(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: U,
|
|
724
724
|
robustness: "",
|
|
725
725
|
encryptionScheme: "cbcs"
|
|
726
726
|
}],
|
|
727
727
|
audioCapabilities: [{
|
|
728
|
-
contentType:
|
|
728
|
+
contentType: Ne,
|
|
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: U,
|
|
736
736
|
robustness: F.video,
|
|
737
737
|
encryptionScheme: F.scheme
|
|
738
738
|
}],
|
|
739
739
|
audioCapabilities: [{
|
|
740
|
-
contentType:
|
|
740
|
+
contentType: Ne,
|
|
741
741
|
robustness: F.audio,
|
|
742
742
|
encryptionScheme: F.scheme
|
|
743
743
|
}]
|
|
744
744
|
}]);
|
|
745
745
|
}
|
|
746
|
-
function
|
|
746
|
+
function Ie(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 Le(e = {}) {
|
|
757
|
+
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Me, 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 = Pe[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 Ie((await Ie(i(n, Fe(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
|
|
781
781
|
verdict: "supported",
|
|
782
782
|
system: e,
|
|
783
783
|
detail: r
|
|
@@ -801,49 +801,49 @@ async function He(e = {}) {
|
|
|
801
801
|
}
|
|
802
802
|
//#endregion
|
|
803
803
|
//#region src/core/manifest.ts
|
|
804
|
-
var
|
|
805
|
-
function
|
|
806
|
-
return
|
|
804
|
+
var Re = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
|
|
805
|
+
function ze(e) {
|
|
806
|
+
return Re.test(e);
|
|
807
807
|
}
|
|
808
808
|
//#endregion
|
|
809
809
|
//#region src/core/env.ts
|
|
810
|
-
var
|
|
810
|
+
var Be = {
|
|
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 Ve(e) {
|
|
815
|
+
let t = Object.prototype.hasOwnProperty.call(Be, e) ? Be[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 He = { droppedFrames: 0 };
|
|
822
|
+
function Ue(e) {
|
|
823
823
|
try {
|
|
824
824
|
return new URL(e).host;
|
|
825
825
|
} catch {
|
|
826
826
|
return "";
|
|
827
827
|
}
|
|
828
828
|
}
|
|
829
|
-
var
|
|
830
|
-
function
|
|
829
|
+
var We = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
|
|
830
|
+
function Ge(e) {
|
|
831
831
|
if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
|
|
832
832
|
let t = "", n = -1, r = performance.getEntriesByType("resource");
|
|
833
|
-
for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" ||
|
|
834
|
-
let e =
|
|
833
|
+
for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || We.test(i.name)) && i.startTime >= n) {
|
|
834
|
+
let e = Ue(i.name);
|
|
835
835
|
e && (t = e, n = i.startTime);
|
|
836
836
|
}
|
|
837
837
|
return t;
|
|
838
838
|
}
|
|
839
|
-
function
|
|
839
|
+
function W(e) {
|
|
840
840
|
let t = e.getVideoPlaybackQuality?.();
|
|
841
841
|
return {
|
|
842
842
|
dropped: t?.droppedVideoFrames ?? 0,
|
|
843
843
|
totalFrames: t?.totalVideoFrames ?? 0
|
|
844
844
|
};
|
|
845
845
|
}
|
|
846
|
-
function
|
|
846
|
+
function Ke(e, t) {
|
|
847
847
|
let n = [
|
|
848
848
|
["playing", () => t("playing")],
|
|
849
849
|
["waiting", () => t("buffering")],
|
|
@@ -860,7 +860,7 @@ function qe(e, t) {
|
|
|
860
860
|
}
|
|
861
861
|
//#endregion
|
|
862
862
|
//#region src/core/engine/native.ts
|
|
863
|
-
function
|
|
863
|
+
function qe(e) {
|
|
864
864
|
try {
|
|
865
865
|
let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
|
|
866
866
|
return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
|
|
@@ -868,10 +868,10 @@ function Je(e) {
|
|
|
868
868
|
return;
|
|
869
869
|
}
|
|
870
870
|
}
|
|
871
|
-
function
|
|
871
|
+
function G(e) {
|
|
872
872
|
return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
|
|
873
873
|
}
|
|
874
|
-
function
|
|
874
|
+
function Je() {
|
|
875
875
|
if (typeof window > "u") return !1;
|
|
876
876
|
let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
|
|
877
877
|
return e || t;
|
|
@@ -934,7 +934,7 @@ var K = class {
|
|
|
934
934
|
});
|
|
935
935
|
this.onEncrypted = (n) => {
|
|
936
936
|
let i = n;
|
|
937
|
-
i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV =
|
|
937
|
+
i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = qe(i.initData), (async () => {
|
|
938
938
|
try {
|
|
939
939
|
let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
|
|
940
940
|
initDataTypes: [i.initDataType],
|
|
@@ -1029,11 +1029,11 @@ var K = class {
|
|
|
1029
1029
|
e.seekable.length > 0 && (e.currentTime = e.seekable.end(e.seekable.length - 1));
|
|
1030
1030
|
}
|
|
1031
1031
|
getStats() {
|
|
1032
|
-
let e = this.deps.video, t =
|
|
1032
|
+
let e = this.deps.video, t = W(e), n = {
|
|
1033
1033
|
droppedFrames: t.dropped,
|
|
1034
1034
|
decodedFrames: t.totalFrames
|
|
1035
1035
|
};
|
|
1036
|
-
return this.cdnHost ||=
|
|
1036
|
+
return this.cdnHost ||= Ge(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity ? (n.isLive = !0, e.seekable.length > 0 && (n.atLiveEdge = e.currentTime >= e.seekable.end(e.seekable.length - 1) - 2)) : Number.isFinite(e.duration) && e.duration > 0 && (n.isLive = !1), n;
|
|
1037
1037
|
}
|
|
1038
1038
|
stop() {
|
|
1039
1039
|
try {
|
|
@@ -1219,21 +1219,21 @@ function it(e, t) {
|
|
|
1219
1219
|
function at() {
|
|
1220
1220
|
return e.isSupported();
|
|
1221
1221
|
}
|
|
1222
|
-
var ot = 3, st = 5, ct = 3, lt = 3e4, ut = 12e3, dt = 3e3, ft = 6e3, pt = 3, mt = .5, ht = 1.
|
|
1223
|
-
function
|
|
1222
|
+
var ot = 3, st = 5, ct = 3, lt = 3e4, ut = 12e3, dt = 3e3, ft = 6e3, pt = 3, mt = .5, ht = 1.1, gt = .25, _t = 5e3, vt = 4e3, yt = 2, bt = 5, xt = 2, St = 2, Ct = 4, wt = 4, Tt = 2e3, Et = 3e4, Dt = .2, Ot = 30, kt = 2, At = 2, jt = 9, Mt = .5, Nt = 64;
|
|
1223
|
+
function Pt(e) {
|
|
1224
1224
|
if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
|
|
1225
1225
|
delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
|
|
1226
1226
|
return;
|
|
1227
1227
|
}
|
|
1228
|
-
e.liveSyncDuration ??=
|
|
1229
|
-
let t = Math.max(12, e.liveSyncDuration +
|
|
1230
|
-
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t),
|
|
1228
|
+
e.liveSyncDuration ??= At;
|
|
1229
|
+
let t = Math.max(12, e.liveSyncDuration + jt);
|
|
1230
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Ft(e, e.liveSyncDuration);
|
|
1231
1231
|
}
|
|
1232
|
-
function
|
|
1232
|
+
function Ft(e, t) {
|
|
1233
1233
|
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
1234
1234
|
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
1235
1235
|
}
|
|
1236
|
-
var
|
|
1236
|
+
var It = class {
|
|
1237
1237
|
name = "hls";
|
|
1238
1238
|
hls = null;
|
|
1239
1239
|
deps;
|
|
@@ -1296,6 +1296,13 @@ var Nt = class {
|
|
|
1296
1296
|
capTimer = null;
|
|
1297
1297
|
sizeCapLevel = null;
|
|
1298
1298
|
bitrateCapLevel = -1;
|
|
1299
|
+
fpsCapBitrate = null;
|
|
1300
|
+
fpsCapFailedHeight = null;
|
|
1301
|
+
fpsCapManaged = !0;
|
|
1302
|
+
fpsLastFrames = -1;
|
|
1303
|
+
fpsLastDropped = -1;
|
|
1304
|
+
fpsBadTicks = 0;
|
|
1305
|
+
fpsDownCaps = 0;
|
|
1299
1306
|
sizeCapManaged = !0;
|
|
1300
1307
|
dprMedia = null;
|
|
1301
1308
|
onDprChange = null;
|
|
@@ -1304,7 +1311,7 @@ var Nt = class {
|
|
|
1304
1311
|
this.deps = e, this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
|
|
1305
1312
|
}
|
|
1306
1313
|
async load() {
|
|
1307
|
-
let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a =
|
|
1314
|
+
let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = G(r) && Je(), o = !!e.drm?.widevine?.licenseUrl && !a;
|
|
1308
1315
|
if (e.drmEnabled && !o) {
|
|
1309
1316
|
i({
|
|
1310
1317
|
type: "error",
|
|
@@ -1313,7 +1320,7 @@ var Nt = class {
|
|
|
1313
1320
|
});
|
|
1314
1321
|
return;
|
|
1315
1322
|
}
|
|
1316
|
-
e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ae(r),
|
|
1323
|
+
e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ae(r), je()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
|
|
1317
1324
|
let e = this.hls;
|
|
1318
1325
|
if (document.visibilityState !== "visible" || !e) return;
|
|
1319
1326
|
let t = e.liveSyncPosition;
|
|
@@ -1339,7 +1346,7 @@ var Nt = class {
|
|
|
1339
1346
|
}, _t));
|
|
1340
1347
|
}
|
|
1341
1348
|
resumeLoading() {
|
|
1342
|
-
if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
|
|
1349
|
+
if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
|
|
1343
1350
|
this.lastAdvanceMs = Date.now(), this.lastFragLoadingMs = 0, this.resetStarvationWindow(), this.resetChaseWindow(), this.clearKick();
|
|
1344
1351
|
try {
|
|
1345
1352
|
this.hls.startLoad(-1);
|
|
@@ -1368,18 +1375,18 @@ var Nt = class {
|
|
|
1368
1375
|
let t = e.liveSyncPosition;
|
|
1369
1376
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
1370
1377
|
let { video: n } = this.deps;
|
|
1371
|
-
n.currentTime <= t +
|
|
1378
|
+
n.currentTime <= t + Mt || (n.currentTime = t);
|
|
1372
1379
|
}
|
|
1373
1380
|
startHls() {
|
|
1374
1381
|
let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
|
|
1375
|
-
this.clearKick(), this.resetStarvationWindow(), this.resetChaseWindow(), this.lastFragLoadingMs = 0, this.lastEndSN = -1, this.lastAdvanceMs = 0;
|
|
1382
|
+
this.clearKick(), this.resetStarvationWindow(), this.resetChaseWindow(), this.resetFrameDropWindow(), this.lastFragLoadingMs = 0, this.lastEndSN = -1, this.lastAdvanceMs = 0;
|
|
1376
1383
|
let u = n.drmEnabled && !!(n.drm?.widevine?.licenseUrl || n.drm?.fairplay?.licenseUrl), d = {
|
|
1377
1384
|
debug: s === !0,
|
|
1378
1385
|
enableWorker: !o,
|
|
1379
1386
|
lowLatencyMode: o,
|
|
1380
1387
|
backBufferLength: 90,
|
|
1381
1388
|
maxBufferHole: .5,
|
|
1382
|
-
maxLiveSyncPlaybackRate: 1.
|
|
1389
|
+
maxLiveSyncPlaybackRate: 1.1,
|
|
1383
1390
|
abrEwmaDefaultEstimate: 1e6,
|
|
1384
1391
|
capLevelToPlayerSize: !1,
|
|
1385
1392
|
...this.loadStarted ? {} : { autoStartLoad: !1 },
|
|
@@ -1415,7 +1422,7 @@ var Nt = class {
|
|
|
1415
1422
|
}), t = tt(e);
|
|
1416
1423
|
t && (this.prefetch = e, d.fLoader = t);
|
|
1417
1424
|
}
|
|
1418
|
-
|
|
1425
|
+
Pt(d), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = d.autoStartLoad !== !1;
|
|
1419
1426
|
let f = new e(d);
|
|
1420
1427
|
if (this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
|
|
1421
1428
|
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" });
|
|
@@ -1430,10 +1437,10 @@ var Nt = class {
|
|
|
1430
1437
|
let n = t?.frag?.stats, r = n?.loaded;
|
|
1431
1438
|
typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
|
|
1432
1439
|
let i = n?.loading;
|
|
1433
|
-
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 >
|
|
1440
|
+
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 > Nt && this.requestTimesMs.shift());
|
|
1434
1441
|
let a = t?.frag?.url;
|
|
1435
1442
|
if (a) {
|
|
1436
|
-
let e =
|
|
1443
|
+
let e = Ue(a);
|
|
1437
1444
|
e && (this.cdnHost = e);
|
|
1438
1445
|
}
|
|
1439
1446
|
}), f.on(e.Events.LEVEL_LOADED, (e, t) => {
|
|
@@ -1454,7 +1461,7 @@ var Nt = class {
|
|
|
1454
1461
|
f.on(e.Events.KEY_LOADED, () => {
|
|
1455
1462
|
u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
|
|
1456
1463
|
}), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
|
|
1457
|
-
this.checkEndStale(), this.checkStarvation(), this.checkFutileChase();
|
|
1464
|
+
this.checkEndStale(), this.checkStarvation(), this.checkFutileChase(), this.checkFrameDrops();
|
|
1458
1465
|
}, dt), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
1459
1466
|
this.renditionSwitches += 1;
|
|
1460
1467
|
let n = this.lastLevelIndex >= 0 ? f.levels[this.lastLevelIndex] : void 0, r = f.levels[t.level];
|
|
@@ -1529,9 +1536,9 @@ var Nt = class {
|
|
|
1529
1536
|
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;
|
|
1530
1537
|
}
|
|
1531
1538
|
dropLevelsWidevineCannotPlay(e) {
|
|
1532
|
-
this.removeLevelsWhere(e, (e) =>
|
|
1539
|
+
this.removeLevelsWhere(e, (e) => H(e) !== !0);
|
|
1533
1540
|
let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && I(e) !== "avc" && !!I(e)));
|
|
1534
|
-
for (let n of t)
|
|
1541
|
+
for (let n of t) V(n).then((t) => {
|
|
1535
1542
|
t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
|
|
1536
1543
|
});
|
|
1537
1544
|
}
|
|
@@ -1542,7 +1549,7 @@ var Nt = class {
|
|
|
1542
1549
|
a && I(a) && t(a) && (r.push(n), i.add(a));
|
|
1543
1550
|
}), !r.length) return !1;
|
|
1544
1551
|
let a = [...i].join(", ");
|
|
1545
|
-
if (!n.some((e, t) => r.includes(t) ? !1 : !I(e.videoCodec) ||
|
|
1552
|
+
if (!n.some((e, t) => r.includes(t) ? !1 : !I(e.videoCodec) || H(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
|
|
1546
1553
|
for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
|
|
1547
1554
|
return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
|
|
1548
1555
|
}
|
|
@@ -1555,8 +1562,12 @@ var Nt = class {
|
|
|
1555
1562
|
pushCap() {
|
|
1556
1563
|
let e = this.hls;
|
|
1557
1564
|
if (!e) return;
|
|
1558
|
-
let t =
|
|
1559
|
-
|
|
1565
|
+
let t = [
|
|
1566
|
+
this.sizeCapLevel ?? -1,
|
|
1567
|
+
this.bitrateCapLevel,
|
|
1568
|
+
this.fpsCapLevel(e)
|
|
1569
|
+
].filter((e) => e >= 0);
|
|
1570
|
+
e.autoLevelCapping = t.length ? Math.min(...t) : -1;
|
|
1560
1571
|
}
|
|
1561
1572
|
getAudioTracks() {
|
|
1562
1573
|
return this.hls ? this.hls.audioTracks.map((e) => ({
|
|
@@ -1588,7 +1599,7 @@ var Nt = class {
|
|
|
1588
1599
|
e.widevine && (this.licenseUrl = e.widevine);
|
|
1589
1600
|
}
|
|
1590
1601
|
getStats() {
|
|
1591
|
-
let e = this.hls, t =
|
|
1602
|
+
let e = this.hls, t = W(this.deps.video), n = {
|
|
1592
1603
|
droppedFrames: t.dropped,
|
|
1593
1604
|
decodedFrames: t.totalFrames,
|
|
1594
1605
|
lowLatency: this.detectedLowLatency,
|
|
@@ -1596,6 +1607,7 @@ var Nt = class {
|
|
|
1596
1607
|
playlistBytesLoaded: this.playlistBytesLoaded,
|
|
1597
1608
|
renditionSwitches: this.renditionSwitches,
|
|
1598
1609
|
liveRetargets: this.liveRetargets,
|
|
1610
|
+
fpsDownCaps: this.fpsDownCaps,
|
|
1599
1611
|
licenseTimeMs: this.licenseTimeMs,
|
|
1600
1612
|
upshifts: this.upshifts,
|
|
1601
1613
|
downshifts: this.downshifts,
|
|
@@ -1650,7 +1662,7 @@ var Nt = class {
|
|
|
1650
1662
|
this.resetStarvationWindow();
|
|
1651
1663
|
return;
|
|
1652
1664
|
}
|
|
1653
|
-
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < ft, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > vt, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } =
|
|
1665
|
+
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < ft, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > vt, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = W(t), c = o - s, l = c !== this.starvedFrames;
|
|
1654
1666
|
if (this.starvedFrames = c, !a || l) {
|
|
1655
1667
|
(t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
|
|
1656
1668
|
return;
|
|
@@ -1673,6 +1685,39 @@ var Nt = class {
|
|
|
1673
1685
|
}
|
|
1674
1686
|
}
|
|
1675
1687
|
}
|
|
1688
|
+
fpsCapLevel(e) {
|
|
1689
|
+
if (this.fpsCapBitrate == null) return -1;
|
|
1690
|
+
let t = this.fpsCapFailedHeight, n = -1;
|
|
1691
|
+
return e.levels.forEach((e, r) => {
|
|
1692
|
+
let i = t == null || !(e.height > 0) || e.height < t;
|
|
1693
|
+
e.bitrate <= this.fpsCapBitrate && i && (n = r);
|
|
1694
|
+
}), n < 0 ? 0 : n;
|
|
1695
|
+
}
|
|
1696
|
+
resetFrameDropWindow() {
|
|
1697
|
+
this.fpsLastFrames = -1, this.fpsLastDropped = -1, this.fpsBadTicks = 0;
|
|
1698
|
+
}
|
|
1699
|
+
checkFrameDrops() {
|
|
1700
|
+
let e = this.hls, { video: t } = this.deps;
|
|
1701
|
+
if (!e || !this.fpsCapManaged || this.loadSuspended || t.paused || !e.autoLevelEnabled || typeof document < "u" && document.hidden) {
|
|
1702
|
+
this.resetFrameDropWindow();
|
|
1703
|
+
return;
|
|
1704
|
+
}
|
|
1705
|
+
let { totalFrames: n, dropped: r } = W(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
|
|
1706
|
+
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Ot || o < 0) {
|
|
1707
|
+
this.fpsBadTicks = 0;
|
|
1708
|
+
return;
|
|
1709
|
+
}
|
|
1710
|
+
if (o <= Dt * a) {
|
|
1711
|
+
this.fpsBadTicks = 0;
|
|
1712
|
+
return;
|
|
1713
|
+
}
|
|
1714
|
+
if (this.fpsBadTicks += 1, this.fpsBadTicks < kt) return;
|
|
1715
|
+
this.fpsBadTicks = 0;
|
|
1716
|
+
let s = e.levels, c = s[e.currentLevel];
|
|
1717
|
+
if (!c) return;
|
|
1718
|
+
let l = s.filter((e) => e.height > 0 && e.height < c.height), u = (l.length ? l : s.filter((e) => e.bitrate < c.bitrate)).map((e) => e.bitrate).sort((e, t) => t - e)[0];
|
|
1719
|
+
u != null && (this.fpsCapBitrate != null && u >= this.fpsCapBitrate || (this.fpsCapBitrate = u, l.length && (this.fpsCapFailedHeight = c.height), this.fpsDownCaps += 1, console.warn(`havik-player: dropping ${Math.round(100 * o / a)}% of frames at ${c.height}p — capping quality below it`), this.pushCap()));
|
|
1720
|
+
}
|
|
1676
1721
|
resetChaseWindow() {
|
|
1677
1722
|
this.chaseLatency = -1, this.chaseTicks = 0;
|
|
1678
1723
|
}
|
|
@@ -1683,7 +1728,7 @@ var Nt = class {
|
|
|
1683
1728
|
return;
|
|
1684
1729
|
}
|
|
1685
1730
|
let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
|
|
1686
|
-
if (!(!t.paused &&
|
|
1731
|
+
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(ht, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
|
|
1687
1732
|
this.resetChaseWindow();
|
|
1688
1733
|
return;
|
|
1689
1734
|
}
|
|
@@ -1811,19 +1856,19 @@ var Nt = class {
|
|
|
1811
1856
|
let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
|
|
1812
1857
|
return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
|
|
1813
1858
|
}
|
|
1814
|
-
},
|
|
1859
|
+
}, Lt = 15e3, Rt = 6e5, zt = 3e5, Bt = 100, q = 1, Vt = 1e3, Ht = 3e4, Ut = 1e3, Wt = {
|
|
1815
1860
|
inline: "PRESENTATION_INLINE",
|
|
1816
1861
|
fullscreen: "PRESENTATION_FULLSCREEN",
|
|
1817
1862
|
pip: "PRESENTATION_PIP"
|
|
1818
|
-
},
|
|
1863
|
+
}, Gt = {
|
|
1819
1864
|
widevine: "KEY_SYSTEM_WIDEVINE",
|
|
1820
1865
|
fairplay: "KEY_SYSTEM_FAIRPLAY",
|
|
1821
1866
|
none: "KEY_SYSTEM_NONE"
|
|
1822
1867
|
};
|
|
1823
|
-
function
|
|
1868
|
+
function Kt(e, t) {
|
|
1824
1869
|
return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
|
|
1825
1870
|
}
|
|
1826
|
-
var
|
|
1871
|
+
var qt = /* @__PURE__ */ new Set([
|
|
1827
1872
|
"INVALID_URN",
|
|
1828
1873
|
"NOT_FOUND",
|
|
1829
1874
|
"GONE",
|
|
@@ -1843,7 +1888,7 @@ var Wt = /* @__PURE__ */ new Set([
|
|
|
1843
1888
|
ended: "PLAYER_STATE_ENDED",
|
|
1844
1889
|
error: "PLAYER_STATE_ERROR"
|
|
1845
1890
|
};
|
|
1846
|
-
function
|
|
1891
|
+
function Jt(e) {
|
|
1847
1892
|
try {
|
|
1848
1893
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
1849
1894
|
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);
|
|
@@ -1851,8 +1896,8 @@ function Gt(e) {
|
|
|
1851
1896
|
return;
|
|
1852
1897
|
}
|
|
1853
1898
|
}
|
|
1854
|
-
var
|
|
1855
|
-
function
|
|
1899
|
+
var Yt = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), Xt = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), Zt = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
|
|
1900
|
+
function Qt(e) {
|
|
1856
1901
|
if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
|
|
1857
1902
|
let t;
|
|
1858
1903
|
try {
|
|
@@ -1861,19 +1906,19 @@ function Yt(e) {
|
|
|
1861
1906
|
} catch {
|
|
1862
1907
|
return;
|
|
1863
1908
|
}
|
|
1864
|
-
if (
|
|
1865
|
-
Y.add(t), g(
|
|
1909
|
+
if (Xt.has(t) && !Y.has(t)) {
|
|
1910
|
+
Y.add(t), g(Zt(new URL(t).origin));
|
|
1866
1911
|
for (let e of X) e.noteCspBlocked();
|
|
1867
1912
|
}
|
|
1868
1913
|
}
|
|
1869
|
-
function
|
|
1914
|
+
function $t(e, t) {
|
|
1870
1915
|
return g(t, e), { disabledReason: t };
|
|
1871
1916
|
}
|
|
1872
|
-
function
|
|
1873
|
-
if (n) return t && !
|
|
1917
|
+
function en(e, t, n) {
|
|
1918
|
+
if (n) return t && !Yt(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
|
|
1874
1919
|
if (t) return { endpoint: t };
|
|
1875
|
-
if (t !== void 0) return
|
|
1876
|
-
let r =
|
|
1920
|
+
if (t !== void 0) return $t("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).");
|
|
1921
|
+
let r = Jt(e);
|
|
1877
1922
|
if (r) return { endpoint: r };
|
|
1878
1923
|
let i;
|
|
1879
1924
|
try {
|
|
@@ -1881,9 +1926,9 @@ function Zt(e, t, n) {
|
|
|
1881
1926
|
} catch {
|
|
1882
1927
|
i = e;
|
|
1883
1928
|
}
|
|
1884
|
-
return
|
|
1929
|
+
return $t(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).`);
|
|
1885
1930
|
}
|
|
1886
|
-
var
|
|
1931
|
+
var tn = class {
|
|
1887
1932
|
opts;
|
|
1888
1933
|
url;
|
|
1889
1934
|
cspKey;
|
|
@@ -1965,8 +2010,8 @@ var Qt = class {
|
|
|
1965
2010
|
constructor(e) {
|
|
1966
2011
|
this.opts = {
|
|
1967
2012
|
...e,
|
|
1968
|
-
heartbeatMs: e.heartbeatMs ??
|
|
1969
|
-
idleMs: e.idleMs ??
|
|
2013
|
+
heartbeatMs: e.heartbeatMs ?? Lt,
|
|
2014
|
+
idleMs: e.idleMs ?? Rt
|
|
1970
2015
|
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
|
|
1971
2016
|
try {
|
|
1972
2017
|
let e = new URL(this.url);
|
|
@@ -1983,11 +2028,11 @@ var Qt = class {
|
|
|
1983
2028
|
sdkVersion: this.opts.sdkVersion,
|
|
1984
2029
|
...this.opts.environment
|
|
1985
2030
|
};
|
|
1986
|
-
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(),
|
|
2031
|
+
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Vt), 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 && Xt.add(this.cspKey), document.addEventListener("securitypolicyviolation", Qt), X.add(this), this.noteCspBlocked(), this.onVisibility());
|
|
1987
2032
|
}
|
|
1988
2033
|
checkSuspension(e) {
|
|
1989
2034
|
if (this.endedFlag || !this.opts.idleMs) return !1;
|
|
1990
|
-
let t = Math.max(this.opts.idleMs,
|
|
2035
|
+
let t = Math.max(this.opts.idleMs, zt);
|
|
1991
2036
|
return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
|
|
1992
2037
|
}
|
|
1993
2038
|
syncIdle(e) {
|
|
@@ -2010,12 +2055,12 @@ var Qt = class {
|
|
|
2010
2055
|
let a = {
|
|
2011
2056
|
fromState: J[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2012
2057
|
toState: J[t] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2013
|
-
presentation:
|
|
2058
|
+
presentation: Wt[this.presentation]
|
|
2014
2059
|
}, o = this.causeOf(e, t, i);
|
|
2015
2060
|
o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
2016
2061
|
}
|
|
2017
2062
|
seekInduced(e) {
|
|
2018
|
-
return this.lastSeekMs >= 0 && e - this.lastSeekMs <
|
|
2063
|
+
return this.lastSeekMs >= 0 && e - this.lastSeekMs < Ut;
|
|
2019
2064
|
}
|
|
2020
2065
|
causeOf(e, t, n) {
|
|
2021
2066
|
if (t === "error") return "TRANSITION_CAUSE_ERROR";
|
|
@@ -2089,7 +2134,7 @@ var Qt = class {
|
|
|
2089
2134
|
let r = n ?? "";
|
|
2090
2135
|
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";
|
|
2091
2136
|
if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
|
|
2092
|
-
if (
|
|
2137
|
+
if (qt.has(e)) return "ERROR_STAGE_RESOLVE";
|
|
2093
2138
|
let i = t ?? "";
|
|
2094
2139
|
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";
|
|
2095
2140
|
}
|
|
@@ -2136,14 +2181,14 @@ var Qt = class {
|
|
|
2136
2181
|
if (this.lastRequestCount = g, _ > 0) {
|
|
2137
2182
|
o.requestCountDelta = _;
|
|
2138
2183
|
let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
|
|
2139
|
-
n.length > 0 && (o.requestTimeP50Ms =
|
|
2184
|
+
n.length > 0 && (o.requestTimeP50Ms = Kt(n, 50), o.requestTimeP95Ms = Kt(n, 95));
|
|
2140
2185
|
}
|
|
2141
2186
|
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();
|
|
2142
2187
|
}
|
|
2143
2188
|
maybeEmitMediaInfo(e) {
|
|
2144
2189
|
if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
|
|
2145
2190
|
let t = {};
|
|
2146
|
-
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem =
|
|
2191
|
+
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = Gt[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);
|
|
2147
2192
|
let n = JSON.stringify(t);
|
|
2148
2193
|
n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
|
|
2149
2194
|
}
|
|
@@ -2163,7 +2208,7 @@ var Qt = class {
|
|
|
2163
2208
|
let c = r?.positionMs ?? 0;
|
|
2164
2209
|
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));
|
|
2165
2210
|
let l = e !== "END_REASON_ENDED";
|
|
2166
|
-
l && this.lastStallMs > 0 && n - this.lastStallMs <=
|
|
2211
|
+
l && this.lastStallMs > 0 && n - this.lastStallMs <= Ht && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Ht && (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);
|
|
2167
2212
|
let u = r?.decodedFrames ?? this.lastDecoded;
|
|
2168
2213
|
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");
|
|
2169
2214
|
}
|
|
@@ -2183,13 +2228,13 @@ var Qt = class {
|
|
|
2183
2228
|
};
|
|
2184
2229
|
}
|
|
2185
2230
|
noteCspBlocked() {
|
|
2186
|
-
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(
|
|
2231
|
+
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(Zt(new URL(this.url).origin)));
|
|
2187
2232
|
}
|
|
2188
2233
|
cspBlocked() {
|
|
2189
2234
|
return !!this.cspKey && Y.has(this.cspKey);
|
|
2190
2235
|
}
|
|
2191
2236
|
enqueue(e) {
|
|
2192
|
-
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length >
|
|
2237
|
+
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Bt;) {
|
|
2193
2238
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
2194
2239
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
2195
2240
|
}
|
|
@@ -2216,7 +2261,7 @@ var Qt = class {
|
|
|
2216
2261
|
};
|
|
2217
2262
|
//#endregion
|
|
2218
2263
|
//#region src/core/environment.ts
|
|
2219
|
-
function
|
|
2264
|
+
function nn() {
|
|
2220
2265
|
if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
|
|
2221
2266
|
let e;
|
|
2222
2267
|
try {
|
|
@@ -2241,14 +2286,14 @@ function $t() {
|
|
|
2241
2286
|
integration: "INTEGRATION_KIND_IFRAME"
|
|
2242
2287
|
};
|
|
2243
2288
|
}
|
|
2244
|
-
function
|
|
2289
|
+
function rn() {
|
|
2245
2290
|
if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
|
|
2246
2291
|
let e = navigator.userAgentData, t = e?.platform ?? "";
|
|
2247
2292
|
if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
|
|
2248
2293
|
let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
|
|
2249
2294
|
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";
|
|
2250
2295
|
}
|
|
2251
|
-
function
|
|
2296
|
+
function an() {
|
|
2252
2297
|
let e = typeof navigator < "u" ? navigator.connection : void 0;
|
|
2253
2298
|
if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
|
|
2254
2299
|
let t = {
|
|
@@ -2267,17 +2312,17 @@ function tn() {
|
|
|
2267
2312
|
}
|
|
2268
2313
|
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;
|
|
2269
2314
|
}
|
|
2270
|
-
function
|
|
2271
|
-
let t =
|
|
2272
|
-
deviceClass:
|
|
2315
|
+
function on(e) {
|
|
2316
|
+
let t = nn(), n = {
|
|
2317
|
+
deviceClass: rn(),
|
|
2273
2318
|
integration: t.integration,
|
|
2274
|
-
...
|
|
2319
|
+
...an()
|
|
2275
2320
|
};
|
|
2276
2321
|
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);
|
|
2277
2322
|
let r = e.getBoundingClientRect?.();
|
|
2278
2323
|
return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
|
|
2279
2324
|
}
|
|
2280
|
-
async function
|
|
2325
|
+
async function sn() {
|
|
2281
2326
|
let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
|
|
2282
2327
|
if (!e?.getHighEntropyValues) return {};
|
|
2283
2328
|
try {
|
|
@@ -2289,7 +2334,7 @@ async function rn() {
|
|
|
2289
2334
|
}
|
|
2290
2335
|
//#endregion
|
|
2291
2336
|
//#region src/core/version.ts
|
|
2292
|
-
var
|
|
2337
|
+
var cn = "2.15.3", ln = {
|
|
2293
2338
|
accent: "#E1B600",
|
|
2294
2339
|
accentText: "#1B1C23",
|
|
2295
2340
|
background: "#0e0f13",
|
|
@@ -2300,7 +2345,7 @@ var an = "2.15.1", on = {
|
|
|
2300
2345
|
border: "rgba(255, 255, 255, 0.1)",
|
|
2301
2346
|
radius: "8px",
|
|
2302
2347
|
fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
|
|
2303
|
-
},
|
|
2348
|
+
}, un = {
|
|
2304
2349
|
accent: "--havik-accent",
|
|
2305
2350
|
accentText: "--havik-accent-text",
|
|
2306
2351
|
background: "--havik-bg",
|
|
@@ -2312,26 +2357,26 @@ var an = "2.15.1", on = {
|
|
|
2312
2357
|
radius: "--havik-radius",
|
|
2313
2358
|
fontFamily: "--havik-font"
|
|
2314
2359
|
};
|
|
2315
|
-
function
|
|
2360
|
+
function dn(e, t) {
|
|
2316
2361
|
let n = {
|
|
2317
|
-
...
|
|
2362
|
+
...ln,
|
|
2318
2363
|
...t
|
|
2319
2364
|
};
|
|
2320
|
-
for (let t of Object.keys(
|
|
2365
|
+
for (let t of Object.keys(un)) e.style.setProperty(un[t], n[t]);
|
|
2321
2366
|
n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
|
|
2322
2367
|
}
|
|
2323
2368
|
//#endregion
|
|
2324
2369
|
//#region src/ui/styles.ts
|
|
2325
|
-
var
|
|
2326
|
-
function
|
|
2327
|
-
let n = e.querySelector(`style#${
|
|
2328
|
-
if (n && (!t ||
|
|
2370
|
+
var fn = "havik-player-styles", pn = "\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", mn = /* @__PURE__ */ new WeakMap();
|
|
2371
|
+
function hn(e = document, t) {
|
|
2372
|
+
let n = e.querySelector(`style#${fn}`);
|
|
2373
|
+
if (n && (!t || mn.get(n) === t)) return;
|
|
2329
2374
|
let r = e.createElement("style");
|
|
2330
|
-
r.id =
|
|
2375
|
+
r.id = fn, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = pn, mn.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
|
|
2331
2376
|
}
|
|
2332
2377
|
//#endregion
|
|
2333
2378
|
//#region src/ui/icons.ts
|
|
2334
|
-
var
|
|
2379
|
+
var gn = {
|
|
2335
2380
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
2336
2381
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
2337
2382
|
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\"/>",
|
|
@@ -2345,20 +2390,20 @@ var pn = {
|
|
|
2345
2390
|
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\"/>"
|
|
2346
2391
|
};
|
|
2347
2392
|
function Z(e) {
|
|
2348
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
2393
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${gn[e]}</svg>`;
|
|
2349
2394
|
}
|
|
2350
2395
|
//#endregion
|
|
2351
2396
|
//#region src/ui/controls.ts
|
|
2352
|
-
var
|
|
2397
|
+
var _n = 3e3, vn = 250, yn = /* @__PURE__ */ new Set([
|
|
2353
2398
|
"GONE",
|
|
2354
2399
|
"NOT_FOUND",
|
|
2355
2400
|
"INVALID_URN",
|
|
2356
2401
|
"UNAUTHORIZED"
|
|
2357
2402
|
]);
|
|
2358
|
-
function
|
|
2359
|
-
return new
|
|
2403
|
+
function bn(e) {
|
|
2404
|
+
return new xn(e);
|
|
2360
2405
|
}
|
|
2361
|
-
var
|
|
2406
|
+
var xn = class {
|
|
2362
2407
|
root;
|
|
2363
2408
|
video;
|
|
2364
2409
|
player;
|
|
@@ -2404,7 +2449,7 @@ var vn = class {
|
|
|
2404
2449
|
scrubbing = !1;
|
|
2405
2450
|
offFns = [];
|
|
2406
2451
|
constructor(e) {
|
|
2407
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
2452
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? _n, 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, hn(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");
|
|
2408
2453
|
let t = (e, t, n) => {
|
|
2409
2454
|
let r = this.doc.createElement(e);
|
|
2410
2455
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -2490,7 +2535,7 @@ var vn = class {
|
|
|
2490
2535
|
let t = this.surfaceWasHidden;
|
|
2491
2536
|
this.tapTimer = setTimeout(() => {
|
|
2492
2537
|
this.tapTimer = void 0, this.toggleBar(t);
|
|
2493
|
-
},
|
|
2538
|
+
}, vn);
|
|
2494
2539
|
}
|
|
2495
2540
|
toggleBar(e) {
|
|
2496
2541
|
e ? this.poke() : this.hideIfIdle();
|
|
@@ -2525,7 +2570,7 @@ var vn = class {
|
|
|
2525
2570
|
e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = Z("play"), e.addEventListener("click", () => void this.player.play()), n.append(e);
|
|
2526
2571
|
} else {
|
|
2527
2572
|
let r = this.doc.createElement("div");
|
|
2528
|
-
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !
|
|
2573
|
+
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !yn.has(this.lastError.code)) {
|
|
2529
2574
|
let e = this.doc.createElement("button");
|
|
2530
2575
|
e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${Z("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), n.append(e);
|
|
2531
2576
|
}
|
|
@@ -2566,7 +2611,7 @@ var vn = class {
|
|
|
2566
2611
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
2567
2612
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
2568
2613
|
}
|
|
2569
|
-
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${
|
|
2614
|
+
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Sn(this.video.currentTime)} / ${Sn(this.video.duration)}`);
|
|
2570
2615
|
}
|
|
2571
2616
|
syncLive() {
|
|
2572
2617
|
let e = this.player.getStats(), t = e.isLive !== !1;
|
|
@@ -2616,17 +2661,17 @@ var vn = class {
|
|
|
2616
2661
|
renderQualityMenu() {
|
|
2617
2662
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
2618
2663
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
2619
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
2664
|
+
for (let n of e) this.menu.append(this.menuItem(Cn(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
2620
2665
|
}
|
|
2621
2666
|
renderAudioMenu() {
|
|
2622
2667
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
2623
2668
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
2624
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2669
|
+
for (let t of e) this.menu.append(this.menuItem(wn(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
2625
2670
|
}
|
|
2626
2671
|
renderCcMenu() {
|
|
2627
2672
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
2628
2673
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
2629
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2674
|
+
for (let t of e) this.menu.append(this.menuItem(Tn(t), !1, () => this.player.setTextTrack(t.id)));
|
|
2630
2675
|
}
|
|
2631
2676
|
onTracksChanged() {
|
|
2632
2677
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -2727,41 +2772,41 @@ var vn = class {
|
|
|
2727
2772
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
2728
2773
|
}
|
|
2729
2774
|
};
|
|
2730
|
-
function
|
|
2775
|
+
function Sn(e) {
|
|
2731
2776
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
2732
2777
|
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");
|
|
2733
2778
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
2734
2779
|
}
|
|
2735
|
-
function
|
|
2780
|
+
function Cn(e) {
|
|
2736
2781
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
2737
2782
|
}
|
|
2738
|
-
function
|
|
2783
|
+
function wn(e) {
|
|
2739
2784
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2740
2785
|
}
|
|
2741
|
-
function
|
|
2786
|
+
function Tn(e) {
|
|
2742
2787
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2743
2788
|
}
|
|
2744
2789
|
//#endregion
|
|
2745
2790
|
//#region src/managed/index.ts
|
|
2746
|
-
var
|
|
2747
|
-
function
|
|
2791
|
+
var En = 6e3, Dn = 45e3, Q = 2e3, On = 3, kn = 2e3, An = 48e4;
|
|
2792
|
+
function jn(e) {
|
|
2748
2793
|
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)})`);
|
|
2749
|
-
if (e.env !== void 0) return
|
|
2794
|
+
if (e.env !== void 0) return Ve(e.env);
|
|
2750
2795
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
|
|
2751
2796
|
return e.baseUrl;
|
|
2752
2797
|
}
|
|
2753
|
-
async function
|
|
2798
|
+
async function Mn(e) {
|
|
2754
2799
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
2755
|
-
let t =
|
|
2800
|
+
let t = jn(e);
|
|
2756
2801
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
2757
2802
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
2758
|
-
let r = new
|
|
2803
|
+
let r = new Nn({
|
|
2759
2804
|
...e,
|
|
2760
2805
|
baseUrl: t
|
|
2761
2806
|
});
|
|
2762
2807
|
return await r.start(), r;
|
|
2763
2808
|
}
|
|
2764
|
-
var
|
|
2809
|
+
var Nn = class {
|
|
2765
2810
|
opts;
|
|
2766
2811
|
abort = new AbortController();
|
|
2767
2812
|
listeners = {};
|
|
@@ -2805,7 +2850,7 @@ var An = class {
|
|
|
2805
2850
|
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");
|
|
2806
2851
|
let e = ++this.loadGen, t = this.resolveOptions();
|
|
2807
2852
|
try {
|
|
2808
|
-
let n = await
|
|
2853
|
+
let n = await y(t);
|
|
2809
2854
|
if (await this.onResolved(n, e), e === this.loadGen && this._state === "error" && this._lastError) {
|
|
2810
2855
|
let e = this._lastError;
|
|
2811
2856
|
throw this.destroy(), e;
|
|
@@ -2832,7 +2877,7 @@ var An = class {
|
|
|
2832
2877
|
r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
|
|
2833
2878
|
}
|
|
2834
2879
|
beginArmingByPolling(e) {
|
|
2835
|
-
|
|
2880
|
+
b({
|
|
2836
2881
|
...this.resolveOptions(),
|
|
2837
2882
|
signal: this.abort.signal,
|
|
2838
2883
|
waitForLive: this.buildWaitConfig(e)
|
|
@@ -2849,7 +2894,7 @@ var An = class {
|
|
|
2849
2894
|
setTimeout(() => {
|
|
2850
2895
|
a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
2851
2896
|
phase: i ? "unavailable" : "tooEarly",
|
|
2852
|
-
retryInMs:
|
|
2897
|
+
retryInMs: Dn,
|
|
2853
2898
|
attempt: 1,
|
|
2854
2899
|
elapsedMs: 0,
|
|
2855
2900
|
...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
|
|
@@ -2866,7 +2911,7 @@ var An = class {
|
|
|
2866
2911
|
}
|
|
2867
2912
|
}
|
|
2868
2913
|
}, h = () => {
|
|
2869
|
-
a || s || p() || (s = !0,
|
|
2914
|
+
a || s || p() || (s = !0, b({
|
|
2870
2915
|
...this.resolveOptions(),
|
|
2871
2916
|
signal: c.signal,
|
|
2872
2917
|
waitForLive: this.buildWaitConfig(e)
|
|
@@ -2874,7 +2919,7 @@ var An = class {
|
|
|
2874
2919
|
a || p() || c.signal.aborted || (a = !0, this.closeArming(), this.fail(e instanceof n ? e : new n("INTERNAL", 0, String(e))));
|
|
2875
2920
|
}));
|
|
2876
2921
|
}, g = () => {
|
|
2877
|
-
a || p() ||
|
|
2922
|
+
a || p() || y(this.resolveOptions()).then((e) => m(e)).catch((e) => {
|
|
2878
2923
|
if (!(a || p())) {
|
|
2879
2924
|
if (e instanceof n && o(e.code)) {
|
|
2880
2925
|
h();
|
|
@@ -2888,13 +2933,13 @@ var An = class {
|
|
|
2888
2933
|
!a && !p() && h();
|
|
2889
2934
|
}, e);
|
|
2890
2935
|
};
|
|
2891
|
-
_(
|
|
2936
|
+
_(En), this.armingSub = T({
|
|
2892
2937
|
eventsBaseUrl: t,
|
|
2893
2938
|
matchUrn: this.opts.matchUrn,
|
|
2894
2939
|
credential: this.opts.credential,
|
|
2895
|
-
onAlive: () => _(
|
|
2940
|
+
onAlive: () => _(Dn),
|
|
2896
2941
|
onState: (e) => {
|
|
2897
|
-
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() *
|
|
2942
|
+
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Q);
|
|
2898
2943
|
},
|
|
2899
2944
|
onError: () => h()
|
|
2900
2945
|
});
|
|
@@ -2917,7 +2962,7 @@ var An = class {
|
|
|
2917
2962
|
let n = await s(this.opts.credential);
|
|
2918
2963
|
if (this.destroyed || t !== this.loadGen) return;
|
|
2919
2964
|
this.setState("loading");
|
|
2920
|
-
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a =
|
|
2965
|
+
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = Ke(this.opts.video, (e) => {
|
|
2921
2966
|
this._state !== "ended" && this._state !== "error" && this.setState(e);
|
|
2922
2967
|
});
|
|
2923
2968
|
if (await i.load(), this.destroyed || t !== this.loadGen) {
|
|
@@ -2939,26 +2984,26 @@ var An = class {
|
|
|
2939
2984
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
|
|
2940
2985
|
let i = e.analytics?.sid;
|
|
2941
2986
|
if (!i) return;
|
|
2942
|
-
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } =
|
|
2987
|
+
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = en(this.opts.baseUrl, a, e.analytics?.endpoint);
|
|
2943
2988
|
if (!o) {
|
|
2944
2989
|
s && setTimeout(() => {
|
|
2945
2990
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
|
|
2946
2991
|
}, 0);
|
|
2947
2992
|
return;
|
|
2948
2993
|
}
|
|
2949
|
-
let c = this.opts.video, l = new
|
|
2994
|
+
let c = this.opts.video, l = new tn({
|
|
2950
2995
|
endpoint: o,
|
|
2951
2996
|
sid: i,
|
|
2952
2997
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
2953
|
-
sdkVersion:
|
|
2954
|
-
environment:
|
|
2998
|
+
sdkVersion: cn,
|
|
2999
|
+
environment: on(c),
|
|
2955
3000
|
idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
|
|
2956
3001
|
onIdle: () => this.onAnalyticsIdle(t),
|
|
2957
3002
|
onBlocked: (e) => setTimeout(() => {
|
|
2958
3003
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
|
|
2959
3004
|
}, 0),
|
|
2960
3005
|
sample: () => {
|
|
2961
|
-
let e = this.engine?.getStats() ??
|
|
3006
|
+
let e = this.engine?.getStats() ?? He, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
|
|
2962
3007
|
return {
|
|
2963
3008
|
...e,
|
|
2964
3009
|
bufferedMs: Math.round(t * 1e3),
|
|
@@ -2972,7 +3017,7 @@ var An = class {
|
|
|
2972
3017
|
let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
|
|
2973
3018
|
c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
|
|
2974
3019
|
c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
|
|
2975
|
-
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()),
|
|
3020
|
+
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), sn().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
|
|
2976
3021
|
}
|
|
2977
3022
|
currentPresentation() {
|
|
2978
3023
|
let e = this.opts.video;
|
|
@@ -2998,10 +3043,10 @@ var An = class {
|
|
|
2998
3043
|
emit: (e) => this.onEngineEvent(e)
|
|
2999
3044
|
}, o = this.opts.engine ?? "auto";
|
|
3000
3045
|
if (o === "native") return new K(a);
|
|
3001
|
-
if (o === "hls") return new
|
|
3002
|
-
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl &&
|
|
3003
|
-
if (at()) return new
|
|
3004
|
-
if (
|
|
3046
|
+
if (o === "hls") return new It(a);
|
|
3047
|
+
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && G(this.opts.video) && Je()) return new K(a);
|
|
3048
|
+
if (at()) return new It(a);
|
|
3049
|
+
if (G(this.opts.video)) return new K(a);
|
|
3005
3050
|
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
3006
3051
|
}
|
|
3007
3052
|
onEngineEvent(e) {
|
|
@@ -3053,7 +3098,7 @@ var An = class {
|
|
|
3053
3098
|
r = 0, i = !1;
|
|
3054
3099
|
},
|
|
3055
3100
|
onError: () => {
|
|
3056
|
-
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >=
|
|
3101
|
+
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= On && (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.`))));
|
|
3057
3102
|
}
|
|
3058
3103
|
});
|
|
3059
3104
|
}
|
|
@@ -3075,7 +3120,7 @@ var An = class {
|
|
|
3075
3120
|
scheduleRejoin(e) {
|
|
3076
3121
|
this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
|
|
3077
3122
|
this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
|
|
3078
|
-
}, Math.random() *
|
|
3123
|
+
}, Math.random() * Q));
|
|
3079
3124
|
}
|
|
3080
3125
|
cancelRejoin() {
|
|
3081
3126
|
this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
|
|
@@ -3099,7 +3144,7 @@ var An = class {
|
|
|
3099
3144
|
}
|
|
3100
3145
|
t.controls = !1;
|
|
3101
3146
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
3102
|
-
r && r.insertBefore(n, t), n.appendChild(t),
|
|
3147
|
+
r && r.insertBefore(n, t), n.appendChild(t), dn(n, this.opts.theme), this.container = n, this.controlBar = bn({
|
|
3103
3148
|
root: n,
|
|
3104
3149
|
video: t,
|
|
3105
3150
|
player: this,
|
|
@@ -3130,7 +3175,7 @@ var An = class {
|
|
|
3130
3175
|
}
|
|
3131
3176
|
startStats() {
|
|
3132
3177
|
this.stopStats();
|
|
3133
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
3178
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? kn);
|
|
3134
3179
|
this.statsTimer = setInterval(() => {
|
|
3135
3180
|
if (!this.engine) return;
|
|
3136
3181
|
let e = this.engine.getStats();
|
|
@@ -3142,7 +3187,7 @@ var An = class {
|
|
|
3142
3187
|
}
|
|
3143
3188
|
scheduleLicenseRefresh() {
|
|
3144
3189
|
this.stopRefresh();
|
|
3145
|
-
let e = this.opts.licenseRefreshMs ??
|
|
3190
|
+
let e = this.opts.licenseRefreshMs ?? An;
|
|
3146
3191
|
e && this._descriptor?.drmEnabled && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
3147
3192
|
}
|
|
3148
3193
|
stopRefresh() {
|
|
@@ -3151,7 +3196,7 @@ var An = class {
|
|
|
3151
3196
|
async refreshLicense() {
|
|
3152
3197
|
let e = this.engine;
|
|
3153
3198
|
if (!this.destroyed && e) try {
|
|
3154
|
-
let t = await
|
|
3199
|
+
let t = await y(this.resolveOptions());
|
|
3155
3200
|
if (this.destroyed || this.engine !== e) return;
|
|
3156
3201
|
let n = t.drm?.widevine?.licenseUrl, r = t.drm?.fairplay?.licenseUrl;
|
|
3157
3202
|
(n || r) && (e.setLicenseUrls({
|
|
@@ -3187,7 +3232,7 @@ var An = class {
|
|
|
3187
3232
|
this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
|
|
3188
3233
|
}
|
|
3189
3234
|
getStats() {
|
|
3190
|
-
return this.engine?.getStats() ??
|
|
3235
|
+
return this.engine?.getStats() ?? He;
|
|
3191
3236
|
}
|
|
3192
3237
|
getQualityLevels() {
|
|
3193
3238
|
return this.engine?.getQualityLevels() ?? [];
|
|
@@ -3239,7 +3284,7 @@ var An = class {
|
|
|
3239
3284
|
let e = ++this.loadGen;
|
|
3240
3285
|
this.teardownPlayback();
|
|
3241
3286
|
try {
|
|
3242
|
-
let t = await
|
|
3287
|
+
let t = await b({
|
|
3243
3288
|
...this.resolveOptions(),
|
|
3244
3289
|
waitForLive: this.opts.waitForLive ? this.buildWaitConfig(e) : void 0
|
|
3245
3290
|
});
|
|
@@ -3297,7 +3342,7 @@ function $(e) {
|
|
|
3297
3342
|
}
|
|
3298
3343
|
//#endregion
|
|
3299
3344
|
//#region src/embed/host.ts
|
|
3300
|
-
function
|
|
3345
|
+
function Pn(e) {
|
|
3301
3346
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
3302
3347
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
3303
3348
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -3356,15 +3401,15 @@ function jn(e) {
|
|
|
3356
3401
|
}
|
|
3357
3402
|
//#endregion
|
|
3358
3403
|
//#region src/embed/page.ts
|
|
3359
|
-
var
|
|
3360
|
-
function
|
|
3404
|
+
var Fn = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
3405
|
+
function In(e) {
|
|
3361
3406
|
if (typeof e == "boolean") return e;
|
|
3362
3407
|
if (typeof e == "object" && e) {
|
|
3363
3408
|
let t = e.endpoint;
|
|
3364
3409
|
return typeof t == "string" ? { endpoint: t } : {};
|
|
3365
3410
|
}
|
|
3366
3411
|
}
|
|
3367
|
-
function
|
|
3412
|
+
function Ln() {
|
|
3368
3413
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
3369
3414
|
if (e) return {
|
|
3370
3415
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -3374,7 +3419,7 @@ function Pn() {
|
|
|
3374
3419
|
autoplay: e.autoplay ?? !0,
|
|
3375
3420
|
muted: e.muted ?? !0,
|
|
3376
3421
|
waitForLive: e.waitForLive ?? !0,
|
|
3377
|
-
analytics:
|
|
3422
|
+
analytics: In(e.analytics)
|
|
3378
3423
|
};
|
|
3379
3424
|
let t = new URLSearchParams(location.search);
|
|
3380
3425
|
return {
|
|
@@ -3387,9 +3432,9 @@ function Pn() {
|
|
|
3387
3432
|
waitForLive: !0
|
|
3388
3433
|
};
|
|
3389
3434
|
}
|
|
3390
|
-
async function
|
|
3391
|
-
let e =
|
|
3392
|
-
|
|
3435
|
+
async function Rn() {
|
|
3436
|
+
let e = Ln();
|
|
3437
|
+
Bn();
|
|
3393
3438
|
let t = document.createElement("video");
|
|
3394
3439
|
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);
|
|
3395
3440
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -3444,12 +3489,12 @@ async function Fn() {
|
|
|
3444
3489
|
code: e.code,
|
|
3445
3490
|
message: e.message
|
|
3446
3491
|
})), e.on("autoplayblocked", () => {
|
|
3447
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
3492
|
+
i({ type: "oddin:autoplayblocked" }), zn(t, e);
|
|
3448
3493
|
});
|
|
3449
3494
|
}, s = async (r) => {
|
|
3450
3495
|
a?.destroy(), a = null;
|
|
3451
3496
|
try {
|
|
3452
|
-
let n = await
|
|
3497
|
+
let n = await Mn({
|
|
3453
3498
|
video: t,
|
|
3454
3499
|
baseUrl: e.baseUrl,
|
|
3455
3500
|
matchUrn: r,
|
|
@@ -3511,7 +3556,7 @@ async function Fn() {
|
|
|
3511
3556
|
a?.retry();
|
|
3512
3557
|
break;
|
|
3513
3558
|
case "oddin:load":
|
|
3514
|
-
typeof e.matchUrn == "string" &&
|
|
3559
|
+
typeof e.matchUrn == "string" && Fn.test(e.matchUrn) && s(e.matchUrn);
|
|
3515
3560
|
break;
|
|
3516
3561
|
case "oddin:destroy": c();
|
|
3517
3562
|
}
|
|
@@ -3523,18 +3568,18 @@ async function Fn() {
|
|
|
3523
3568
|
protocol: 1
|
|
3524
3569
|
});
|
|
3525
3570
|
}
|
|
3526
|
-
function
|
|
3571
|
+
function zn(e, t) {
|
|
3527
3572
|
if (document.getElementById("havik-tap")) return;
|
|
3528
3573
|
let n = document.createElement("button");
|
|
3529
3574
|
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", () => {
|
|
3530
3575
|
n.remove(), t.play();
|
|
3531
3576
|
}), document.body.appendChild(n);
|
|
3532
3577
|
}
|
|
3533
|
-
function
|
|
3578
|
+
function Bn() {
|
|
3534
3579
|
let e = document.createElement("style");
|
|
3535
3580
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
3536
3581
|
}
|
|
3537
3582
|
//#endregion
|
|
3538
|
-
export {
|
|
3583
|
+
export { ln as ODDIN_THEME, n as PlaybackError, dn as applyTheme, Ve as baseUrlForEnv, Rn as bootEmbed, Te as clearDeviceId, Mn as createPlayer, E as deriveEventsBaseUrl, Le as detectDrmSupport, C as enterVideoFullscreen, w as exitVideoFullscreen, _e as fetchCatalog, ye as fetchTournament, xe as flattenMatches, k as getDeviceId, ze as isLowLatencyManifest, $ as isOddinMessage, De as licenseRequestHeaders, Pn as mountEmbed, v as pollToLive, b as resolveStream, T as subscribeLiveState, S as videoFullscreenActive, Ce as watchStatus };
|
|
3539
3584
|
|
|
3540
3585
|
//# sourceMappingURL=index.js.map
|