@oddin-gg/havik-player 2.15.0 → 2.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +230 -201
- package/dist/index.js.map +1 -1
- package/docs/API.md +11 -0
- 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 de(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 v(e, t, r) {
|
|
|
200
200
|
}
|
|
201
201
|
//#endregion
|
|
202
202
|
//#region src/core/resolve.ts
|
|
203
|
-
async function
|
|
203
|
+
async function v(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 fe(t);
|
|
211
|
+
return he(await t.json(), e.matchUrn);
|
|
212
212
|
}
|
|
213
|
-
function
|
|
214
|
-
let t = () =>
|
|
215
|
-
return e.waitForLive ?
|
|
213
|
+
function y(e) {
|
|
214
|
+
let t = () => v(e);
|
|
215
|
+
return e.waitForLive ? de(t, e.waitForLive, e.signal) : t();
|
|
216
216
|
}
|
|
217
|
-
async function
|
|
217
|
+
async function fe(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 de(e) {
|
|
|
230
230
|
liveStartsAtMs: s
|
|
231
231
|
});
|
|
232
232
|
}
|
|
233
|
-
var
|
|
233
|
+
var pe = /* @__PURE__ */ new Set([
|
|
234
234
|
"matchUrn",
|
|
235
235
|
"protocol",
|
|
236
236
|
"drmEnabled",
|
|
@@ -241,7 +241,7 @@ var fe = /* @__PURE__ */ new Set([
|
|
|
241
241
|
"expiresAt",
|
|
242
242
|
"analytics"
|
|
243
243
|
]);
|
|
244
|
-
function
|
|
244
|
+
function b(e, t) {
|
|
245
245
|
let r;
|
|
246
246
|
try {
|
|
247
247
|
r = new URL(t);
|
|
@@ -251,7 +251,7 @@ function x(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 me(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 pe(e) {
|
|
|
260
260
|
g(`server analytics.endpoint ${JSON.stringify(e)} ignored: not a bare https origin.`);
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
|
-
function
|
|
263
|
+
function he(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: b("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 = me(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: b("widevine licenseUrl", e.drm.widevine.licenseUrl) }), e.drm.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && (t.fairplay = {
|
|
280
|
+
licenseUrl: b("fairplay licenseUrl", e.drm.fairplay.licenseUrl),
|
|
281
|
+
certificateUrl: b("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)) pe.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 ge(e) {
|
|
291
291
|
return e.ownerDocument ?? document;
|
|
292
292
|
}
|
|
293
|
-
function
|
|
293
|
+
function x(e) {
|
|
294
294
|
return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
|
|
295
295
|
}
|
|
296
296
|
function S(e, t) {
|
|
297
|
-
let n = ge(
|
|
297
|
+
let n = x(ge(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 = ge(e), i = x(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 je = {
|
|
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
|
+
}, Me = /* @__PURE__ */ new Map(), R = /* @__PURE__ */ new Map();
|
|
680
|
+
function Ne(e) {
|
|
681
|
+
let t = L(e), n = Me.get(t);
|
|
682
682
|
if (n) return n;
|
|
683
683
|
let r = {
|
|
684
684
|
initDataTypes: ["cenc"],
|
|
@@ -696,23 +696,23 @@ function V(e) {
|
|
|
696
696
|
} catch {
|
|
697
697
|
return !1;
|
|
698
698
|
}
|
|
699
|
-
})().then((e) => (
|
|
700
|
-
return
|
|
699
|
+
})().then((e) => (R.set(t, e), e));
|
|
700
|
+
return Me.set(t, i), i;
|
|
701
701
|
}
|
|
702
|
-
function
|
|
703
|
-
if (j()) for (let e of Object.values(
|
|
702
|
+
function Pe() {
|
|
703
|
+
if (j()) for (let e of Object.values(je)) Ne(e);
|
|
704
704
|
}
|
|
705
|
-
function
|
|
705
|
+
function Fe(e) {
|
|
706
706
|
let t = I(e);
|
|
707
|
-
if (t) return t === "avc" ? !0 :
|
|
707
|
+
if (t) return t === "avc" ? !0 : R.get(L(e)) ?? R.get(L(je[t]));
|
|
708
708
|
}
|
|
709
709
|
//#endregion
|
|
710
710
|
//#region src/core/drm/support.ts
|
|
711
|
-
var
|
|
711
|
+
var Ie = 5e3, Le = "video/mp4; codecs=\"avc1.42E01E\"", Re = "audio/mp4; codecs=\"mp4a.40.2\"", ze = {
|
|
712
712
|
widevine: ["com.widevine.alpha"],
|
|
713
713
|
fairplay: ["com.apple.fps"]
|
|
714
714
|
};
|
|
715
|
-
function
|
|
715
|
+
function Be(e) {
|
|
716
716
|
return e === "fairplay" ? [{
|
|
717
717
|
initDataTypes: [
|
|
718
718
|
"sinf",
|
|
@@ -720,30 +720,30 @@ function Fe(e) {
|
|
|
720
720
|
"cenc"
|
|
721
721
|
],
|
|
722
722
|
videoCapabilities: [{
|
|
723
|
-
contentType:
|
|
723
|
+
contentType: Le,
|
|
724
724
|
robustness: "",
|
|
725
725
|
encryptionScheme: "cbcs"
|
|
726
726
|
}],
|
|
727
727
|
audioCapabilities: [{
|
|
728
|
-
contentType:
|
|
728
|
+
contentType: Re,
|
|
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: Le,
|
|
736
736
|
robustness: F.video,
|
|
737
737
|
encryptionScheme: F.scheme
|
|
738
738
|
}],
|
|
739
739
|
audioCapabilities: [{
|
|
740
|
-
contentType:
|
|
740
|
+
contentType: Re,
|
|
741
741
|
robustness: F.audio,
|
|
742
742
|
encryptionScheme: F.scheme
|
|
743
743
|
}]
|
|
744
744
|
}]);
|
|
745
745
|
}
|
|
746
|
-
function
|
|
746
|
+
function Ve(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 Ie(e, t) {
|
|
|
753
753
|
});
|
|
754
754
|
});
|
|
755
755
|
}
|
|
756
|
-
async function
|
|
757
|
-
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ??
|
|
756
|
+
async function He(e = {}) {
|
|
757
|
+
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Ie, 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 Le(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 = ze[e];
|
|
770
770
|
if (!t) {
|
|
771
771
|
r[e] = "unknown system";
|
|
772
772
|
continue;
|
|
@@ -777,7 +777,7 @@ async function Le(e = {}) {
|
|
|
777
777
|
break;
|
|
778
778
|
}
|
|
779
779
|
try {
|
|
780
|
-
return await
|
|
780
|
+
return await Ve((await Ve(i(n, Be(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 Le(e = {}) {
|
|
|
801
801
|
}
|
|
802
802
|
//#endregion
|
|
803
803
|
//#region src/core/manifest.ts
|
|
804
|
-
var
|
|
805
|
-
function
|
|
806
|
-
return
|
|
804
|
+
var Ue = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
|
|
805
|
+
function We(e) {
|
|
806
|
+
return Ue.test(e);
|
|
807
807
|
}
|
|
808
808
|
//#endregion
|
|
809
809
|
//#region src/core/env.ts
|
|
810
|
-
var
|
|
810
|
+
var z = {
|
|
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 B(e) {
|
|
815
|
+
let t = Object.prototype.hasOwnProperty.call(z, e) ? z[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 V = { droppedFrames: 0 };
|
|
822
|
+
function H(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 Ge = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
|
|
830
|
+
function Ke(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" || Ge.test(i.name)) && i.startTime >= n) {
|
|
834
|
+
let e = H(i.name);
|
|
835
835
|
e && (t = e, n = i.startTime);
|
|
836
836
|
}
|
|
837
837
|
return t;
|
|
838
838
|
}
|
|
839
|
-
function
|
|
839
|
+
function U(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 qe(e, t) {
|
|
847
847
|
let n = [
|
|
848
848
|
["playing", () => t("playing")],
|
|
849
849
|
["waiting", () => t("buffering")],
|
|
@@ -860,7 +860,7 @@ function Ke(e, t) {
|
|
|
860
860
|
}
|
|
861
861
|
//#endregion
|
|
862
862
|
//#region src/core/engine/native.ts
|
|
863
|
-
function
|
|
863
|
+
function Je(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 qe(e) {
|
|
|
868
868
|
return;
|
|
869
869
|
}
|
|
870
870
|
}
|
|
871
|
-
function
|
|
871
|
+
function W(e) {
|
|
872
872
|
return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
|
|
873
873
|
}
|
|
874
|
-
function
|
|
874
|
+
function G() {
|
|
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 = Je(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 = U(e), n = {
|
|
1033
1033
|
droppedFrames: t.dropped,
|
|
1034
1034
|
decodedFrames: t.totalFrames
|
|
1035
1035
|
};
|
|
1036
|
-
return this.cdnHost ||=
|
|
1036
|
+
return this.cdnHost ||= Ke(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 =
|
|
1223
|
-
function
|
|
1222
|
+
var ot = 3, st = 5, ct = 3, lt = 3e4, ut = 12e3, dt = 3e3, ft = 6e3, pt = 3, mt = .5, ht = 1.2, 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 = 9, kt = .5, At = 64;
|
|
1223
|
+
function jt(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 ??= Dt;
|
|
1229
|
+
let t = Math.max(12, e.liveSyncDuration + Ot);
|
|
1230
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Mt(e, e.liveSyncDuration);
|
|
1231
1231
|
}
|
|
1232
|
-
function
|
|
1232
|
+
function Mt(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 Nt = class {
|
|
1237
1237
|
name = "hls";
|
|
1238
1238
|
hls = null;
|
|
1239
1239
|
deps;
|
|
@@ -1289,6 +1289,9 @@ var kt = class {
|
|
|
1289
1289
|
chaseSuspended = !1;
|
|
1290
1290
|
savedLiveMaxLatency;
|
|
1291
1291
|
savedMaxSyncRate;
|
|
1292
|
+
chaseLatency = -1;
|
|
1293
|
+
chaseTicks = 0;
|
|
1294
|
+
liveRetargets = 0;
|
|
1292
1295
|
capObserver = null;
|
|
1293
1296
|
capTimer = null;
|
|
1294
1297
|
sizeCapLevel = null;
|
|
@@ -1301,7 +1304,7 @@ var kt = class {
|
|
|
1301
1304
|
this.deps = e, this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
|
|
1302
1305
|
}
|
|
1303
1306
|
async load() {
|
|
1304
|
-
let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a =
|
|
1307
|
+
let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = W(r) && G(), o = !!e.drm?.widevine?.licenseUrl && !a;
|
|
1305
1308
|
if (e.drmEnabled && !o) {
|
|
1306
1309
|
i({
|
|
1307
1310
|
type: "error",
|
|
@@ -1310,7 +1313,7 @@ var kt = class {
|
|
|
1310
1313
|
});
|
|
1311
1314
|
return;
|
|
1312
1315
|
}
|
|
1313
|
-
e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ae(r),
|
|
1316
|
+
e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ae(r), Pe()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
|
|
1314
1317
|
let e = this.hls;
|
|
1315
1318
|
if (document.visibilityState !== "visible" || !e) return;
|
|
1316
1319
|
let t = e.liveSyncPosition;
|
|
@@ -1333,11 +1336,11 @@ var kt = class {
|
|
|
1333
1336
|
}
|
|
1334
1337
|
this.loadSuspended = !0;
|
|
1335
1338
|
}
|
|
1336
|
-
},
|
|
1339
|
+
}, _t));
|
|
1337
1340
|
}
|
|
1338
1341
|
resumeLoading() {
|
|
1339
|
-
if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
|
|
1340
|
-
this.lastAdvanceMs = Date.now(), this.lastFragLoadingMs = 0, this.resetStarvationWindow(), this.clearKick();
|
|
1342
|
+
if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
|
|
1343
|
+
this.lastAdvanceMs = Date.now(), this.lastFragLoadingMs = 0, this.resetStarvationWindow(), this.resetChaseWindow(), this.clearKick();
|
|
1341
1344
|
try {
|
|
1342
1345
|
this.hls.startLoad(-1);
|
|
1343
1346
|
} catch {}
|
|
@@ -1365,11 +1368,11 @@ var kt = class {
|
|
|
1365
1368
|
let t = e.liveSyncPosition;
|
|
1366
1369
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
1367
1370
|
let { video: n } = this.deps;
|
|
1368
|
-
n.currentTime <= t +
|
|
1371
|
+
n.currentTime <= t + kt || (n.currentTime = t);
|
|
1369
1372
|
}
|
|
1370
1373
|
startHls() {
|
|
1371
1374
|
let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
|
|
1372
|
-
this.clearKick(), this.resetStarvationWindow(), this.lastFragLoadingMs = 0, this.lastEndSN = -1, this.lastAdvanceMs = 0;
|
|
1375
|
+
this.clearKick(), this.resetStarvationWindow(), this.resetChaseWindow(), this.lastFragLoadingMs = 0, this.lastEndSN = -1, this.lastAdvanceMs = 0;
|
|
1373
1376
|
let u = n.drmEnabled && !!(n.drm?.widevine?.licenseUrl || n.drm?.fairplay?.licenseUrl), d = {
|
|
1374
1377
|
debug: s === !0,
|
|
1375
1378
|
enableWorker: !o,
|
|
@@ -1412,7 +1415,7 @@ var kt = class {
|
|
|
1412
1415
|
}), t = tt(e);
|
|
1413
1416
|
t && (this.prefetch = e, d.fLoader = t);
|
|
1414
1417
|
}
|
|
1415
|
-
|
|
1418
|
+
jt(d), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.loadStarted = d.autoStartLoad !== !1;
|
|
1416
1419
|
let f = new e(d);
|
|
1417
1420
|
if (this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
|
|
1418
1421
|
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" });
|
|
@@ -1427,10 +1430,10 @@ var kt = class {
|
|
|
1427
1430
|
let n = t?.frag?.stats, r = n?.loaded;
|
|
1428
1431
|
typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
|
|
1429
1432
|
let i = n?.loading;
|
|
1430
|
-
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 >
|
|
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 > At && this.requestTimesMs.shift());
|
|
1431
1434
|
let a = t?.frag?.url;
|
|
1432
1435
|
if (a) {
|
|
1433
|
-
let e =
|
|
1436
|
+
let e = H(a);
|
|
1434
1437
|
e && (this.cdnHost = e);
|
|
1435
1438
|
}
|
|
1436
1439
|
}), f.on(e.Events.LEVEL_LOADED, (e, t) => {
|
|
@@ -1451,7 +1454,7 @@ var kt = class {
|
|
|
1451
1454
|
f.on(e.Events.KEY_LOADED, () => {
|
|
1452
1455
|
u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
|
|
1453
1456
|
}), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
|
|
1454
|
-
this.checkEndStale(), this.checkStarvation();
|
|
1457
|
+
this.checkEndStale(), this.checkStarvation(), this.checkFutileChase();
|
|
1455
1458
|
}, dt), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
1456
1459
|
this.renditionSwitches += 1;
|
|
1457
1460
|
let n = this.lastLevelIndex >= 0 ? f.levels[this.lastLevelIndex] : void 0, r = f.levels[t.level];
|
|
@@ -1516,7 +1519,7 @@ var kt = class {
|
|
|
1516
1519
|
return;
|
|
1517
1520
|
}
|
|
1518
1521
|
this.capTimer && clearTimeout(this.capTimer);
|
|
1519
|
-
let t = e > this.sizeCapLevel ?
|
|
1522
|
+
let t = e > this.sizeCapLevel ? Tt : Et;
|
|
1520
1523
|
this.capTimer = setTimeout(() => {
|
|
1521
1524
|
this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
|
|
1522
1525
|
}, t);
|
|
@@ -1526,9 +1529,9 @@ var kt = class {
|
|
|
1526
1529
|
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;
|
|
1527
1530
|
}
|
|
1528
1531
|
dropLevelsWidevineCannotPlay(e) {
|
|
1529
|
-
this.removeLevelsWhere(e, (e) =>
|
|
1532
|
+
this.removeLevelsWhere(e, (e) => Fe(e) !== !0);
|
|
1530
1533
|
let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && I(e) !== "avc" && !!I(e)));
|
|
1531
|
-
for (let n of t)
|
|
1534
|
+
for (let n of t) Ne(n).then((t) => {
|
|
1532
1535
|
t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
|
|
1533
1536
|
});
|
|
1534
1537
|
}
|
|
@@ -1539,7 +1542,7 @@ var kt = class {
|
|
|
1539
1542
|
a && I(a) && t(a) && (r.push(n), i.add(a));
|
|
1540
1543
|
}), !r.length) return !1;
|
|
1541
1544
|
let a = [...i].join(", ");
|
|
1542
|
-
if (!n.some((e, t) => r.includes(t) ? !1 : !I(e.videoCodec) ||
|
|
1545
|
+
if (!n.some((e, t) => r.includes(t) ? !1 : !I(e.videoCodec) || Fe(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
|
|
1543
1546
|
for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
|
|
1544
1547
|
return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
|
|
1545
1548
|
}
|
|
@@ -1585,13 +1588,14 @@ var kt = class {
|
|
|
1585
1588
|
e.widevine && (this.licenseUrl = e.widevine);
|
|
1586
1589
|
}
|
|
1587
1590
|
getStats() {
|
|
1588
|
-
let e = this.hls, t =
|
|
1591
|
+
let e = this.hls, t = U(this.deps.video), n = {
|
|
1589
1592
|
droppedFrames: t.dropped,
|
|
1590
1593
|
decodedFrames: t.totalFrames,
|
|
1591
1594
|
lowLatency: this.detectedLowLatency,
|
|
1592
1595
|
bytesLoaded: this.bytesLoaded,
|
|
1593
1596
|
playlistBytesLoaded: this.playlistBytesLoaded,
|
|
1594
1597
|
renditionSwitches: this.renditionSwitches,
|
|
1598
|
+
liveRetargets: this.liveRetargets,
|
|
1595
1599
|
licenseTimeMs: this.licenseTimeMs,
|
|
1596
1600
|
upshifts: this.upshifts,
|
|
1597
1601
|
downshifts: this.downshifts,
|
|
@@ -1646,7 +1650,7 @@ var kt = class {
|
|
|
1646
1650
|
this.resetStarvationWindow();
|
|
1647
1651
|
return;
|
|
1648
1652
|
}
|
|
1649
|
-
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < ft, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs >
|
|
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 } = U(t), c = o - s, l = c !== this.starvedFrames;
|
|
1650
1654
|
if (this.starvedFrames = c, !a || l) {
|
|
1651
1655
|
(t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
|
|
1652
1656
|
return;
|
|
@@ -1655,12 +1659,12 @@ var kt = class {
|
|
|
1655
1659
|
this.resetStarvationWindow();
|
|
1656
1660
|
return;
|
|
1657
1661
|
}
|
|
1658
|
-
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 >
|
|
1662
|
+
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 > Ct && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= xt && (this.clearKick(), this.starvationRebuilds < St)) {
|
|
1659
1663
|
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");
|
|
1660
1664
|
return;
|
|
1661
1665
|
}
|
|
1662
|
-
let u = i && this.starvedTicks >=
|
|
1663
|
-
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >=
|
|
1666
|
+
let u = i && this.starvedTicks >= yt, d = !i && this.deadTicks >= Ct && this.recentMainFrags.reduce((e, t) => e + t, 0) >= wt;
|
|
1667
|
+
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= bt))) {
|
|
1664
1668
|
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");
|
|
1665
1669
|
try {
|
|
1666
1670
|
e.stopLoad(), e.startLoad(-1);
|
|
@@ -1669,6 +1673,31 @@ var kt = class {
|
|
|
1669
1673
|
}
|
|
1670
1674
|
}
|
|
1671
1675
|
}
|
|
1676
|
+
resetChaseWindow() {
|
|
1677
|
+
this.chaseLatency = -1, this.chaseTicks = 0;
|
|
1678
|
+
}
|
|
1679
|
+
checkFutileChase() {
|
|
1680
|
+
let e = this.hls, { video: t } = this.deps;
|
|
1681
|
+
if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended || this.loadSuspended || typeof document < "u" && document.hidden) {
|
|
1682
|
+
this.resetChaseWindow();
|
|
1683
|
+
return;
|
|
1684
|
+
}
|
|
1685
|
+
let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
|
|
1686
|
+
if (!(!t.paused && r >= ht && typeof i == "number" && i > 1 && r <= i && typeof n == "number" && Number.isFinite(n))) {
|
|
1687
|
+
this.resetChaseWindow();
|
|
1688
|
+
return;
|
|
1689
|
+
}
|
|
1690
|
+
if (this.chaseLatency < 0 || this.chaseLatency - n >= mt) {
|
|
1691
|
+
this.chaseLatency = n, this.chaseTicks = 0;
|
|
1692
|
+
return;
|
|
1693
|
+
}
|
|
1694
|
+
if (this.chaseTicks += 1, this.chaseTicks < pt) return;
|
|
1695
|
+
this.resetChaseWindow();
|
|
1696
|
+
let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
|
|
1697
|
+
if (!(a > 1)) return;
|
|
1698
|
+
let o = typeof e.targetLatency == "number" ? e.targetLatency : 0, s = Math.min(n, a - 1);
|
|
1699
|
+
s < o + gt || (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);
|
|
1700
|
+
}
|
|
1672
1701
|
suspendChasing() {
|
|
1673
1702
|
let e = this.hls;
|
|
1674
1703
|
e && (this.chaseSuspended = !0, this.savedLiveMaxLatency = e.config.liveMaxLatencyDuration, this.savedMaxSyncRate = e.config.maxLiveSyncPlaybackRate, e.config.liveMaxLatencyDuration = 2 ** 53 - 1, e.config.maxLiveSyncPlaybackRate = 1);
|
|
@@ -1782,19 +1811,19 @@ var kt = class {
|
|
|
1782
1811
|
let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
|
|
1783
1812
|
return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
|
|
1784
1813
|
}
|
|
1785
|
-
},
|
|
1814
|
+
}, Pt = 15e3, Ft = 6e5, It = 3e5, Lt = 100, q = 1, Rt = 1e3, zt = 3e4, Bt = 1e3, Vt = {
|
|
1786
1815
|
inline: "PRESENTATION_INLINE",
|
|
1787
1816
|
fullscreen: "PRESENTATION_FULLSCREEN",
|
|
1788
1817
|
pip: "PRESENTATION_PIP"
|
|
1789
|
-
},
|
|
1818
|
+
}, Ht = {
|
|
1790
1819
|
widevine: "KEY_SYSTEM_WIDEVINE",
|
|
1791
1820
|
fairplay: "KEY_SYSTEM_FAIRPLAY",
|
|
1792
1821
|
none: "KEY_SYSTEM_NONE"
|
|
1793
1822
|
};
|
|
1794
|
-
function
|
|
1823
|
+
function Ut(e, t) {
|
|
1795
1824
|
return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
|
|
1796
1825
|
}
|
|
1797
|
-
var
|
|
1826
|
+
var Wt = /* @__PURE__ */ new Set([
|
|
1798
1827
|
"INVALID_URN",
|
|
1799
1828
|
"NOT_FOUND",
|
|
1800
1829
|
"GONE",
|
|
@@ -1814,7 +1843,7 @@ var Bt = /* @__PURE__ */ new Set([
|
|
|
1814
1843
|
ended: "PLAYER_STATE_ENDED",
|
|
1815
1844
|
error: "PLAYER_STATE_ERROR"
|
|
1816
1845
|
};
|
|
1817
|
-
function
|
|
1846
|
+
function Gt(e) {
|
|
1818
1847
|
try {
|
|
1819
1848
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
1820
1849
|
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);
|
|
@@ -1822,8 +1851,8 @@ function Vt(e) {
|
|
|
1822
1851
|
return;
|
|
1823
1852
|
}
|
|
1824
1853
|
}
|
|
1825
|
-
var
|
|
1826
|
-
function
|
|
1854
|
+
var Kt = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), qt = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), Jt = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
|
|
1855
|
+
function Yt(e) {
|
|
1827
1856
|
if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
|
|
1828
1857
|
let t;
|
|
1829
1858
|
try {
|
|
@@ -1832,19 +1861,19 @@ function Gt(e) {
|
|
|
1832
1861
|
} catch {
|
|
1833
1862
|
return;
|
|
1834
1863
|
}
|
|
1835
|
-
if (
|
|
1836
|
-
Y.add(t), g(
|
|
1864
|
+
if (qt.has(t) && !Y.has(t)) {
|
|
1865
|
+
Y.add(t), g(Jt(new URL(t).origin));
|
|
1837
1866
|
for (let e of X) e.noteCspBlocked();
|
|
1838
1867
|
}
|
|
1839
1868
|
}
|
|
1840
|
-
function
|
|
1869
|
+
function Xt(e, t) {
|
|
1841
1870
|
return g(t, e), { disabledReason: t };
|
|
1842
1871
|
}
|
|
1843
|
-
function
|
|
1844
|
-
if (n) return t && !
|
|
1872
|
+
function Zt(e, t, n) {
|
|
1873
|
+
if (n) return t && !Kt(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
|
|
1845
1874
|
if (t) return { endpoint: t };
|
|
1846
|
-
if (t !== void 0) return
|
|
1847
|
-
let r =
|
|
1875
|
+
if (t !== void 0) return Xt("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).");
|
|
1876
|
+
let r = Gt(e);
|
|
1848
1877
|
if (r) return { endpoint: r };
|
|
1849
1878
|
let i;
|
|
1850
1879
|
try {
|
|
@@ -1852,9 +1881,9 @@ function qt(e, t, n) {
|
|
|
1852
1881
|
} catch {
|
|
1853
1882
|
i = e;
|
|
1854
1883
|
}
|
|
1855
|
-
return
|
|
1884
|
+
return Xt(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).`);
|
|
1856
1885
|
}
|
|
1857
|
-
var
|
|
1886
|
+
var Qt = class {
|
|
1858
1887
|
opts;
|
|
1859
1888
|
url;
|
|
1860
1889
|
cspKey;
|
|
@@ -1936,8 +1965,8 @@ var Jt = class {
|
|
|
1936
1965
|
constructor(e) {
|
|
1937
1966
|
this.opts = {
|
|
1938
1967
|
...e,
|
|
1939
|
-
heartbeatMs: e.heartbeatMs ??
|
|
1940
|
-
idleMs: e.idleMs ??
|
|
1968
|
+
heartbeatMs: e.heartbeatMs ?? Pt,
|
|
1969
|
+
idleMs: e.idleMs ?? Ft
|
|
1941
1970
|
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
|
|
1942
1971
|
try {
|
|
1943
1972
|
let e = new URL(this.url);
|
|
@@ -1954,11 +1983,11 @@ var Jt = class {
|
|
|
1954
1983
|
sdkVersion: this.opts.sdkVersion,
|
|
1955
1984
|
...this.opts.environment
|
|
1956
1985
|
};
|
|
1957
|
-
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(),
|
|
1986
|
+
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Rt), 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 && qt.add(this.cspKey), document.addEventListener("securitypolicyviolation", Yt), X.add(this), this.noteCspBlocked(), this.onVisibility());
|
|
1958
1987
|
}
|
|
1959
1988
|
checkSuspension(e) {
|
|
1960
1989
|
if (this.endedFlag || !this.opts.idleMs) return !1;
|
|
1961
|
-
let t = Math.max(this.opts.idleMs,
|
|
1990
|
+
let t = Math.max(this.opts.idleMs, It);
|
|
1962
1991
|
return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
|
|
1963
1992
|
}
|
|
1964
1993
|
syncIdle(e) {
|
|
@@ -1981,12 +2010,12 @@ var Jt = class {
|
|
|
1981
2010
|
let a = {
|
|
1982
2011
|
fromState: J[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
1983
2012
|
toState: J[t] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
1984
|
-
presentation:
|
|
2013
|
+
presentation: Vt[this.presentation]
|
|
1985
2014
|
}, o = this.causeOf(e, t, i);
|
|
1986
2015
|
o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
1987
2016
|
}
|
|
1988
2017
|
seekInduced(e) {
|
|
1989
|
-
return this.lastSeekMs >= 0 && e - this.lastSeekMs <
|
|
2018
|
+
return this.lastSeekMs >= 0 && e - this.lastSeekMs < Bt;
|
|
1990
2019
|
}
|
|
1991
2020
|
causeOf(e, t, n) {
|
|
1992
2021
|
if (t === "error") return "TRANSITION_CAUSE_ERROR";
|
|
@@ -2060,7 +2089,7 @@ var Jt = class {
|
|
|
2060
2089
|
let r = n ?? "";
|
|
2061
2090
|
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";
|
|
2062
2091
|
if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
|
|
2063
|
-
if (
|
|
2092
|
+
if (Wt.has(e)) return "ERROR_STAGE_RESOLVE";
|
|
2064
2093
|
let i = t ?? "";
|
|
2065
2094
|
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";
|
|
2066
2095
|
}
|
|
@@ -2107,14 +2136,14 @@ var Jt = class {
|
|
|
2107
2136
|
if (this.lastRequestCount = g, _ > 0) {
|
|
2108
2137
|
o.requestCountDelta = _;
|
|
2109
2138
|
let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
|
|
2110
|
-
n.length > 0 && (o.requestTimeP50Ms =
|
|
2139
|
+
n.length > 0 && (o.requestTimeP50Ms = Ut(n, 50), o.requestTimeP95Ms = Ut(n, 95));
|
|
2111
2140
|
}
|
|
2112
2141
|
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();
|
|
2113
2142
|
}
|
|
2114
2143
|
maybeEmitMediaInfo(e) {
|
|
2115
2144
|
if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
|
|
2116
2145
|
let t = {};
|
|
2117
|
-
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem =
|
|
2146
|
+
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = Ht[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);
|
|
2118
2147
|
let n = JSON.stringify(t);
|
|
2119
2148
|
n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
|
|
2120
2149
|
}
|
|
@@ -2134,7 +2163,7 @@ var Jt = class {
|
|
|
2134
2163
|
let c = r?.positionMs ?? 0;
|
|
2135
2164
|
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));
|
|
2136
2165
|
let l = e !== "END_REASON_ENDED";
|
|
2137
|
-
l && this.lastStallMs > 0 && n - this.lastStallMs <=
|
|
2166
|
+
l && this.lastStallMs > 0 && n - this.lastStallMs <= zt && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= zt && (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);
|
|
2138
2167
|
let u = r?.decodedFrames ?? this.lastDecoded;
|
|
2139
2168
|
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");
|
|
2140
2169
|
}
|
|
@@ -2154,13 +2183,13 @@ var Jt = class {
|
|
|
2154
2183
|
};
|
|
2155
2184
|
}
|
|
2156
2185
|
noteCspBlocked() {
|
|
2157
|
-
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(
|
|
2186
|
+
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(Jt(new URL(this.url).origin)));
|
|
2158
2187
|
}
|
|
2159
2188
|
cspBlocked() {
|
|
2160
2189
|
return !!this.cspKey && Y.has(this.cspKey);
|
|
2161
2190
|
}
|
|
2162
2191
|
enqueue(e) {
|
|
2163
|
-
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length >
|
|
2192
|
+
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Lt;) {
|
|
2164
2193
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
2165
2194
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
2166
2195
|
}
|
|
@@ -2187,7 +2216,7 @@ var Jt = class {
|
|
|
2187
2216
|
};
|
|
2188
2217
|
//#endregion
|
|
2189
2218
|
//#region src/core/environment.ts
|
|
2190
|
-
function
|
|
2219
|
+
function $t() {
|
|
2191
2220
|
if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
|
|
2192
2221
|
let e;
|
|
2193
2222
|
try {
|
|
@@ -2212,14 +2241,14 @@ function Yt() {
|
|
|
2212
2241
|
integration: "INTEGRATION_KIND_IFRAME"
|
|
2213
2242
|
};
|
|
2214
2243
|
}
|
|
2215
|
-
function
|
|
2244
|
+
function en() {
|
|
2216
2245
|
if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
|
|
2217
2246
|
let e = navigator.userAgentData, t = e?.platform ?? "";
|
|
2218
2247
|
if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
|
|
2219
2248
|
let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
|
|
2220
2249
|
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";
|
|
2221
2250
|
}
|
|
2222
|
-
function
|
|
2251
|
+
function tn() {
|
|
2223
2252
|
let e = typeof navigator < "u" ? navigator.connection : void 0;
|
|
2224
2253
|
if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
|
|
2225
2254
|
let t = {
|
|
@@ -2238,17 +2267,17 @@ function Zt() {
|
|
|
2238
2267
|
}
|
|
2239
2268
|
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;
|
|
2240
2269
|
}
|
|
2241
|
-
function
|
|
2242
|
-
let t =
|
|
2243
|
-
deviceClass:
|
|
2270
|
+
function nn(e) {
|
|
2271
|
+
let t = $t(), n = {
|
|
2272
|
+
deviceClass: en(),
|
|
2244
2273
|
integration: t.integration,
|
|
2245
|
-
...
|
|
2274
|
+
...tn()
|
|
2246
2275
|
};
|
|
2247
2276
|
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);
|
|
2248
2277
|
let r = e.getBoundingClientRect?.();
|
|
2249
2278
|
return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
|
|
2250
2279
|
}
|
|
2251
|
-
async function
|
|
2280
|
+
async function rn() {
|
|
2252
2281
|
let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
|
|
2253
2282
|
if (!e?.getHighEntropyValues) return {};
|
|
2254
2283
|
try {
|
|
@@ -2260,7 +2289,7 @@ async function $t() {
|
|
|
2260
2289
|
}
|
|
2261
2290
|
//#endregion
|
|
2262
2291
|
//#region src/core/version.ts
|
|
2263
|
-
var
|
|
2292
|
+
var an = "2.15.1", on = {
|
|
2264
2293
|
accent: "#E1B600",
|
|
2265
2294
|
accentText: "#1B1C23",
|
|
2266
2295
|
background: "#0e0f13",
|
|
@@ -2271,7 +2300,7 @@ var en = "2.15.0", tn = {
|
|
|
2271
2300
|
border: "rgba(255, 255, 255, 0.1)",
|
|
2272
2301
|
radius: "8px",
|
|
2273
2302
|
fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
|
|
2274
|
-
},
|
|
2303
|
+
}, sn = {
|
|
2275
2304
|
accent: "--havik-accent",
|
|
2276
2305
|
accentText: "--havik-accent-text",
|
|
2277
2306
|
background: "--havik-bg",
|
|
@@ -2283,26 +2312,26 @@ var en = "2.15.0", tn = {
|
|
|
2283
2312
|
radius: "--havik-radius",
|
|
2284
2313
|
fontFamily: "--havik-font"
|
|
2285
2314
|
};
|
|
2286
|
-
function
|
|
2315
|
+
function cn(e, t) {
|
|
2287
2316
|
let n = {
|
|
2288
|
-
...
|
|
2317
|
+
...on,
|
|
2289
2318
|
...t
|
|
2290
2319
|
};
|
|
2291
|
-
for (let t of Object.keys(
|
|
2320
|
+
for (let t of Object.keys(sn)) e.style.setProperty(sn[t], n[t]);
|
|
2292
2321
|
n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
|
|
2293
2322
|
}
|
|
2294
2323
|
//#endregion
|
|
2295
2324
|
//#region src/ui/styles.ts
|
|
2296
|
-
var
|
|
2297
|
-
function
|
|
2298
|
-
let n = e.querySelector(`style#${
|
|
2299
|
-
if (n && (!t ||
|
|
2325
|
+
var ln = "havik-player-styles", un = "\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", dn = /* @__PURE__ */ new WeakMap();
|
|
2326
|
+
function fn(e = document, t) {
|
|
2327
|
+
let n = e.querySelector(`style#${ln}`);
|
|
2328
|
+
if (n && (!t || dn.get(n) === t)) return;
|
|
2300
2329
|
let r = e.createElement("style");
|
|
2301
|
-
r.id =
|
|
2330
|
+
r.id = ln, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = un, dn.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
|
|
2302
2331
|
}
|
|
2303
2332
|
//#endregion
|
|
2304
2333
|
//#region src/ui/icons.ts
|
|
2305
|
-
var
|
|
2334
|
+
var pn = {
|
|
2306
2335
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
2307
2336
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
2308
2337
|
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\"/>",
|
|
@@ -2316,20 +2345,20 @@ var ln = {
|
|
|
2316
2345
|
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\"/>"
|
|
2317
2346
|
};
|
|
2318
2347
|
function Z(e) {
|
|
2319
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
2348
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${pn[e]}</svg>`;
|
|
2320
2349
|
}
|
|
2321
2350
|
//#endregion
|
|
2322
2351
|
//#region src/ui/controls.ts
|
|
2323
|
-
var
|
|
2352
|
+
var mn = 3e3, hn = 250, gn = /* @__PURE__ */ new Set([
|
|
2324
2353
|
"GONE",
|
|
2325
2354
|
"NOT_FOUND",
|
|
2326
2355
|
"INVALID_URN",
|
|
2327
2356
|
"UNAUTHORIZED"
|
|
2328
2357
|
]);
|
|
2329
|
-
function
|
|
2330
|
-
return new
|
|
2358
|
+
function _n(e) {
|
|
2359
|
+
return new vn(e);
|
|
2331
2360
|
}
|
|
2332
|
-
var
|
|
2361
|
+
var vn = class {
|
|
2333
2362
|
root;
|
|
2334
2363
|
video;
|
|
2335
2364
|
player;
|
|
@@ -2375,7 +2404,7 @@ var mn = class {
|
|
|
2375
2404
|
scrubbing = !1;
|
|
2376
2405
|
offFns = [];
|
|
2377
2406
|
constructor(e) {
|
|
2378
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
2407
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? mn, 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, fn(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");
|
|
2379
2408
|
let t = (e, t, n) => {
|
|
2380
2409
|
let r = this.doc.createElement(e);
|
|
2381
2410
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -2461,7 +2490,7 @@ var mn = class {
|
|
|
2461
2490
|
let t = this.surfaceWasHidden;
|
|
2462
2491
|
this.tapTimer = setTimeout(() => {
|
|
2463
2492
|
this.tapTimer = void 0, this.toggleBar(t);
|
|
2464
|
-
},
|
|
2493
|
+
}, hn);
|
|
2465
2494
|
}
|
|
2466
2495
|
toggleBar(e) {
|
|
2467
2496
|
e ? this.poke() : this.hideIfIdle();
|
|
@@ -2496,7 +2525,7 @@ var mn = class {
|
|
|
2496
2525
|
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);
|
|
2497
2526
|
} else {
|
|
2498
2527
|
let r = this.doc.createElement("div");
|
|
2499
|
-
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !
|
|
2528
|
+
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !gn.has(this.lastError.code)) {
|
|
2500
2529
|
let e = this.doc.createElement("button");
|
|
2501
2530
|
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);
|
|
2502
2531
|
}
|
|
@@ -2537,7 +2566,7 @@ var mn = class {
|
|
|
2537
2566
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
2538
2567
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
2539
2568
|
}
|
|
2540
|
-
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${
|
|
2569
|
+
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${yn(this.video.currentTime)} / ${yn(this.video.duration)}`);
|
|
2541
2570
|
}
|
|
2542
2571
|
syncLive() {
|
|
2543
2572
|
let e = this.player.getStats(), t = e.isLive !== !1;
|
|
@@ -2587,17 +2616,17 @@ var mn = class {
|
|
|
2587
2616
|
renderQualityMenu() {
|
|
2588
2617
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
2589
2618
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
2590
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
2619
|
+
for (let n of e) this.menu.append(this.menuItem(bn(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
2591
2620
|
}
|
|
2592
2621
|
renderAudioMenu() {
|
|
2593
2622
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
2594
2623
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
2595
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2624
|
+
for (let t of e) this.menu.append(this.menuItem(xn(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
2596
2625
|
}
|
|
2597
2626
|
renderCcMenu() {
|
|
2598
2627
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
2599
2628
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
2600
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2629
|
+
for (let t of e) this.menu.append(this.menuItem(Sn(t), !1, () => this.player.setTextTrack(t.id)));
|
|
2601
2630
|
}
|
|
2602
2631
|
onTracksChanged() {
|
|
2603
2632
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -2698,41 +2727,41 @@ var mn = class {
|
|
|
2698
2727
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
2699
2728
|
}
|
|
2700
2729
|
};
|
|
2701
|
-
function
|
|
2730
|
+
function yn(e) {
|
|
2702
2731
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
2703
2732
|
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");
|
|
2704
2733
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
2705
2734
|
}
|
|
2706
|
-
function
|
|
2735
|
+
function bn(e) {
|
|
2707
2736
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
2708
2737
|
}
|
|
2709
|
-
function
|
|
2738
|
+
function xn(e) {
|
|
2710
2739
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2711
2740
|
}
|
|
2712
|
-
function
|
|
2741
|
+
function Sn(e) {
|
|
2713
2742
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2714
2743
|
}
|
|
2715
2744
|
//#endregion
|
|
2716
2745
|
//#region src/managed/index.ts
|
|
2717
|
-
var
|
|
2718
|
-
function
|
|
2746
|
+
var Cn = 6e3, Q = 45e3, wn = 2e3, Tn = 3, En = 2e3, Dn = 48e4;
|
|
2747
|
+
function On(e) {
|
|
2719
2748
|
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)})`);
|
|
2720
|
-
if (e.env !== void 0) return
|
|
2749
|
+
if (e.env !== void 0) return B(e.env);
|
|
2721
2750
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
|
|
2722
2751
|
return e.baseUrl;
|
|
2723
2752
|
}
|
|
2724
|
-
async function
|
|
2753
|
+
async function kn(e) {
|
|
2725
2754
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
2726
|
-
let t =
|
|
2755
|
+
let t = On(e);
|
|
2727
2756
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
2728
2757
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
2729
|
-
let r = new
|
|
2758
|
+
let r = new An({
|
|
2730
2759
|
...e,
|
|
2731
2760
|
baseUrl: t
|
|
2732
2761
|
});
|
|
2733
2762
|
return await r.start(), r;
|
|
2734
2763
|
}
|
|
2735
|
-
var
|
|
2764
|
+
var An = class {
|
|
2736
2765
|
opts;
|
|
2737
2766
|
abort = new AbortController();
|
|
2738
2767
|
listeners = {};
|
|
@@ -2776,7 +2805,7 @@ var En = class {
|
|
|
2776
2805
|
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");
|
|
2777
2806
|
let e = ++this.loadGen, t = this.resolveOptions();
|
|
2778
2807
|
try {
|
|
2779
|
-
let n = await
|
|
2808
|
+
let n = await v(t);
|
|
2780
2809
|
if (await this.onResolved(n, e), e === this.loadGen && this._state === "error" && this._lastError) {
|
|
2781
2810
|
let e = this._lastError;
|
|
2782
2811
|
throw this.destroy(), e;
|
|
@@ -2803,7 +2832,7 @@ var En = class {
|
|
|
2803
2832
|
r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
|
|
2804
2833
|
}
|
|
2805
2834
|
beginArmingByPolling(e) {
|
|
2806
|
-
|
|
2835
|
+
y({
|
|
2807
2836
|
...this.resolveOptions(),
|
|
2808
2837
|
signal: this.abort.signal,
|
|
2809
2838
|
waitForLive: this.buildWaitConfig(e)
|
|
@@ -2820,7 +2849,7 @@ var En = class {
|
|
|
2820
2849
|
setTimeout(() => {
|
|
2821
2850
|
a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
2822
2851
|
phase: i ? "unavailable" : "tooEarly",
|
|
2823
|
-
retryInMs:
|
|
2852
|
+
retryInMs: Q,
|
|
2824
2853
|
attempt: 1,
|
|
2825
2854
|
elapsedMs: 0,
|
|
2826
2855
|
...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
|
|
@@ -2837,7 +2866,7 @@ var En = class {
|
|
|
2837
2866
|
}
|
|
2838
2867
|
}
|
|
2839
2868
|
}, h = () => {
|
|
2840
|
-
a || s || p() || (s = !0,
|
|
2869
|
+
a || s || p() || (s = !0, y({
|
|
2841
2870
|
...this.resolveOptions(),
|
|
2842
2871
|
signal: c.signal,
|
|
2843
2872
|
waitForLive: this.buildWaitConfig(e)
|
|
@@ -2845,7 +2874,7 @@ var En = class {
|
|
|
2845
2874
|
a || p() || c.signal.aborted || (a = !0, this.closeArming(), this.fail(e instanceof n ? e : new n("INTERNAL", 0, String(e))));
|
|
2846
2875
|
}));
|
|
2847
2876
|
}, g = () => {
|
|
2848
|
-
a || p() ||
|
|
2877
|
+
a || p() || v(this.resolveOptions()).then((e) => m(e)).catch((e) => {
|
|
2849
2878
|
if (!(a || p())) {
|
|
2850
2879
|
if (e instanceof n && o(e.code)) {
|
|
2851
2880
|
h();
|
|
@@ -2859,13 +2888,13 @@ var En = class {
|
|
|
2859
2888
|
!a && !p() && h();
|
|
2860
2889
|
}, e);
|
|
2861
2890
|
};
|
|
2862
|
-
_(
|
|
2891
|
+
_(Cn), this.armingSub = T({
|
|
2863
2892
|
eventsBaseUrl: t,
|
|
2864
2893
|
matchUrn: this.opts.matchUrn,
|
|
2865
2894
|
credential: this.opts.credential,
|
|
2866
|
-
onAlive: () => _(
|
|
2895
|
+
onAlive: () => _(Q),
|
|
2867
2896
|
onState: (e) => {
|
|
2868
|
-
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() *
|
|
2897
|
+
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * wn);
|
|
2869
2898
|
},
|
|
2870
2899
|
onError: () => h()
|
|
2871
2900
|
});
|
|
@@ -2888,7 +2917,7 @@ var En = class {
|
|
|
2888
2917
|
let n = await s(this.opts.credential);
|
|
2889
2918
|
if (this.destroyed || t !== this.loadGen) return;
|
|
2890
2919
|
this.setState("loading");
|
|
2891
|
-
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a =
|
|
2920
|
+
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = qe(this.opts.video, (e) => {
|
|
2892
2921
|
this._state !== "ended" && this._state !== "error" && this.setState(e);
|
|
2893
2922
|
});
|
|
2894
2923
|
if (await i.load(), this.destroyed || t !== this.loadGen) {
|
|
@@ -2910,26 +2939,26 @@ var En = class {
|
|
|
2910
2939
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
|
|
2911
2940
|
let i = e.analytics?.sid;
|
|
2912
2941
|
if (!i) return;
|
|
2913
|
-
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } =
|
|
2942
|
+
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = Zt(this.opts.baseUrl, a, e.analytics?.endpoint);
|
|
2914
2943
|
if (!o) {
|
|
2915
2944
|
s && setTimeout(() => {
|
|
2916
2945
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
|
|
2917
2946
|
}, 0);
|
|
2918
2947
|
return;
|
|
2919
2948
|
}
|
|
2920
|
-
let c = this.opts.video, l = new
|
|
2949
|
+
let c = this.opts.video, l = new Qt({
|
|
2921
2950
|
endpoint: o,
|
|
2922
2951
|
sid: i,
|
|
2923
2952
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
2924
|
-
sdkVersion:
|
|
2925
|
-
environment:
|
|
2953
|
+
sdkVersion: an,
|
|
2954
|
+
environment: nn(c),
|
|
2926
2955
|
idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
|
|
2927
2956
|
onIdle: () => this.onAnalyticsIdle(t),
|
|
2928
2957
|
onBlocked: (e) => setTimeout(() => {
|
|
2929
2958
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
|
|
2930
2959
|
}, 0),
|
|
2931
2960
|
sample: () => {
|
|
2932
|
-
let e = this.engine?.getStats() ??
|
|
2961
|
+
let e = this.engine?.getStats() ?? V, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
|
|
2933
2962
|
return {
|
|
2934
2963
|
...e,
|
|
2935
2964
|
bufferedMs: Math.round(t * 1e3),
|
|
@@ -2943,7 +2972,7 @@ var En = class {
|
|
|
2943
2972
|
let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
|
|
2944
2973
|
c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
|
|
2945
2974
|
c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
|
|
2946
|
-
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()),
|
|
2975
|
+
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), rn().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
|
|
2947
2976
|
}
|
|
2948
2977
|
currentPresentation() {
|
|
2949
2978
|
let e = this.opts.video;
|
|
@@ -2969,10 +2998,10 @@ var En = class {
|
|
|
2969
2998
|
emit: (e) => this.onEngineEvent(e)
|
|
2970
2999
|
}, o = this.opts.engine ?? "auto";
|
|
2971
3000
|
if (o === "native") return new K(a);
|
|
2972
|
-
if (o === "hls") return new
|
|
2973
|
-
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl &&
|
|
2974
|
-
if (at()) return new
|
|
2975
|
-
if (
|
|
3001
|
+
if (o === "hls") return new Nt(a);
|
|
3002
|
+
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && W(this.opts.video) && G()) return new K(a);
|
|
3003
|
+
if (at()) return new Nt(a);
|
|
3004
|
+
if (W(this.opts.video)) return new K(a);
|
|
2976
3005
|
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
2977
3006
|
}
|
|
2978
3007
|
onEngineEvent(e) {
|
|
@@ -3024,7 +3053,7 @@ var En = class {
|
|
|
3024
3053
|
r = 0, i = !1;
|
|
3025
3054
|
},
|
|
3026
3055
|
onError: () => {
|
|
3027
|
-
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >=
|
|
3056
|
+
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= Tn && (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.`))));
|
|
3028
3057
|
}
|
|
3029
3058
|
});
|
|
3030
3059
|
}
|
|
@@ -3046,7 +3075,7 @@ var En = class {
|
|
|
3046
3075
|
scheduleRejoin(e) {
|
|
3047
3076
|
this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
|
|
3048
3077
|
this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
|
|
3049
|
-
}, Math.random() *
|
|
3078
|
+
}, Math.random() * wn));
|
|
3050
3079
|
}
|
|
3051
3080
|
cancelRejoin() {
|
|
3052
3081
|
this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
|
|
@@ -3070,7 +3099,7 @@ var En = class {
|
|
|
3070
3099
|
}
|
|
3071
3100
|
t.controls = !1;
|
|
3072
3101
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
3073
|
-
r && r.insertBefore(n, t), n.appendChild(t),
|
|
3102
|
+
r && r.insertBefore(n, t), n.appendChild(t), cn(n, this.opts.theme), this.container = n, this.controlBar = _n({
|
|
3074
3103
|
root: n,
|
|
3075
3104
|
video: t,
|
|
3076
3105
|
player: this,
|
|
@@ -3101,7 +3130,7 @@ var En = class {
|
|
|
3101
3130
|
}
|
|
3102
3131
|
startStats() {
|
|
3103
3132
|
this.stopStats();
|
|
3104
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
3133
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? En);
|
|
3105
3134
|
this.statsTimer = setInterval(() => {
|
|
3106
3135
|
if (!this.engine) return;
|
|
3107
3136
|
let e = this.engine.getStats();
|
|
@@ -3113,7 +3142,7 @@ var En = class {
|
|
|
3113
3142
|
}
|
|
3114
3143
|
scheduleLicenseRefresh() {
|
|
3115
3144
|
this.stopRefresh();
|
|
3116
|
-
let e = this.opts.licenseRefreshMs ??
|
|
3145
|
+
let e = this.opts.licenseRefreshMs ?? Dn;
|
|
3117
3146
|
e && this._descriptor?.drmEnabled && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
3118
3147
|
}
|
|
3119
3148
|
stopRefresh() {
|
|
@@ -3122,7 +3151,7 @@ var En = class {
|
|
|
3122
3151
|
async refreshLicense() {
|
|
3123
3152
|
let e = this.engine;
|
|
3124
3153
|
if (!this.destroyed && e) try {
|
|
3125
|
-
let t = await
|
|
3154
|
+
let t = await v(this.resolveOptions());
|
|
3126
3155
|
if (this.destroyed || this.engine !== e) return;
|
|
3127
3156
|
let n = t.drm?.widevine?.licenseUrl, r = t.drm?.fairplay?.licenseUrl;
|
|
3128
3157
|
(n || r) && (e.setLicenseUrls({
|
|
@@ -3158,7 +3187,7 @@ var En = class {
|
|
|
3158
3187
|
this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
|
|
3159
3188
|
}
|
|
3160
3189
|
getStats() {
|
|
3161
|
-
return this.engine?.getStats() ??
|
|
3190
|
+
return this.engine?.getStats() ?? V;
|
|
3162
3191
|
}
|
|
3163
3192
|
getQualityLevels() {
|
|
3164
3193
|
return this.engine?.getQualityLevels() ?? [];
|
|
@@ -3210,7 +3239,7 @@ var En = class {
|
|
|
3210
3239
|
let e = ++this.loadGen;
|
|
3211
3240
|
this.teardownPlayback();
|
|
3212
3241
|
try {
|
|
3213
|
-
let t = await
|
|
3242
|
+
let t = await y({
|
|
3214
3243
|
...this.resolveOptions(),
|
|
3215
3244
|
waitForLive: this.opts.waitForLive ? this.buildWaitConfig(e) : void 0
|
|
3216
3245
|
});
|
|
@@ -3268,7 +3297,7 @@ function $(e) {
|
|
|
3268
3297
|
}
|
|
3269
3298
|
//#endregion
|
|
3270
3299
|
//#region src/embed/host.ts
|
|
3271
|
-
function
|
|
3300
|
+
function jn(e) {
|
|
3272
3301
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
3273
3302
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
3274
3303
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -3327,15 +3356,15 @@ function Dn(e) {
|
|
|
3327
3356
|
}
|
|
3328
3357
|
//#endregion
|
|
3329
3358
|
//#region src/embed/page.ts
|
|
3330
|
-
var
|
|
3331
|
-
function
|
|
3359
|
+
var Mn = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
3360
|
+
function Nn(e) {
|
|
3332
3361
|
if (typeof e == "boolean") return e;
|
|
3333
3362
|
if (typeof e == "object" && e) {
|
|
3334
3363
|
let t = e.endpoint;
|
|
3335
3364
|
return typeof t == "string" ? { endpoint: t } : {};
|
|
3336
3365
|
}
|
|
3337
3366
|
}
|
|
3338
|
-
function
|
|
3367
|
+
function Pn() {
|
|
3339
3368
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
3340
3369
|
if (e) return {
|
|
3341
3370
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -3345,7 +3374,7 @@ function An() {
|
|
|
3345
3374
|
autoplay: e.autoplay ?? !0,
|
|
3346
3375
|
muted: e.muted ?? !0,
|
|
3347
3376
|
waitForLive: e.waitForLive ?? !0,
|
|
3348
|
-
analytics:
|
|
3377
|
+
analytics: Nn(e.analytics)
|
|
3349
3378
|
};
|
|
3350
3379
|
let t = new URLSearchParams(location.search);
|
|
3351
3380
|
return {
|
|
@@ -3358,9 +3387,9 @@ function An() {
|
|
|
3358
3387
|
waitForLive: !0
|
|
3359
3388
|
};
|
|
3360
3389
|
}
|
|
3361
|
-
async function
|
|
3362
|
-
let e =
|
|
3363
|
-
|
|
3390
|
+
async function Fn() {
|
|
3391
|
+
let e = Pn();
|
|
3392
|
+
Ln();
|
|
3364
3393
|
let t = document.createElement("video");
|
|
3365
3394
|
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);
|
|
3366
3395
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -3415,12 +3444,12 @@ async function jn() {
|
|
|
3415
3444
|
code: e.code,
|
|
3416
3445
|
message: e.message
|
|
3417
3446
|
})), e.on("autoplayblocked", () => {
|
|
3418
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
3447
|
+
i({ type: "oddin:autoplayblocked" }), In(t, e);
|
|
3419
3448
|
});
|
|
3420
3449
|
}, s = async (r) => {
|
|
3421
3450
|
a?.destroy(), a = null;
|
|
3422
3451
|
try {
|
|
3423
|
-
let n = await
|
|
3452
|
+
let n = await kn({
|
|
3424
3453
|
video: t,
|
|
3425
3454
|
baseUrl: e.baseUrl,
|
|
3426
3455
|
matchUrn: r,
|
|
@@ -3482,7 +3511,7 @@ async function jn() {
|
|
|
3482
3511
|
a?.retry();
|
|
3483
3512
|
break;
|
|
3484
3513
|
case "oddin:load":
|
|
3485
|
-
typeof e.matchUrn == "string" &&
|
|
3514
|
+
typeof e.matchUrn == "string" && Mn.test(e.matchUrn) && s(e.matchUrn);
|
|
3486
3515
|
break;
|
|
3487
3516
|
case "oddin:destroy": c();
|
|
3488
3517
|
}
|
|
@@ -3494,18 +3523,18 @@ async function jn() {
|
|
|
3494
3523
|
protocol: 1
|
|
3495
3524
|
});
|
|
3496
3525
|
}
|
|
3497
|
-
function
|
|
3526
|
+
function In(e, t) {
|
|
3498
3527
|
if (document.getElementById("havik-tap")) return;
|
|
3499
3528
|
let n = document.createElement("button");
|
|
3500
3529
|
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", () => {
|
|
3501
3530
|
n.remove(), t.play();
|
|
3502
3531
|
}), document.body.appendChild(n);
|
|
3503
3532
|
}
|
|
3504
|
-
function
|
|
3533
|
+
function Ln() {
|
|
3505
3534
|
let e = document.createElement("style");
|
|
3506
3535
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
3507
3536
|
}
|
|
3508
3537
|
//#endregion
|
|
3509
|
-
export {
|
|
3538
|
+
export { on as ODDIN_THEME, n as PlaybackError, cn as applyTheme, B as baseUrlForEnv, Fn as bootEmbed, Te as clearDeviceId, kn as createPlayer, E as deriveEventsBaseUrl, He as detectDrmSupport, C as enterVideoFullscreen, w as exitVideoFullscreen, _e as fetchCatalog, ye as fetchTournament, xe as flattenMatches, k as getDeviceId, We as isLowLatencyManifest, $ as isOddinMessage, De as licenseRequestHeaders, jn as mountEmbed, de as pollToLive, y as resolveStream, T as subscribeLiveState, S as videoFullscreenActive, Ce as watchStatus };
|
|
3510
3539
|
|
|
3511
3540
|
//# sourceMappingURL=index.js.map
|