@oddin-gg/havik-player 2.22.1 → 2.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/havik-player.global.js +22 -20
- 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 +367 -248
- package/dist/index.js.map +1 -1
- package/docs/API.md +96 -53
- package/embed/index.html +1 -1
- package/examples/vanilla.html +1 -1
- package/package.json +2 -2
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 wn = 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;
|
|
@@ -1593,11 +1616,11 @@ var wn = class {
|
|
|
1593
1616
|
frameCounter;
|
|
1594
1617
|
detachFrames = null;
|
|
1595
1618
|
constructor(e) {
|
|
1596
|
-
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;
|
|
1597
1620
|
}
|
|
1598
1621
|
async load() {
|
|
1599
1622
|
this.detachFrames ??= this.frameCounter.attach();
|
|
1600
|
-
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;
|
|
1601
1624
|
if (e.drmEnabled && !o) {
|
|
1602
1625
|
i({
|
|
1603
1626
|
type: "error",
|
|
@@ -1629,7 +1652,7 @@ var wn = class {
|
|
|
1629
1652
|
}
|
|
1630
1653
|
this.loadSuspended = !0;
|
|
1631
1654
|
}
|
|
1632
|
-
},
|
|
1655
|
+
}, tn));
|
|
1633
1656
|
}
|
|
1634
1657
|
resumeLoading() {
|
|
1635
1658
|
if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
|
|
@@ -1661,7 +1684,7 @@ var wn = class {
|
|
|
1661
1684
|
let t = e.liveSyncPosition;
|
|
1662
1685
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
1663
1686
|
let { video: n } = this.deps;
|
|
1664
|
-
n.currentTime <= t +
|
|
1687
|
+
n.currentTime <= t + xn || (n.currentTime = t);
|
|
1665
1688
|
}
|
|
1666
1689
|
reanchorPartTimeline(e, t) {
|
|
1667
1690
|
let { frag: n, part: r } = t;
|
|
@@ -1673,7 +1696,7 @@ var wn = class {
|
|
|
1673
1696
|
let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
|
|
1674
1697
|
if (!s) return;
|
|
1675
1698
|
let c = a.startPTS - s.start;
|
|
1676
|
-
if (!(!Number.isFinite(c) || Math.abs(c) <
|
|
1699
|
+
if (!(!Number.isFinite(c) || Math.abs(c) < Jt)) {
|
|
1677
1700
|
for (let e of i.fragments) e && e.setStart(e.start + c);
|
|
1678
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})`);
|
|
1679
1702
|
}
|
|
@@ -1681,7 +1704,7 @@ var wn = class {
|
|
|
1681
1704
|
startHls() {
|
|
1682
1705
|
let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
|
|
1683
1706
|
this.clearKick(), this.resetStarvationWindow(), this.resetChaseWindow(), this.resetFrameDropWindow(), this.lastFragLoadingMs = 0, this.lastEndSN = -1, this.lastAdvanceMs = 0;
|
|
1684
|
-
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 = {
|
|
1685
1708
|
debug: s === !0,
|
|
1686
1709
|
enableWorker: !o,
|
|
1687
1710
|
lowLatencyMode: o,
|
|
@@ -1708,12 +1731,12 @@ var wn = class {
|
|
|
1708
1731
|
this.licenseTimeMs === 0 && (this.licenseTimeMs = Math.max(1, Math.round(performance.now() - o)));
|
|
1709
1732
|
});
|
|
1710
1733
|
}, { freshLicenseUrl: c } = this.deps;
|
|
1711
|
-
if (!c || !
|
|
1734
|
+
if (!c || !G(this.licenseUrl)) {
|
|
1712
1735
|
s();
|
|
1713
1736
|
return;
|
|
1714
1737
|
}
|
|
1715
1738
|
let l = this.hls, u, d = new Promise((e) => {
|
|
1716
|
-
u = setTimeout(() => e(void 0),
|
|
1739
|
+
u = setTimeout(() => e(void 0), Wt);
|
|
1717
1740
|
});
|
|
1718
1741
|
return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
|
|
1719
1742
|
if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
|
|
@@ -1729,20 +1752,20 @@ var wn = class {
|
|
|
1729
1752
|
...c
|
|
1730
1753
|
};
|
|
1731
1754
|
if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !f.fLoader) {
|
|
1732
|
-
let e = new
|
|
1755
|
+
let e = new Mt({
|
|
1733
1756
|
sessionId: n.analytics?.sid,
|
|
1734
1757
|
contentId: n.matchUrn
|
|
1735
|
-
}), t =
|
|
1758
|
+
}), t = Nt(e);
|
|
1736
1759
|
t && (this.prefetch = e, f.fLoader = t);
|
|
1737
1760
|
}
|
|
1738
|
-
|
|
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;
|
|
1739
1762
|
let p = new e(f);
|
|
1740
|
-
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, () => {
|
|
1741
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" });
|
|
1742
1765
|
}), p.on(e.Events.FRAG_BUFFERED, (e, t) => {
|
|
1743
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(() => {
|
|
1744
1767
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
|
|
1745
|
-
},
|
|
1768
|
+
}, Gt)));
|
|
1746
1769
|
}), p.on(e.Events.FRAG_LOADING, (e, t) => {
|
|
1747
1770
|
t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
|
|
1748
1771
|
}), p.on(e.Events.FRAG_LOADED, (e, t) => {
|
|
@@ -1750,10 +1773,10 @@ var wn = class {
|
|
|
1750
1773
|
let n = t?.frag?.stats, r = n?.loaded;
|
|
1751
1774
|
typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
|
|
1752
1775
|
let i = n?.loading;
|
|
1753
|
-
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);
|
|
1754
1777
|
let a = t?.frag?.url;
|
|
1755
1778
|
if (a) {
|
|
1756
|
-
let e =
|
|
1779
|
+
let e = st(a);
|
|
1757
1780
|
e && (this.cdnHost = e);
|
|
1758
1781
|
}
|
|
1759
1782
|
}), p.on(e.Events.LEVEL_LOADED, (e, t) => {
|
|
@@ -1767,15 +1790,15 @@ var wn = class {
|
|
|
1767
1790
|
}), p.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
|
|
1768
1791
|
let t = this.prefetch;
|
|
1769
1792
|
p.on(e.Events.KEY_LOADING, (e, n) => {
|
|
1770
|
-
let r = n?.frag, i =
|
|
1771
|
-
if (r && t.isActive(i)) for (let e of
|
|
1772
|
-
}), 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)));
|
|
1773
1796
|
}
|
|
1774
1797
|
p.on(e.Events.KEY_LOADED, () => {
|
|
1775
1798
|
u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
|
|
1776
1799
|
}), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
|
|
1777
|
-
this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.checkFrameDrops();
|
|
1778
|
-
},
|
|
1800
|
+
this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.adaptHoldBack(), this.checkFrameDrops();
|
|
1801
|
+
}, qt), p.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
1779
1802
|
this.renditionSwitches += 1;
|
|
1780
1803
|
let n = this.lastLevelIndex >= 0 ? p.levels[this.lastLevelIndex] : void 0, r = p.levels[t.level];
|
|
1781
1804
|
n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, this.armFrameDropGrace(), l({
|
|
@@ -1826,9 +1849,9 @@ var wn = class {
|
|
|
1826
1849
|
let o = e.config ?? {}, s = typeof self < "u" && self.devicePixelRatio > 0 ? self.devicePixelRatio : 1, c = o.ignoreDevicePixelRatio ? 1 : s;
|
|
1827
1850
|
c = Math.min(c, o.maxDevicePixelRatio ?? Infinity);
|
|
1828
1851
|
let l = t.getMaxLevelByMediaSize(e.levels, i * c, a * c), u = this.deps.sizeCapHeadroom;
|
|
1829
|
-
if (u == null && s >=
|
|
1830
|
-
let d = u ??
|
|
1831
|
-
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);
|
|
1832
1855
|
}
|
|
1833
1856
|
onMediaResize() {
|
|
1834
1857
|
if (!this.sizeCapManaged) return;
|
|
@@ -1843,7 +1866,7 @@ var wn = class {
|
|
|
1843
1866
|
return;
|
|
1844
1867
|
}
|
|
1845
1868
|
this.capTimer && clearTimeout(this.capTimer);
|
|
1846
|
-
let t = e > this.sizeCapLevel ?
|
|
1869
|
+
let t = e > this.sizeCapLevel ? un : dn;
|
|
1847
1870
|
this.capTimer = setTimeout(() => {
|
|
1848
1871
|
this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
|
|
1849
1872
|
}, t);
|
|
@@ -1925,6 +1948,7 @@ var wn = class {
|
|
|
1925
1948
|
playlistBytesLoaded: this.playlistBytesLoaded,
|
|
1926
1949
|
renditionSwitches: this.renditionSwitches,
|
|
1927
1950
|
liveRetargets: this.liveRetargets,
|
|
1951
|
+
holdBackSteps: this.holdBackSteps,
|
|
1928
1952
|
fpsDownCaps: this.fpsDownCaps,
|
|
1929
1953
|
licenseTimeMs: this.licenseTimeMs,
|
|
1930
1954
|
upshifts: this.upshifts,
|
|
@@ -1953,9 +1977,10 @@ var wn = class {
|
|
|
1953
1977
|
let t = e.details;
|
|
1954
1978
|
if (t) {
|
|
1955
1979
|
if (t.live === !0) {
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
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());
|
|
1959
1984
|
return;
|
|
1960
1985
|
}
|
|
1961
1986
|
this.sawLive && this.emitEnded("endlist");
|
|
@@ -1972,7 +1997,7 @@ var wn = class {
|
|
|
1972
1997
|
return;
|
|
1973
1998
|
}
|
|
1974
1999
|
let e = Date.now() - this.lastAdvanceMs;
|
|
1975
|
-
!this.chaseSuspended && e >
|
|
2000
|
+
!this.chaseSuspended && e > Yt && this.suspendChasing(), e > Kt && this.emitEnded("stalled");
|
|
1976
2001
|
}
|
|
1977
2002
|
resetStarvationWindow() {
|
|
1978
2003
|
this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
|
|
@@ -1987,7 +2012,7 @@ var wn = class {
|
|
|
1987
2012
|
this.resetStarvationWindow();
|
|
1988
2013
|
return;
|
|
1989
2014
|
}
|
|
1990
|
-
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;
|
|
1991
2016
|
if (this.starvedFrames = c, !a || l) {
|
|
1992
2017
|
(t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
|
|
1993
2018
|
return;
|
|
@@ -1996,12 +2021,12 @@ var wn = class {
|
|
|
1996
2021
|
this.resetStarvationWindow();
|
|
1997
2022
|
return;
|
|
1998
2023
|
}
|
|
1999
|
-
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)) {
|
|
2000
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");
|
|
2001
2026
|
return;
|
|
2002
2027
|
}
|
|
2003
|
-
let u = i && this.starvedTicks >=
|
|
2004
|
-
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))) {
|
|
2005
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");
|
|
2006
2031
|
try {
|
|
2007
2032
|
e.stopLoad(), e.startLoad(-1);
|
|
@@ -2016,7 +2041,7 @@ var wn = class {
|
|
|
2016
2041
|
let t = e.latency, n = e.targetLatency;
|
|
2017
2042
|
if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
|
|
2018
2043
|
let r = t - n;
|
|
2019
|
-
!this.catchUpEngaged && r >
|
|
2044
|
+
!this.catchUpEngaged && r > Xt ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= Xt && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
|
|
2020
2045
|
let i = this.catchUpEngaged ? this.catchUpRate : 1;
|
|
2021
2046
|
e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
|
|
2022
2047
|
}
|
|
@@ -2029,7 +2054,7 @@ var wn = class {
|
|
|
2029
2054
|
}), n < 0 ? 0 : n;
|
|
2030
2055
|
}
|
|
2031
2056
|
armFrameDropGrace() {
|
|
2032
|
-
this.fpsGraceTicks > 0 || (this.fpsGraceTicks =
|
|
2057
|
+
this.fpsGraceTicks > 0 || (this.fpsGraceTicks = vn, this.fpsBadTicks = 0);
|
|
2033
2058
|
}
|
|
2034
2059
|
resetFrameDropWindow() {
|
|
2035
2060
|
this.fpsLastFrames = -1, this.fpsLastDropped = -1, this.fpsBadTicks = 0;
|
|
@@ -2040,8 +2065,8 @@ var wn = class {
|
|
|
2040
2065
|
this.resetFrameDropWindow();
|
|
2041
2066
|
return;
|
|
2042
2067
|
}
|
|
2043
|
-
let { totalFrames: n, dropped: r } =
|
|
2044
|
-
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) {
|
|
2045
2070
|
this.fpsBadTicks = 0;
|
|
2046
2071
|
return;
|
|
2047
2072
|
}
|
|
@@ -2049,11 +2074,11 @@ var wn = class {
|
|
|
2049
2074
|
--this.fpsGraceTicks, this.fpsBadTicks = 0;
|
|
2050
2075
|
return;
|
|
2051
2076
|
}
|
|
2052
|
-
if (o <=
|
|
2077
|
+
if (o <= hn * a) {
|
|
2053
2078
|
this.fpsBadTicks = 0;
|
|
2054
2079
|
return;
|
|
2055
2080
|
}
|
|
2056
|
-
if (this.fpsBadTicks += 1, this.fpsBadTicks <
|
|
2081
|
+
if (this.fpsBadTicks += 1, this.fpsBadTicks < _n) return;
|
|
2057
2082
|
this.fpsBadTicks = 0;
|
|
2058
2083
|
let s = e.levels, c = s[e.currentLevel];
|
|
2059
2084
|
if (!c) return;
|
|
@@ -2070,20 +2095,113 @@ var wn = class {
|
|
|
2070
2095
|
return;
|
|
2071
2096
|
}
|
|
2072
2097
|
let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
|
|
2073
|
-
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))) {
|
|
2074
2099
|
this.resetChaseWindow();
|
|
2075
2100
|
return;
|
|
2076
2101
|
}
|
|
2077
|
-
if (this.chaseLatency < 0 || this.chaseLatency - n >=
|
|
2102
|
+
if (this.chaseLatency < 0 || this.chaseLatency - n >= Qt) {
|
|
2078
2103
|
this.chaseLatency = n, this.chaseTicks = 0;
|
|
2079
2104
|
return;
|
|
2080
2105
|
}
|
|
2081
|
-
if (this.chaseTicks += 1, this.chaseTicks <
|
|
2106
|
+
if (this.chaseTicks += 1, this.chaseTicks < Zt) return;
|
|
2082
2107
|
this.resetChaseWindow();
|
|
2083
2108
|
let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
|
|
2084
2109
|
if (!(a > 1)) return;
|
|
2085
|
-
let o =
|
|
2086
|
-
|
|
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
|
+
});
|
|
2087
2205
|
}
|
|
2088
2206
|
suspendChasing() {
|
|
2089
2207
|
let e = this.hls;
|
|
@@ -2113,12 +2231,12 @@ var wn = class {
|
|
|
2113
2231
|
} catch {}
|
|
2114
2232
|
}
|
|
2115
2233
|
startEstimate() {
|
|
2116
|
-
return this.deps.rememberBandwidth === !1 ?
|
|
2234
|
+
return this.deps.rememberBandwidth === !1 ? Rt : Ie() ?? Rt;
|
|
2117
2235
|
}
|
|
2118
2236
|
maybeRememberBandwidth(e) {
|
|
2119
|
-
if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded <
|
|
2237
|
+
if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < zt) return;
|
|
2120
2238
|
let t = Date.now();
|
|
2121
|
-
if (!e && t - this.bwSavedAt <
|
|
2239
|
+
if (!e && t - this.bwSavedAt < Bt) return;
|
|
2122
2240
|
let n = this.hls?.bandwidthEstimate;
|
|
2123
2241
|
typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Le(n));
|
|
2124
2242
|
}
|
|
@@ -2138,7 +2256,7 @@ var wn = class {
|
|
|
2138
2256
|
scheduleLicenseRetry(t) {
|
|
2139
2257
|
if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
|
|
2140
2258
|
let n = t.response?.code ?? 0;
|
|
2141
|
-
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;
|
|
2142
2260
|
this.licenseRecoveries += 1;
|
|
2143
2261
|
let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
|
|
2144
2262
|
return this.licenseRetryTimer = setTimeout(() => {
|
|
@@ -2170,7 +2288,7 @@ var wn = class {
|
|
|
2170
2288
|
return;
|
|
2171
2289
|
}
|
|
2172
2290
|
if (t.type === e.ErrorTypes.NETWORK_ERROR) {
|
|
2173
|
-
if (this.networkRecoveries <
|
|
2291
|
+
if (this.networkRecoveries < Ht) {
|
|
2174
2292
|
this.networkRecoveries += 1;
|
|
2175
2293
|
let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
|
|
2176
2294
|
this.networkRetryTimer = setTimeout(() => {
|
|
@@ -2187,7 +2305,7 @@ var wn = class {
|
|
|
2187
2305
|
return;
|
|
2188
2306
|
}
|
|
2189
2307
|
if (t.type === e.ErrorTypes.MEDIA_ERROR) {
|
|
2190
|
-
if (this.mediaRecoveries <
|
|
2308
|
+
if (this.mediaRecoveries < Vt) {
|
|
2191
2309
|
this.mediaRecoveries += 1, n.recoverMediaError();
|
|
2192
2310
|
return;
|
|
2193
2311
|
}
|
|
@@ -2208,22 +2326,18 @@ var wn = class {
|
|
|
2208
2326
|
}
|
|
2209
2327
|
}
|
|
2210
2328
|
toError(t, r = "PLAYBACK") {
|
|
2211
|
-
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;
|
|
2212
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);
|
|
2213
2331
|
}
|
|
2214
|
-
},
|
|
2332
|
+
}, In = 15e3, Ln = 6e5, Rn = 3e5, zn = 100, J = 1, Bn = 1e3, Vn = 3e4, Hn = 1e3, Un = {
|
|
2215
2333
|
inline: "PRESENTATION_INLINE",
|
|
2216
2334
|
fullscreen: "PRESENTATION_FULLSCREEN",
|
|
2217
2335
|
pip: "PRESENTATION_PIP"
|
|
2218
|
-
},
|
|
2336
|
+
}, Wn = {
|
|
2219
2337
|
widevine: "KEY_SYSTEM_WIDEVINE",
|
|
2220
2338
|
fairplay: "KEY_SYSTEM_FAIRPLAY",
|
|
2221
2339
|
none: "KEY_SYSTEM_NONE"
|
|
2222
|
-
}
|
|
2223
|
-
function Pn(e, t) {
|
|
2224
|
-
return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
|
|
2225
|
-
}
|
|
2226
|
-
var Fn = /* @__PURE__ */ new Set([
|
|
2340
|
+
}, Gn = /* @__PURE__ */ new Set([
|
|
2227
2341
|
"INVALID_URN",
|
|
2228
2342
|
"NOT_FOUND",
|
|
2229
2343
|
"GEO_DENIED",
|
|
@@ -2234,7 +2348,7 @@ var Fn = /* @__PURE__ */ new Set([
|
|
|
2234
2348
|
"FORBIDDEN",
|
|
2235
2349
|
"RATE_LIMITED",
|
|
2236
2350
|
"TIMEOUT"
|
|
2237
|
-
]),
|
|
2351
|
+
]), Y = {
|
|
2238
2352
|
idle: "PLAYER_STATE_IDLE",
|
|
2239
2353
|
waiting: "PLAYER_STATE_WAITING",
|
|
2240
2354
|
loading: "PLAYER_STATE_LOADING",
|
|
@@ -2244,7 +2358,7 @@ var Fn = /* @__PURE__ */ new Set([
|
|
|
2244
2358
|
ended: "PLAYER_STATE_ENDED",
|
|
2245
2359
|
error: "PLAYER_STATE_ERROR"
|
|
2246
2360
|
};
|
|
2247
|
-
function
|
|
2361
|
+
function Kn(e) {
|
|
2248
2362
|
try {
|
|
2249
2363
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
2250
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);
|
|
@@ -2252,8 +2366,8 @@ function In(e) {
|
|
|
2252
2366
|
return;
|
|
2253
2367
|
}
|
|
2254
2368
|
}
|
|
2255
|
-
var
|
|
2256
|
-
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) {
|
|
2257
2371
|
if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
|
|
2258
2372
|
let t;
|
|
2259
2373
|
try {
|
|
@@ -2262,19 +2376,19 @@ function Bn(e) {
|
|
|
2262
2376
|
} catch {
|
|
2263
2377
|
return;
|
|
2264
2378
|
}
|
|
2265
|
-
if (
|
|
2266
|
-
|
|
2267
|
-
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();
|
|
2268
2382
|
}
|
|
2269
2383
|
}
|
|
2270
|
-
function
|
|
2384
|
+
function Zn(e, t) {
|
|
2271
2385
|
return _(t, e), { disabledReason: t };
|
|
2272
2386
|
}
|
|
2273
|
-
function
|
|
2274
|
-
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 };
|
|
2275
2389
|
if (t) return { endpoint: t };
|
|
2276
|
-
if (t !== void 0) return
|
|
2277
|
-
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);
|
|
2278
2392
|
if (r) return { endpoint: r };
|
|
2279
2393
|
let i;
|
|
2280
2394
|
try {
|
|
@@ -2282,9 +2396,9 @@ function Vn(e, t, n) {
|
|
|
2282
2396
|
} catch {
|
|
2283
2397
|
i = e;
|
|
2284
2398
|
}
|
|
2285
|
-
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).`);
|
|
2286
2400
|
}
|
|
2287
|
-
var
|
|
2401
|
+
var $n = class {
|
|
2288
2402
|
opts;
|
|
2289
2403
|
url;
|
|
2290
2404
|
cspKey;
|
|
@@ -2366,8 +2480,8 @@ var Hn = class {
|
|
|
2366
2480
|
constructor(e) {
|
|
2367
2481
|
this.opts = {
|
|
2368
2482
|
...e,
|
|
2369
|
-
heartbeatMs: e.heartbeatMs ??
|
|
2370
|
-
idleMs: e.idleMs ??
|
|
2483
|
+
heartbeatMs: e.heartbeatMs ?? In,
|
|
2484
|
+
idleMs: e.idleMs ?? Ln
|
|
2371
2485
|
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
|
|
2372
2486
|
try {
|
|
2373
2487
|
let e = new URL(this.url);
|
|
@@ -2384,11 +2498,11 @@ var Hn = class {
|
|
|
2384
2498
|
sdkVersion: this.opts.sdkVersion,
|
|
2385
2499
|
...this.opts.environment
|
|
2386
2500
|
};
|
|
2387
|
-
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());
|
|
2388
2502
|
}
|
|
2389
2503
|
checkSuspension(e) {
|
|
2390
2504
|
if (this.endedFlag || !this.opts.idleMs) return !1;
|
|
2391
|
-
let t = Math.max(this.opts.idleMs,
|
|
2505
|
+
let t = Math.max(this.opts.idleMs, Rn);
|
|
2392
2506
|
return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
|
|
2393
2507
|
}
|
|
2394
2508
|
syncIdle(e) {
|
|
@@ -2402,21 +2516,21 @@ var Hn = class {
|
|
|
2402
2516
|
noteStateChange(e, t, n, r) {
|
|
2403
2517
|
if (this.endedFlag || e === t) return;
|
|
2404
2518
|
let i = this.now();
|
|
2405
|
-
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") {
|
|
2406
2520
|
this.stallIsSeekInduced = this.seekInduced(i);
|
|
2407
2521
|
let e = !this.isHidden && !this.stallIsSeekInduced;
|
|
2408
|
-
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)));
|
|
2409
2523
|
} else e === "buffering" && (this.isBuffering = !1, this.stallIsSeekInduced = !1);
|
|
2410
2524
|
this.syncBuffering(), t === "paused" && (this.pauseCount += 1), this.syncIdle(t);
|
|
2411
2525
|
let a = {
|
|
2412
|
-
fromState:
|
|
2413
|
-
toState:
|
|
2414
|
-
presentation:
|
|
2526
|
+
fromState: Y[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2527
|
+
toState: Y[t] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2528
|
+
presentation: Un[this.presentation]
|
|
2415
2529
|
}, o = this.causeOf(e, t, i);
|
|
2416
2530
|
o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
2417
2531
|
}
|
|
2418
2532
|
seekInduced(e) {
|
|
2419
|
-
return this.lastSeekMs >= 0 && e - this.lastSeekMs <
|
|
2533
|
+
return this.lastSeekMs >= 0 && e - this.lastSeekMs < Hn;
|
|
2420
2534
|
}
|
|
2421
2535
|
causeOf(e, t, n) {
|
|
2422
2536
|
if (t === "error") return "TRANSITION_CAUSE_ERROR";
|
|
@@ -2453,25 +2567,25 @@ var Hn = class {
|
|
|
2453
2567
|
}
|
|
2454
2568
|
this.muteChanges += 1;
|
|
2455
2569
|
let r = this.now();
|
|
2456
|
-
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();
|
|
2457
2571
|
}
|
|
2458
2572
|
notePresentation(e) {
|
|
2459
2573
|
this.endedFlag || e === this.presentation || (this.closePresentation(), this.presentation = e);
|
|
2460
2574
|
}
|
|
2461
2575
|
notePlayIntent() {
|
|
2462
|
-
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));
|
|
2463
2577
|
}
|
|
2464
2578
|
noteReady() {
|
|
2465
|
-
this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(
|
|
2579
|
+
this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(J, this.now() - this.startupAnchorMs));
|
|
2466
2580
|
}
|
|
2467
2581
|
noteFirstPlaylist() {
|
|
2468
|
-
this.firstPlaylistMs === 0 && (this.firstPlaylistMs = Math.max(
|
|
2582
|
+
this.firstPlaylistMs === 0 && (this.firstPlaylistMs = Math.max(J, this.now() - this.startupAnchorMs));
|
|
2469
2583
|
}
|
|
2470
2584
|
noteDrmReady() {
|
|
2471
|
-
this.drmSetupMs === 0 && (this.drmSetupMs = Math.max(
|
|
2585
|
+
this.drmSetupMs === 0 && (this.drmSetupMs = Math.max(J, this.now() - this.startupAnchorMs));
|
|
2472
2586
|
}
|
|
2473
2587
|
noteFirstBytes() {
|
|
2474
|
-
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));
|
|
2475
2589
|
}
|
|
2476
2590
|
noteSeek() {
|
|
2477
2591
|
this.endedFlag || (this.seekCount += 1, this.lastSeekMs = this.now());
|
|
@@ -2490,7 +2604,7 @@ var Hn = class {
|
|
|
2490
2604
|
let r = n ?? "";
|
|
2491
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";
|
|
2492
2606
|
if (e === "DRM_CLIENT" || e === "DRM_DEVICE_REVOKED") return "ERROR_STAGE_DRM";
|
|
2493
|
-
if (
|
|
2607
|
+
if (Gn.has(e)) return "ERROR_STAGE_RESOLVE";
|
|
2494
2608
|
let i = t ?? "";
|
|
2495
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";
|
|
2496
2610
|
}
|
|
@@ -2522,7 +2636,7 @@ var Hn = class {
|
|
|
2522
2636
|
let l = t.droppedFrames ?? 0;
|
|
2523
2637
|
l > this.lastDropped && (o.droppedFramesDelta = l - this.lastDropped), this.lastDropped = l;
|
|
2524
2638
|
let u = t.renditionSwitches ?? 0;
|
|
2525
|
-
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";
|
|
2526
2640
|
let d = this.mutedTotalMs;
|
|
2527
2641
|
this.mutedSinceMs !== null && (d += e - this.mutedSinceMs), d > this.lastHbMutedMs && (o.mutedMsDelta = Math.round(d - this.lastHbMutedMs)), this.lastHbMutedMs = d;
|
|
2528
2642
|
let f = t.upshifts ?? 0;
|
|
@@ -2537,20 +2651,20 @@ var Hn = class {
|
|
|
2537
2651
|
if (this.lastRequestCount = g, _ > 0) {
|
|
2538
2652
|
o.requestCountDelta = _;
|
|
2539
2653
|
let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
|
|
2540
|
-
n.length > 0 && (o.requestTimeP50Ms =
|
|
2654
|
+
n.length > 0 && (o.requestTimeP50Ms = K(n, 50), o.requestTimeP95Ms = K(n, 95));
|
|
2541
2655
|
}
|
|
2542
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();
|
|
2543
2657
|
}
|
|
2544
2658
|
maybeEmitMediaInfo(e) {
|
|
2545
2659
|
if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
|
|
2546
2660
|
let t = {};
|
|
2547
|
-
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);
|
|
2548
2662
|
let n = JSON.stringify(t);
|
|
2549
2663
|
n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
|
|
2550
2664
|
}
|
|
2551
2665
|
end(e, t) {
|
|
2552
2666
|
if (this.endedFlag) return;
|
|
2553
|
-
this.endedFlag = !0,
|
|
2667
|
+
this.endedFlag = !0, Z.delete(this);
|
|
2554
2668
|
let n = t ?? this.now();
|
|
2555
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));
|
|
2556
2670
|
let r = this.safeSample();
|
|
@@ -2564,7 +2678,7 @@ var Hn = class {
|
|
|
2564
2678
|
let c = r?.positionMs ?? 0;
|
|
2565
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));
|
|
2566
2680
|
let l = e !== "END_REASON_ENDED";
|
|
2567
|
-
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);
|
|
2568
2682
|
let u = r?.decodedFrames ?? this.lastDecoded;
|
|
2569
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");
|
|
2570
2684
|
}
|
|
@@ -2584,13 +2698,13 @@ var Hn = class {
|
|
|
2584
2698
|
};
|
|
2585
2699
|
}
|
|
2586
2700
|
noteCspBlocked() {
|
|
2587
|
-
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)));
|
|
2588
2702
|
}
|
|
2589
2703
|
cspBlocked() {
|
|
2590
|
-
return !!this.cspKey &&
|
|
2704
|
+
return !!this.cspKey && X.has(this.cspKey);
|
|
2591
2705
|
}
|
|
2592
2706
|
enqueue(e) {
|
|
2593
|
-
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;) {
|
|
2594
2708
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
2595
2709
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
2596
2710
|
}
|
|
@@ -2617,7 +2731,7 @@ var Hn = class {
|
|
|
2617
2731
|
};
|
|
2618
2732
|
//#endregion
|
|
2619
2733
|
//#region src/core/environment.ts
|
|
2620
|
-
function
|
|
2734
|
+
function er() {
|
|
2621
2735
|
if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
|
|
2622
2736
|
let e;
|
|
2623
2737
|
try {
|
|
@@ -2642,14 +2756,14 @@ function Un() {
|
|
|
2642
2756
|
integration: "INTEGRATION_KIND_IFRAME"
|
|
2643
2757
|
};
|
|
2644
2758
|
}
|
|
2645
|
-
function
|
|
2759
|
+
function tr() {
|
|
2646
2760
|
if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
|
|
2647
2761
|
let e = navigator.userAgentData, t = e?.platform ?? "";
|
|
2648
2762
|
if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
|
|
2649
2763
|
let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
|
|
2650
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";
|
|
2651
2765
|
}
|
|
2652
|
-
function
|
|
2766
|
+
function nr() {
|
|
2653
2767
|
let e = typeof navigator < "u" ? navigator.connection : void 0;
|
|
2654
2768
|
if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
|
|
2655
2769
|
let t = {
|
|
@@ -2668,17 +2782,17 @@ function Gn() {
|
|
|
2668
2782
|
}
|
|
2669
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;
|
|
2670
2784
|
}
|
|
2671
|
-
function
|
|
2672
|
-
let t =
|
|
2673
|
-
deviceClass:
|
|
2785
|
+
function rr(e) {
|
|
2786
|
+
let t = er(), n = {
|
|
2787
|
+
deviceClass: tr(),
|
|
2674
2788
|
integration: t.integration,
|
|
2675
|
-
...
|
|
2789
|
+
...nr()
|
|
2676
2790
|
};
|
|
2677
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);
|
|
2678
2792
|
let r = e.getBoundingClientRect?.();
|
|
2679
2793
|
return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
|
|
2680
2794
|
}
|
|
2681
|
-
async function
|
|
2795
|
+
async function ir() {
|
|
2682
2796
|
let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
|
|
2683
2797
|
if (!e?.getHighEntropyValues) return {};
|
|
2684
2798
|
try {
|
|
@@ -2690,7 +2804,7 @@ async function qn() {
|
|
|
2690
2804
|
}
|
|
2691
2805
|
//#endregion
|
|
2692
2806
|
//#region src/core/version.ts
|
|
2693
|
-
var
|
|
2807
|
+
var ar = "2.23.1", or = {
|
|
2694
2808
|
accent: "#E1B600",
|
|
2695
2809
|
accentText: "#1B1C23",
|
|
2696
2810
|
background: "#0e0f13",
|
|
@@ -2701,7 +2815,7 @@ var Jn = "2.22.1", Yn = {
|
|
|
2701
2815
|
border: "rgba(255, 255, 255, 0.1)",
|
|
2702
2816
|
radius: "8px",
|
|
2703
2817
|
fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
|
|
2704
|
-
},
|
|
2818
|
+
}, sr = {
|
|
2705
2819
|
accent: "--havik-accent",
|
|
2706
2820
|
accentText: "--havik-accent-text",
|
|
2707
2821
|
background: "--havik-bg",
|
|
@@ -2713,26 +2827,26 @@ var Jn = "2.22.1", Yn = {
|
|
|
2713
2827
|
radius: "--havik-radius",
|
|
2714
2828
|
fontFamily: "--havik-font"
|
|
2715
2829
|
};
|
|
2716
|
-
function
|
|
2830
|
+
function cr(e, t) {
|
|
2717
2831
|
let n = {
|
|
2718
|
-
...
|
|
2832
|
+
...or,
|
|
2719
2833
|
...t
|
|
2720
2834
|
};
|
|
2721
|
-
for (let t of Object.keys(
|
|
2835
|
+
for (let t of Object.keys(sr)) e.style.setProperty(sr[t], n[t]);
|
|
2722
2836
|
n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
|
|
2723
2837
|
}
|
|
2724
2838
|
//#endregion
|
|
2725
2839
|
//#region src/ui/styles.ts
|
|
2726
|
-
var
|
|
2727
|
-
function
|
|
2728
|
-
let n = e.querySelector(`style#${
|
|
2729
|
-
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;
|
|
2730
2844
|
let r = e.createElement("style");
|
|
2731
|
-
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);
|
|
2732
2846
|
}
|
|
2733
2847
|
//#endregion
|
|
2734
2848
|
//#region src/ui/icons.ts
|
|
2735
|
-
var
|
|
2849
|
+
var pr = {
|
|
2736
2850
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
2737
2851
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
2738
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\"/>",
|
|
@@ -2746,11 +2860,11 @@ var nr = {
|
|
|
2746
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\"/>"
|
|
2747
2861
|
};
|
|
2748
2862
|
function Q(e) {
|
|
2749
|
-
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>`;
|
|
2750
2864
|
}
|
|
2751
2865
|
//#endregion
|
|
2752
2866
|
//#region src/ui/controls.ts
|
|
2753
|
-
var
|
|
2867
|
+
var mr = 3e3, hr = 250, gr = /* @__PURE__ */ new Set([
|
|
2754
2868
|
"GONE",
|
|
2755
2869
|
"NOT_FOUND",
|
|
2756
2870
|
"GEO_DENIED",
|
|
@@ -2758,15 +2872,15 @@ var rr = 3e3, ir = 250, ar = /* @__PURE__ */ new Set([
|
|
|
2758
2872
|
"UNAUTHORIZED",
|
|
2759
2873
|
"DRM_DEVICE_REVOKED"
|
|
2760
2874
|
]);
|
|
2761
|
-
function
|
|
2875
|
+
function _r(e) {
|
|
2762
2876
|
let t = "This match isn't available in your country";
|
|
2763
2877
|
return e ? `${t} (${e})` : t;
|
|
2764
2878
|
}
|
|
2765
|
-
var
|
|
2766
|
-
function
|
|
2767
|
-
return new
|
|
2879
|
+
var vr = "This device can't play protected video";
|
|
2880
|
+
function yr(e) {
|
|
2881
|
+
return new br(e);
|
|
2768
2882
|
}
|
|
2769
|
-
var
|
|
2883
|
+
var br = class {
|
|
2770
2884
|
root;
|
|
2771
2885
|
video;
|
|
2772
2886
|
player;
|
|
@@ -2814,7 +2928,7 @@ var lr = class {
|
|
|
2814
2928
|
scrubbing = !1;
|
|
2815
2929
|
offFns = [];
|
|
2816
2930
|
constructor(e) {
|
|
2817
|
-
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");
|
|
2818
2932
|
let t = (e, t, n) => {
|
|
2819
2933
|
let r = this.doc.createElement(e);
|
|
2820
2934
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -2900,7 +3014,7 @@ var lr = class {
|
|
|
2900
3014
|
let t = this.surfaceWasHidden;
|
|
2901
3015
|
this.tapTimer = setTimeout(() => {
|
|
2902
3016
|
this.tapTimer = void 0, this.toggleBar(t);
|
|
2903
|
-
},
|
|
3017
|
+
}, hr);
|
|
2904
3018
|
}
|
|
2905
3019
|
toggleBar(e) {
|
|
2906
3020
|
e ? this.poke() : this.hideIfIdle();
|
|
@@ -2920,7 +3034,7 @@ var lr = class {
|
|
|
2920
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);
|
|
2921
3035
|
}
|
|
2922
3036
|
statusMessageFor(e) {
|
|
2923
|
-
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;
|
|
2924
3038
|
}
|
|
2925
3039
|
renderStatus(e) {
|
|
2926
3040
|
let t = this.statusMessageFor(e);
|
|
@@ -2935,7 +3049,7 @@ var lr = class {
|
|
|
2935
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);
|
|
2936
3050
|
} else {
|
|
2937
3051
|
let r = this.doc.createElement("div");
|
|
2938
|
-
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)) {
|
|
2939
3053
|
let e = this.doc.createElement("button");
|
|
2940
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);
|
|
2941
3055
|
}
|
|
@@ -2976,7 +3090,7 @@ var lr = class {
|
|
|
2976
3090
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
2977
3091
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
2978
3092
|
}
|
|
2979
|
-
!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)}`);
|
|
2980
3094
|
}
|
|
2981
3095
|
syncLive() {
|
|
2982
3096
|
let e = this.player.getStats(), t = e.isLive !== !1, n = this.player.state === "ended", r = !t && !this.streamEnded();
|
|
@@ -3026,17 +3140,17 @@ var lr = class {
|
|
|
3026
3140
|
renderQualityMenu() {
|
|
3027
3141
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
3028
3142
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
3029
|
-
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)));
|
|
3030
3144
|
}
|
|
3031
3145
|
renderAudioMenu() {
|
|
3032
3146
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
3033
3147
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
3034
|
-
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)));
|
|
3035
3149
|
}
|
|
3036
3150
|
renderCcMenu() {
|
|
3037
3151
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
3038
3152
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
3039
|
-
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)));
|
|
3040
3154
|
}
|
|
3041
3155
|
onTracksChanged() {
|
|
3042
3156
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -3141,41 +3255,41 @@ var lr = class {
|
|
|
3141
3255
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
3142
3256
|
}
|
|
3143
3257
|
};
|
|
3144
|
-
function
|
|
3258
|
+
function xr(e) {
|
|
3145
3259
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
3146
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");
|
|
3147
3261
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
3148
3262
|
}
|
|
3149
|
-
function
|
|
3263
|
+
function Sr(e) {
|
|
3150
3264
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
3151
3265
|
}
|
|
3152
|
-
function
|
|
3266
|
+
function Cr(e) {
|
|
3153
3267
|
return e.name || e.lang || `Track ${e.id}`;
|
|
3154
3268
|
}
|
|
3155
|
-
function
|
|
3269
|
+
function wr(e) {
|
|
3156
3270
|
return e.name || e.lang || `Track ${e.id}`;
|
|
3157
3271
|
}
|
|
3158
3272
|
//#endregion
|
|
3159
3273
|
//#region src/managed/index.ts
|
|
3160
|
-
var
|
|
3161
|
-
function
|
|
3274
|
+
var Tr = 6e3, Er = 45e3, Dr = 2e3, Or = 3, kr = 5e3, Ar = 2e3, jr = 48e4, Mr = "keySystemLicenseRequestFailed";
|
|
3275
|
+
function Nr(e) {
|
|
3162
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)})`);
|
|
3163
3277
|
if (e.env !== void 0) return at(e.env);
|
|
3164
3278
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
|
|
3165
3279
|
return e.baseUrl;
|
|
3166
3280
|
}
|
|
3167
|
-
async function
|
|
3281
|
+
async function Pr(e) {
|
|
3168
3282
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
3169
|
-
let t =
|
|
3283
|
+
let t = Nr(e);
|
|
3170
3284
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
3171
3285
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
3172
|
-
let r = new
|
|
3286
|
+
let r = new Fr({
|
|
3173
3287
|
...e,
|
|
3174
3288
|
baseUrl: t
|
|
3175
3289
|
});
|
|
3176
3290
|
return await r.start(), r;
|
|
3177
3291
|
}
|
|
3178
|
-
var
|
|
3292
|
+
var Fr = class {
|
|
3179
3293
|
opts;
|
|
3180
3294
|
abort = new AbortController();
|
|
3181
3295
|
listeners = {};
|
|
@@ -3270,7 +3384,7 @@ var wr = class {
|
|
|
3270
3384
|
setTimeout(() => {
|
|
3271
3385
|
a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
3272
3386
|
phase: i ? "unavailable" : "tooEarly",
|
|
3273
|
-
retryInMs:
|
|
3387
|
+
retryInMs: Er,
|
|
3274
3388
|
attempt: 1,
|
|
3275
3389
|
elapsedMs: 0,
|
|
3276
3390
|
...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
|
|
@@ -3309,13 +3423,13 @@ var wr = class {
|
|
|
3309
3423
|
!a && !p() && h();
|
|
3310
3424
|
}, e);
|
|
3311
3425
|
};
|
|
3312
|
-
_(
|
|
3426
|
+
_(Tr), this.armingSub = E({
|
|
3313
3427
|
eventsBaseUrl: t,
|
|
3314
3428
|
matchUrn: this.opts.matchUrn,
|
|
3315
3429
|
credential: this.opts.credential,
|
|
3316
|
-
onAlive: () => _(
|
|
3430
|
+
onAlive: () => _(Er),
|
|
3317
3431
|
onState: (e) => {
|
|
3318
|
-
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);
|
|
3319
3433
|
},
|
|
3320
3434
|
onError: () => h()
|
|
3321
3435
|
});
|
|
@@ -3338,7 +3452,7 @@ var wr = class {
|
|
|
3338
3452
|
let n = await c(this.opts.credential);
|
|
3339
3453
|
if (this.destroyed || t !== this.loadGen) return;
|
|
3340
3454
|
this.setState("loading");
|
|
3341
|
-
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) => {
|
|
3342
3456
|
this._state !== "ended" && this._state !== "error" && this.setState(e);
|
|
3343
3457
|
});
|
|
3344
3458
|
if (await i.load(), this.destroyed || t !== this.loadGen) {
|
|
@@ -3360,26 +3474,26 @@ var wr = class {
|
|
|
3360
3474
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
|
|
3361
3475
|
let i = e.analytics?.sid;
|
|
3362
3476
|
if (!i) return;
|
|
3363
|
-
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);
|
|
3364
3478
|
if (!o) {
|
|
3365
3479
|
s && setTimeout(() => {
|
|
3366
3480
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
|
|
3367
3481
|
}, 0);
|
|
3368
3482
|
return;
|
|
3369
3483
|
}
|
|
3370
|
-
let c = this.opts.video, l = new
|
|
3484
|
+
let c = this.opts.video, l = new $n({
|
|
3371
3485
|
endpoint: o,
|
|
3372
3486
|
sid: i,
|
|
3373
3487
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
3374
|
-
sdkVersion:
|
|
3375
|
-
environment:
|
|
3488
|
+
sdkVersion: ar,
|
|
3489
|
+
environment: rr(c),
|
|
3376
3490
|
idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
|
|
3377
3491
|
onIdle: () => this.onAnalyticsIdle(t),
|
|
3378
3492
|
onBlocked: (e) => setTimeout(() => {
|
|
3379
3493
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
|
|
3380
3494
|
}, 0),
|
|
3381
3495
|
sample: () => {
|
|
3382
|
-
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;
|
|
3383
3497
|
return {
|
|
3384
3498
|
...e,
|
|
3385
3499
|
bufferedMs: Math.round(t * 1e3),
|
|
@@ -3393,7 +3507,7 @@ var wr = class {
|
|
|
3393
3507
|
let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
|
|
3394
3508
|
c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
|
|
3395
3509
|
c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
|
|
3396
|
-
}, 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");
|
|
3397
3511
|
}
|
|
3398
3512
|
currentPresentation() {
|
|
3399
3513
|
let e = this.opts.video;
|
|
@@ -3414,6 +3528,8 @@ var wr = class {
|
|
|
3414
3528
|
snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
|
|
3415
3529
|
rememberBandwidth: this.opts.rememberBandwidth,
|
|
3416
3530
|
sizeCapHeadroom: this.opts.sizeCapHeadroom,
|
|
3531
|
+
adaptiveHoldBack: this.opts.adaptiveHoldBack,
|
|
3532
|
+
adaptiveHoldBackCeiling: this.opts.adaptiveHoldBackCeiling,
|
|
3417
3533
|
mediaDuringKey: this.opts.mediaDuringKey,
|
|
3418
3534
|
debug: this.opts.debug,
|
|
3419
3535
|
deferLoad: r,
|
|
@@ -3421,11 +3537,11 @@ var wr = class {
|
|
|
3421
3537
|
emit: (e) => this.onEngineEvent(e),
|
|
3422
3538
|
freshLicenseUrl: () => this.refreshLicense()
|
|
3423
3539
|
}, o = this.opts.engine ?? "auto";
|
|
3424
|
-
if (o === "native") return new
|
|
3425
|
-
if (o === "hls") return new
|
|
3426
|
-
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl &&
|
|
3427
|
-
if (
|
|
3428
|
-
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);
|
|
3429
3545
|
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
3430
3546
|
}
|
|
3431
3547
|
onEngineEvent(e) {
|
|
@@ -3445,6 +3561,9 @@ var wr = class {
|
|
|
3445
3561
|
case "lowLatencyDetected":
|
|
3446
3562
|
this._descriptor && (this._descriptor.isLowLatency = e.value);
|
|
3447
3563
|
break;
|
|
3564
|
+
case "livetargetchange":
|
|
3565
|
+
this.emit("latencytargetchange", e.change);
|
|
3566
|
+
break;
|
|
3448
3567
|
case "qualitychange":
|
|
3449
3568
|
this.emit("qualitychange", e.index);
|
|
3450
3569
|
break;
|
|
@@ -3487,7 +3606,7 @@ var wr = class {
|
|
|
3487
3606
|
r = 0, i = !1;
|
|
3488
3607
|
},
|
|
3489
3608
|
onError: () => {
|
|
3490
|
-
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.`))));
|
|
3491
3610
|
}
|
|
3492
3611
|
});
|
|
3493
3612
|
}
|
|
@@ -3501,7 +3620,7 @@ var wr = class {
|
|
|
3501
3620
|
return;
|
|
3502
3621
|
}
|
|
3503
3622
|
let e = this.hiddenAtMs;
|
|
3504
|
-
this.hiddenAtMs = null, e != null && Date.now() - e >=
|
|
3623
|
+
this.hiddenAtMs = null, e != null && Date.now() - e >= kr && this.resyncLiveState();
|
|
3505
3624
|
}, this.onReturnPageShow = (e) => {
|
|
3506
3625
|
e.persisted && this.resyncLiveState();
|
|
3507
3626
|
}, document.addEventListener("visibilitychange", this.onReturnVisible), typeof window < "u" && window.addEventListener("pageshow", this.onReturnPageShow));
|
|
@@ -3533,7 +3652,7 @@ var wr = class {
|
|
|
3533
3652
|
scheduleRejoin(e) {
|
|
3534
3653
|
this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
|
|
3535
3654
|
this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
|
|
3536
|
-
}, Math.random() *
|
|
3655
|
+
}, Math.random() * Dr));
|
|
3537
3656
|
}
|
|
3538
3657
|
cancelRejoin() {
|
|
3539
3658
|
this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
|
|
@@ -3557,7 +3676,7 @@ var wr = class {
|
|
|
3557
3676
|
}
|
|
3558
3677
|
t.controls = !1;
|
|
3559
3678
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
3560
|
-
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({
|
|
3561
3680
|
root: n,
|
|
3562
3681
|
video: t,
|
|
3563
3682
|
player: this,
|
|
@@ -3595,7 +3714,7 @@ var wr = class {
|
|
|
3595
3714
|
}
|
|
3596
3715
|
startStats() {
|
|
3597
3716
|
this.stopStats();
|
|
3598
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
3717
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? Ar);
|
|
3599
3718
|
this.statsTimer = setInterval(() => {
|
|
3600
3719
|
if (!this.engine) return;
|
|
3601
3720
|
let e = this.engine.getStats();
|
|
@@ -3606,14 +3725,14 @@ var wr = class {
|
|
|
3606
3725
|
this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
|
|
3607
3726
|
}
|
|
3608
3727
|
isStaleLicenseDenial(e) {
|
|
3609
|
-
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);
|
|
3610
3729
|
}
|
|
3611
3730
|
scheduleLicenseRefresh() {
|
|
3612
3731
|
if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
|
|
3613
3732
|
typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
|
|
3614
|
-
document.visibilityState !== "visible" || this.destroyed ||
|
|
3733
|
+
document.visibilityState !== "visible" || this.destroyed || G(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
|
|
3615
3734
|
}, document.addEventListener("visibilitychange", this.onRefocus));
|
|
3616
|
-
let e = this.opts.licenseRefreshMs ??
|
|
3735
|
+
let e = this.opts.licenseRefreshMs ?? jr;
|
|
3617
3736
|
e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
3618
3737
|
}
|
|
3619
3738
|
stopRefresh() {
|
|
@@ -3670,7 +3789,7 @@ var wr = class {
|
|
|
3670
3789
|
this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
|
|
3671
3790
|
}
|
|
3672
3791
|
getStats() {
|
|
3673
|
-
return this.engine?.getStats() ??
|
|
3792
|
+
return this.engine?.getStats() ?? ot;
|
|
3674
3793
|
}
|
|
3675
3794
|
getQualityLevels() {
|
|
3676
3795
|
return this.engine?.getQualityLevels() ?? [];
|
|
@@ -3783,7 +3902,7 @@ function $(e) {
|
|
|
3783
3902
|
}
|
|
3784
3903
|
//#endregion
|
|
3785
3904
|
//#region src/embed/host.ts
|
|
3786
|
-
function
|
|
3905
|
+
function Ir(e) {
|
|
3787
3906
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
3788
3907
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
3789
3908
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -3842,15 +3961,15 @@ function Tr(e) {
|
|
|
3842
3961
|
}
|
|
3843
3962
|
//#endregion
|
|
3844
3963
|
//#region src/embed/page.ts
|
|
3845
|
-
var
|
|
3846
|
-
function
|
|
3964
|
+
var Lr = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
3965
|
+
function Rr(e) {
|
|
3847
3966
|
if (typeof e == "boolean") return e;
|
|
3848
3967
|
if (typeof e == "object" && e) {
|
|
3849
3968
|
let t = e.endpoint;
|
|
3850
3969
|
return typeof t == "string" ? { endpoint: t } : {};
|
|
3851
3970
|
}
|
|
3852
3971
|
}
|
|
3853
|
-
function
|
|
3972
|
+
function zr() {
|
|
3854
3973
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
3855
3974
|
if (e) return {
|
|
3856
3975
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -3860,7 +3979,7 @@ function Or() {
|
|
|
3860
3979
|
autoplay: e.autoplay ?? !0,
|
|
3861
3980
|
muted: e.muted ?? !0,
|
|
3862
3981
|
waitForLive: e.waitForLive ?? !0,
|
|
3863
|
-
analytics:
|
|
3982
|
+
analytics: Rr(e.analytics)
|
|
3864
3983
|
};
|
|
3865
3984
|
let t = new URLSearchParams(location.search);
|
|
3866
3985
|
return {
|
|
@@ -3873,9 +3992,9 @@ function Or() {
|
|
|
3873
3992
|
waitForLive: !0
|
|
3874
3993
|
};
|
|
3875
3994
|
}
|
|
3876
|
-
async function
|
|
3877
|
-
let e =
|
|
3878
|
-
|
|
3995
|
+
async function Br() {
|
|
3996
|
+
let e = zr();
|
|
3997
|
+
Hr();
|
|
3879
3998
|
let t = document.createElement("video");
|
|
3880
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);
|
|
3881
4000
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -3931,12 +4050,12 @@ async function kr() {
|
|
|
3931
4050
|
message: e.message,
|
|
3932
4051
|
...e.country === void 0 ? {} : { country: e.country }
|
|
3933
4052
|
})), e.on("autoplayblocked", () => {
|
|
3934
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
4053
|
+
i({ type: "oddin:autoplayblocked" }), Vr(t, e);
|
|
3935
4054
|
});
|
|
3936
4055
|
}, s = async (r) => {
|
|
3937
4056
|
a?.destroy(), a = null;
|
|
3938
4057
|
try {
|
|
3939
|
-
let n = await
|
|
4058
|
+
let n = await Pr({
|
|
3940
4059
|
video: t,
|
|
3941
4060
|
baseUrl: e.baseUrl,
|
|
3942
4061
|
matchUrn: r,
|
|
@@ -3999,7 +4118,7 @@ async function kr() {
|
|
|
3999
4118
|
a?.retry();
|
|
4000
4119
|
break;
|
|
4001
4120
|
case "oddin:load":
|
|
4002
|
-
typeof e.matchUrn == "string" &&
|
|
4121
|
+
typeof e.matchUrn == "string" && Lr.test(e.matchUrn) && s(e.matchUrn);
|
|
4003
4122
|
break;
|
|
4004
4123
|
case "oddin:destroy": c();
|
|
4005
4124
|
}
|
|
@@ -4011,18 +4130,18 @@ async function kr() {
|
|
|
4011
4130
|
protocol: 1
|
|
4012
4131
|
});
|
|
4013
4132
|
}
|
|
4014
|
-
function
|
|
4133
|
+
function Vr(e, t) {
|
|
4015
4134
|
if (document.getElementById("havik-tap")) return;
|
|
4016
4135
|
let n = document.createElement("button");
|
|
4017
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", () => {
|
|
4018
4137
|
n.remove(), t.play();
|
|
4019
4138
|
}), document.body.appendChild(n);
|
|
4020
4139
|
}
|
|
4021
|
-
function
|
|
4140
|
+
function Hr() {
|
|
4022
4141
|
let e = document.createElement("style");
|
|
4023
4142
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
4024
4143
|
}
|
|
4025
4144
|
//#endregion
|
|
4026
|
-
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 };
|
|
4027
4146
|
|
|
4028
4147
|
//# sourceMappingURL=index.js.map
|