@oddin-gg/havik-player 2.22.0 → 2.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/havik-player.global.js +2 -2
- package/dist/havik-player.global.js.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +61 -1
- package/dist/index.d.ts +61 -1
- package/dist/index.js +376 -249
- package/dist/index.js.map +1 -1
- package/docs/API.md +99 -54
- package/embed/index.html +1 -1
- package/examples/vanilla.html +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -897,32 +897,32 @@ function at(e) {
|
|
|
897
897
|
}
|
|
898
898
|
//#endregion
|
|
899
899
|
//#region src/core/stats.ts
|
|
900
|
-
var
|
|
901
|
-
function
|
|
900
|
+
var ot = { droppedFrames: 0 };
|
|
901
|
+
function st(e) {
|
|
902
902
|
try {
|
|
903
903
|
return new URL(e).host;
|
|
904
904
|
} catch {
|
|
905
905
|
return "";
|
|
906
906
|
}
|
|
907
907
|
}
|
|
908
|
-
var
|
|
909
|
-
function
|
|
908
|
+
var ct = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
|
|
909
|
+
function lt(e) {
|
|
910
910
|
if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
|
|
911
911
|
let t = "", n = -1, r = performance.getEntriesByType("resource");
|
|
912
|
-
for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" ||
|
|
913
|
-
let e =
|
|
912
|
+
for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || ct.test(i.name)) && i.startTime >= n) {
|
|
913
|
+
let e = st(i.name);
|
|
914
914
|
e && (t = e, n = i.startTime);
|
|
915
915
|
}
|
|
916
916
|
return t;
|
|
917
917
|
}
|
|
918
|
-
function
|
|
918
|
+
function z(e) {
|
|
919
919
|
let t = e.getVideoPlaybackQuality?.();
|
|
920
920
|
return {
|
|
921
921
|
dropped: t?.droppedVideoFrames ?? 0,
|
|
922
922
|
totalFrames: t?.totalVideoFrames ?? 0
|
|
923
923
|
};
|
|
924
924
|
}
|
|
925
|
-
var
|
|
925
|
+
var ut = class {
|
|
926
926
|
video;
|
|
927
927
|
baseFrames = 0;
|
|
928
928
|
baseDropped = 0;
|
|
@@ -932,7 +932,7 @@ var lt = class {
|
|
|
932
932
|
this.video = e;
|
|
933
933
|
}
|
|
934
934
|
read() {
|
|
935
|
-
let e =
|
|
935
|
+
let e = z(this.video);
|
|
936
936
|
return e.totalFrames < this.lastFrames && (this.baseFrames += this.lastFrames), e.dropped < this.lastDropped && (this.baseDropped += this.lastDropped), this.lastFrames = e.totalFrames, this.lastDropped = e.dropped, {
|
|
937
937
|
dropped: this.baseDropped + e.dropped,
|
|
938
938
|
totalFrames: this.baseFrames + e.totalFrames
|
|
@@ -945,7 +945,7 @@ var lt = class {
|
|
|
945
945
|
};
|
|
946
946
|
}
|
|
947
947
|
};
|
|
948
|
-
function
|
|
948
|
+
function dt(e, t) {
|
|
949
949
|
let n = [
|
|
950
950
|
["playing", () => t("playing")],
|
|
951
951
|
["waiting", () => t("buffering")],
|
|
@@ -962,8 +962,8 @@ function ut(e, t) {
|
|
|
962
962
|
}
|
|
963
963
|
//#endregion
|
|
964
964
|
//#region src/core/engine/native.ts
|
|
965
|
-
var
|
|
966
|
-
function
|
|
965
|
+
var ft = 2e3, pt = 3, B = 500, mt = 6e3, ht = .25, gt = 250, _t = .05, vt = 4, yt = 12e3, bt = .25, xt = 1e3;
|
|
966
|
+
function St(e) {
|
|
967
967
|
try {
|
|
968
968
|
let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
|
|
969
969
|
return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
|
|
@@ -971,20 +971,20 @@ function xt(e) {
|
|
|
971
971
|
return;
|
|
972
972
|
}
|
|
973
973
|
}
|
|
974
|
-
function
|
|
974
|
+
function V(e) {
|
|
975
975
|
return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
|
|
976
976
|
}
|
|
977
|
-
function
|
|
977
|
+
function H() {
|
|
978
978
|
if (typeof window > "u") return !1;
|
|
979
979
|
let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
|
|
980
980
|
return e || t;
|
|
981
981
|
}
|
|
982
|
-
function
|
|
983
|
-
if (typeof navigator > "u" || !
|
|
982
|
+
function Ct() {
|
|
983
|
+
if (typeof navigator > "u" || !H()) return !1;
|
|
984
984
|
let e = navigator.userAgent ?? "";
|
|
985
985
|
return /iPhone|iPad|iPod/.test(e) ? !0 : /Macintosh/.test(e) && typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1;
|
|
986
986
|
}
|
|
987
|
-
var
|
|
987
|
+
var U = class {
|
|
988
988
|
name = "native";
|
|
989
989
|
deps;
|
|
990
990
|
onLoaded;
|
|
@@ -1014,7 +1014,7 @@ var W = class {
|
|
|
1014
1014
|
frameCounter;
|
|
1015
1015
|
detachFrames = null;
|
|
1016
1016
|
constructor(e) {
|
|
1017
|
-
this.deps = e, this.frameCounter = new
|
|
1017
|
+
this.deps = e, this.frameCounter = new ut(e.video), this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
|
|
1018
1018
|
}
|
|
1019
1019
|
async load() {
|
|
1020
1020
|
this.detachFrames ??= this.frameCounter.attach();
|
|
@@ -1035,7 +1035,7 @@ var W = class {
|
|
|
1035
1035
|
type: "error",
|
|
1036
1036
|
error: new n("INTERNAL", 0, "native HLS playback error"),
|
|
1037
1037
|
fatal: !0
|
|
1038
|
-
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src =
|
|
1038
|
+
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Tt(t.manifestUrl, t.analytics?.sid), e.load();
|
|
1039
1039
|
}
|
|
1040
1040
|
startLoad() {
|
|
1041
1041
|
this.loadStarted || (this.loadStarted = !0, this.restorePreload());
|
|
@@ -1063,7 +1063,7 @@ var W = class {
|
|
|
1063
1063
|
};
|
|
1064
1064
|
this.onEncrypted = (n) => {
|
|
1065
1065
|
let a = n;
|
|
1066
|
-
a.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV =
|
|
1066
|
+
a.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = St(a.initData), (async () => {
|
|
1067
1067
|
try {
|
|
1068
1068
|
let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
|
|
1069
1069
|
initDataTypes: [a.initDataType],
|
|
@@ -1163,10 +1163,10 @@ var W = class {
|
|
|
1163
1163
|
droppedFrames: t.dropped,
|
|
1164
1164
|
decodedFrames: t.totalFrames
|
|
1165
1165
|
};
|
|
1166
|
-
if (this.cdnHost ||=
|
|
1166
|
+
if (this.cdnHost ||= lt(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity) {
|
|
1167
1167
|
n.isLive = !0;
|
|
1168
1168
|
let t = this.liveEdgeEstimate(), r = t == null ? NaN : t - e.currentTime;
|
|
1169
|
-
Number.isFinite(r) && (n.atLiveEdge = r <=
|
|
1169
|
+
Number.isFinite(r) && (n.atLiveEdge = r <= vt, !e.paused && r >= 0 && (n.latencySeconds = r));
|
|
1170
1170
|
} else Number.isFinite(e.duration) && e.duration > 0 && (n.isLive = !1);
|
|
1171
1171
|
return n;
|
|
1172
1172
|
}
|
|
@@ -1178,30 +1178,30 @@ var W = class {
|
|
|
1178
1178
|
}
|
|
1179
1179
|
watchRefocus() {
|
|
1180
1180
|
this.deps.snapToLiveOnRefocus === !1 || typeof document > "u" || this.onVisibility || (this.onVisibility = () => {
|
|
1181
|
-
let e =
|
|
1181
|
+
let e = W();
|
|
1182
1182
|
if (document.visibilityState === "hidden") {
|
|
1183
1183
|
this.hiddenSince = e, this.cancelRefocus();
|
|
1184
1184
|
return;
|
|
1185
1185
|
}
|
|
1186
1186
|
let t = this.hiddenSince;
|
|
1187
|
-
this.hiddenSince = null, t != null && e - t >=
|
|
1187
|
+
this.hiddenSince = null, t != null && e - t >= ft && this.armRefocus();
|
|
1188
1188
|
}, this.onPageShow = (e) => {
|
|
1189
1189
|
e.persisted && this.armRefocus();
|
|
1190
1190
|
}, document.addEventListener("visibilitychange", this.onVisibility), typeof window < "u" && window.addEventListener("pageshow", this.onPageShow));
|
|
1191
1191
|
}
|
|
1192
1192
|
armRefocus() {
|
|
1193
1193
|
if (this.cancelRefocus(), Number.isFinite(this.deps.video.duration)) return;
|
|
1194
|
-
let e = this.liveEnd(), t =
|
|
1194
|
+
let e = this.liveEnd(), t = W, n = t(), r = 0, i = () => {
|
|
1195
1195
|
if (this.refocusTimer = null, Number.isFinite(this.deps.video.duration)) return;
|
|
1196
|
-
r +=
|
|
1197
|
-
let a = this.liveEnd(), o = a != null && (e == null || a >= e +
|
|
1196
|
+
r += B;
|
|
1197
|
+
let a = this.liveEnd(), o = a != null && (e == null || a >= e + ht), s = Math.max(r, t() - n) >= mt;
|
|
1198
1198
|
if (o || s && a != null) {
|
|
1199
1199
|
this.snapToLive();
|
|
1200
1200
|
return;
|
|
1201
1201
|
}
|
|
1202
|
-
this.refocusTimer = setTimeout(i,
|
|
1202
|
+
this.refocusTimer = setTimeout(i, B);
|
|
1203
1203
|
};
|
|
1204
|
-
this.refocusTimer = setTimeout(i,
|
|
1204
|
+
this.refocusTimer = setTimeout(i, B);
|
|
1205
1205
|
}
|
|
1206
1206
|
cancelRefocus() {
|
|
1207
1207
|
this.refocusTimer != null && clearTimeout(this.refocusTimer), this.refocusTimer = null;
|
|
@@ -1214,24 +1214,24 @@ var W = class {
|
|
|
1214
1214
|
}, e.addEventListener("seeking", this.onEdgeReset), e.addEventListener("emptied", this.onEdgeReset), this.edgeTimer = setInterval(() => {
|
|
1215
1215
|
if (e.duration !== Infinity) return;
|
|
1216
1216
|
this.checkEndStale();
|
|
1217
|
-
let t =
|
|
1218
|
-
t != null && ((this.lastBufferedEnd == null || Math.abs(t - this.lastBufferedEnd) >=
|
|
1219
|
-
},
|
|
1217
|
+
let t = wt(e, e.currentTime);
|
|
1218
|
+
t != null && ((this.lastBufferedEnd == null || Math.abs(t - this.lastBufferedEnd) >= _t) && (this.bufferedAdvancedAt = W()), this.lastBufferedEnd = t);
|
|
1219
|
+
}, gt);
|
|
1220
1220
|
}
|
|
1221
1221
|
checkEndStale() {
|
|
1222
1222
|
if (this.endedEmitted) return;
|
|
1223
|
-
let e =
|
|
1223
|
+
let e = W(), t = this.lastTickAt == null ? 0 : e - this.lastTickAt;
|
|
1224
1224
|
this.lastTickAt = e;
|
|
1225
1225
|
let n = this.liveEnd();
|
|
1226
1226
|
if (n == null) return;
|
|
1227
|
-
let r = this.lastSeekableEnd == null || Math.abs(n - this.lastSeekableEnd) >=
|
|
1227
|
+
let r = this.lastSeekableEnd == null || Math.abs(n - this.lastSeekableEnd) >= bt;
|
|
1228
1228
|
this.lastSeekableEnd = n;
|
|
1229
1229
|
let i = this.deps.video, a = typeof document < "u" && document.visibilityState === "hidden";
|
|
1230
|
-
if (r || t >
|
|
1230
|
+
if (r || t > xt || a || i.paused) {
|
|
1231
1231
|
this.edgeStampedAt = e;
|
|
1232
1232
|
return;
|
|
1233
1233
|
}
|
|
1234
|
-
e - (this.edgeStampedAt ?? e) >
|
|
1234
|
+
e - (this.edgeStampedAt ?? e) > yt && (this.endedEmitted = !0, this.deps.emit({
|
|
1235
1235
|
type: "ended",
|
|
1236
1236
|
reason: "stalled"
|
|
1237
1237
|
}));
|
|
@@ -1245,9 +1245,9 @@ var W = class {
|
|
|
1245
1245
|
liveEdgeEstimate() {
|
|
1246
1246
|
let e = this.deps.video;
|
|
1247
1247
|
if (e.duration !== Infinity) return null;
|
|
1248
|
-
let t = this.liveEnd(), n =
|
|
1248
|
+
let t = this.liveEnd(), n = wt(e, e.currentTime) ?? this.lastBufferedEnd;
|
|
1249
1249
|
if (n != null) {
|
|
1250
|
-
let e = this.bufferedAdvancedAt, r = n + (e == null ? 0 : Math.max(0, (
|
|
1250
|
+
let e = this.bufferedAdvancedAt, r = n + (e == null ? 0 : Math.max(0, (W() - e) / 1e3));
|
|
1251
1251
|
(t == null || r > t) && (t = r);
|
|
1252
1252
|
}
|
|
1253
1253
|
return t != null && Number.isFinite(t) ? t : null;
|
|
@@ -1261,7 +1261,7 @@ var W = class {
|
|
|
1261
1261
|
snapToLive() {
|
|
1262
1262
|
let e = this.deps.video, t = this.liveEnd();
|
|
1263
1263
|
if (t == null) return;
|
|
1264
|
-
let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t -
|
|
1264
|
+
let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t - pt, r);
|
|
1265
1265
|
try {
|
|
1266
1266
|
e.currentTime = i;
|
|
1267
1267
|
} catch {}
|
|
@@ -1279,10 +1279,10 @@ var W = class {
|
|
|
1279
1279
|
} catch {}
|
|
1280
1280
|
}
|
|
1281
1281
|
};
|
|
1282
|
-
function
|
|
1282
|
+
function W() {
|
|
1283
1283
|
return typeof performance < "u" ? performance.now() : Date.now();
|
|
1284
1284
|
}
|
|
1285
|
-
function
|
|
1285
|
+
function wt(e, t) {
|
|
1286
1286
|
let n = e.buffered;
|
|
1287
1287
|
if (!n || !Number.isFinite(t)) return null;
|
|
1288
1288
|
for (let e = 0; e < n.length; e += 1) if (n.start(e) <= t + .1 && n.end(e) > t) {
|
|
@@ -1291,12 +1291,12 @@ function Ct(e, t) {
|
|
|
1291
1291
|
}
|
|
1292
1292
|
return null;
|
|
1293
1293
|
}
|
|
1294
|
-
function
|
|
1294
|
+
function Tt(e, t) {
|
|
1295
1295
|
return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
|
|
1296
1296
|
}
|
|
1297
1297
|
//#endregion
|
|
1298
1298
|
//#region src/core/drm/signedUrl.ts
|
|
1299
|
-
function
|
|
1299
|
+
function G(e, t = Date.now()) {
|
|
1300
1300
|
if (!e) return !1;
|
|
1301
1301
|
let n;
|
|
1302
1302
|
try {
|
|
@@ -1308,13 +1308,13 @@ function K(e, t = Date.now()) {
|
|
|
1308
1308
|
}
|
|
1309
1309
|
//#endregion
|
|
1310
1310
|
//#region src/core/drm/xhrBody.ts
|
|
1311
|
-
var
|
|
1312
|
-
function
|
|
1311
|
+
var Et = 4096;
|
|
1312
|
+
function Dt(e) {
|
|
1313
1313
|
if (!e || typeof e != "object") return;
|
|
1314
1314
|
let { response: t } = e;
|
|
1315
1315
|
if (typeof t == "string") return t;
|
|
1316
1316
|
let n;
|
|
1317
|
-
if (Object.prototype.toString.call(t) === "[object ArrayBuffer]" ? n = new Uint8Array(t) : ArrayBuffer.isView(t) && (n = new Uint8Array(t.buffer, t.byteOffset, t.byteLength)), !(!n || n.byteLength === 0 || n.byteLength >
|
|
1317
|
+
if (Object.prototype.toString.call(t) === "[object ArrayBuffer]" ? n = new Uint8Array(t) : ArrayBuffer.isView(t) && (n = new Uint8Array(t.buffer, t.byteOffset, t.byteLength)), !(!n || n.byteLength === 0 || n.byteLength > Et)) try {
|
|
1318
1318
|
return new TextDecoder().decode(n);
|
|
1319
1319
|
} catch {
|
|
1320
1320
|
return;
|
|
@@ -1322,8 +1322,8 @@ function Et(e) {
|
|
|
1322
1322
|
}
|
|
1323
1323
|
//#endregion
|
|
1324
1324
|
//#region src/core/engine/prefetch.ts
|
|
1325
|
-
var
|
|
1326
|
-
function
|
|
1325
|
+
var Ot = 15e3, kt = 5e3, At = 6;
|
|
1326
|
+
function jt(e) {
|
|
1327
1327
|
try {
|
|
1328
1328
|
let t = new URL(e);
|
|
1329
1329
|
return t.searchParams.delete("CMCD"), t.toString();
|
|
@@ -1331,7 +1331,7 @@ function At(e) {
|
|
|
1331
1331
|
return e;
|
|
1332
1332
|
}
|
|
1333
1333
|
}
|
|
1334
|
-
var
|
|
1334
|
+
var Mt = class {
|
|
1335
1335
|
cmcd;
|
|
1336
1336
|
entries = /* @__PURE__ */ new Map();
|
|
1337
1337
|
keyed = /* @__PURE__ */ new Set();
|
|
@@ -1354,10 +1354,10 @@ var jt = class {
|
|
|
1354
1354
|
}
|
|
1355
1355
|
prefetch(e, t, n) {
|
|
1356
1356
|
if (!this.isActive(t)) return;
|
|
1357
|
-
let r =
|
|
1357
|
+
let r = jt(e);
|
|
1358
1358
|
if (this.entries.has(r)) return;
|
|
1359
1359
|
let i = this.perTrack.get(t) ?? 0;
|
|
1360
|
-
if (i >=
|
|
1360
|
+
if (i >= At) return;
|
|
1361
1361
|
this.perTrack.set(t, i + 1);
|
|
1362
1362
|
let a = new AbortController(), o = {
|
|
1363
1363
|
started: performance.now(),
|
|
@@ -1371,10 +1371,10 @@ var jt = class {
|
|
|
1371
1371
|
signal: a.signal
|
|
1372
1372
|
}).then(async (e) => (o.first = performance.now(), e.ok ? e.arrayBuffer() : null)).catch(() => null), this.entries.set(r, o), this.stats.started += 1, setTimeout(() => {
|
|
1373
1373
|
this.entries.get(r) === o && (this.entries.delete(r), a.abort(), this.stats.expired += 1);
|
|
1374
|
-
},
|
|
1374
|
+
}, Ot);
|
|
1375
1375
|
}
|
|
1376
1376
|
take(e) {
|
|
1377
|
-
let t =
|
|
1377
|
+
let t = jt(e), n = this.entries.get(t);
|
|
1378
1378
|
return n && this.entries.delete(t), n;
|
|
1379
1379
|
}
|
|
1380
1380
|
destroy() {
|
|
@@ -1394,13 +1394,13 @@ var jt = class {
|
|
|
1394
1394
|
}
|
|
1395
1395
|
}
|
|
1396
1396
|
};
|
|
1397
|
-
function
|
|
1397
|
+
function Nt(t) {
|
|
1398
1398
|
let n = e.DefaultConfig?.loader;
|
|
1399
1399
|
if (typeof n != "function") return;
|
|
1400
1400
|
class r extends n {
|
|
1401
1401
|
served = !1;
|
|
1402
1402
|
cancelled = !1;
|
|
1403
|
-
stats =
|
|
1403
|
+
stats = Pt();
|
|
1404
1404
|
load(e, n, r) {
|
|
1405
1405
|
let i = e.rangeEnd ? void 0 : t.take(e.url);
|
|
1406
1406
|
if (!i) {
|
|
@@ -1408,7 +1408,7 @@ function Mt(t) {
|
|
|
1408
1408
|
return;
|
|
1409
1409
|
}
|
|
1410
1410
|
this.served = !0;
|
|
1411
|
-
let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs ||
|
|
1411
|
+
let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || kt, s = setTimeout(() => {
|
|
1412
1412
|
!this.cancelled && this.served && (i.abort.abort(), t.stats.failed += 1, this.served = !1, super.load(e, n, r));
|
|
1413
1413
|
}, o);
|
|
1414
1414
|
i.bytes.then((o) => {
|
|
@@ -1435,7 +1435,7 @@ function Mt(t) {
|
|
|
1435
1435
|
}
|
|
1436
1436
|
return r;
|
|
1437
1437
|
}
|
|
1438
|
-
function
|
|
1438
|
+
function Pt() {
|
|
1439
1439
|
return {
|
|
1440
1440
|
aborted: !1,
|
|
1441
1441
|
loaded: 0,
|
|
@@ -1459,10 +1459,10 @@ function Nt() {
|
|
|
1459
1459
|
}
|
|
1460
1460
|
};
|
|
1461
1461
|
}
|
|
1462
|
-
function
|
|
1462
|
+
function Ft(e) {
|
|
1463
1463
|
return e === "audio" ? "audio" : "main";
|
|
1464
1464
|
}
|
|
1465
|
-
function
|
|
1465
|
+
function It(e, t) {
|
|
1466
1466
|
let n = [];
|
|
1467
1467
|
t.initSegment?.url && !t.initSegment.data && n.push({
|
|
1468
1468
|
url: t.initSegment.url,
|
|
@@ -1480,12 +1480,17 @@ function Ft(e, t) {
|
|
|
1480
1480
|
return n;
|
|
1481
1481
|
}
|
|
1482
1482
|
//#endregion
|
|
1483
|
+
//#region src/core/percentile.ts
|
|
1484
|
+
function K(e, t) {
|
|
1485
|
+
return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
|
|
1486
|
+
}
|
|
1487
|
+
//#endregion
|
|
1483
1488
|
//#region src/core/engine/hls.ts
|
|
1484
|
-
function
|
|
1489
|
+
function Lt() {
|
|
1485
1490
|
return e.isSupported();
|
|
1486
1491
|
}
|
|
1487
|
-
var
|
|
1488
|
-
function
|
|
1492
|
+
var Rt = 1e6, zt = 20, Bt = 1e4, Vt = 3, Ht = 5, Ut = 3, Wt = 1e4, Gt = 3e4, Kt = 12e3, qt = 3e3, Jt = .02, Yt = 6e3, Xt = .5, Zt = 3, Qt = .5, $t = 1.1, en = .25, tn = 5e3, nn = 4e3, rn = 2, an = 5, on = 2, sn = 2, cn = 4, ln = 4, un = 2e3, dn = 3e4, fn = 1, pn = 2;
|
|
1493
|
+
function mn(e, t, n) {
|
|
1489
1494
|
if (n <= 0 || t < 0 || t >= e.length) return t;
|
|
1490
1495
|
let r = (t, n) => e[t].width === e[n].width && e[t].height === e[n].height, i = (t) => {
|
|
1491
1496
|
for (; t + 1 < e.length && r(t + 1, t);) t++;
|
|
@@ -1494,21 +1499,30 @@ function pn(e, t, n) {
|
|
|
1494
1499
|
for (let t = 0; t < n && a + 1 < e.length; t++) a = i(a + 1);
|
|
1495
1500
|
return a;
|
|
1496
1501
|
}
|
|
1497
|
-
var
|
|
1498
|
-
function
|
|
1502
|
+
var hn = .2, gn = 30, _n = 2, vn = 2, yn = 2, bn = 9, xn = .5, Sn = 64, Cn = 1e4, wn = 8, Tn = .6, En = .4, Dn = .4, On = 2, kn = 6e4, q = .5, An = 3.5, jn = 300;
|
|
1503
|
+
function Mn() {
|
|
1504
|
+
if (typeof navigator > "u") return 0;
|
|
1505
|
+
try {
|
|
1506
|
+
let e = navigator.connection?.rtt;
|
|
1507
|
+
return typeof e == "number" && Number.isFinite(e) && e > 0 ? e : 0;
|
|
1508
|
+
} catch {
|
|
1509
|
+
return 0;
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
function Nn(e) {
|
|
1499
1513
|
if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
|
|
1500
1514
|
delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
|
|
1501
1515
|
return;
|
|
1502
1516
|
}
|
|
1503
|
-
e.liveSyncDuration ??=
|
|
1504
|
-
let t = Math.max(12, e.liveSyncDuration +
|
|
1505
|
-
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t),
|
|
1517
|
+
e.liveSyncDuration ??= yn;
|
|
1518
|
+
let t = Math.max(12, e.liveSyncDuration + bn);
|
|
1519
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Pn(e, e.liveSyncDuration);
|
|
1506
1520
|
}
|
|
1507
|
-
function
|
|
1521
|
+
function Pn(e, t) {
|
|
1508
1522
|
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
1509
1523
|
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
1510
1524
|
}
|
|
1511
|
-
var
|
|
1525
|
+
var Fn = class {
|
|
1512
1526
|
name = "hls";
|
|
1513
1527
|
hls = null;
|
|
1514
1528
|
deps;
|
|
@@ -1572,6 +1586,15 @@ var Cn = class {
|
|
|
1572
1586
|
onTimeUpdate = null;
|
|
1573
1587
|
chaseTicks = 0;
|
|
1574
1588
|
liveRetargets = 0;
|
|
1589
|
+
holdBackEnabled;
|
|
1590
|
+
holdBackSamples = [];
|
|
1591
|
+
holdBackBase = -1;
|
|
1592
|
+
holdBackStepCount = 0;
|
|
1593
|
+
holdBackApplied = 0;
|
|
1594
|
+
holdBackSlowTicks = 0;
|
|
1595
|
+
holdBackFastSince = 0;
|
|
1596
|
+
holdBackSteps = 0;
|
|
1597
|
+
holdBackPriorChecked = !1;
|
|
1575
1598
|
capObserver = null;
|
|
1576
1599
|
capTimer = null;
|
|
1577
1600
|
sizeCapLevel = null;
|
|
@@ -1584,6 +1607,7 @@ var Cn = class {
|
|
|
1584
1607
|
fpsLastFrames = -1;
|
|
1585
1608
|
fpsLastDropped = -1;
|
|
1586
1609
|
fpsBadTicks = 0;
|
|
1610
|
+
fpsGraceTicks = 0;
|
|
1587
1611
|
fpsDownCaps = 0;
|
|
1588
1612
|
sizeCapManaged = !0;
|
|
1589
1613
|
dprMedia = null;
|
|
@@ -1592,11 +1616,11 @@ var Cn = class {
|
|
|
1592
1616
|
frameCounter;
|
|
1593
1617
|
detachFrames = null;
|
|
1594
1618
|
constructor(e) {
|
|
1595
|
-
this.deps = e, this.frameCounter = new
|
|
1619
|
+
this.deps = e, this.holdBackEnabled = e.adaptiveHoldBack !== !1, this.frameCounter = new ut(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
|
|
1596
1620
|
}
|
|
1597
1621
|
async load() {
|
|
1598
1622
|
this.detachFrames ??= this.frameCounter.attach();
|
|
1599
|
-
let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a =
|
|
1623
|
+
let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = V(r) && H(), o = !!e.drm?.widevine?.licenseUrl && !a;
|
|
1600
1624
|
if (e.drmEnabled && !o) {
|
|
1601
1625
|
i({
|
|
1602
1626
|
type: "error",
|
|
@@ -1628,7 +1652,7 @@ var Cn = class {
|
|
|
1628
1652
|
}
|
|
1629
1653
|
this.loadSuspended = !0;
|
|
1630
1654
|
}
|
|
1631
|
-
},
|
|
1655
|
+
}, tn));
|
|
1632
1656
|
}
|
|
1633
1657
|
resumeLoading() {
|
|
1634
1658
|
if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
|
|
@@ -1660,7 +1684,7 @@ var Cn = class {
|
|
|
1660
1684
|
let t = e.liveSyncPosition;
|
|
1661
1685
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
1662
1686
|
let { video: n } = this.deps;
|
|
1663
|
-
n.currentTime <= t +
|
|
1687
|
+
n.currentTime <= t + xn || (n.currentTime = t);
|
|
1664
1688
|
}
|
|
1665
1689
|
reanchorPartTimeline(e, t) {
|
|
1666
1690
|
let { frag: n, part: r } = t;
|
|
@@ -1672,7 +1696,7 @@ var Cn = class {
|
|
|
1672
1696
|
let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
|
|
1673
1697
|
if (!s) return;
|
|
1674
1698
|
let c = a.startPTS - s.start;
|
|
1675
|
-
if (!(!Number.isFinite(c) || Math.abs(c) <
|
|
1699
|
+
if (!(!Number.isFinite(c) || Math.abs(c) < Jt)) {
|
|
1676
1700
|
for (let e of i.fragments) e && e.setStart(e.start + c);
|
|
1677
1701
|
i.fragmentHint?.setStart(i.fragmentHint.start + c), this.deps.debug === !0 && console.info(`havik-player: LL-HLS timeline re-anchored by ${c >= 0 ? "+" : ""}${c.toFixed(3)}s at sn ${n.sn} (level ${n.level})`);
|
|
1678
1702
|
}
|
|
@@ -1680,7 +1704,7 @@ var Cn = class {
|
|
|
1680
1704
|
startHls() {
|
|
1681
1705
|
let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
|
|
1682
1706
|
this.clearKick(), this.resetStarvationWindow(), this.resetChaseWindow(), this.resetFrameDropWindow(), this.lastFragLoadingMs = 0, this.lastEndSN = -1, this.lastAdvanceMs = 0;
|
|
1683
|
-
let u = n.drmEnabled && !!(n.drm?.widevine?.licenseUrl || n.drm?.fairplay?.licenseUrl), d =
|
|
1707
|
+
let u = n.drmEnabled && !!(n.drm?.widevine?.licenseUrl || n.drm?.fairplay?.licenseUrl), d = V(this.deps.video) && H(), f = {
|
|
1684
1708
|
debug: s === !0,
|
|
1685
1709
|
enableWorker: !o,
|
|
1686
1710
|
lowLatencyMode: o,
|
|
@@ -1707,12 +1731,12 @@ var Cn = class {
|
|
|
1707
1731
|
this.licenseTimeMs === 0 && (this.licenseTimeMs = Math.max(1, Math.round(performance.now() - o)));
|
|
1708
1732
|
});
|
|
1709
1733
|
}, { freshLicenseUrl: c } = this.deps;
|
|
1710
|
-
if (!c || !
|
|
1734
|
+
if (!c || !G(this.licenseUrl)) {
|
|
1711
1735
|
s();
|
|
1712
1736
|
return;
|
|
1713
1737
|
}
|
|
1714
1738
|
let l = this.hls, u, d = new Promise((e) => {
|
|
1715
|
-
u = setTimeout(() => e(void 0),
|
|
1739
|
+
u = setTimeout(() => e(void 0), Wt);
|
|
1716
1740
|
});
|
|
1717
1741
|
return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
|
|
1718
1742
|
if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
|
|
@@ -1728,20 +1752,20 @@ var Cn = class {
|
|
|
1728
1752
|
...c
|
|
1729
1753
|
};
|
|
1730
1754
|
if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !f.fLoader) {
|
|
1731
|
-
let e = new
|
|
1755
|
+
let e = new Mt({
|
|
1732
1756
|
sessionId: n.analytics?.sid,
|
|
1733
1757
|
contentId: n.matchUrn
|
|
1734
|
-
}), t =
|
|
1758
|
+
}), t = Nt(e);
|
|
1735
1759
|
t && (this.prefetch = e, f.fLoader = t);
|
|
1736
1760
|
}
|
|
1737
|
-
|
|
1761
|
+
Nn(f), this.catchUpRate = typeof f.maxLiveSyncPlaybackRate == "number" ? f.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (f.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = f.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = f.autoStartLoad !== !1;
|
|
1738
1762
|
let p = new e(f);
|
|
1739
|
-
if (this.hls = p, p.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(p, t)), p.on(e.Events.MANIFEST_PARSED, () => {
|
|
1763
|
+
if (this.hls = p, this.armHoldBack(p, f), p.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(p, t)), p.on(e.Events.MANIFEST_PARSED, () => {
|
|
1740
1764
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(p), this.measureLadder(p), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
|
|
1741
1765
|
}), p.on(e.Events.FRAG_BUFFERED, (e, t) => {
|
|
1742
1766
|
t?.frag?.type === "main" && (this.kickKind !== "dead" && this.clearKick(), (this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0 || this.starvationKicks > 0 || this.starvationRebuilds > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
|
|
1743
1767
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
|
|
1744
|
-
},
|
|
1768
|
+
}, Gt)));
|
|
1745
1769
|
}), p.on(e.Events.FRAG_LOADING, (e, t) => {
|
|
1746
1770
|
t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
|
|
1747
1771
|
}), p.on(e.Events.FRAG_LOADED, (e, t) => {
|
|
@@ -1749,10 +1773,10 @@ var Cn = class {
|
|
|
1749
1773
|
let n = t?.frag?.stats, r = n?.loaded;
|
|
1750
1774
|
typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
|
|
1751
1775
|
let i = n?.loading;
|
|
1752
|
-
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 >
|
|
1776
|
+
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 > Sn && this.requestTimesMs.shift()), this.sampleHoldBack(t);
|
|
1753
1777
|
let a = t?.frag?.url;
|
|
1754
1778
|
if (a) {
|
|
1755
|
-
let e =
|
|
1779
|
+
let e = st(a);
|
|
1756
1780
|
e && (this.cdnHost = e);
|
|
1757
1781
|
}
|
|
1758
1782
|
}), p.on(e.Events.LEVEL_LOADED, (e, t) => {
|
|
@@ -1766,18 +1790,18 @@ var Cn = class {
|
|
|
1766
1790
|
}), p.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
|
|
1767
1791
|
let t = this.prefetch;
|
|
1768
1792
|
p.on(e.Events.KEY_LOADING, (e, n) => {
|
|
1769
|
-
let r = n?.frag, i =
|
|
1770
|
-
if (r && t.isActive(i)) for (let e of
|
|
1771
|
-
}), p.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(
|
|
1793
|
+
let r = n?.frag, i = Ft(r?.type);
|
|
1794
|
+
if (r && t.isActive(i)) for (let e of It(p, r)) t.prefetch(e.url, i, e.kind);
|
|
1795
|
+
}), p.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(Ft(n?.frag?.type)));
|
|
1772
1796
|
}
|
|
1773
1797
|
p.on(e.Events.KEY_LOADED, () => {
|
|
1774
1798
|
u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
|
|
1775
1799
|
}), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
|
|
1776
|
-
this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.checkFrameDrops();
|
|
1777
|
-
},
|
|
1800
|
+
this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.adaptHoldBack(), this.checkFrameDrops();
|
|
1801
|
+
}, qt), p.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
1778
1802
|
this.renditionSwitches += 1;
|
|
1779
1803
|
let n = this.lastLevelIndex >= 0 ? p.levels[this.lastLevelIndex] : void 0, r = p.levels[t.level];
|
|
1780
|
-
n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
|
|
1804
|
+
n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, this.armFrameDropGrace(), l({
|
|
1781
1805
|
type: "qualitychange",
|
|
1782
1806
|
index: t.level
|
|
1783
1807
|
});
|
|
@@ -1825,9 +1849,9 @@ var Cn = class {
|
|
|
1825
1849
|
let o = e.config ?? {}, s = typeof self < "u" && self.devicePixelRatio > 0 ? self.devicePixelRatio : 1, c = o.ignoreDevicePixelRatio ? 1 : s;
|
|
1826
1850
|
c = Math.min(c, o.maxDevicePixelRatio ?? Infinity);
|
|
1827
1851
|
let l = t.getMaxLevelByMediaSize(e.levels, i * c, a * c), u = this.deps.sizeCapHeadroom;
|
|
1828
|
-
if (u == null && s >=
|
|
1829
|
-
let d = u ??
|
|
1830
|
-
return
|
|
1852
|
+
if (u == null && s >= pn) return l;
|
|
1853
|
+
let d = u ?? fn, f = Number.isNaN(d) ? fn : d === Infinity ? e.levels.length : Math.max(0, Math.floor(d));
|
|
1854
|
+
return mn(e.levels, l, f);
|
|
1831
1855
|
}
|
|
1832
1856
|
onMediaResize() {
|
|
1833
1857
|
if (!this.sizeCapManaged) return;
|
|
@@ -1842,7 +1866,7 @@ var Cn = class {
|
|
|
1842
1866
|
return;
|
|
1843
1867
|
}
|
|
1844
1868
|
this.capTimer && clearTimeout(this.capTimer);
|
|
1845
|
-
let t = e > this.sizeCapLevel ?
|
|
1869
|
+
let t = e > this.sizeCapLevel ? un : dn;
|
|
1846
1870
|
this.capTimer = setTimeout(() => {
|
|
1847
1871
|
this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
|
|
1848
1872
|
}, t);
|
|
@@ -1924,6 +1948,7 @@ var Cn = class {
|
|
|
1924
1948
|
playlistBytesLoaded: this.playlistBytesLoaded,
|
|
1925
1949
|
renditionSwitches: this.renditionSwitches,
|
|
1926
1950
|
liveRetargets: this.liveRetargets,
|
|
1951
|
+
holdBackSteps: this.holdBackSteps,
|
|
1927
1952
|
fpsDownCaps: this.fpsDownCaps,
|
|
1928
1953
|
licenseTimeMs: this.licenseTimeMs,
|
|
1929
1954
|
upshifts: this.upshifts,
|
|
@@ -1952,9 +1977,10 @@ var Cn = class {
|
|
|
1952
1977
|
let t = e.details;
|
|
1953
1978
|
if (t) {
|
|
1954
1979
|
if (t.live === !0) {
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1980
|
+
let e = !this.sawLive;
|
|
1981
|
+
this.sawLive = !0, e && this.applyHoldBackPrior();
|
|
1982
|
+
let n = t.endSN ?? -1;
|
|
1983
|
+
n !== this.lastEndSN && (this.lastEndSN = n, this.lastAdvanceMs = Date.now(), this.chaseSuspended && this.resumeChasing());
|
|
1958
1984
|
return;
|
|
1959
1985
|
}
|
|
1960
1986
|
this.sawLive && this.emitEnded("endlist");
|
|
@@ -1971,7 +1997,7 @@ var Cn = class {
|
|
|
1971
1997
|
return;
|
|
1972
1998
|
}
|
|
1973
1999
|
let e = Date.now() - this.lastAdvanceMs;
|
|
1974
|
-
!this.chaseSuspended && e >
|
|
2000
|
+
!this.chaseSuspended && e > Yt && this.suspendChasing(), e > Kt && this.emitEnded("stalled");
|
|
1975
2001
|
}
|
|
1976
2002
|
resetStarvationWindow() {
|
|
1977
2003
|
this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
|
|
@@ -1986,7 +2012,7 @@ var Cn = class {
|
|
|
1986
2012
|
this.resetStarvationWindow();
|
|
1987
2013
|
return;
|
|
1988
2014
|
}
|
|
1989
|
-
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs <
|
|
2015
|
+
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < Yt, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > nn, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = z(t), c = o - s, l = c !== this.starvedFrames;
|
|
1990
2016
|
if (this.starvedFrames = c, !a || l) {
|
|
1991
2017
|
(t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
|
|
1992
2018
|
return;
|
|
@@ -1995,12 +2021,12 @@ var Cn = class {
|
|
|
1995
2021
|
this.resetStarvationWindow();
|
|
1996
2022
|
return;
|
|
1997
2023
|
}
|
|
1998
|
-
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 >
|
|
2024
|
+
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 > cn && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= on && (this.clearKick(), this.starvationRebuilds < sn)) {
|
|
1999
2025
|
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");
|
|
2000
2026
|
return;
|
|
2001
2027
|
}
|
|
2002
|
-
let u = i && this.starvedTicks >=
|
|
2003
|
-
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >=
|
|
2028
|
+
let u = i && this.starvedTicks >= rn, d = !i && this.deadTicks >= cn && this.recentMainFrags.reduce((e, t) => e + t, 0) >= ln;
|
|
2029
|
+
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= an))) {
|
|
2004
2030
|
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");
|
|
2005
2031
|
try {
|
|
2006
2032
|
e.stopLoad(), e.startLoad(-1);
|
|
@@ -2015,7 +2041,7 @@ var Cn = class {
|
|
|
2015
2041
|
let t = e.latency, n = e.targetLatency;
|
|
2016
2042
|
if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
|
|
2017
2043
|
let r = t - n;
|
|
2018
|
-
!this.catchUpEngaged && r >
|
|
2044
|
+
!this.catchUpEngaged && r > Xt ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= Xt && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
|
|
2019
2045
|
let i = this.catchUpEngaged ? this.catchUpRate : 1;
|
|
2020
2046
|
e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
|
|
2021
2047
|
}
|
|
@@ -2027,6 +2053,9 @@ var Cn = class {
|
|
|
2027
2053
|
e.bitrate <= this.fpsCapBitrate && i && (n = r);
|
|
2028
2054
|
}), n < 0 ? 0 : n;
|
|
2029
2055
|
}
|
|
2056
|
+
armFrameDropGrace() {
|
|
2057
|
+
this.fpsGraceTicks > 0 || (this.fpsGraceTicks = vn, this.fpsBadTicks = 0);
|
|
2058
|
+
}
|
|
2030
2059
|
resetFrameDropWindow() {
|
|
2031
2060
|
this.fpsLastFrames = -1, this.fpsLastDropped = -1, this.fpsBadTicks = 0;
|
|
2032
2061
|
}
|
|
@@ -2036,16 +2065,20 @@ var Cn = class {
|
|
|
2036
2065
|
this.resetFrameDropWindow();
|
|
2037
2066
|
return;
|
|
2038
2067
|
}
|
|
2039
|
-
let { totalFrames: n, dropped: r } =
|
|
2040
|
-
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a <
|
|
2068
|
+
let { totalFrames: n, dropped: r } = z(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
|
|
2069
|
+
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < gn || o < 0) {
|
|
2041
2070
|
this.fpsBadTicks = 0;
|
|
2042
2071
|
return;
|
|
2043
2072
|
}
|
|
2044
|
-
if (
|
|
2073
|
+
if (this.fpsGraceTicks > 0) {
|
|
2074
|
+
--this.fpsGraceTicks, this.fpsBadTicks = 0;
|
|
2075
|
+
return;
|
|
2076
|
+
}
|
|
2077
|
+
if (o <= hn * a) {
|
|
2045
2078
|
this.fpsBadTicks = 0;
|
|
2046
2079
|
return;
|
|
2047
2080
|
}
|
|
2048
|
-
if (this.fpsBadTicks += 1, this.fpsBadTicks <
|
|
2081
|
+
if (this.fpsBadTicks += 1, this.fpsBadTicks < _n) return;
|
|
2049
2082
|
this.fpsBadTicks = 0;
|
|
2050
2083
|
let s = e.levels, c = s[e.currentLevel];
|
|
2051
2084
|
if (!c) return;
|
|
@@ -2062,20 +2095,113 @@ var Cn = class {
|
|
|
2062
2095
|
return;
|
|
2063
2096
|
}
|
|
2064
2097
|
let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
|
|
2065
|
-
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(
|
|
2098
|
+
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min($t, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
|
|
2066
2099
|
this.resetChaseWindow();
|
|
2067
2100
|
return;
|
|
2068
2101
|
}
|
|
2069
|
-
if (this.chaseLatency < 0 || this.chaseLatency - n >=
|
|
2102
|
+
if (this.chaseLatency < 0 || this.chaseLatency - n >= Qt) {
|
|
2070
2103
|
this.chaseLatency = n, this.chaseTicks = 0;
|
|
2071
2104
|
return;
|
|
2072
2105
|
}
|
|
2073
|
-
if (this.chaseTicks += 1, this.chaseTicks <
|
|
2106
|
+
if (this.chaseTicks += 1, this.chaseTicks < Zt) return;
|
|
2074
2107
|
this.resetChaseWindow();
|
|
2075
2108
|
let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
|
|
2076
2109
|
if (!(a > 1)) return;
|
|
2077
|
-
let o =
|
|
2078
|
-
|
|
2110
|
+
let o = e.targetLatency;
|
|
2111
|
+
if (typeof o != "number" || !(o > 0)) return;
|
|
2112
|
+
let s = Math.min(n, a - 1);
|
|
2113
|
+
s < o + en || (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, this.deps.emit({
|
|
2114
|
+
type: "livetargetchange",
|
|
2115
|
+
change: {
|
|
2116
|
+
targetSeconds: s,
|
|
2117
|
+
previousSeconds: o,
|
|
2118
|
+
reason: "futile-chase"
|
|
2119
|
+
}
|
|
2120
|
+
}));
|
|
2121
|
+
}
|
|
2122
|
+
armHoldBack(e, t) {
|
|
2123
|
+
this.holdBackEnabled && (this.holdBackSlowTicks = 0, this.holdBackFastSince = 0, this.holdBackSamples = [], this.holdBackBase < 0 && typeof t.liveSyncDuration == "number" && (this.holdBackBase = t.liveSyncDuration), this.holdBackApplied > 0 && (e.targetLatency = this.holdBackApplied));
|
|
2124
|
+
}
|
|
2125
|
+
applyHoldBackPrior() {
|
|
2126
|
+
let e = this.hls;
|
|
2127
|
+
if (!this.holdBackEnabled || this.holdBackPriorChecked || !e || (this.holdBackPriorChecked = !0, this.holdBackApplied > 0 || this.holdBackStepCount > 0)) return;
|
|
2128
|
+
let t = e.targetLatency;
|
|
2129
|
+
if (this.holdBackBase < 0 && typeof t == "number" && t > 0 && (this.holdBackBase = t), this.holdBackBase < 0) return;
|
|
2130
|
+
let n = Mn();
|
|
2131
|
+
if (!(n >= jn)) return;
|
|
2132
|
+
let r = typeof t == "number" && t > 0 ? t : this.holdBackBase, i = Math.min(this.holdBackCeiling(e), this.holdBackBase + q);
|
|
2133
|
+
i > r && (this.holdBackStepCount = 1, this.moveHoldBack(e, r, i, "connection-rtt", `connection rtt ${n} ms`));
|
|
2134
|
+
}
|
|
2135
|
+
holdBackCeiling(e) {
|
|
2136
|
+
let t = this.deps.adaptiveHoldBackCeiling, n = typeof t == "number" && Number.isFinite(t) ? t : An, r = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
|
|
2137
|
+
return r > 1 ? Math.min(n, r - 1) : n;
|
|
2138
|
+
}
|
|
2139
|
+
sampleHoldBack(e) {
|
|
2140
|
+
if (!this.holdBackEnabled || typeof document < "u" && document.hidden) return;
|
|
2141
|
+
let t = e.frag?.type;
|
|
2142
|
+
if (t !== "main" && t !== "audio") return;
|
|
2143
|
+
let n = e.part ? e.part.duration : this.detectedLowLatency ? 0 : e.frag?.duration;
|
|
2144
|
+
if (typeof n != "number" || !(n > 0)) return;
|
|
2145
|
+
let r = (e.part ?? e.frag)?.stats?.loading;
|
|
2146
|
+
if (!r || !(r.start > 0) || !(r.end > 0)) return;
|
|
2147
|
+
let i = r.first > r.start ? r.first : r.end, a = Math.max(0, i - r.start) / (n * 1e3);
|
|
2148
|
+
this.holdBackSamples.push({
|
|
2149
|
+
t: Date.now(),
|
|
2150
|
+
ratio: a
|
|
2151
|
+
}), this.holdBackSamples.length > 256 && this.holdBackSamples.shift();
|
|
2152
|
+
}
|
|
2153
|
+
adaptHoldBack() {
|
|
2154
|
+
if (!this.holdBackEnabled) return;
|
|
2155
|
+
let e = this.hls;
|
|
2156
|
+
if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended || this.loadSuspended || typeof document < "u" && document.hidden) {
|
|
2157
|
+
this.holdBackSlowTicks = 0, this.holdBackFastSince = 0, this.holdBackSamples = [];
|
|
2158
|
+
return;
|
|
2159
|
+
}
|
|
2160
|
+
let t = Date.now(), n = t - Cn, r = this.holdBackSamples, i = 0;
|
|
2161
|
+
for (; i < r.length && r[i].t < n;) i += 1;
|
|
2162
|
+
i > 0 && r.splice(0, i);
|
|
2163
|
+
let a = e.targetLatency;
|
|
2164
|
+
if (typeof a != "number" || !(a > 0)) return;
|
|
2165
|
+
this.holdBackBase < 0 && (this.holdBackBase = a);
|
|
2166
|
+
let o = this.holdBackBase, s = this.holdBackCeiling(e);
|
|
2167
|
+
if (r.length < wn) {
|
|
2168
|
+
this.holdBackSlowTicks = 0;
|
|
2169
|
+
return;
|
|
2170
|
+
}
|
|
2171
|
+
let c = r.map((e) => e.ratio).sort((e, t) => e - t), l = K(c, 95), u = K(c, 50), d = Math.round(l * 1e3);
|
|
2172
|
+
if (l >= Tn && u >= En) {
|
|
2173
|
+
if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks < On) return;
|
|
2174
|
+
this.holdBackSlowTicks = 0;
|
|
2175
|
+
let t = Math.ceil((s - o) / q), n = Math.ceil((a - o) / q - 1e-9);
|
|
2176
|
+
if (n > this.holdBackStepCount && (this.holdBackStepCount = n), this.holdBackStepCount >= t) return;
|
|
2177
|
+
this.holdBackStepCount += 1;
|
|
2178
|
+
let r = Math.min(s, o + this.holdBackStepCount * q);
|
|
2179
|
+
if (r <= a) return;
|
|
2180
|
+
this.moveHoldBack(e, a, r, "slow-fetches", `part fetches slow (first byte p50 ${Math.round(u * 1e3)} / p95 ${d} ms per 1 s of media)`);
|
|
2181
|
+
return;
|
|
2182
|
+
}
|
|
2183
|
+
if (this.holdBackSlowTicks = 0, l >= Dn) {
|
|
2184
|
+
this.holdBackFastSince = 0;
|
|
2185
|
+
return;
|
|
2186
|
+
}
|
|
2187
|
+
if (this.holdBackFastSince === 0) {
|
|
2188
|
+
this.holdBackFastSince = t;
|
|
2189
|
+
return;
|
|
2190
|
+
}
|
|
2191
|
+
if (t - this.holdBackFastSince < kn || (this.holdBackFastSince = t, this.holdBackStepCount === 0 || a !== this.holdBackApplied)) return;
|
|
2192
|
+
--this.holdBackStepCount;
|
|
2193
|
+
let f = Math.max(o, o + this.holdBackStepCount * q);
|
|
2194
|
+
f >= a || this.moveHoldBack(e, a, f, "fast-fetches", `part fetches fast again (p95 first byte ${d} ms per 1 s of media)`);
|
|
2195
|
+
}
|
|
2196
|
+
moveHoldBack(e, t, n, r, i) {
|
|
2197
|
+
console.info(`havik-player: ${i}; live target ${t.toFixed(1)}s → ${n.toFixed(1)}s`), this.holdBackApplied = n, this.holdBackSteps += 1, e.targetLatency = n, this.deps.emit({
|
|
2198
|
+
type: "livetargetchange",
|
|
2199
|
+
change: {
|
|
2200
|
+
targetSeconds: n,
|
|
2201
|
+
previousSeconds: t,
|
|
2202
|
+
reason: r
|
|
2203
|
+
}
|
|
2204
|
+
});
|
|
2079
2205
|
}
|
|
2080
2206
|
suspendChasing() {
|
|
2081
2207
|
let e = this.hls;
|
|
@@ -2105,12 +2231,12 @@ var Cn = class {
|
|
|
2105
2231
|
} catch {}
|
|
2106
2232
|
}
|
|
2107
2233
|
startEstimate() {
|
|
2108
|
-
return this.deps.rememberBandwidth === !1 ?
|
|
2234
|
+
return this.deps.rememberBandwidth === !1 ? Rt : Ie() ?? Rt;
|
|
2109
2235
|
}
|
|
2110
2236
|
maybeRememberBandwidth(e) {
|
|
2111
|
-
if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded <
|
|
2237
|
+
if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < zt) return;
|
|
2112
2238
|
let t = Date.now();
|
|
2113
|
-
if (!e && t - this.bwSavedAt <
|
|
2239
|
+
if (!e && t - this.bwSavedAt < Bt) return;
|
|
2114
2240
|
let n = this.hls?.bandwidthEstimate;
|
|
2115
2241
|
typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Le(n));
|
|
2116
2242
|
}
|
|
@@ -2130,7 +2256,7 @@ var Cn = class {
|
|
|
2130
2256
|
scheduleLicenseRetry(t) {
|
|
2131
2257
|
if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
|
|
2132
2258
|
let n = t.response?.code ?? 0;
|
|
2133
|
-
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >=
|
|
2259
|
+
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Ut) return !1;
|
|
2134
2260
|
this.licenseRecoveries += 1;
|
|
2135
2261
|
let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
|
|
2136
2262
|
return this.licenseRetryTimer = setTimeout(() => {
|
|
@@ -2144,7 +2270,7 @@ var Cn = class {
|
|
|
2144
2270
|
} catch (t) {
|
|
2145
2271
|
console.warn(`havik-player: hls.js destroy() threw during ${e}`, t);
|
|
2146
2272
|
}
|
|
2147
|
-
this.hls = null, this.startHls();
|
|
2273
|
+
this.hls = null, this.startHls(), this.armFrameDropGrace();
|
|
2148
2274
|
}
|
|
2149
2275
|
}
|
|
2150
2276
|
onError(t) {
|
|
@@ -2162,7 +2288,7 @@ var Cn = class {
|
|
|
2162
2288
|
return;
|
|
2163
2289
|
}
|
|
2164
2290
|
if (t.type === e.ErrorTypes.NETWORK_ERROR) {
|
|
2165
|
-
if (this.networkRecoveries <
|
|
2291
|
+
if (this.networkRecoveries < Ht) {
|
|
2166
2292
|
this.networkRecoveries += 1;
|
|
2167
2293
|
let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
|
|
2168
2294
|
this.networkRetryTimer = setTimeout(() => {
|
|
@@ -2179,7 +2305,7 @@ var Cn = class {
|
|
|
2179
2305
|
return;
|
|
2180
2306
|
}
|
|
2181
2307
|
if (t.type === e.ErrorTypes.MEDIA_ERROR) {
|
|
2182
|
-
if (this.mediaRecoveries <
|
|
2308
|
+
if (this.mediaRecoveries < Vt) {
|
|
2183
2309
|
this.mediaRecoveries += 1, n.recoverMediaError();
|
|
2184
2310
|
return;
|
|
2185
2311
|
}
|
|
@@ -2200,22 +2326,18 @@ var Cn = class {
|
|
|
2200
2326
|
}
|
|
2201
2327
|
}
|
|
2202
2328
|
toError(t, r = "PLAYBACK") {
|
|
2203
|
-
let o = t.response?.code ?? 0, s = t.details ?? t.type, c = t.reason ?? t.error?.message ?? "", l = r === "DRM" && o === 403 && t.details === e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED ? i(
|
|
2329
|
+
let o = t.response?.code ?? 0, s = t.details ?? t.type, c = t.reason ?? t.error?.message ?? "", l = r === "DRM" && o === 403 && t.details === e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED ? i(Dt(t.networkDetails)) : void 0;
|
|
2204
2330
|
return new n(r === "DRM" ? a(o, l) : o === 401 ? "UNAUTHORIZED" : o === 403 ? "FORBIDDEN" : "INTERNAL", o, `${r} error: ${s}${c ? ` (${c})` : ""}`, l ? { serverCode: l } : void 0);
|
|
2205
2331
|
}
|
|
2206
|
-
},
|
|
2332
|
+
}, In = 15e3, Ln = 6e5, Rn = 3e5, zn = 100, J = 1, Bn = 1e3, Vn = 3e4, Hn = 1e3, Un = {
|
|
2207
2333
|
inline: "PRESENTATION_INLINE",
|
|
2208
2334
|
fullscreen: "PRESENTATION_FULLSCREEN",
|
|
2209
2335
|
pip: "PRESENTATION_PIP"
|
|
2210
|
-
},
|
|
2336
|
+
}, Wn = {
|
|
2211
2337
|
widevine: "KEY_SYSTEM_WIDEVINE",
|
|
2212
2338
|
fairplay: "KEY_SYSTEM_FAIRPLAY",
|
|
2213
2339
|
none: "KEY_SYSTEM_NONE"
|
|
2214
|
-
}
|
|
2215
|
-
function Nn(e, t) {
|
|
2216
|
-
return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
|
|
2217
|
-
}
|
|
2218
|
-
var Pn = /* @__PURE__ */ new Set([
|
|
2340
|
+
}, Gn = /* @__PURE__ */ new Set([
|
|
2219
2341
|
"INVALID_URN",
|
|
2220
2342
|
"NOT_FOUND",
|
|
2221
2343
|
"GEO_DENIED",
|
|
@@ -2226,7 +2348,7 @@ var Pn = /* @__PURE__ */ new Set([
|
|
|
2226
2348
|
"FORBIDDEN",
|
|
2227
2349
|
"RATE_LIMITED",
|
|
2228
2350
|
"TIMEOUT"
|
|
2229
|
-
]),
|
|
2351
|
+
]), Y = {
|
|
2230
2352
|
idle: "PLAYER_STATE_IDLE",
|
|
2231
2353
|
waiting: "PLAYER_STATE_WAITING",
|
|
2232
2354
|
loading: "PLAYER_STATE_LOADING",
|
|
@@ -2236,7 +2358,7 @@ var Pn = /* @__PURE__ */ new Set([
|
|
|
2236
2358
|
ended: "PLAYER_STATE_ENDED",
|
|
2237
2359
|
error: "PLAYER_STATE_ERROR"
|
|
2238
2360
|
};
|
|
2239
|
-
function
|
|
2361
|
+
function Kn(e) {
|
|
2240
2362
|
try {
|
|
2241
2363
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
2242
2364
|
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);
|
|
@@ -2244,8 +2366,8 @@ function Fn(e) {
|
|
|
2244
2366
|
return;
|
|
2245
2367
|
}
|
|
2246
2368
|
}
|
|
2247
|
-
var
|
|
2248
|
-
function
|
|
2369
|
+
var qn = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), Jn = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), Z = /* @__PURE__ */ new Set(), Yn = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
|
|
2370
|
+
function Xn(e) {
|
|
2249
2371
|
if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
|
|
2250
2372
|
let t;
|
|
2251
2373
|
try {
|
|
@@ -2254,19 +2376,19 @@ function zn(e) {
|
|
|
2254
2376
|
} catch {
|
|
2255
2377
|
return;
|
|
2256
2378
|
}
|
|
2257
|
-
if (
|
|
2258
|
-
|
|
2259
|
-
for (let e of
|
|
2379
|
+
if (Jn.has(t) && !X.has(t)) {
|
|
2380
|
+
X.add(t), _(Yn(new URL(t).origin));
|
|
2381
|
+
for (let e of Z) e.noteCspBlocked();
|
|
2260
2382
|
}
|
|
2261
2383
|
}
|
|
2262
|
-
function
|
|
2384
|
+
function Zn(e, t) {
|
|
2263
2385
|
return _(t, e), { disabledReason: t };
|
|
2264
2386
|
}
|
|
2265
|
-
function
|
|
2266
|
-
if (n) return t && !
|
|
2387
|
+
function Qn(e, t, n) {
|
|
2388
|
+
if (n) return t && !qn(t, n) && _(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
|
|
2267
2389
|
if (t) return { endpoint: t };
|
|
2268
|
-
if (t !== void 0) return
|
|
2269
|
-
let r =
|
|
2390
|
+
if (t !== void 0) return Zn("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).");
|
|
2391
|
+
let r = Kn(e);
|
|
2270
2392
|
if (r) return { endpoint: r };
|
|
2271
2393
|
let i;
|
|
2272
2394
|
try {
|
|
@@ -2274,9 +2396,9 @@ function Bn(e, t, n) {
|
|
|
2274
2396
|
} catch {
|
|
2275
2397
|
i = e;
|
|
2276
2398
|
}
|
|
2277
|
-
return
|
|
2399
|
+
return Zn(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).`);
|
|
2278
2400
|
}
|
|
2279
|
-
var
|
|
2401
|
+
var $n = class {
|
|
2280
2402
|
opts;
|
|
2281
2403
|
url;
|
|
2282
2404
|
cspKey;
|
|
@@ -2358,8 +2480,8 @@ var Vn = class {
|
|
|
2358
2480
|
constructor(e) {
|
|
2359
2481
|
this.opts = {
|
|
2360
2482
|
...e,
|
|
2361
|
-
heartbeatMs: e.heartbeatMs ??
|
|
2362
|
-
idleMs: e.idleMs ??
|
|
2483
|
+
heartbeatMs: e.heartbeatMs ?? In,
|
|
2484
|
+
idleMs: e.idleMs ?? Ln
|
|
2363
2485
|
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
|
|
2364
2486
|
try {
|
|
2365
2487
|
let e = new URL(this.url);
|
|
@@ -2376,11 +2498,11 @@ var Vn = class {
|
|
|
2376
2498
|
sdkVersion: this.opts.sdkVersion,
|
|
2377
2499
|
...this.opts.environment
|
|
2378
2500
|
};
|
|
2379
|
-
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(),
|
|
2501
|
+
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Bn), 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 && Jn.add(this.cspKey), document.addEventListener("securitypolicyviolation", Xn), Z.add(this), this.noteCspBlocked(), this.onVisibility());
|
|
2380
2502
|
}
|
|
2381
2503
|
checkSuspension(e) {
|
|
2382
2504
|
if (this.endedFlag || !this.opts.idleMs) return !1;
|
|
2383
|
-
let t = Math.max(this.opts.idleMs,
|
|
2505
|
+
let t = Math.max(this.opts.idleMs, Rn);
|
|
2384
2506
|
return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
|
|
2385
2507
|
}
|
|
2386
2508
|
syncIdle(e) {
|
|
@@ -2394,21 +2516,21 @@ var Vn = class {
|
|
|
2394
2516
|
noteStateChange(e, t, n, r) {
|
|
2395
2517
|
if (this.endedFlag || e === t) return;
|
|
2396
2518
|
let i = this.now();
|
|
2397
|
-
if (t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(
|
|
2519
|
+
if (t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(J, i - this.startupAnchorMs)), this.firstAudioMs === 0 && !this.isMuted && (this.firstAudioMs = Math.max(J, i - this.startupAnchorMs)), this.isMuted && this.mutedSinceMs === null && (this.mutedSinceMs = i)) : this.playingSinceMs !== null && (this.playingTotalMs += i - this.playingSinceMs, this.playingSinceMs = null, this.mutedSinceMs !== null && (this.mutedTotalMs += i - this.mutedSinceMs, this.mutedSinceMs = null)), this.isPlaying = t === "playing", this.syncActive(), t === "waiting" ? this.waitingSinceMs = i : this.waitingSinceMs !== null && (this.waitingTotalMs += i - this.waitingSinceMs, this.waitingSinceMs = null), t === "buffering" && e === "playing") {
|
|
2398
2520
|
this.stallIsSeekInduced = this.seekInduced(i);
|
|
2399
2521
|
let e = !this.isHidden && !this.stallIsSeekInduced;
|
|
2400
|
-
e && (this.rebufferCount += 1), this.isBuffering = !0, this.lastStallMs = i, e && this.timeToFirstStallMs === 0 && (this.timeToFirstStallMs = Math.max(
|
|
2522
|
+
e && (this.rebufferCount += 1), this.isBuffering = !0, this.lastStallMs = i, e && this.timeToFirstStallMs === 0 && (this.timeToFirstStallMs = Math.max(J, Math.round(this.playingTotalMs)));
|
|
2401
2523
|
} else e === "buffering" && (this.isBuffering = !1, this.stallIsSeekInduced = !1);
|
|
2402
2524
|
this.syncBuffering(), t === "paused" && (this.pauseCount += 1), this.syncIdle(t);
|
|
2403
2525
|
let a = {
|
|
2404
|
-
fromState:
|
|
2405
|
-
toState:
|
|
2406
|
-
presentation:
|
|
2526
|
+
fromState: Y[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2527
|
+
toState: Y[t] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2528
|
+
presentation: Un[this.presentation]
|
|
2407
2529
|
}, o = this.causeOf(e, t, i);
|
|
2408
2530
|
o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
2409
2531
|
}
|
|
2410
2532
|
seekInduced(e) {
|
|
2411
|
-
return this.lastSeekMs >= 0 && e - this.lastSeekMs <
|
|
2533
|
+
return this.lastSeekMs >= 0 && e - this.lastSeekMs < Hn;
|
|
2412
2534
|
}
|
|
2413
2535
|
causeOf(e, t, n) {
|
|
2414
2536
|
if (t === "error") return "TRANSITION_CAUSE_ERROR";
|
|
@@ -2445,25 +2567,25 @@ var Vn = class {
|
|
|
2445
2567
|
}
|
|
2446
2568
|
this.muteChanges += 1;
|
|
2447
2569
|
let r = this.now();
|
|
2448
|
-
n ? this.isPlaying && this.mutedSinceMs === null && (this.mutedSinceMs = r) : (this.mutedSinceMs !== null && (this.mutedTotalMs += r - this.mutedSinceMs, this.mutedSinceMs = null), this.firstAudioMs === 0 && this.isPlaying && (this.firstAudioMs = Math.max(
|
|
2570
|
+
n ? this.isPlaying && this.mutedSinceMs === null && (this.mutedSinceMs = r) : (this.mutedSinceMs !== null && (this.mutedTotalMs += r - this.mutedSinceMs, this.mutedSinceMs = null), this.firstAudioMs === 0 && this.isPlaying && (this.firstAudioMs = Math.max(J, r - this.startupAnchorMs))), this.isMuted = n, this.syncActive();
|
|
2449
2571
|
}
|
|
2450
2572
|
notePresentation(e) {
|
|
2451
2573
|
this.endedFlag || e === this.presentation || (this.closePresentation(), this.presentation = e);
|
|
2452
2574
|
}
|
|
2453
2575
|
notePlayIntent() {
|
|
2454
|
-
this.endedFlag || this.startupTimeMs > 0 || (this.startupAnchorMs = this.now(), this.manifestLoadMs > 0 && (this.manifestLoadMs =
|
|
2576
|
+
this.endedFlag || this.startupTimeMs > 0 || (this.startupAnchorMs = this.now(), this.manifestLoadMs > 0 && (this.manifestLoadMs = J), this.firstPlaylistMs > 0 && (this.firstPlaylistMs = J), this.firstFragLoadMs > 0 && (this.firstFragLoadMs = J), this.drmSetupMs > 0 && (this.drmSetupMs = J));
|
|
2455
2577
|
}
|
|
2456
2578
|
noteReady() {
|
|
2457
|
-
this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(
|
|
2579
|
+
this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(J, this.now() - this.startupAnchorMs));
|
|
2458
2580
|
}
|
|
2459
2581
|
noteFirstPlaylist() {
|
|
2460
|
-
this.firstPlaylistMs === 0 && (this.firstPlaylistMs = Math.max(
|
|
2582
|
+
this.firstPlaylistMs === 0 && (this.firstPlaylistMs = Math.max(J, this.now() - this.startupAnchorMs));
|
|
2461
2583
|
}
|
|
2462
2584
|
noteDrmReady() {
|
|
2463
|
-
this.drmSetupMs === 0 && (this.drmSetupMs = Math.max(
|
|
2585
|
+
this.drmSetupMs === 0 && (this.drmSetupMs = Math.max(J, this.now() - this.startupAnchorMs));
|
|
2464
2586
|
}
|
|
2465
2587
|
noteFirstBytes() {
|
|
2466
|
-
this.sawFirstBytes = !0, this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(
|
|
2588
|
+
this.sawFirstBytes = !0, this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(J, this.now() - this.startupAnchorMs));
|
|
2467
2589
|
}
|
|
2468
2590
|
noteSeek() {
|
|
2469
2591
|
this.endedFlag || (this.seekCount += 1, this.lastSeekMs = this.now());
|
|
@@ -2482,7 +2604,7 @@ var Vn = class {
|
|
|
2482
2604
|
let r = n ?? "";
|
|
2483
2605
|
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";
|
|
2484
2606
|
if (e === "DRM_CLIENT" || e === "DRM_DEVICE_REVOKED") return "ERROR_STAGE_DRM";
|
|
2485
|
-
if (
|
|
2607
|
+
if (Gn.has(e)) return "ERROR_STAGE_RESOLVE";
|
|
2486
2608
|
let i = t ?? "";
|
|
2487
2609
|
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";
|
|
2488
2610
|
}
|
|
@@ -2514,7 +2636,7 @@ var Vn = class {
|
|
|
2514
2636
|
let l = t.droppedFrames ?? 0;
|
|
2515
2637
|
l > this.lastDropped && (o.droppedFramesDelta = l - this.lastDropped), this.lastDropped = l;
|
|
2516
2638
|
let u = t.renditionSwitches ?? 0;
|
|
2517
|
-
u > this.lastSwitches && (o.renditionSwitchesDelta = u - this.lastSwitches), this.lastSwitches = u, n > this.lastHbPlayingMs && (o.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (o.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, i > this.lastHbRebufferMs && (o.rebufferMsDelta = Math.round(i - this.lastHbRebufferMs)), this.lastHbRebufferMs = i, this.rebufferCount > this.lastHbRebufferCount && (o.rebufferCountDelta = this.rebufferCount - this.lastHbRebufferCount), this.lastHbRebufferCount = this.rebufferCount, a > this.lastHbActiveMs && (o.activeMsDelta = Math.round(a - this.lastHbActiveMs)), this.lastHbActiveMs = a, typeof t.latencySeconds == "number" && (o.latencyMs = Math.round(t.latencySeconds * 1e3)), typeof t.targetLatencySeconds == "number" && (o.targetLatencyMs = Math.round(t.targetLatencySeconds * 1e3)), typeof t.bandwidthKbps == "number" && (o.bandwidthEstKbps = t.bandwidthKbps), typeof t.levelHeight == "number" && (o.renditionHeight = t.levelHeight), typeof t.renditionBitrateKbps == "number" && (o.renditionBitrateKbps = t.renditionBitrateKbps), t.atLiveEdge === !0 && (o.atLiveEdge = !0), typeof t.bufferedMs == "number" && t.bufferedMs > 0 && (o.bufferedMs = Math.round(t.bufferedMs)), o.playerState =
|
|
2639
|
+
u > this.lastSwitches && (o.renditionSwitchesDelta = u - this.lastSwitches), this.lastSwitches = u, n > this.lastHbPlayingMs && (o.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (o.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, i > this.lastHbRebufferMs && (o.rebufferMsDelta = Math.round(i - this.lastHbRebufferMs)), this.lastHbRebufferMs = i, this.rebufferCount > this.lastHbRebufferCount && (o.rebufferCountDelta = this.rebufferCount - this.lastHbRebufferCount), this.lastHbRebufferCount = this.rebufferCount, a > this.lastHbActiveMs && (o.activeMsDelta = Math.round(a - this.lastHbActiveMs)), this.lastHbActiveMs = a, typeof t.latencySeconds == "number" && (o.latencyMs = Math.round(t.latencySeconds * 1e3)), typeof t.targetLatencySeconds == "number" && (o.targetLatencyMs = Math.round(t.targetLatencySeconds * 1e3)), typeof t.bandwidthKbps == "number" && (o.bandwidthEstKbps = t.bandwidthKbps), typeof t.levelHeight == "number" && (o.renditionHeight = t.levelHeight), typeof t.renditionBitrateKbps == "number" && (o.renditionBitrateKbps = t.renditionBitrateKbps), t.atLiveEdge === !0 && (o.atLiveEdge = !0), typeof t.bufferedMs == "number" && t.bufferedMs > 0 && (o.bufferedMs = Math.round(t.bufferedMs)), o.playerState = Y[t.state] ?? "PLAYER_STATE_UNSPECIFIED";
|
|
2518
2640
|
let d = this.mutedTotalMs;
|
|
2519
2641
|
this.mutedSinceMs !== null && (d += e - this.mutedSinceMs), d > this.lastHbMutedMs && (o.mutedMsDelta = Math.round(d - this.lastHbMutedMs)), this.lastHbMutedMs = d;
|
|
2520
2642
|
let f = t.upshifts ?? 0;
|
|
@@ -2529,20 +2651,20 @@ var Vn = class {
|
|
|
2529
2651
|
if (this.lastRequestCount = g, _ > 0) {
|
|
2530
2652
|
o.requestCountDelta = _;
|
|
2531
2653
|
let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
|
|
2532
|
-
n.length > 0 && (o.requestTimeP50Ms =
|
|
2654
|
+
n.length > 0 && (o.requestTimeP50Ms = K(n, 50), o.requestTimeP95Ms = K(n, 95));
|
|
2533
2655
|
}
|
|
2534
2656
|
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();
|
|
2535
2657
|
}
|
|
2536
2658
|
maybeEmitMediaInfo(e) {
|
|
2537
2659
|
if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
|
|
2538
2660
|
let t = {};
|
|
2539
|
-
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem =
|
|
2661
|
+
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = Wn[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);
|
|
2540
2662
|
let n = JSON.stringify(t);
|
|
2541
2663
|
n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
|
|
2542
2664
|
}
|
|
2543
2665
|
end(e, t) {
|
|
2544
2666
|
if (this.endedFlag) return;
|
|
2545
|
-
this.endedFlag = !0,
|
|
2667
|
+
this.endedFlag = !0, Z.delete(this);
|
|
2546
2668
|
let n = t ?? this.now();
|
|
2547
2669
|
this.playingSinceMs !== null && (this.playingTotalMs += n - this.playingSinceMs, this.playingSinceMs = null), this.hiddenSinceMs !== null && (this.hiddenTotalMs += n - this.hiddenSinceMs, this.hiddenSinceMs = null), this.bufferingSinceMs !== null && (this.rebufferTotalMs += n - this.bufferingSinceMs, this.bufferingSinceMs = null), this.mutedSinceMs !== null && (this.mutedTotalMs += n - this.mutedSinceMs, this.mutedSinceMs = null), this.waitingSinceMs !== null && (this.waitingTotalMs += n - this.waitingSinceMs, this.waitingSinceMs = null), this.isPlaying = !1, this.syncActive(n), this.closePresentation(n), this.firstFlushTimer &&= (clearTimeout(this.firstFlushTimer), null), this.timer &&= (clearInterval(this.timer), null), this.idleTimer &&= (clearTimeout(this.idleTimer), null), typeof window < "u" && window.removeEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), document.removeEventListener("freeze", this.onFreeze), document.removeEventListener("resume", this.onResume));
|
|
2548
2670
|
let r = this.safeSample();
|
|
@@ -2556,7 +2678,7 @@ var Vn = class {
|
|
|
2556
2678
|
let c = r?.positionMs ?? 0;
|
|
2557
2679
|
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));
|
|
2558
2680
|
let l = e !== "END_REASON_ENDED";
|
|
2559
|
-
l && this.lastStallMs > 0 && n - this.lastStallMs <=
|
|
2681
|
+
l && this.lastStallMs > 0 && n - this.lastStallMs <= Vn && (i.abandonAfterStallMs = Math.max(J, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Vn && (i.abandonAfterErrorMs = Math.max(J, 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);
|
|
2560
2682
|
let u = r?.decodedFrames ?? this.lastDecoded;
|
|
2561
2683
|
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");
|
|
2562
2684
|
}
|
|
@@ -2576,13 +2698,13 @@ var Vn = class {
|
|
|
2576
2698
|
};
|
|
2577
2699
|
}
|
|
2578
2700
|
noteCspBlocked() {
|
|
2579
|
-
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(
|
|
2701
|
+
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(Yn(new URL(this.url).origin)));
|
|
2580
2702
|
}
|
|
2581
2703
|
cspBlocked() {
|
|
2582
|
-
return !!this.cspKey &&
|
|
2704
|
+
return !!this.cspKey && X.has(this.cspKey);
|
|
2583
2705
|
}
|
|
2584
2706
|
enqueue(e) {
|
|
2585
|
-
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length >
|
|
2707
|
+
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > zn;) {
|
|
2586
2708
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
2587
2709
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
2588
2710
|
}
|
|
@@ -2609,7 +2731,7 @@ var Vn = class {
|
|
|
2609
2731
|
};
|
|
2610
2732
|
//#endregion
|
|
2611
2733
|
//#region src/core/environment.ts
|
|
2612
|
-
function
|
|
2734
|
+
function er() {
|
|
2613
2735
|
if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
|
|
2614
2736
|
let e;
|
|
2615
2737
|
try {
|
|
@@ -2634,14 +2756,14 @@ function Hn() {
|
|
|
2634
2756
|
integration: "INTEGRATION_KIND_IFRAME"
|
|
2635
2757
|
};
|
|
2636
2758
|
}
|
|
2637
|
-
function
|
|
2759
|
+
function tr() {
|
|
2638
2760
|
if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
|
|
2639
2761
|
let e = navigator.userAgentData, t = e?.platform ?? "";
|
|
2640
2762
|
if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
|
|
2641
2763
|
let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
|
|
2642
2764
|
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";
|
|
2643
2765
|
}
|
|
2644
|
-
function
|
|
2766
|
+
function nr() {
|
|
2645
2767
|
let e = typeof navigator < "u" ? navigator.connection : void 0;
|
|
2646
2768
|
if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
|
|
2647
2769
|
let t = {
|
|
@@ -2660,17 +2782,17 @@ function Wn() {
|
|
|
2660
2782
|
}
|
|
2661
2783
|
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;
|
|
2662
2784
|
}
|
|
2663
|
-
function
|
|
2664
|
-
let t =
|
|
2665
|
-
deviceClass:
|
|
2785
|
+
function rr(e) {
|
|
2786
|
+
let t = er(), n = {
|
|
2787
|
+
deviceClass: tr(),
|
|
2666
2788
|
integration: t.integration,
|
|
2667
|
-
...
|
|
2789
|
+
...nr()
|
|
2668
2790
|
};
|
|
2669
2791
|
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);
|
|
2670
2792
|
let r = e.getBoundingClientRect?.();
|
|
2671
2793
|
return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
|
|
2672
2794
|
}
|
|
2673
|
-
async function
|
|
2795
|
+
async function ir() {
|
|
2674
2796
|
let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
|
|
2675
2797
|
if (!e?.getHighEntropyValues) return {};
|
|
2676
2798
|
try {
|
|
@@ -2682,7 +2804,7 @@ async function Kn() {
|
|
|
2682
2804
|
}
|
|
2683
2805
|
//#endregion
|
|
2684
2806
|
//#region src/core/version.ts
|
|
2685
|
-
var
|
|
2807
|
+
var ar = "2.23.0", or = {
|
|
2686
2808
|
accent: "#E1B600",
|
|
2687
2809
|
accentText: "#1B1C23",
|
|
2688
2810
|
background: "#0e0f13",
|
|
@@ -2693,7 +2815,7 @@ var qn = "2.22.0", Jn = {
|
|
|
2693
2815
|
border: "rgba(255, 255, 255, 0.1)",
|
|
2694
2816
|
radius: "8px",
|
|
2695
2817
|
fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
|
|
2696
|
-
},
|
|
2818
|
+
}, sr = {
|
|
2697
2819
|
accent: "--havik-accent",
|
|
2698
2820
|
accentText: "--havik-accent-text",
|
|
2699
2821
|
background: "--havik-bg",
|
|
@@ -2705,26 +2827,26 @@ var qn = "2.22.0", Jn = {
|
|
|
2705
2827
|
radius: "--havik-radius",
|
|
2706
2828
|
fontFamily: "--havik-font"
|
|
2707
2829
|
};
|
|
2708
|
-
function
|
|
2830
|
+
function cr(e, t) {
|
|
2709
2831
|
let n = {
|
|
2710
|
-
...
|
|
2832
|
+
...or,
|
|
2711
2833
|
...t
|
|
2712
2834
|
};
|
|
2713
|
-
for (let t of Object.keys(
|
|
2835
|
+
for (let t of Object.keys(sr)) e.style.setProperty(sr[t], n[t]);
|
|
2714
2836
|
n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
|
|
2715
2837
|
}
|
|
2716
2838
|
//#endregion
|
|
2717
2839
|
//#region src/ui/styles.ts
|
|
2718
|
-
var
|
|
2719
|
-
function
|
|
2720
|
-
let n = e.querySelector(`style#${
|
|
2721
|
-
if (n && (!t ||
|
|
2840
|
+
var lr = "havik-player-styles", ur = "\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", dr = /* @__PURE__ */ new WeakMap();
|
|
2841
|
+
function fr(e = document, t) {
|
|
2842
|
+
let n = e.querySelector(`style#${lr}`);
|
|
2843
|
+
if (n && (!t || dr.get(n) === t)) return;
|
|
2722
2844
|
let r = e.createElement("style");
|
|
2723
|
-
r.id =
|
|
2845
|
+
r.id = lr, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = ur, dr.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
|
|
2724
2846
|
}
|
|
2725
2847
|
//#endregion
|
|
2726
2848
|
//#region src/ui/icons.ts
|
|
2727
|
-
var
|
|
2849
|
+
var pr = {
|
|
2728
2850
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
2729
2851
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
2730
2852
|
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\"/>",
|
|
@@ -2738,11 +2860,11 @@ var tr = {
|
|
|
2738
2860
|
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\"/>"
|
|
2739
2861
|
};
|
|
2740
2862
|
function Q(e) {
|
|
2741
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
2863
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${pr[e]}</svg>`;
|
|
2742
2864
|
}
|
|
2743
2865
|
//#endregion
|
|
2744
2866
|
//#region src/ui/controls.ts
|
|
2745
|
-
var
|
|
2867
|
+
var mr = 3e3, hr = 250, gr = /* @__PURE__ */ new Set([
|
|
2746
2868
|
"GONE",
|
|
2747
2869
|
"NOT_FOUND",
|
|
2748
2870
|
"GEO_DENIED",
|
|
@@ -2750,15 +2872,15 @@ var nr = 3e3, rr = 250, ir = /* @__PURE__ */ new Set([
|
|
|
2750
2872
|
"UNAUTHORIZED",
|
|
2751
2873
|
"DRM_DEVICE_REVOKED"
|
|
2752
2874
|
]);
|
|
2753
|
-
function
|
|
2875
|
+
function _r(e) {
|
|
2754
2876
|
let t = "This match isn't available in your country";
|
|
2755
2877
|
return e ? `${t} (${e})` : t;
|
|
2756
2878
|
}
|
|
2757
|
-
var
|
|
2758
|
-
function
|
|
2759
|
-
return new
|
|
2879
|
+
var vr = "This device can't play protected video";
|
|
2880
|
+
function yr(e) {
|
|
2881
|
+
return new br(e);
|
|
2760
2882
|
}
|
|
2761
|
-
var
|
|
2883
|
+
var br = class {
|
|
2762
2884
|
root;
|
|
2763
2885
|
video;
|
|
2764
2886
|
player;
|
|
@@ -2806,7 +2928,7 @@ var cr = class {
|
|
|
2806
2928
|
scrubbing = !1;
|
|
2807
2929
|
offFns = [];
|
|
2808
2930
|
constructor(e) {
|
|
2809
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
2931
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? mr, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.streamEnded = e.streamEnded ?? (() => !1), this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, fr(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");
|
|
2810
2932
|
let t = (e, t, n) => {
|
|
2811
2933
|
let r = this.doc.createElement(e);
|
|
2812
2934
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -2892,7 +3014,7 @@ var cr = class {
|
|
|
2892
3014
|
let t = this.surfaceWasHidden;
|
|
2893
3015
|
this.tapTimer = setTimeout(() => {
|
|
2894
3016
|
this.tapTimer = void 0, this.toggleBar(t);
|
|
2895
|
-
},
|
|
3017
|
+
}, hr);
|
|
2896
3018
|
}
|
|
2897
3019
|
toggleBar(e) {
|
|
2898
3020
|
e ? this.poke() : this.hideIfIdle();
|
|
@@ -2912,7 +3034,7 @@ var cr = class {
|
|
|
2912
3034
|
this.statusOverlays && (e === "ended" ? t = "ended" : e === "error" ? t = "error" : e === "waiting" ? t = "waiting" : !this.hasPlayed && (e === "idle" || e === "paused") && (t = "preplay")), this.renderStatus(t);
|
|
2913
3035
|
}
|
|
2914
3036
|
statusMessageFor(e) {
|
|
2915
|
-
return e === "ended" ? this.player.endedReason === "interrupted" ? this.interruptedMessage : this.endedMessage : e === "waiting" ? this.hasPlayed ? "Reconnecting — please stand by" : "Starting soon…" : e === "error" ? this.errorMessage === void 0 ? this.lastError?.code === "GEO_DENIED" ?
|
|
3037
|
+
return e === "ended" ? this.player.endedReason === "interrupted" ? this.interruptedMessage : this.endedMessage : e === "waiting" ? this.hasPlayed ? "Reconnecting — please stand by" : "Starting soon…" : e === "error" ? this.errorMessage === void 0 ? this.lastError?.code === "GEO_DENIED" ? _r(this.lastError.country) : this.lastError?.code === "DRM_DEVICE_REVOKED" ? vr : this.lastError?.message ?? "Playback unavailable" : this.errorMessage : null;
|
|
2916
3038
|
}
|
|
2917
3039
|
renderStatus(e) {
|
|
2918
3040
|
let t = this.statusMessageFor(e);
|
|
@@ -2927,7 +3049,7 @@ var cr = class {
|
|
|
2927
3049
|
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);
|
|
2928
3050
|
} else {
|
|
2929
3051
|
let r = this.doc.createElement("div");
|
|
2930
|
-
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !
|
|
3052
|
+
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !gr.has(this.lastError.code)) {
|
|
2931
3053
|
let e = this.doc.createElement("button");
|
|
2932
3054
|
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);
|
|
2933
3055
|
}
|
|
@@ -2968,7 +3090,7 @@ var cr = class {
|
|
|
2968
3090
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
2969
3091
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
2970
3092
|
}
|
|
2971
|
-
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${
|
|
3093
|
+
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${xr(this.video.currentTime)} / ${xr(this.video.duration)}`);
|
|
2972
3094
|
}
|
|
2973
3095
|
syncLive() {
|
|
2974
3096
|
let e = this.player.getStats(), t = e.isLive !== !1, n = this.player.state === "ended", r = !t && !this.streamEnded();
|
|
@@ -3018,17 +3140,17 @@ var cr = class {
|
|
|
3018
3140
|
renderQualityMenu() {
|
|
3019
3141
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
3020
3142
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
3021
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
3143
|
+
for (let n of e) this.menu.append(this.menuItem(Sr(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
3022
3144
|
}
|
|
3023
3145
|
renderAudioMenu() {
|
|
3024
3146
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
3025
3147
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
3026
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
3148
|
+
for (let t of e) this.menu.append(this.menuItem(Cr(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
3027
3149
|
}
|
|
3028
3150
|
renderCcMenu() {
|
|
3029
3151
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
3030
3152
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
3031
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
3153
|
+
for (let t of e) this.menu.append(this.menuItem(wr(t), !1, () => this.player.setTextTrack(t.id)));
|
|
3032
3154
|
}
|
|
3033
3155
|
onTracksChanged() {
|
|
3034
3156
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -3133,41 +3255,41 @@ var cr = class {
|
|
|
3133
3255
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
3134
3256
|
}
|
|
3135
3257
|
};
|
|
3136
|
-
function
|
|
3258
|
+
function xr(e) {
|
|
3137
3259
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
3138
3260
|
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");
|
|
3139
3261
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
3140
3262
|
}
|
|
3141
|
-
function
|
|
3263
|
+
function Sr(e) {
|
|
3142
3264
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
3143
3265
|
}
|
|
3144
|
-
function
|
|
3266
|
+
function Cr(e) {
|
|
3145
3267
|
return e.name || e.lang || `Track ${e.id}`;
|
|
3146
3268
|
}
|
|
3147
|
-
function
|
|
3269
|
+
function wr(e) {
|
|
3148
3270
|
return e.name || e.lang || `Track ${e.id}`;
|
|
3149
3271
|
}
|
|
3150
3272
|
//#endregion
|
|
3151
3273
|
//#region src/managed/index.ts
|
|
3152
|
-
var
|
|
3153
|
-
function
|
|
3274
|
+
var Tr = 6e3, Er = 45e3, Dr = 2e3, Or = 3, kr = 5e3, Ar = 2e3, jr = 48e4, Mr = "keySystemLicenseRequestFailed";
|
|
3275
|
+
function Nr(e) {
|
|
3154
3276
|
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)})`);
|
|
3155
3277
|
if (e.env !== void 0) return at(e.env);
|
|
3156
3278
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
|
|
3157
3279
|
return e.baseUrl;
|
|
3158
3280
|
}
|
|
3159
|
-
async function
|
|
3281
|
+
async function Pr(e) {
|
|
3160
3282
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
3161
|
-
let t =
|
|
3283
|
+
let t = Nr(e);
|
|
3162
3284
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
3163
3285
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
3164
|
-
let r = new
|
|
3286
|
+
let r = new Fr({
|
|
3165
3287
|
...e,
|
|
3166
3288
|
baseUrl: t
|
|
3167
3289
|
});
|
|
3168
3290
|
return await r.start(), r;
|
|
3169
3291
|
}
|
|
3170
|
-
var
|
|
3292
|
+
var Fr = class {
|
|
3171
3293
|
opts;
|
|
3172
3294
|
abort = new AbortController();
|
|
3173
3295
|
listeners = {};
|
|
@@ -3262,7 +3384,7 @@ var Cr = class {
|
|
|
3262
3384
|
setTimeout(() => {
|
|
3263
3385
|
a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
3264
3386
|
phase: i ? "unavailable" : "tooEarly",
|
|
3265
|
-
retryInMs:
|
|
3387
|
+
retryInMs: Er,
|
|
3266
3388
|
attempt: 1,
|
|
3267
3389
|
elapsedMs: 0,
|
|
3268
3390
|
...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
|
|
@@ -3301,13 +3423,13 @@ var Cr = class {
|
|
|
3301
3423
|
!a && !p() && h();
|
|
3302
3424
|
}, e);
|
|
3303
3425
|
};
|
|
3304
|
-
_(
|
|
3426
|
+
_(Tr), this.armingSub = E({
|
|
3305
3427
|
eventsBaseUrl: t,
|
|
3306
3428
|
matchUrn: this.opts.matchUrn,
|
|
3307
3429
|
credential: this.opts.credential,
|
|
3308
|
-
onAlive: () => _(
|
|
3430
|
+
onAlive: () => _(Er),
|
|
3309
3431
|
onState: (e) => {
|
|
3310
|
-
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() *
|
|
3432
|
+
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Dr);
|
|
3311
3433
|
},
|
|
3312
3434
|
onError: () => h()
|
|
3313
3435
|
});
|
|
@@ -3330,7 +3452,7 @@ var Cr = class {
|
|
|
3330
3452
|
let n = await c(this.opts.credential);
|
|
3331
3453
|
if (this.destroyed || t !== this.loadGen) return;
|
|
3332
3454
|
this.setState("loading");
|
|
3333
|
-
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a =
|
|
3455
|
+
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = dt(this.opts.video, (e) => {
|
|
3334
3456
|
this._state !== "ended" && this._state !== "error" && this.setState(e);
|
|
3335
3457
|
});
|
|
3336
3458
|
if (await i.load(), this.destroyed || t !== this.loadGen) {
|
|
@@ -3352,26 +3474,26 @@ var Cr = class {
|
|
|
3352
3474
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
|
|
3353
3475
|
let i = e.analytics?.sid;
|
|
3354
3476
|
if (!i) return;
|
|
3355
|
-
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } =
|
|
3477
|
+
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = Qn(this.opts.baseUrl, a, e.analytics?.endpoint);
|
|
3356
3478
|
if (!o) {
|
|
3357
3479
|
s && setTimeout(() => {
|
|
3358
3480
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
|
|
3359
3481
|
}, 0);
|
|
3360
3482
|
return;
|
|
3361
3483
|
}
|
|
3362
|
-
let c = this.opts.video, l = new
|
|
3484
|
+
let c = this.opts.video, l = new $n({
|
|
3363
3485
|
endpoint: o,
|
|
3364
3486
|
sid: i,
|
|
3365
3487
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
3366
|
-
sdkVersion:
|
|
3367
|
-
environment:
|
|
3488
|
+
sdkVersion: ar,
|
|
3489
|
+
environment: rr(c),
|
|
3368
3490
|
idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
|
|
3369
3491
|
onIdle: () => this.onAnalyticsIdle(t),
|
|
3370
3492
|
onBlocked: (e) => setTimeout(() => {
|
|
3371
3493
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
|
|
3372
3494
|
}, 0),
|
|
3373
3495
|
sample: () => {
|
|
3374
|
-
let e = this.engine?.getStats() ??
|
|
3496
|
+
let e = this.engine?.getStats() ?? ot, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
|
|
3375
3497
|
return {
|
|
3376
3498
|
...e,
|
|
3377
3499
|
bufferedMs: Math.round(t * 1e3),
|
|
@@ -3385,7 +3507,7 @@ var Cr = class {
|
|
|
3385
3507
|
let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
|
|
3386
3508
|
c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
|
|
3387
3509
|
c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
|
|
3388
|
-
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()),
|
|
3510
|
+
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), ir().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
|
|
3389
3511
|
}
|
|
3390
3512
|
currentPresentation() {
|
|
3391
3513
|
let e = this.opts.video;
|
|
@@ -3406,6 +3528,8 @@ var Cr = class {
|
|
|
3406
3528
|
snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
|
|
3407
3529
|
rememberBandwidth: this.opts.rememberBandwidth,
|
|
3408
3530
|
sizeCapHeadroom: this.opts.sizeCapHeadroom,
|
|
3531
|
+
adaptiveHoldBack: this.opts.adaptiveHoldBack,
|
|
3532
|
+
adaptiveHoldBackCeiling: this.opts.adaptiveHoldBackCeiling,
|
|
3409
3533
|
mediaDuringKey: this.opts.mediaDuringKey,
|
|
3410
3534
|
debug: this.opts.debug,
|
|
3411
3535
|
deferLoad: r,
|
|
@@ -3413,11 +3537,11 @@ var Cr = class {
|
|
|
3413
3537
|
emit: (e) => this.onEngineEvent(e),
|
|
3414
3538
|
freshLicenseUrl: () => this.refreshLicense()
|
|
3415
3539
|
}, o = this.opts.engine ?? "auto";
|
|
3416
|
-
if (o === "native") return new
|
|
3417
|
-
if (o === "hls") return new
|
|
3418
|
-
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl &&
|
|
3419
|
-
if (
|
|
3420
|
-
if (
|
|
3540
|
+
if (o === "native") return new U(a);
|
|
3541
|
+
if (o === "hls") return new Fn(a);
|
|
3542
|
+
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && V(this.opts.video) && H() || !e.drmEnabled && Ct() && V(this.opts.video)) return new U(a);
|
|
3543
|
+
if (Lt()) return new Fn(a);
|
|
3544
|
+
if (V(this.opts.video)) return new U(a);
|
|
3421
3545
|
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
3422
3546
|
}
|
|
3423
3547
|
onEngineEvent(e) {
|
|
@@ -3437,6 +3561,9 @@ var Cr = class {
|
|
|
3437
3561
|
case "lowLatencyDetected":
|
|
3438
3562
|
this._descriptor && (this._descriptor.isLowLatency = e.value);
|
|
3439
3563
|
break;
|
|
3564
|
+
case "livetargetchange":
|
|
3565
|
+
this.emit("latencytargetchange", e.change);
|
|
3566
|
+
break;
|
|
3440
3567
|
case "qualitychange":
|
|
3441
3568
|
this.emit("qualitychange", e.index);
|
|
3442
3569
|
break;
|
|
@@ -3479,7 +3606,7 @@ var Cr = class {
|
|
|
3479
3606
|
r = 0, i = !1;
|
|
3480
3607
|
},
|
|
3481
3608
|
onError: () => {
|
|
3482
|
-
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >=
|
|
3609
|
+
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= Or && (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.`))));
|
|
3483
3610
|
}
|
|
3484
3611
|
});
|
|
3485
3612
|
}
|
|
@@ -3493,7 +3620,7 @@ var Cr = class {
|
|
|
3493
3620
|
return;
|
|
3494
3621
|
}
|
|
3495
3622
|
let e = this.hiddenAtMs;
|
|
3496
|
-
this.hiddenAtMs = null, e != null && Date.now() - e >=
|
|
3623
|
+
this.hiddenAtMs = null, e != null && Date.now() - e >= kr && this.resyncLiveState();
|
|
3497
3624
|
}, this.onReturnPageShow = (e) => {
|
|
3498
3625
|
e.persisted && this.resyncLiveState();
|
|
3499
3626
|
}, document.addEventListener("visibilitychange", this.onReturnVisible), typeof window < "u" && window.addEventListener("pageshow", this.onReturnPageShow));
|
|
@@ -3525,7 +3652,7 @@ var Cr = class {
|
|
|
3525
3652
|
scheduleRejoin(e) {
|
|
3526
3653
|
this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
|
|
3527
3654
|
this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
|
|
3528
|
-
}, Math.random() *
|
|
3655
|
+
}, Math.random() * Dr));
|
|
3529
3656
|
}
|
|
3530
3657
|
cancelRejoin() {
|
|
3531
3658
|
this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
|
|
@@ -3549,7 +3676,7 @@ var Cr = class {
|
|
|
3549
3676
|
}
|
|
3550
3677
|
t.controls = !1;
|
|
3551
3678
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
3552
|
-
r && r.insertBefore(n, t), n.appendChild(t),
|
|
3679
|
+
r && r.insertBefore(n, t), n.appendChild(t), cr(n, this.opts.theme), this.container = n, this.controlBar = yr({
|
|
3553
3680
|
root: n,
|
|
3554
3681
|
video: t,
|
|
3555
3682
|
player: this,
|
|
@@ -3587,7 +3714,7 @@ var Cr = class {
|
|
|
3587
3714
|
}
|
|
3588
3715
|
startStats() {
|
|
3589
3716
|
this.stopStats();
|
|
3590
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
3717
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? Ar);
|
|
3591
3718
|
this.statsTimer = setInterval(() => {
|
|
3592
3719
|
if (!this.engine) return;
|
|
3593
3720
|
let e = this.engine.getStats();
|
|
@@ -3598,14 +3725,14 @@ var Cr = class {
|
|
|
3598
3725
|
this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
|
|
3599
3726
|
}
|
|
3600
3727
|
isStaleLicenseDenial(e) {
|
|
3601
|
-
return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !==
|
|
3728
|
+
return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== Mr || e.error.httpStatus !== 403 || e.error.code !== "FORBIDDEN" || e.error.serverCode === "license_refused" ? !1 : G(this._descriptor?.drm?.widevine?.licenseUrl);
|
|
3602
3729
|
}
|
|
3603
3730
|
scheduleLicenseRefresh() {
|
|
3604
3731
|
if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
|
|
3605
3732
|
typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
|
|
3606
|
-
document.visibilityState !== "visible" || this.destroyed ||
|
|
3733
|
+
document.visibilityState !== "visible" || this.destroyed || G(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
|
|
3607
3734
|
}, document.addEventListener("visibilitychange", this.onRefocus));
|
|
3608
|
-
let e = this.opts.licenseRefreshMs ??
|
|
3735
|
+
let e = this.opts.licenseRefreshMs ?? jr;
|
|
3609
3736
|
e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
3610
3737
|
}
|
|
3611
3738
|
stopRefresh() {
|
|
@@ -3662,7 +3789,7 @@ var Cr = class {
|
|
|
3662
3789
|
this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
|
|
3663
3790
|
}
|
|
3664
3791
|
getStats() {
|
|
3665
|
-
return this.engine?.getStats() ??
|
|
3792
|
+
return this.engine?.getStats() ?? ot;
|
|
3666
3793
|
}
|
|
3667
3794
|
getQualityLevels() {
|
|
3668
3795
|
return this.engine?.getQualityLevels() ?? [];
|
|
@@ -3775,7 +3902,7 @@ function $(e) {
|
|
|
3775
3902
|
}
|
|
3776
3903
|
//#endregion
|
|
3777
3904
|
//#region src/embed/host.ts
|
|
3778
|
-
function
|
|
3905
|
+
function Ir(e) {
|
|
3779
3906
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
3780
3907
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
3781
3908
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -3834,15 +3961,15 @@ function wr(e) {
|
|
|
3834
3961
|
}
|
|
3835
3962
|
//#endregion
|
|
3836
3963
|
//#region src/embed/page.ts
|
|
3837
|
-
var
|
|
3838
|
-
function
|
|
3964
|
+
var Lr = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
3965
|
+
function Rr(e) {
|
|
3839
3966
|
if (typeof e == "boolean") return e;
|
|
3840
3967
|
if (typeof e == "object" && e) {
|
|
3841
3968
|
let t = e.endpoint;
|
|
3842
3969
|
return typeof t == "string" ? { endpoint: t } : {};
|
|
3843
3970
|
}
|
|
3844
3971
|
}
|
|
3845
|
-
function
|
|
3972
|
+
function zr() {
|
|
3846
3973
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
3847
3974
|
if (e) return {
|
|
3848
3975
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -3852,7 +3979,7 @@ function Dr() {
|
|
|
3852
3979
|
autoplay: e.autoplay ?? !0,
|
|
3853
3980
|
muted: e.muted ?? !0,
|
|
3854
3981
|
waitForLive: e.waitForLive ?? !0,
|
|
3855
|
-
analytics:
|
|
3982
|
+
analytics: Rr(e.analytics)
|
|
3856
3983
|
};
|
|
3857
3984
|
let t = new URLSearchParams(location.search);
|
|
3858
3985
|
return {
|
|
@@ -3865,9 +3992,9 @@ function Dr() {
|
|
|
3865
3992
|
waitForLive: !0
|
|
3866
3993
|
};
|
|
3867
3994
|
}
|
|
3868
|
-
async function
|
|
3869
|
-
let e =
|
|
3870
|
-
|
|
3995
|
+
async function Br() {
|
|
3996
|
+
let e = zr();
|
|
3997
|
+
Hr();
|
|
3871
3998
|
let t = document.createElement("video");
|
|
3872
3999
|
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);
|
|
3873
4000
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -3923,12 +4050,12 @@ async function Or() {
|
|
|
3923
4050
|
message: e.message,
|
|
3924
4051
|
...e.country === void 0 ? {} : { country: e.country }
|
|
3925
4052
|
})), e.on("autoplayblocked", () => {
|
|
3926
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
4053
|
+
i({ type: "oddin:autoplayblocked" }), Vr(t, e);
|
|
3927
4054
|
});
|
|
3928
4055
|
}, s = async (r) => {
|
|
3929
4056
|
a?.destroy(), a = null;
|
|
3930
4057
|
try {
|
|
3931
|
-
let n = await
|
|
4058
|
+
let n = await Pr({
|
|
3932
4059
|
video: t,
|
|
3933
4060
|
baseUrl: e.baseUrl,
|
|
3934
4061
|
matchUrn: r,
|
|
@@ -3991,7 +4118,7 @@ async function Or() {
|
|
|
3991
4118
|
a?.retry();
|
|
3992
4119
|
break;
|
|
3993
4120
|
case "oddin:load":
|
|
3994
|
-
typeof e.matchUrn == "string" &&
|
|
4121
|
+
typeof e.matchUrn == "string" && Lr.test(e.matchUrn) && s(e.matchUrn);
|
|
3995
4122
|
break;
|
|
3996
4123
|
case "oddin:destroy": c();
|
|
3997
4124
|
}
|
|
@@ -4003,18 +4130,18 @@ async function Or() {
|
|
|
4003
4130
|
protocol: 1
|
|
4004
4131
|
});
|
|
4005
4132
|
}
|
|
4006
|
-
function
|
|
4133
|
+
function Vr(e, t) {
|
|
4007
4134
|
if (document.getElementById("havik-tap")) return;
|
|
4008
4135
|
let n = document.createElement("button");
|
|
4009
4136
|
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", () => {
|
|
4010
4137
|
n.remove(), t.play();
|
|
4011
4138
|
}), document.body.appendChild(n);
|
|
4012
4139
|
}
|
|
4013
|
-
function
|
|
4140
|
+
function Hr() {
|
|
4014
4141
|
let e = document.createElement("style");
|
|
4015
4142
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
4016
4143
|
}
|
|
4017
4144
|
//#endregion
|
|
4018
|
-
export {
|
|
4145
|
+
export { or as ODDIN_THEME, n as PlaybackError, cr as applyTheme, at as baseUrlForEnv, Br as bootEmbed, Ee as clearDeviceId, Re as clearRememberedBandwidth, Pr as createPlayer, D as deriveEventsBaseUrl, tt as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, ve as fetchCatalog, be as fetchTournament, Se as flattenMatches, C as fullscreenSupported, A as getDeviceId, rt as isLowLatencyManifest, $ as isOddinMessage, Oe as licenseRequestHeaders, Ir as mountEmbed, fe as pollToLive, y as resolveStream, E as subscribeLiveState, S as videoFullscreenActive, we as watchStatus };
|
|
4019
4146
|
|
|
4020
4147
|
//# sourceMappingURL=index.js.map
|