@oddin-gg/havik-player 2.15.3 → 2.15.4
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.js +211 -195
- package/dist/index.js.map +1 -1
- package/docs/API.md +5 -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 = .5, mt = 3, ht = .5, gt = 1.1, _t = .25, vt = 5e3, yt = 4e3, bt = 2, xt = 5, St = 2, Ct = 2, wt = 4, Tt = 4, Et = 2e3, Dt = 3e4, Ot = .2, kt = 30, At = 2, jt = 2, Mt = 9, Nt = .5, Pt = 64;
|
|
1223
|
+
function Ft(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 ??= jt;
|
|
1229
|
+
let t = Math.max(12, e.liveSyncDuration + Mt);
|
|
1230
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), It(e, e.liveSyncDuration);
|
|
1231
1231
|
}
|
|
1232
|
-
function
|
|
1232
|
+
function It(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 Lt = class {
|
|
1237
1237
|
name = "hls";
|
|
1238
1238
|
hls = null;
|
|
1239
1239
|
deps;
|
|
@@ -1290,6 +1290,9 @@ var It = class {
|
|
|
1290
1290
|
savedLiveMaxLatency;
|
|
1291
1291
|
savedMaxSyncRate;
|
|
1292
1292
|
chaseLatency = -1;
|
|
1293
|
+
catchUpRate = 1;
|
|
1294
|
+
catchUpEngaged = !1;
|
|
1295
|
+
onTimeUpdate = null;
|
|
1293
1296
|
chaseTicks = 0;
|
|
1294
1297
|
liveRetargets = 0;
|
|
1295
1298
|
capObserver = null;
|
|
@@ -1311,7 +1314,7 @@ var It = class {
|
|
|
1311
1314
|
this.deps = e, this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
|
|
1312
1315
|
}
|
|
1313
1316
|
async load() {
|
|
1314
|
-
let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a =
|
|
1317
|
+
let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = W(r) && G(), o = !!e.drm?.widevine?.licenseUrl && !a;
|
|
1315
1318
|
if (e.drmEnabled && !o) {
|
|
1316
1319
|
i({
|
|
1317
1320
|
type: "error",
|
|
@@ -1320,7 +1323,7 @@ var It = class {
|
|
|
1320
1323
|
});
|
|
1321
1324
|
return;
|
|
1322
1325
|
}
|
|
1323
|
-
e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ae(r),
|
|
1326
|
+
e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ae(r), Pe()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
|
|
1324
1327
|
let e = this.hls;
|
|
1325
1328
|
if (document.visibilityState !== "visible" || !e) return;
|
|
1326
1329
|
let t = e.liveSyncPosition;
|
|
@@ -1329,7 +1332,7 @@ var It = class {
|
|
|
1329
1332
|
t - r.currentTime > Math.max(n * 3, 8) && (r.currentTime = t);
|
|
1330
1333
|
}, document.addEventListener("visibilitychange", this.onVisibility)), this.onSeeking = () => {
|
|
1331
1334
|
this.clampOverSeek(), this.loadSuspended && (this.resumeLoading(), this.schedulePauseSuspend());
|
|
1332
|
-
}, r.addEventListener("seeking", this.onSeeking), this.onPause = () => this.schedulePauseSuspend(), this.onPlay = () => this.resumeLoading(), r.addEventListener("pause", this.onPause), r.addEventListener("play", this.onPlay), this.sizeCapManaged && typeof ResizeObserver < "u" && (this.capObserver = new ResizeObserver(() => this.onMediaResize()), this.capObserver.observe(r), this.watchDprChanges());
|
|
1335
|
+
}, r.addEventListener("seeking", this.onSeeking), this.onTimeUpdate = () => this.updateCatchUpBand(), r.addEventListener("timeupdate", this.onTimeUpdate), this.onPause = () => this.schedulePauseSuspend(), this.onPlay = () => this.resumeLoading(), r.addEventListener("pause", this.onPause), r.addEventListener("play", this.onPlay), this.sizeCapManaged && typeof ResizeObserver < "u" && (this.capObserver = new ResizeObserver(() => this.onMediaResize()), this.capObserver.observe(r), this.watchDprChanges());
|
|
1333
1336
|
}
|
|
1334
1337
|
schedulePauseSuspend() {
|
|
1335
1338
|
this.pauseSuspendTimer || this.loadSuspended || this.stopped || !this.loadStarted || (this.pauseSuspendTimer = setTimeout(() => {
|
|
@@ -1343,7 +1346,7 @@ var It = class {
|
|
|
1343
1346
|
}
|
|
1344
1347
|
this.loadSuspended = !0;
|
|
1345
1348
|
}
|
|
1346
|
-
},
|
|
1349
|
+
}, vt));
|
|
1347
1350
|
}
|
|
1348
1351
|
resumeLoading() {
|
|
1349
1352
|
if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
|
|
@@ -1375,7 +1378,7 @@ var It = class {
|
|
|
1375
1378
|
let t = e.liveSyncPosition;
|
|
1376
1379
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
1377
1380
|
let { video: n } = this.deps;
|
|
1378
|
-
n.currentTime <= t +
|
|
1381
|
+
n.currentTime <= t + Nt || (n.currentTime = t);
|
|
1379
1382
|
}
|
|
1380
1383
|
startHls() {
|
|
1381
1384
|
let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
|
|
@@ -1422,7 +1425,7 @@ var It = class {
|
|
|
1422
1425
|
}), t = tt(e);
|
|
1423
1426
|
t && (this.prefetch = e, d.fLoader = t);
|
|
1424
1427
|
}
|
|
1425
|
-
|
|
1428
|
+
Ft(d), this.catchUpRate = typeof d.maxLiveSyncPlaybackRate == "number" ? d.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (d.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = d.autoStartLoad !== !1;
|
|
1426
1429
|
let f = new e(d);
|
|
1427
1430
|
if (this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
|
|
1428
1431
|
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" });
|
|
@@ -1437,10 +1440,10 @@ var It = class {
|
|
|
1437
1440
|
let n = t?.frag?.stats, r = n?.loaded;
|
|
1438
1441
|
typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
|
|
1439
1442
|
let i = n?.loading;
|
|
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 >
|
|
1443
|
+
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 > Pt && this.requestTimesMs.shift());
|
|
1441
1444
|
let a = t?.frag?.url;
|
|
1442
1445
|
if (a) {
|
|
1443
|
-
let e =
|
|
1446
|
+
let e = H(a);
|
|
1444
1447
|
e && (this.cdnHost = e);
|
|
1445
1448
|
}
|
|
1446
1449
|
}), f.on(e.Events.LEVEL_LOADED, (e, t) => {
|
|
@@ -1461,7 +1464,7 @@ var It = class {
|
|
|
1461
1464
|
f.on(e.Events.KEY_LOADED, () => {
|
|
1462
1465
|
u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
|
|
1463
1466
|
}), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
|
|
1464
|
-
this.checkEndStale(), this.checkStarvation(), this.checkFutileChase(), this.checkFrameDrops();
|
|
1467
|
+
this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.checkFrameDrops();
|
|
1465
1468
|
}, dt), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
1466
1469
|
this.renditionSwitches += 1;
|
|
1467
1470
|
let n = this.lastLevelIndex >= 0 ? f.levels[this.lastLevelIndex] : void 0, r = f.levels[t.level];
|
|
@@ -1526,7 +1529,7 @@ var It = class {
|
|
|
1526
1529
|
return;
|
|
1527
1530
|
}
|
|
1528
1531
|
this.capTimer && clearTimeout(this.capTimer);
|
|
1529
|
-
let t = e > this.sizeCapLevel ?
|
|
1532
|
+
let t = e > this.sizeCapLevel ? Et : Dt;
|
|
1530
1533
|
this.capTimer = setTimeout(() => {
|
|
1531
1534
|
this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
|
|
1532
1535
|
}, t);
|
|
@@ -1536,9 +1539,9 @@ var It = class {
|
|
|
1536
1539
|
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;
|
|
1537
1540
|
}
|
|
1538
1541
|
dropLevelsWidevineCannotPlay(e) {
|
|
1539
|
-
this.removeLevelsWhere(e, (e) =>
|
|
1542
|
+
this.removeLevelsWhere(e, (e) => Fe(e) !== !0);
|
|
1540
1543
|
let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && I(e) !== "avc" && !!I(e)));
|
|
1541
|
-
for (let n of t)
|
|
1544
|
+
for (let n of t) Ne(n).then((t) => {
|
|
1542
1545
|
t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
|
|
1543
1546
|
});
|
|
1544
1547
|
}
|
|
@@ -1549,7 +1552,7 @@ var It = class {
|
|
|
1549
1552
|
a && I(a) && t(a) && (r.push(n), i.add(a));
|
|
1550
1553
|
}), !r.length) return !1;
|
|
1551
1554
|
let a = [...i].join(", ");
|
|
1552
|
-
if (!n.some((e, t) => r.includes(t) ? !1 : !I(e.videoCodec) ||
|
|
1555
|
+
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;
|
|
1553
1556
|
for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
|
|
1554
1557
|
return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
|
|
1555
1558
|
}
|
|
@@ -1599,7 +1602,7 @@ var It = class {
|
|
|
1599
1602
|
e.widevine && (this.licenseUrl = e.widevine);
|
|
1600
1603
|
}
|
|
1601
1604
|
getStats() {
|
|
1602
|
-
let e = this.hls, t =
|
|
1605
|
+
let e = this.hls, t = U(this.deps.video), n = {
|
|
1603
1606
|
droppedFrames: t.dropped,
|
|
1604
1607
|
decodedFrames: t.totalFrames,
|
|
1605
1608
|
lowLatency: this.detectedLowLatency,
|
|
@@ -1662,7 +1665,7 @@ var It = class {
|
|
|
1662
1665
|
this.resetStarvationWindow();
|
|
1663
1666
|
return;
|
|
1664
1667
|
}
|
|
1665
|
-
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < ft, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs >
|
|
1668
|
+
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < ft, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > yt, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = U(t), c = o - s, l = c !== this.starvedFrames;
|
|
1666
1669
|
if (this.starvedFrames = c, !a || l) {
|
|
1667
1670
|
(t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
|
|
1668
1671
|
return;
|
|
@@ -1671,12 +1674,12 @@ var It = class {
|
|
|
1671
1674
|
this.resetStarvationWindow();
|
|
1672
1675
|
return;
|
|
1673
1676
|
}
|
|
1674
|
-
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 >
|
|
1677
|
+
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 > wt && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= St && (this.clearKick(), this.starvationRebuilds < Ct)) {
|
|
1675
1678
|
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");
|
|
1676
1679
|
return;
|
|
1677
1680
|
}
|
|
1678
|
-
let u = i && this.starvedTicks >=
|
|
1679
|
-
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >=
|
|
1681
|
+
let u = i && this.starvedTicks >= bt, d = !i && this.deadTicks >= wt && this.recentMainFrags.reduce((e, t) => e + t, 0) >= Tt;
|
|
1682
|
+
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= xt))) {
|
|
1680
1683
|
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");
|
|
1681
1684
|
try {
|
|
1682
1685
|
e.stopLoad(), e.startLoad(-1);
|
|
@@ -1685,6 +1688,16 @@ var It = class {
|
|
|
1685
1688
|
}
|
|
1686
1689
|
}
|
|
1687
1690
|
}
|
|
1691
|
+
updateCatchUpBand() {
|
|
1692
|
+
let e = this.hls;
|
|
1693
|
+
if (!e || this.catchUpRate <= 1 || this.chaseSuspended || this.loadSuspended) return;
|
|
1694
|
+
let t = e.latency, n = e.targetLatency;
|
|
1695
|
+
if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
|
|
1696
|
+
let r = t - n;
|
|
1697
|
+
!this.catchUpEngaged && r > pt ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= pt && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
|
|
1698
|
+
let i = this.catchUpEngaged ? this.catchUpRate : 1;
|
|
1699
|
+
e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
|
|
1700
|
+
}
|
|
1688
1701
|
fpsCapLevel(e) {
|
|
1689
1702
|
if (this.fpsCapBitrate == null) return -1;
|
|
1690
1703
|
let t = this.fpsCapFailedHeight, n = -1;
|
|
@@ -1702,16 +1715,16 @@ var It = class {
|
|
|
1702
1715
|
this.resetFrameDropWindow();
|
|
1703
1716
|
return;
|
|
1704
1717
|
}
|
|
1705
|
-
let { totalFrames: n, dropped: r } =
|
|
1706
|
-
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a <
|
|
1718
|
+
let { totalFrames: n, dropped: r } = U(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
|
|
1719
|
+
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < kt || o < 0) {
|
|
1707
1720
|
this.fpsBadTicks = 0;
|
|
1708
1721
|
return;
|
|
1709
1722
|
}
|
|
1710
|
-
if (o <=
|
|
1723
|
+
if (o <= Ot * a) {
|
|
1711
1724
|
this.fpsBadTicks = 0;
|
|
1712
1725
|
return;
|
|
1713
1726
|
}
|
|
1714
|
-
if (this.fpsBadTicks += 1, this.fpsBadTicks <
|
|
1727
|
+
if (this.fpsBadTicks += 1, this.fpsBadTicks < At) return;
|
|
1715
1728
|
this.fpsBadTicks = 0;
|
|
1716
1729
|
let s = e.levels, c = s[e.currentLevel];
|
|
1717
1730
|
if (!c) return;
|
|
@@ -1728,24 +1741,27 @@ var It = class {
|
|
|
1728
1741
|
return;
|
|
1729
1742
|
}
|
|
1730
1743
|
let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
|
|
1731
|
-
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(
|
|
1744
|
+
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(gt, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
|
|
1732
1745
|
this.resetChaseWindow();
|
|
1733
1746
|
return;
|
|
1734
1747
|
}
|
|
1735
|
-
if (this.chaseLatency < 0 || this.chaseLatency - n >=
|
|
1748
|
+
if (this.chaseLatency < 0 || this.chaseLatency - n >= ht) {
|
|
1736
1749
|
this.chaseLatency = n, this.chaseTicks = 0;
|
|
1737
1750
|
return;
|
|
1738
1751
|
}
|
|
1739
|
-
if (this.chaseTicks += 1, this.chaseTicks <
|
|
1752
|
+
if (this.chaseTicks += 1, this.chaseTicks < mt) return;
|
|
1740
1753
|
this.resetChaseWindow();
|
|
1741
1754
|
let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
|
|
1742
1755
|
if (!(a > 1)) return;
|
|
1743
1756
|
let o = typeof e.targetLatency == "number" ? e.targetLatency : 0, s = Math.min(n, a - 1);
|
|
1744
|
-
s < o +
|
|
1757
|
+
s < o + _t || (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);
|
|
1745
1758
|
}
|
|
1746
1759
|
suspendChasing() {
|
|
1747
1760
|
let e = this.hls;
|
|
1748
|
-
|
|
1761
|
+
if (!e) return;
|
|
1762
|
+
this.chaseSuspended = !0, this.savedLiveMaxLatency = e.config.liveMaxLatencyDuration, this.savedMaxSyncRate = e.config.maxLiveSyncPlaybackRate, e.config.liveMaxLatencyDuration = 2 ** 53 - 1, e.config.maxLiveSyncPlaybackRate = 1;
|
|
1763
|
+
let { video: t } = this.deps, n = this.savedMaxSyncRate;
|
|
1764
|
+
t.playbackRate > 1 && typeof n == "number" && t.playbackRate <= n && (t.playbackRate = 1);
|
|
1749
1765
|
}
|
|
1750
1766
|
resumeChasing() {
|
|
1751
1767
|
this.chaseSuspended = !1;
|
|
@@ -1768,7 +1784,7 @@ var It = class {
|
|
|
1768
1784
|
} catch {}
|
|
1769
1785
|
}
|
|
1770
1786
|
destroy() {
|
|
1771
|
-
if (this.prefetch?.destroy(), this.prefetch = null, this.clearRecoveryReset(), this.capTimer &&= (clearTimeout(this.capTimer), null), this.capObserver &&= (this.capObserver.disconnect(), null), this.unwatchDprChanges(), this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.onSeeking &&= (this.deps.video.removeEventListener("seeking", this.onSeeking), null), this.onPause &&= (this.deps.video.removeEventListener("pause", this.onPause), null), this.onPlay &&= (this.deps.video.removeEventListener("play", this.onPlay), null), this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), this.licenseRetryTimer &&= (clearTimeout(this.licenseRetryTimer), null), this.hls) {
|
|
1787
|
+
if (this.prefetch?.destroy(), this.prefetch = null, this.clearRecoveryReset(), this.capTimer &&= (clearTimeout(this.capTimer), null), this.capObserver &&= (this.capObserver.disconnect(), null), this.unwatchDprChanges(), this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.onSeeking &&= (this.deps.video.removeEventListener("seeking", this.onSeeking), null), this.onTimeUpdate &&= (this.deps.video.removeEventListener("timeupdate", this.onTimeUpdate), null), this.onPause &&= (this.deps.video.removeEventListener("pause", this.onPause), null), this.onPlay &&= (this.deps.video.removeEventListener("play", this.onPlay), null), this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), this.licenseRetryTimer &&= (clearTimeout(this.licenseRetryTimer), null), this.hls) {
|
|
1772
1788
|
try {
|
|
1773
1789
|
this.hls.destroy();
|
|
1774
1790
|
} catch (e) {
|
|
@@ -1856,19 +1872,19 @@ var It = class {
|
|
|
1856
1872
|
let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
|
|
1857
1873
|
return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
|
|
1858
1874
|
}
|
|
1859
|
-
},
|
|
1875
|
+
}, Rt = 15e3, zt = 6e5, Bt = 3e5, Vt = 100, q = 1, Ht = 1e3, Ut = 3e4, Wt = 1e3, Gt = {
|
|
1860
1876
|
inline: "PRESENTATION_INLINE",
|
|
1861
1877
|
fullscreen: "PRESENTATION_FULLSCREEN",
|
|
1862
1878
|
pip: "PRESENTATION_PIP"
|
|
1863
|
-
},
|
|
1879
|
+
}, Kt = {
|
|
1864
1880
|
widevine: "KEY_SYSTEM_WIDEVINE",
|
|
1865
1881
|
fairplay: "KEY_SYSTEM_FAIRPLAY",
|
|
1866
1882
|
none: "KEY_SYSTEM_NONE"
|
|
1867
1883
|
};
|
|
1868
|
-
function
|
|
1884
|
+
function qt(e, t) {
|
|
1869
1885
|
return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
|
|
1870
1886
|
}
|
|
1871
|
-
var
|
|
1887
|
+
var Jt = /* @__PURE__ */ new Set([
|
|
1872
1888
|
"INVALID_URN",
|
|
1873
1889
|
"NOT_FOUND",
|
|
1874
1890
|
"GONE",
|
|
@@ -1888,7 +1904,7 @@ var qt = /* @__PURE__ */ new Set([
|
|
|
1888
1904
|
ended: "PLAYER_STATE_ENDED",
|
|
1889
1905
|
error: "PLAYER_STATE_ERROR"
|
|
1890
1906
|
};
|
|
1891
|
-
function
|
|
1907
|
+
function Yt(e) {
|
|
1892
1908
|
try {
|
|
1893
1909
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
1894
1910
|
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);
|
|
@@ -1896,8 +1912,8 @@ function Jt(e) {
|
|
|
1896
1912
|
return;
|
|
1897
1913
|
}
|
|
1898
1914
|
}
|
|
1899
|
-
var
|
|
1900
|
-
function
|
|
1915
|
+
var Xt = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), Zt = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), Qt = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
|
|
1916
|
+
function $t(e) {
|
|
1901
1917
|
if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
|
|
1902
1918
|
let t;
|
|
1903
1919
|
try {
|
|
@@ -1906,19 +1922,19 @@ function Qt(e) {
|
|
|
1906
1922
|
} catch {
|
|
1907
1923
|
return;
|
|
1908
1924
|
}
|
|
1909
|
-
if (
|
|
1910
|
-
Y.add(t), g(
|
|
1925
|
+
if (Zt.has(t) && !Y.has(t)) {
|
|
1926
|
+
Y.add(t), g(Qt(new URL(t).origin));
|
|
1911
1927
|
for (let e of X) e.noteCspBlocked();
|
|
1912
1928
|
}
|
|
1913
1929
|
}
|
|
1914
|
-
function
|
|
1930
|
+
function en(e, t) {
|
|
1915
1931
|
return g(t, e), { disabledReason: t };
|
|
1916
1932
|
}
|
|
1917
|
-
function
|
|
1918
|
-
if (n) return t && !
|
|
1933
|
+
function tn(e, t, n) {
|
|
1934
|
+
if (n) return t && !Xt(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
|
|
1919
1935
|
if (t) return { endpoint: t };
|
|
1920
|
-
if (t !== void 0) return
|
|
1921
|
-
let r =
|
|
1936
|
+
if (t !== void 0) return en("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).");
|
|
1937
|
+
let r = Yt(e);
|
|
1922
1938
|
if (r) return { endpoint: r };
|
|
1923
1939
|
let i;
|
|
1924
1940
|
try {
|
|
@@ -1926,9 +1942,9 @@ function en(e, t, n) {
|
|
|
1926
1942
|
} catch {
|
|
1927
1943
|
i = e;
|
|
1928
1944
|
}
|
|
1929
|
-
return
|
|
1945
|
+
return en(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).`);
|
|
1930
1946
|
}
|
|
1931
|
-
var
|
|
1947
|
+
var nn = class {
|
|
1932
1948
|
opts;
|
|
1933
1949
|
url;
|
|
1934
1950
|
cspKey;
|
|
@@ -2010,8 +2026,8 @@ var tn = class {
|
|
|
2010
2026
|
constructor(e) {
|
|
2011
2027
|
this.opts = {
|
|
2012
2028
|
...e,
|
|
2013
|
-
heartbeatMs: e.heartbeatMs ??
|
|
2014
|
-
idleMs: e.idleMs ??
|
|
2029
|
+
heartbeatMs: e.heartbeatMs ?? Rt,
|
|
2030
|
+
idleMs: e.idleMs ?? zt
|
|
2015
2031
|
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
|
|
2016
2032
|
try {
|
|
2017
2033
|
let e = new URL(this.url);
|
|
@@ -2028,11 +2044,11 @@ var tn = class {
|
|
|
2028
2044
|
sdkVersion: this.opts.sdkVersion,
|
|
2029
2045
|
...this.opts.environment
|
|
2030
2046
|
};
|
|
2031
|
-
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(),
|
|
2047
|
+
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Ht), 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 && Zt.add(this.cspKey), document.addEventListener("securitypolicyviolation", $t), X.add(this), this.noteCspBlocked(), this.onVisibility());
|
|
2032
2048
|
}
|
|
2033
2049
|
checkSuspension(e) {
|
|
2034
2050
|
if (this.endedFlag || !this.opts.idleMs) return !1;
|
|
2035
|
-
let t = Math.max(this.opts.idleMs,
|
|
2051
|
+
let t = Math.max(this.opts.idleMs, Bt);
|
|
2036
2052
|
return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
|
|
2037
2053
|
}
|
|
2038
2054
|
syncIdle(e) {
|
|
@@ -2055,12 +2071,12 @@ var tn = class {
|
|
|
2055
2071
|
let a = {
|
|
2056
2072
|
fromState: J[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2057
2073
|
toState: J[t] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2058
|
-
presentation:
|
|
2074
|
+
presentation: Gt[this.presentation]
|
|
2059
2075
|
}, o = this.causeOf(e, t, i);
|
|
2060
2076
|
o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
2061
2077
|
}
|
|
2062
2078
|
seekInduced(e) {
|
|
2063
|
-
return this.lastSeekMs >= 0 && e - this.lastSeekMs <
|
|
2079
|
+
return this.lastSeekMs >= 0 && e - this.lastSeekMs < Wt;
|
|
2064
2080
|
}
|
|
2065
2081
|
causeOf(e, t, n) {
|
|
2066
2082
|
if (t === "error") return "TRANSITION_CAUSE_ERROR";
|
|
@@ -2134,7 +2150,7 @@ var tn = class {
|
|
|
2134
2150
|
let r = n ?? "";
|
|
2135
2151
|
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";
|
|
2136
2152
|
if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
|
|
2137
|
-
if (
|
|
2153
|
+
if (Jt.has(e)) return "ERROR_STAGE_RESOLVE";
|
|
2138
2154
|
let i = t ?? "";
|
|
2139
2155
|
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";
|
|
2140
2156
|
}
|
|
@@ -2181,14 +2197,14 @@ var tn = class {
|
|
|
2181
2197
|
if (this.lastRequestCount = g, _ > 0) {
|
|
2182
2198
|
o.requestCountDelta = _;
|
|
2183
2199
|
let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
|
|
2184
|
-
n.length > 0 && (o.requestTimeP50Ms =
|
|
2200
|
+
n.length > 0 && (o.requestTimeP50Ms = qt(n, 50), o.requestTimeP95Ms = qt(n, 95));
|
|
2185
2201
|
}
|
|
2186
2202
|
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();
|
|
2187
2203
|
}
|
|
2188
2204
|
maybeEmitMediaInfo(e) {
|
|
2189
2205
|
if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
|
|
2190
2206
|
let t = {};
|
|
2191
|
-
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem =
|
|
2207
|
+
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = Kt[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);
|
|
2192
2208
|
let n = JSON.stringify(t);
|
|
2193
2209
|
n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
|
|
2194
2210
|
}
|
|
@@ -2208,7 +2224,7 @@ var tn = class {
|
|
|
2208
2224
|
let c = r?.positionMs ?? 0;
|
|
2209
2225
|
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));
|
|
2210
2226
|
let l = e !== "END_REASON_ENDED";
|
|
2211
|
-
l && this.lastStallMs > 0 && n - this.lastStallMs <=
|
|
2227
|
+
l && this.lastStallMs > 0 && n - this.lastStallMs <= Ut && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Ut && (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);
|
|
2212
2228
|
let u = r?.decodedFrames ?? this.lastDecoded;
|
|
2213
2229
|
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");
|
|
2214
2230
|
}
|
|
@@ -2228,13 +2244,13 @@ var tn = class {
|
|
|
2228
2244
|
};
|
|
2229
2245
|
}
|
|
2230
2246
|
noteCspBlocked() {
|
|
2231
|
-
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(
|
|
2247
|
+
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(Qt(new URL(this.url).origin)));
|
|
2232
2248
|
}
|
|
2233
2249
|
cspBlocked() {
|
|
2234
2250
|
return !!this.cspKey && Y.has(this.cspKey);
|
|
2235
2251
|
}
|
|
2236
2252
|
enqueue(e) {
|
|
2237
|
-
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length >
|
|
2253
|
+
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Vt;) {
|
|
2238
2254
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
2239
2255
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
2240
2256
|
}
|
|
@@ -2261,7 +2277,7 @@ var tn = class {
|
|
|
2261
2277
|
};
|
|
2262
2278
|
//#endregion
|
|
2263
2279
|
//#region src/core/environment.ts
|
|
2264
|
-
function
|
|
2280
|
+
function rn() {
|
|
2265
2281
|
if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
|
|
2266
2282
|
let e;
|
|
2267
2283
|
try {
|
|
@@ -2286,14 +2302,14 @@ function nn() {
|
|
|
2286
2302
|
integration: "INTEGRATION_KIND_IFRAME"
|
|
2287
2303
|
};
|
|
2288
2304
|
}
|
|
2289
|
-
function
|
|
2305
|
+
function an() {
|
|
2290
2306
|
if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
|
|
2291
2307
|
let e = navigator.userAgentData, t = e?.platform ?? "";
|
|
2292
2308
|
if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
|
|
2293
2309
|
let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
|
|
2294
2310
|
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";
|
|
2295
2311
|
}
|
|
2296
|
-
function
|
|
2312
|
+
function on() {
|
|
2297
2313
|
let e = typeof navigator < "u" ? navigator.connection : void 0;
|
|
2298
2314
|
if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
|
|
2299
2315
|
let t = {
|
|
@@ -2312,17 +2328,17 @@ function an() {
|
|
|
2312
2328
|
}
|
|
2313
2329
|
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;
|
|
2314
2330
|
}
|
|
2315
|
-
function
|
|
2316
|
-
let t =
|
|
2317
|
-
deviceClass:
|
|
2331
|
+
function sn(e) {
|
|
2332
|
+
let t = rn(), n = {
|
|
2333
|
+
deviceClass: an(),
|
|
2318
2334
|
integration: t.integration,
|
|
2319
|
-
...
|
|
2335
|
+
...on()
|
|
2320
2336
|
};
|
|
2321
2337
|
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);
|
|
2322
2338
|
let r = e.getBoundingClientRect?.();
|
|
2323
2339
|
return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
|
|
2324
2340
|
}
|
|
2325
|
-
async function
|
|
2341
|
+
async function cn() {
|
|
2326
2342
|
let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
|
|
2327
2343
|
if (!e?.getHighEntropyValues) return {};
|
|
2328
2344
|
try {
|
|
@@ -2334,7 +2350,7 @@ async function sn() {
|
|
|
2334
2350
|
}
|
|
2335
2351
|
//#endregion
|
|
2336
2352
|
//#region src/core/version.ts
|
|
2337
|
-
var
|
|
2353
|
+
var ln = "2.15.4", un = {
|
|
2338
2354
|
accent: "#E1B600",
|
|
2339
2355
|
accentText: "#1B1C23",
|
|
2340
2356
|
background: "#0e0f13",
|
|
@@ -2345,7 +2361,7 @@ var cn = "2.15.3", ln = {
|
|
|
2345
2361
|
border: "rgba(255, 255, 255, 0.1)",
|
|
2346
2362
|
radius: "8px",
|
|
2347
2363
|
fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
|
|
2348
|
-
},
|
|
2364
|
+
}, dn = {
|
|
2349
2365
|
accent: "--havik-accent",
|
|
2350
2366
|
accentText: "--havik-accent-text",
|
|
2351
2367
|
background: "--havik-bg",
|
|
@@ -2357,22 +2373,22 @@ var cn = "2.15.3", ln = {
|
|
|
2357
2373
|
radius: "--havik-radius",
|
|
2358
2374
|
fontFamily: "--havik-font"
|
|
2359
2375
|
};
|
|
2360
|
-
function
|
|
2376
|
+
function fn(e, t) {
|
|
2361
2377
|
let n = {
|
|
2362
|
-
...
|
|
2378
|
+
...un,
|
|
2363
2379
|
...t
|
|
2364
2380
|
};
|
|
2365
|
-
for (let t of Object.keys(
|
|
2381
|
+
for (let t of Object.keys(dn)) e.style.setProperty(dn[t], n[t]);
|
|
2366
2382
|
n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
|
|
2367
2383
|
}
|
|
2368
2384
|
//#endregion
|
|
2369
2385
|
//#region src/ui/styles.ts
|
|
2370
|
-
var
|
|
2386
|
+
var pn = "havik-player-styles", mn = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer;\n touch-action:manipulation}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n/* Absolutely centred, NOT a flex sibling of .havik-center: the hidden center\n button (.havik-gone) still occupies its 74px in the row, which pushed an\n in-flow spinner 37px right of centre. */\n.havik-spinner{position:absolute;inset:0;margin:auto;width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n", Z = /* @__PURE__ */ new WeakMap();
|
|
2371
2387
|
function hn(e = document, t) {
|
|
2372
|
-
let n = e.querySelector(`style#${
|
|
2373
|
-
if (n && (!t ||
|
|
2388
|
+
let n = e.querySelector(`style#${pn}`);
|
|
2389
|
+
if (n && (!t || Z.get(n) === t)) return;
|
|
2374
2390
|
let r = e.createElement("style");
|
|
2375
|
-
r.id =
|
|
2391
|
+
r.id = pn, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = mn, Z.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
|
|
2376
2392
|
}
|
|
2377
2393
|
//#endregion
|
|
2378
2394
|
//#region src/ui/icons.ts
|
|
@@ -2389,7 +2405,7 @@ var gn = {
|
|
|
2389
2405
|
liveDot: "<circle cx=\"12\" cy=\"12\" r=\"6\"/>",
|
|
2390
2406
|
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\"/>"
|
|
2391
2407
|
};
|
|
2392
|
-
function
|
|
2408
|
+
function Q(e) {
|
|
2393
2409
|
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${gn[e]}</svg>`;
|
|
2394
2410
|
}
|
|
2395
2411
|
//#endregion
|
|
@@ -2460,12 +2476,12 @@ var xn = class {
|
|
|
2460
2476
|
"aria-label": r,
|
|
2461
2477
|
title: r
|
|
2462
2478
|
});
|
|
2463
|
-
return i.innerHTML =
|
|
2479
|
+
return i.innerHTML = Q(n), i;
|
|
2464
2480
|
};
|
|
2465
2481
|
this.overlay = t("div", "havik-overlay"), this.center = t("button", "havik-center", {
|
|
2466
2482
|
type: "button",
|
|
2467
2483
|
"aria-label": "Play"
|
|
2468
|
-
}), this.center.innerHTML =
|
|
2484
|
+
}), this.center.innerHTML = Q("play"), this.spinner = t("div", "havik-spinner"), this.spinner.style.display = "none", this.overlay.append(this.center, this.spinner), this.gradient = t("div", "havik-gradient"), this.bar = t("div", "havik-bar"), this.seek = t("div", "havik-seek", {
|
|
2469
2485
|
role: "slider",
|
|
2470
2486
|
"aria-label": "Seek",
|
|
2471
2487
|
"aria-valuemin": "0",
|
|
@@ -2483,7 +2499,7 @@ var xn = class {
|
|
|
2483
2499
|
"aria-label": "Volume"
|
|
2484
2500
|
});
|
|
2485
2501
|
let a = t("div", "havik-vol");
|
|
2486
|
-
a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML =
|
|
2502
|
+
a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML = Q("liveDot");
|
|
2487
2503
|
let o = this.doc.createElement("span");
|
|
2488
2504
|
o.textContent = "LIVE", this.liveGo = t("button", "havik-live__go", { type: "button" }), this.liveGo.textContent = "Go live", this.live.append(o, this.liveGo), this.time = t("div", "havik-time"), this.time.textContent = "0:00", this.time.style.display = "none";
|
|
2489
2505
|
let s = t("div", "havik-spacer");
|
|
@@ -2567,12 +2583,12 @@ var xn = class {
|
|
|
2567
2583
|
}
|
|
2568
2584
|
if (e === "preplay") {
|
|
2569
2585
|
let e = this.doc.createElement("button");
|
|
2570
|
-
e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML =
|
|
2586
|
+
e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = Q("play"), e.addEventListener("click", () => void this.player.play()), n.append(e);
|
|
2571
2587
|
} else {
|
|
2572
2588
|
let r = this.doc.createElement("div");
|
|
2573
2589
|
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !yn.has(this.lastError.code)) {
|
|
2574
2590
|
let e = this.doc.createElement("button");
|
|
2575
|
-
e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${
|
|
2591
|
+
e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${Q("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), n.append(e);
|
|
2576
2592
|
}
|
|
2577
2593
|
}
|
|
2578
2594
|
this.root.append(n), this.statusBox = n, this.show();
|
|
@@ -2755,7 +2771,7 @@ var xn = class {
|
|
|
2755
2771
|
}
|
|
2756
2772
|
}
|
|
2757
2773
|
setIcon(e, t) {
|
|
2758
|
-
e.innerHTML =
|
|
2774
|
+
e.innerHTML = Q(t);
|
|
2759
2775
|
}
|
|
2760
2776
|
destroy() {
|
|
2761
2777
|
this.hideTimer && clearTimeout(this.hideTimer), this.tapTimer && clearTimeout(this.tapTimer);
|
|
@@ -2788,25 +2804,25 @@ function Tn(e) {
|
|
|
2788
2804
|
}
|
|
2789
2805
|
//#endregion
|
|
2790
2806
|
//#region src/managed/index.ts
|
|
2791
|
-
var En = 6e3, Dn = 45e3,
|
|
2792
|
-
function
|
|
2807
|
+
var En = 6e3, Dn = 45e3, On = 2e3, kn = 3, An = 2e3, jn = 48e4;
|
|
2808
|
+
function Mn(e) {
|
|
2793
2809
|
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)})`);
|
|
2794
|
-
if (e.env !== void 0) return
|
|
2810
|
+
if (e.env !== void 0) return B(e.env);
|
|
2795
2811
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
|
|
2796
2812
|
return e.baseUrl;
|
|
2797
2813
|
}
|
|
2798
|
-
async function
|
|
2814
|
+
async function Nn(e) {
|
|
2799
2815
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
2800
|
-
let t =
|
|
2816
|
+
let t = Mn(e);
|
|
2801
2817
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
2802
2818
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
2803
|
-
let r = new
|
|
2819
|
+
let r = new Pn({
|
|
2804
2820
|
...e,
|
|
2805
2821
|
baseUrl: t
|
|
2806
2822
|
});
|
|
2807
2823
|
return await r.start(), r;
|
|
2808
2824
|
}
|
|
2809
|
-
var
|
|
2825
|
+
var Pn = class {
|
|
2810
2826
|
opts;
|
|
2811
2827
|
abort = new AbortController();
|
|
2812
2828
|
listeners = {};
|
|
@@ -2850,7 +2866,7 @@ var Nn = class {
|
|
|
2850
2866
|
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");
|
|
2851
2867
|
let e = ++this.loadGen, t = this.resolveOptions();
|
|
2852
2868
|
try {
|
|
2853
|
-
let n = await
|
|
2869
|
+
let n = await v(t);
|
|
2854
2870
|
if (await this.onResolved(n, e), e === this.loadGen && this._state === "error" && this._lastError) {
|
|
2855
2871
|
let e = this._lastError;
|
|
2856
2872
|
throw this.destroy(), e;
|
|
@@ -2877,7 +2893,7 @@ var Nn = class {
|
|
|
2877
2893
|
r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
|
|
2878
2894
|
}
|
|
2879
2895
|
beginArmingByPolling(e) {
|
|
2880
|
-
|
|
2896
|
+
y({
|
|
2881
2897
|
...this.resolveOptions(),
|
|
2882
2898
|
signal: this.abort.signal,
|
|
2883
2899
|
waitForLive: this.buildWaitConfig(e)
|
|
@@ -2911,7 +2927,7 @@ var Nn = class {
|
|
|
2911
2927
|
}
|
|
2912
2928
|
}
|
|
2913
2929
|
}, h = () => {
|
|
2914
|
-
a || s || p() || (s = !0,
|
|
2930
|
+
a || s || p() || (s = !0, y({
|
|
2915
2931
|
...this.resolveOptions(),
|
|
2916
2932
|
signal: c.signal,
|
|
2917
2933
|
waitForLive: this.buildWaitConfig(e)
|
|
@@ -2919,7 +2935,7 @@ var Nn = class {
|
|
|
2919
2935
|
a || p() || c.signal.aborted || (a = !0, this.closeArming(), this.fail(e instanceof n ? e : new n("INTERNAL", 0, String(e))));
|
|
2920
2936
|
}));
|
|
2921
2937
|
}, g = () => {
|
|
2922
|
-
a || p() ||
|
|
2938
|
+
a || p() || v(this.resolveOptions()).then((e) => m(e)).catch((e) => {
|
|
2923
2939
|
if (!(a || p())) {
|
|
2924
2940
|
if (e instanceof n && o(e.code)) {
|
|
2925
2941
|
h();
|
|
@@ -2939,7 +2955,7 @@ var Nn = class {
|
|
|
2939
2955
|
credential: this.opts.credential,
|
|
2940
2956
|
onAlive: () => _(Dn),
|
|
2941
2957
|
onState: (e) => {
|
|
2942
|
-
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() *
|
|
2958
|
+
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * On);
|
|
2943
2959
|
},
|
|
2944
2960
|
onError: () => h()
|
|
2945
2961
|
});
|
|
@@ -2962,7 +2978,7 @@ var Nn = class {
|
|
|
2962
2978
|
let n = await s(this.opts.credential);
|
|
2963
2979
|
if (this.destroyed || t !== this.loadGen) return;
|
|
2964
2980
|
this.setState("loading");
|
|
2965
|
-
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a =
|
|
2981
|
+
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = qe(this.opts.video, (e) => {
|
|
2966
2982
|
this._state !== "ended" && this._state !== "error" && this.setState(e);
|
|
2967
2983
|
});
|
|
2968
2984
|
if (await i.load(), this.destroyed || t !== this.loadGen) {
|
|
@@ -2984,26 +3000,26 @@ var Nn = class {
|
|
|
2984
3000
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
|
|
2985
3001
|
let i = e.analytics?.sid;
|
|
2986
3002
|
if (!i) return;
|
|
2987
|
-
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } =
|
|
3003
|
+
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = tn(this.opts.baseUrl, a, e.analytics?.endpoint);
|
|
2988
3004
|
if (!o) {
|
|
2989
3005
|
s && setTimeout(() => {
|
|
2990
3006
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
|
|
2991
3007
|
}, 0);
|
|
2992
3008
|
return;
|
|
2993
3009
|
}
|
|
2994
|
-
let c = this.opts.video, l = new
|
|
3010
|
+
let c = this.opts.video, l = new nn({
|
|
2995
3011
|
endpoint: o,
|
|
2996
3012
|
sid: i,
|
|
2997
3013
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
2998
|
-
sdkVersion:
|
|
2999
|
-
environment:
|
|
3014
|
+
sdkVersion: ln,
|
|
3015
|
+
environment: sn(c),
|
|
3000
3016
|
idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
|
|
3001
3017
|
onIdle: () => this.onAnalyticsIdle(t),
|
|
3002
3018
|
onBlocked: (e) => setTimeout(() => {
|
|
3003
3019
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
|
|
3004
3020
|
}, 0),
|
|
3005
3021
|
sample: () => {
|
|
3006
|
-
let e = this.engine?.getStats() ??
|
|
3022
|
+
let e = this.engine?.getStats() ?? V, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
|
|
3007
3023
|
return {
|
|
3008
3024
|
...e,
|
|
3009
3025
|
bufferedMs: Math.round(t * 1e3),
|
|
@@ -3017,7 +3033,7 @@ var Nn = class {
|
|
|
3017
3033
|
let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
|
|
3018
3034
|
c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
|
|
3019
3035
|
c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
|
|
3020
|
-
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()),
|
|
3036
|
+
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), cn().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
|
|
3021
3037
|
}
|
|
3022
3038
|
currentPresentation() {
|
|
3023
3039
|
let e = this.opts.video;
|
|
@@ -3043,10 +3059,10 @@ var Nn = class {
|
|
|
3043
3059
|
emit: (e) => this.onEngineEvent(e)
|
|
3044
3060
|
}, o = this.opts.engine ?? "auto";
|
|
3045
3061
|
if (o === "native") return new K(a);
|
|
3046
|
-
if (o === "hls") return new
|
|
3047
|
-
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl &&
|
|
3048
|
-
if (at()) return new
|
|
3049
|
-
if (
|
|
3062
|
+
if (o === "hls") return new Lt(a);
|
|
3063
|
+
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && W(this.opts.video) && G()) return new K(a);
|
|
3064
|
+
if (at()) return new Lt(a);
|
|
3065
|
+
if (W(this.opts.video)) return new K(a);
|
|
3050
3066
|
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
3051
3067
|
}
|
|
3052
3068
|
onEngineEvent(e) {
|
|
@@ -3098,7 +3114,7 @@ var Nn = class {
|
|
|
3098
3114
|
r = 0, i = !1;
|
|
3099
3115
|
},
|
|
3100
3116
|
onError: () => {
|
|
3101
|
-
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >=
|
|
3117
|
+
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= kn && (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.`))));
|
|
3102
3118
|
}
|
|
3103
3119
|
});
|
|
3104
3120
|
}
|
|
@@ -3120,7 +3136,7 @@ var Nn = class {
|
|
|
3120
3136
|
scheduleRejoin(e) {
|
|
3121
3137
|
this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
|
|
3122
3138
|
this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
|
|
3123
|
-
}, Math.random() *
|
|
3139
|
+
}, Math.random() * On));
|
|
3124
3140
|
}
|
|
3125
3141
|
cancelRejoin() {
|
|
3126
3142
|
this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
|
|
@@ -3144,7 +3160,7 @@ var Nn = class {
|
|
|
3144
3160
|
}
|
|
3145
3161
|
t.controls = !1;
|
|
3146
3162
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
3147
|
-
r && r.insertBefore(n, t), n.appendChild(t),
|
|
3163
|
+
r && r.insertBefore(n, t), n.appendChild(t), fn(n, this.opts.theme), this.container = n, this.controlBar = bn({
|
|
3148
3164
|
root: n,
|
|
3149
3165
|
video: t,
|
|
3150
3166
|
player: this,
|
|
@@ -3175,7 +3191,7 @@ var Nn = class {
|
|
|
3175
3191
|
}
|
|
3176
3192
|
startStats() {
|
|
3177
3193
|
this.stopStats();
|
|
3178
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
3194
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? An);
|
|
3179
3195
|
this.statsTimer = setInterval(() => {
|
|
3180
3196
|
if (!this.engine) return;
|
|
3181
3197
|
let e = this.engine.getStats();
|
|
@@ -3187,7 +3203,7 @@ var Nn = class {
|
|
|
3187
3203
|
}
|
|
3188
3204
|
scheduleLicenseRefresh() {
|
|
3189
3205
|
this.stopRefresh();
|
|
3190
|
-
let e = this.opts.licenseRefreshMs ??
|
|
3206
|
+
let e = this.opts.licenseRefreshMs ?? jn;
|
|
3191
3207
|
e && this._descriptor?.drmEnabled && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
3192
3208
|
}
|
|
3193
3209
|
stopRefresh() {
|
|
@@ -3196,7 +3212,7 @@ var Nn = class {
|
|
|
3196
3212
|
async refreshLicense() {
|
|
3197
3213
|
let e = this.engine;
|
|
3198
3214
|
if (!this.destroyed && e) try {
|
|
3199
|
-
let t = await
|
|
3215
|
+
let t = await v(this.resolveOptions());
|
|
3200
3216
|
if (this.destroyed || this.engine !== e) return;
|
|
3201
3217
|
let n = t.drm?.widevine?.licenseUrl, r = t.drm?.fairplay?.licenseUrl;
|
|
3202
3218
|
(n || r) && (e.setLicenseUrls({
|
|
@@ -3232,7 +3248,7 @@ var Nn = class {
|
|
|
3232
3248
|
this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
|
|
3233
3249
|
}
|
|
3234
3250
|
getStats() {
|
|
3235
|
-
return this.engine?.getStats() ??
|
|
3251
|
+
return this.engine?.getStats() ?? V;
|
|
3236
3252
|
}
|
|
3237
3253
|
getQualityLevels() {
|
|
3238
3254
|
return this.engine?.getQualityLevels() ?? [];
|
|
@@ -3284,7 +3300,7 @@ var Nn = class {
|
|
|
3284
3300
|
let e = ++this.loadGen;
|
|
3285
3301
|
this.teardownPlayback();
|
|
3286
3302
|
try {
|
|
3287
|
-
let t = await
|
|
3303
|
+
let t = await y({
|
|
3288
3304
|
...this.resolveOptions(),
|
|
3289
3305
|
waitForLive: this.opts.waitForLive ? this.buildWaitConfig(e) : void 0
|
|
3290
3306
|
});
|
|
@@ -3342,7 +3358,7 @@ function $(e) {
|
|
|
3342
3358
|
}
|
|
3343
3359
|
//#endregion
|
|
3344
3360
|
//#region src/embed/host.ts
|
|
3345
|
-
function
|
|
3361
|
+
function Fn(e) {
|
|
3346
3362
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
3347
3363
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
3348
3364
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -3401,15 +3417,15 @@ function Pn(e) {
|
|
|
3401
3417
|
}
|
|
3402
3418
|
//#endregion
|
|
3403
3419
|
//#region src/embed/page.ts
|
|
3404
|
-
var
|
|
3405
|
-
function
|
|
3420
|
+
var In = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
3421
|
+
function Ln(e) {
|
|
3406
3422
|
if (typeof e == "boolean") return e;
|
|
3407
3423
|
if (typeof e == "object" && e) {
|
|
3408
3424
|
let t = e.endpoint;
|
|
3409
3425
|
return typeof t == "string" ? { endpoint: t } : {};
|
|
3410
3426
|
}
|
|
3411
3427
|
}
|
|
3412
|
-
function
|
|
3428
|
+
function Rn() {
|
|
3413
3429
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
3414
3430
|
if (e) return {
|
|
3415
3431
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -3419,7 +3435,7 @@ function Ln() {
|
|
|
3419
3435
|
autoplay: e.autoplay ?? !0,
|
|
3420
3436
|
muted: e.muted ?? !0,
|
|
3421
3437
|
waitForLive: e.waitForLive ?? !0,
|
|
3422
|
-
analytics:
|
|
3438
|
+
analytics: Ln(e.analytics)
|
|
3423
3439
|
};
|
|
3424
3440
|
let t = new URLSearchParams(location.search);
|
|
3425
3441
|
return {
|
|
@@ -3432,9 +3448,9 @@ function Ln() {
|
|
|
3432
3448
|
waitForLive: !0
|
|
3433
3449
|
};
|
|
3434
3450
|
}
|
|
3435
|
-
async function
|
|
3436
|
-
let e =
|
|
3437
|
-
|
|
3451
|
+
async function zn() {
|
|
3452
|
+
let e = Rn();
|
|
3453
|
+
Vn();
|
|
3438
3454
|
let t = document.createElement("video");
|
|
3439
3455
|
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);
|
|
3440
3456
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -3489,12 +3505,12 @@ async function Rn() {
|
|
|
3489
3505
|
code: e.code,
|
|
3490
3506
|
message: e.message
|
|
3491
3507
|
})), e.on("autoplayblocked", () => {
|
|
3492
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
3508
|
+
i({ type: "oddin:autoplayblocked" }), Bn(t, e);
|
|
3493
3509
|
});
|
|
3494
3510
|
}, s = async (r) => {
|
|
3495
3511
|
a?.destroy(), a = null;
|
|
3496
3512
|
try {
|
|
3497
|
-
let n = await
|
|
3513
|
+
let n = await Nn({
|
|
3498
3514
|
video: t,
|
|
3499
3515
|
baseUrl: e.baseUrl,
|
|
3500
3516
|
matchUrn: r,
|
|
@@ -3556,7 +3572,7 @@ async function Rn() {
|
|
|
3556
3572
|
a?.retry();
|
|
3557
3573
|
break;
|
|
3558
3574
|
case "oddin:load":
|
|
3559
|
-
typeof e.matchUrn == "string" &&
|
|
3575
|
+
typeof e.matchUrn == "string" && In.test(e.matchUrn) && s(e.matchUrn);
|
|
3560
3576
|
break;
|
|
3561
3577
|
case "oddin:destroy": c();
|
|
3562
3578
|
}
|
|
@@ -3568,18 +3584,18 @@ async function Rn() {
|
|
|
3568
3584
|
protocol: 1
|
|
3569
3585
|
});
|
|
3570
3586
|
}
|
|
3571
|
-
function
|
|
3587
|
+
function Bn(e, t) {
|
|
3572
3588
|
if (document.getElementById("havik-tap")) return;
|
|
3573
3589
|
let n = document.createElement("button");
|
|
3574
3590
|
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", () => {
|
|
3575
3591
|
n.remove(), t.play();
|
|
3576
3592
|
}), document.body.appendChild(n);
|
|
3577
3593
|
}
|
|
3578
|
-
function
|
|
3594
|
+
function Vn() {
|
|
3579
3595
|
let e = document.createElement("style");
|
|
3580
3596
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
3581
3597
|
}
|
|
3582
3598
|
//#endregion
|
|
3583
|
-
export {
|
|
3599
|
+
export { un as ODDIN_THEME, n as PlaybackError, fn as applyTheme, B as baseUrlForEnv, zn as bootEmbed, Te as clearDeviceId, Nn 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, Fn as mountEmbed, de as pollToLive, y as resolveStream, T as subscribeLiveState, S as videoFullscreenActive, Ce as watchStatus };
|
|
3584
3600
|
|
|
3585
3601
|
//# sourceMappingURL=index.js.map
|