@oddin-gg/havik-player 2.15.6 → 2.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/havik-player.global.js +2 -2
- package/dist/havik-player.global.js.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +191 -155
- package/dist/index.js.map +1 -1
- package/docs/API.md +2 -2
- package/embed/index.html +1 -1
- package/examples/vanilla.html +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -860,7 +860,8 @@ function qe(e, t) {
|
|
|
860
860
|
}
|
|
861
861
|
//#endregion
|
|
862
862
|
//#region src/core/engine/native.ts
|
|
863
|
-
|
|
863
|
+
var Je = 2e3, Ye = 3;
|
|
864
|
+
function Xe(e) {
|
|
864
865
|
try {
|
|
865
866
|
let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
|
|
866
867
|
return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
|
|
@@ -876,7 +877,7 @@ function G() {
|
|
|
876
877
|
let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
|
|
877
878
|
return e || t;
|
|
878
879
|
}
|
|
879
|
-
function
|
|
880
|
+
function Ze() {
|
|
880
881
|
if (typeof navigator > "u" || !G()) return !1;
|
|
881
882
|
let e = navigator.userAgent ?? "";
|
|
882
883
|
return /iPhone|iPad|iPod/.test(e) ? !0 : /Macintosh/.test(e) && typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1;
|
|
@@ -890,6 +891,9 @@ var K = class {
|
|
|
890
891
|
fairplayLicenseUrl;
|
|
891
892
|
keySession = null;
|
|
892
893
|
fairplayArmed = !1;
|
|
894
|
+
onVisibility = null;
|
|
895
|
+
onPageShow = null;
|
|
896
|
+
hiddenSince = null;
|
|
893
897
|
fairplayKeyIV;
|
|
894
898
|
loadStarted;
|
|
895
899
|
preloadTouched = !1;
|
|
@@ -901,7 +905,7 @@ var K = class {
|
|
|
901
905
|
}
|
|
902
906
|
async load() {
|
|
903
907
|
let { video: e, descriptor: t, emit: r } = this.deps;
|
|
904
|
-
if (this.loadStarted || (this.preloadTouched = !0, this.savedPreload = e.getAttribute("preload"), e.preload = "none"), t.drmEnabled) {
|
|
908
|
+
if (this.watchRefocus(), this.loadStarted || (this.preloadTouched = !0, this.savedPreload = e.getAttribute("preload"), e.preload = "none"), t.drmEnabled) {
|
|
905
909
|
if (!t.drm?.fairplay) {
|
|
906
910
|
r({
|
|
907
911
|
type: "error",
|
|
@@ -917,7 +921,7 @@ var K = class {
|
|
|
917
921
|
type: "error",
|
|
918
922
|
error: new n("INTERNAL", 0, "native HLS playback error"),
|
|
919
923
|
fatal: !0
|
|
920
|
-
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src =
|
|
924
|
+
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Qe(t.manifestUrl, t.analytics?.sid), e.load();
|
|
921
925
|
}
|
|
922
926
|
startLoad() {
|
|
923
927
|
this.loadStarted || (this.loadStarted = !0, this.restorePreload());
|
|
@@ -939,7 +943,7 @@ var K = class {
|
|
|
939
943
|
});
|
|
940
944
|
this.onEncrypted = (n) => {
|
|
941
945
|
let i = n;
|
|
942
|
-
i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV =
|
|
946
|
+
i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = Xe(i.initData), (async () => {
|
|
943
947
|
try {
|
|
944
948
|
let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
|
|
945
949
|
initDataTypes: [i.initDataType],
|
|
@@ -1038,14 +1042,46 @@ var K = class {
|
|
|
1038
1042
|
droppedFrames: t.dropped,
|
|
1039
1043
|
decodedFrames: t.totalFrames
|
|
1040
1044
|
};
|
|
1041
|
-
|
|
1045
|
+
if (this.cdnHost ||= Ke(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity) {
|
|
1046
|
+
if (n.isLive = !0, e.seekable.length > 0) {
|
|
1047
|
+
let t = e.seekable.end(e.seekable.length - 1);
|
|
1048
|
+
n.atLiveEdge = e.currentTime >= t - 2;
|
|
1049
|
+
let r = t - e.currentTime;
|
|
1050
|
+
Number.isFinite(r) && r >= 0 && (n.latencySeconds = r);
|
|
1051
|
+
}
|
|
1052
|
+
} else Number.isFinite(e.duration) && e.duration > 0 && (n.isLive = !1);
|
|
1053
|
+
return n;
|
|
1042
1054
|
}
|
|
1043
1055
|
stop() {
|
|
1044
1056
|
try {
|
|
1045
1057
|
this.deps.video.pause();
|
|
1046
1058
|
} catch {}
|
|
1047
1059
|
}
|
|
1060
|
+
watchRefocus() {
|
|
1061
|
+
this.deps.snapToLiveOnRefocus === !1 || typeof document > "u" || this.onVisibility || (this.onVisibility = () => {
|
|
1062
|
+
let e = typeof performance < "u" ? performance.now() : Date.now();
|
|
1063
|
+
if (document.visibilityState === "hidden") {
|
|
1064
|
+
this.hiddenSince = e;
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1067
|
+
let t = this.hiddenSince;
|
|
1068
|
+
this.hiddenSince = null, t != null && e - t >= Je && this.snapToLive();
|
|
1069
|
+
}, this.onPageShow = (e) => {
|
|
1070
|
+
e.persisted && this.snapToLive();
|
|
1071
|
+
}, document.addEventListener("visibilitychange", this.onVisibility), typeof window < "u" && window.addEventListener("pageshow", this.onPageShow));
|
|
1072
|
+
}
|
|
1073
|
+
snapToLive() {
|
|
1074
|
+
let e = this.deps.video;
|
|
1075
|
+
if (e.duration !== Infinity || e.seekable.length === 0) return;
|
|
1076
|
+
let t = e.seekable.start(e.seekable.length - 1), n = e.seekable.end(e.seekable.length - 1);
|
|
1077
|
+
if (!Number.isFinite(n)) return;
|
|
1078
|
+
let r = Math.max(t, n - Ye);
|
|
1079
|
+
try {
|
|
1080
|
+
e.currentTime = r;
|
|
1081
|
+
} catch {}
|
|
1082
|
+
}
|
|
1048
1083
|
destroy() {
|
|
1084
|
+
this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.onPageShow && typeof window < "u" && (window.removeEventListener("pageshow", this.onPageShow), this.onPageShow = null);
|
|
1049
1085
|
let { video: e } = this.deps;
|
|
1050
1086
|
this.onLoaded && e.removeEventListener("loadedmetadata", this.onLoaded), this.onError && e.removeEventListener("error", this.onError), this.onEncrypted && e.removeEventListener("encrypted", this.onEncrypted), this.keySession?.close().catch(() => {}), this.keySession = null, this.fairplayArmed = !1, this.fairplayKeyIV = void 0;
|
|
1051
1087
|
try {
|
|
@@ -1057,13 +1093,13 @@ var K = class {
|
|
|
1057
1093
|
} catch {}
|
|
1058
1094
|
}
|
|
1059
1095
|
};
|
|
1060
|
-
function
|
|
1096
|
+
function Qe(e, t) {
|
|
1061
1097
|
return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
|
|
1062
1098
|
}
|
|
1063
1099
|
//#endregion
|
|
1064
1100
|
//#region src/core/engine/prefetch.ts
|
|
1065
|
-
var
|
|
1066
|
-
function
|
|
1101
|
+
var $e = 15e3, et = 5e3, tt = 6;
|
|
1102
|
+
function nt(e) {
|
|
1067
1103
|
try {
|
|
1068
1104
|
let t = new URL(e);
|
|
1069
1105
|
return t.searchParams.delete("CMCD"), t.toString();
|
|
@@ -1071,7 +1107,7 @@ function et(e) {
|
|
|
1071
1107
|
return e;
|
|
1072
1108
|
}
|
|
1073
1109
|
}
|
|
1074
|
-
var
|
|
1110
|
+
var rt = class {
|
|
1075
1111
|
cmcd;
|
|
1076
1112
|
entries = /* @__PURE__ */ new Map();
|
|
1077
1113
|
keyed = /* @__PURE__ */ new Set();
|
|
@@ -1094,10 +1130,10 @@ var tt = class {
|
|
|
1094
1130
|
}
|
|
1095
1131
|
prefetch(e, t, n) {
|
|
1096
1132
|
if (!this.isActive(t)) return;
|
|
1097
|
-
let r =
|
|
1133
|
+
let r = nt(e);
|
|
1098
1134
|
if (this.entries.has(r)) return;
|
|
1099
1135
|
let i = this.perTrack.get(t) ?? 0;
|
|
1100
|
-
if (i >=
|
|
1136
|
+
if (i >= tt) return;
|
|
1101
1137
|
this.perTrack.set(t, i + 1);
|
|
1102
1138
|
let a = new AbortController(), o = {
|
|
1103
1139
|
started: performance.now(),
|
|
@@ -1111,10 +1147,10 @@ var tt = class {
|
|
|
1111
1147
|
signal: a.signal
|
|
1112
1148
|
}).then(async (e) => (o.first = performance.now(), e.ok ? e.arrayBuffer() : null)).catch(() => null), this.entries.set(r, o), this.stats.started += 1, setTimeout(() => {
|
|
1113
1149
|
this.entries.get(r) === o && (this.entries.delete(r), a.abort(), this.stats.expired += 1);
|
|
1114
|
-
},
|
|
1150
|
+
}, $e);
|
|
1115
1151
|
}
|
|
1116
1152
|
take(e) {
|
|
1117
|
-
let t =
|
|
1153
|
+
let t = nt(e), n = this.entries.get(t);
|
|
1118
1154
|
return n && this.entries.delete(t), n;
|
|
1119
1155
|
}
|
|
1120
1156
|
destroy() {
|
|
@@ -1134,13 +1170,13 @@ var tt = class {
|
|
|
1134
1170
|
}
|
|
1135
1171
|
}
|
|
1136
1172
|
};
|
|
1137
|
-
function
|
|
1173
|
+
function it(t) {
|
|
1138
1174
|
let n = e.DefaultConfig?.loader;
|
|
1139
1175
|
if (typeof n != "function") return;
|
|
1140
1176
|
class r extends n {
|
|
1141
1177
|
served = !1;
|
|
1142
1178
|
cancelled = !1;
|
|
1143
|
-
stats =
|
|
1179
|
+
stats = at();
|
|
1144
1180
|
load(e, n, r) {
|
|
1145
1181
|
let i = e.rangeEnd ? void 0 : t.take(e.url);
|
|
1146
1182
|
if (!i) {
|
|
@@ -1148,7 +1184,7 @@ function nt(t) {
|
|
|
1148
1184
|
return;
|
|
1149
1185
|
}
|
|
1150
1186
|
this.served = !0;
|
|
1151
|
-
let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs ||
|
|
1187
|
+
let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || et, s = setTimeout(() => {
|
|
1152
1188
|
!this.cancelled && this.served && (i.abort.abort(), t.stats.failed += 1, this.served = !1, super.load(e, n, r));
|
|
1153
1189
|
}, o);
|
|
1154
1190
|
i.bytes.then((o) => {
|
|
@@ -1175,7 +1211,7 @@ function nt(t) {
|
|
|
1175
1211
|
}
|
|
1176
1212
|
return r;
|
|
1177
1213
|
}
|
|
1178
|
-
function
|
|
1214
|
+
function at() {
|
|
1179
1215
|
return {
|
|
1180
1216
|
aborted: !1,
|
|
1181
1217
|
loaded: 0,
|
|
@@ -1199,10 +1235,10 @@ function rt() {
|
|
|
1199
1235
|
}
|
|
1200
1236
|
};
|
|
1201
1237
|
}
|
|
1202
|
-
function
|
|
1238
|
+
function ot(e) {
|
|
1203
1239
|
return e === "audio" ? "audio" : "main";
|
|
1204
1240
|
}
|
|
1205
|
-
function
|
|
1241
|
+
function st(e, t) {
|
|
1206
1242
|
let n = [];
|
|
1207
1243
|
t.initSegment?.url && !t.initSegment.data && n.push({
|
|
1208
1244
|
url: t.initSegment.url,
|
|
@@ -1221,24 +1257,24 @@ function at(e, t) {
|
|
|
1221
1257
|
}
|
|
1222
1258
|
//#endregion
|
|
1223
1259
|
//#region src/core/engine/hls.ts
|
|
1224
|
-
function
|
|
1260
|
+
function ct() {
|
|
1225
1261
|
return e.isSupported();
|
|
1226
1262
|
}
|
|
1227
|
-
var
|
|
1228
|
-
function
|
|
1263
|
+
var lt = 3, ut = 5, dt = 3, ft = 3e4, pt = 12e3, mt = 3e3, ht = 6e3, gt = .5, _t = 3, vt = .5, yt = 1.1, bt = .25, xt = 5e3, St = 4e3, Ct = 2, wt = 5, Tt = 2, Et = 2, Dt = 4, Ot = 4, kt = 2e3, At = 3e4, jt = .2, Mt = 30, Nt = 2, Pt = 2, Ft = 9, It = .5, Lt = 64;
|
|
1264
|
+
function Rt(e) {
|
|
1229
1265
|
if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
|
|
1230
1266
|
delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
|
|
1231
1267
|
return;
|
|
1232
1268
|
}
|
|
1233
|
-
e.liveSyncDuration ??=
|
|
1234
|
-
let t = Math.max(12, e.liveSyncDuration +
|
|
1235
|
-
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t),
|
|
1269
|
+
e.liveSyncDuration ??= Pt;
|
|
1270
|
+
let t = Math.max(12, e.liveSyncDuration + Ft);
|
|
1271
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), zt(e, e.liveSyncDuration);
|
|
1236
1272
|
}
|
|
1237
|
-
function
|
|
1273
|
+
function zt(e, t) {
|
|
1238
1274
|
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
1239
1275
|
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
1240
1276
|
}
|
|
1241
|
-
var
|
|
1277
|
+
var Bt = class {
|
|
1242
1278
|
name = "hls";
|
|
1243
1279
|
hls = null;
|
|
1244
1280
|
deps;
|
|
@@ -1351,7 +1387,7 @@ var Rt = class {
|
|
|
1351
1387
|
}
|
|
1352
1388
|
this.loadSuspended = !0;
|
|
1353
1389
|
}
|
|
1354
|
-
},
|
|
1390
|
+
}, xt));
|
|
1355
1391
|
}
|
|
1356
1392
|
resumeLoading() {
|
|
1357
1393
|
if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
|
|
@@ -1383,7 +1419,7 @@ var Rt = class {
|
|
|
1383
1419
|
let t = e.liveSyncPosition;
|
|
1384
1420
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
1385
1421
|
let { video: n } = this.deps;
|
|
1386
|
-
n.currentTime <= t +
|
|
1422
|
+
n.currentTime <= t + It || (n.currentTime = t);
|
|
1387
1423
|
}
|
|
1388
1424
|
startHls() {
|
|
1389
1425
|
let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
|
|
@@ -1424,20 +1460,20 @@ var Rt = class {
|
|
|
1424
1460
|
...c
|
|
1425
1461
|
};
|
|
1426
1462
|
if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !d.fLoader) {
|
|
1427
|
-
let e = new
|
|
1463
|
+
let e = new rt({
|
|
1428
1464
|
sessionId: n.analytics?.sid,
|
|
1429
1465
|
contentId: n.matchUrn
|
|
1430
|
-
}), t =
|
|
1466
|
+
}), t = it(e);
|
|
1431
1467
|
t && (this.prefetch = e, d.fLoader = t);
|
|
1432
1468
|
}
|
|
1433
|
-
|
|
1469
|
+
Rt(d), this.catchUpRate = typeof d.maxLiveSyncPlaybackRate == "number" ? d.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (d.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = d.autoStartLoad !== !1;
|
|
1434
1470
|
let f = new e(d);
|
|
1435
1471
|
if (this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
|
|
1436
1472
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(f), this.measureLadder(f), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
|
|
1437
1473
|
}), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
|
|
1438
1474
|
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(() => {
|
|
1439
1475
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
|
|
1440
|
-
},
|
|
1476
|
+
}, ft)));
|
|
1441
1477
|
}), f.on(e.Events.FRAG_LOADING, (e, t) => {
|
|
1442
1478
|
t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
|
|
1443
1479
|
}), f.on(e.Events.FRAG_LOADED, (e, t) => {
|
|
@@ -1445,7 +1481,7 @@ var Rt = class {
|
|
|
1445
1481
|
let n = t?.frag?.stats, r = n?.loaded;
|
|
1446
1482
|
typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
|
|
1447
1483
|
let i = n?.loading;
|
|
1448
|
-
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 >
|
|
1484
|
+
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 > Lt && this.requestTimesMs.shift());
|
|
1449
1485
|
let a = t?.frag?.url;
|
|
1450
1486
|
if (a) {
|
|
1451
1487
|
let e = H(a);
|
|
@@ -1462,15 +1498,15 @@ var Rt = class {
|
|
|
1462
1498
|
}), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
|
|
1463
1499
|
let t = this.prefetch;
|
|
1464
1500
|
f.on(e.Events.KEY_LOADING, (e, n) => {
|
|
1465
|
-
let r = n?.frag, i =
|
|
1466
|
-
if (r && t.isActive(i)) for (let e of
|
|
1467
|
-
}), f.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(
|
|
1501
|
+
let r = n?.frag, i = ot(r?.type);
|
|
1502
|
+
if (r && t.isActive(i)) for (let e of st(f, r)) t.prefetch(e.url, i, e.kind);
|
|
1503
|
+
}), f.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(ot(n?.frag?.type)));
|
|
1468
1504
|
}
|
|
1469
1505
|
f.on(e.Events.KEY_LOADED, () => {
|
|
1470
1506
|
u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
|
|
1471
1507
|
}), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
|
|
1472
1508
|
this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.checkFrameDrops();
|
|
1473
|
-
},
|
|
1509
|
+
}, mt), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
1474
1510
|
this.renditionSwitches += 1;
|
|
1475
1511
|
let n = this.lastLevelIndex >= 0 ? f.levels[this.lastLevelIndex] : void 0, r = f.levels[t.level];
|
|
1476
1512
|
n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
|
|
@@ -1534,7 +1570,7 @@ var Rt = class {
|
|
|
1534
1570
|
return;
|
|
1535
1571
|
}
|
|
1536
1572
|
this.capTimer && clearTimeout(this.capTimer);
|
|
1537
|
-
let t = e > this.sizeCapLevel ?
|
|
1573
|
+
let t = e > this.sizeCapLevel ? kt : At;
|
|
1538
1574
|
this.capTimer = setTimeout(() => {
|
|
1539
1575
|
this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
|
|
1540
1576
|
}, t);
|
|
@@ -1655,7 +1691,7 @@ var Rt = class {
|
|
|
1655
1691
|
return;
|
|
1656
1692
|
}
|
|
1657
1693
|
let e = Date.now() - this.lastAdvanceMs;
|
|
1658
|
-
!this.chaseSuspended && e >
|
|
1694
|
+
!this.chaseSuspended && e > ht && this.suspendChasing(), e > pt && this.emitEnded("stalled");
|
|
1659
1695
|
}
|
|
1660
1696
|
resetStarvationWindow() {
|
|
1661
1697
|
this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
|
|
@@ -1670,7 +1706,7 @@ var Rt = class {
|
|
|
1670
1706
|
this.resetStarvationWindow();
|
|
1671
1707
|
return;
|
|
1672
1708
|
}
|
|
1673
|
-
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs <
|
|
1709
|
+
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < ht, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > St, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = U(t), c = o - s, l = c !== this.starvedFrames;
|
|
1674
1710
|
if (this.starvedFrames = c, !a || l) {
|
|
1675
1711
|
(t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
|
|
1676
1712
|
return;
|
|
@@ -1679,12 +1715,12 @@ var Rt = class {
|
|
|
1679
1715
|
this.resetStarvationWindow();
|
|
1680
1716
|
return;
|
|
1681
1717
|
}
|
|
1682
|
-
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 >
|
|
1718
|
+
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 > Dt && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= Tt && (this.clearKick(), this.starvationRebuilds < Et)) {
|
|
1683
1719
|
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");
|
|
1684
1720
|
return;
|
|
1685
1721
|
}
|
|
1686
|
-
let u = i && this.starvedTicks >=
|
|
1687
|
-
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >=
|
|
1722
|
+
let u = i && this.starvedTicks >= Ct, d = !i && this.deadTicks >= Dt && this.recentMainFrags.reduce((e, t) => e + t, 0) >= Ot;
|
|
1723
|
+
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= wt))) {
|
|
1688
1724
|
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");
|
|
1689
1725
|
try {
|
|
1690
1726
|
e.stopLoad(), e.startLoad(-1);
|
|
@@ -1699,7 +1735,7 @@ var Rt = class {
|
|
|
1699
1735
|
let t = e.latency, n = e.targetLatency;
|
|
1700
1736
|
if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
|
|
1701
1737
|
let r = t - n;
|
|
1702
|
-
!this.catchUpEngaged && r >
|
|
1738
|
+
!this.catchUpEngaged && r > gt ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= gt && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
|
|
1703
1739
|
let i = this.catchUpEngaged ? this.catchUpRate : 1;
|
|
1704
1740
|
e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
|
|
1705
1741
|
}
|
|
@@ -1721,15 +1757,15 @@ var Rt = class {
|
|
|
1721
1757
|
return;
|
|
1722
1758
|
}
|
|
1723
1759
|
let { totalFrames: n, dropped: r } = U(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
|
|
1724
|
-
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a <
|
|
1760
|
+
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Mt || o < 0) {
|
|
1725
1761
|
this.fpsBadTicks = 0;
|
|
1726
1762
|
return;
|
|
1727
1763
|
}
|
|
1728
|
-
if (o <=
|
|
1764
|
+
if (o <= jt * a) {
|
|
1729
1765
|
this.fpsBadTicks = 0;
|
|
1730
1766
|
return;
|
|
1731
1767
|
}
|
|
1732
|
-
if (this.fpsBadTicks += 1, this.fpsBadTicks <
|
|
1768
|
+
if (this.fpsBadTicks += 1, this.fpsBadTicks < Nt) return;
|
|
1733
1769
|
this.fpsBadTicks = 0;
|
|
1734
1770
|
let s = e.levels, c = s[e.currentLevel];
|
|
1735
1771
|
if (!c) return;
|
|
@@ -1746,20 +1782,20 @@ var Rt = class {
|
|
|
1746
1782
|
return;
|
|
1747
1783
|
}
|
|
1748
1784
|
let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
|
|
1749
|
-
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(
|
|
1785
|
+
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(yt, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
|
|
1750
1786
|
this.resetChaseWindow();
|
|
1751
1787
|
return;
|
|
1752
1788
|
}
|
|
1753
|
-
if (this.chaseLatency < 0 || this.chaseLatency - n >=
|
|
1789
|
+
if (this.chaseLatency < 0 || this.chaseLatency - n >= vt) {
|
|
1754
1790
|
this.chaseLatency = n, this.chaseTicks = 0;
|
|
1755
1791
|
return;
|
|
1756
1792
|
}
|
|
1757
|
-
if (this.chaseTicks += 1, this.chaseTicks <
|
|
1793
|
+
if (this.chaseTicks += 1, this.chaseTicks < _t) return;
|
|
1758
1794
|
this.resetChaseWindow();
|
|
1759
1795
|
let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
|
|
1760
1796
|
if (!(a > 1)) return;
|
|
1761
1797
|
let o = typeof e.targetLatency == "number" ? e.targetLatency : 0, s = Math.min(n, a - 1);
|
|
1762
|
-
s < o +
|
|
1798
|
+
s < o + bt || (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);
|
|
1763
1799
|
}
|
|
1764
1800
|
suspendChasing() {
|
|
1765
1801
|
let e = this.hls;
|
|
@@ -1804,7 +1840,7 @@ var Rt = class {
|
|
|
1804
1840
|
scheduleLicenseRetry(t) {
|
|
1805
1841
|
if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
|
|
1806
1842
|
let n = t.response?.code ?? 0;
|
|
1807
|
-
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >=
|
|
1843
|
+
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= dt) return !1;
|
|
1808
1844
|
this.licenseRecoveries += 1;
|
|
1809
1845
|
let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
|
|
1810
1846
|
return this.licenseRetryTimer = setTimeout(() => {
|
|
@@ -1836,7 +1872,7 @@ var Rt = class {
|
|
|
1836
1872
|
return;
|
|
1837
1873
|
}
|
|
1838
1874
|
if (t.type === e.ErrorTypes.NETWORK_ERROR) {
|
|
1839
|
-
if (this.networkRecoveries <
|
|
1875
|
+
if (this.networkRecoveries < ut) {
|
|
1840
1876
|
this.networkRecoveries += 1;
|
|
1841
1877
|
let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
|
|
1842
1878
|
this.networkRetryTimer = setTimeout(() => {
|
|
@@ -1853,7 +1889,7 @@ var Rt = class {
|
|
|
1853
1889
|
return;
|
|
1854
1890
|
}
|
|
1855
1891
|
if (t.type === e.ErrorTypes.MEDIA_ERROR) {
|
|
1856
|
-
if (this.mediaRecoveries <
|
|
1892
|
+
if (this.mediaRecoveries < lt) {
|
|
1857
1893
|
this.mediaRecoveries += 1, n.recoverMediaError();
|
|
1858
1894
|
return;
|
|
1859
1895
|
}
|
|
@@ -1877,19 +1913,19 @@ var Rt = class {
|
|
|
1877
1913
|
let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
|
|
1878
1914
|
return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
|
|
1879
1915
|
}
|
|
1880
|
-
},
|
|
1916
|
+
}, Vt = 15e3, Ht = 6e5, Ut = 3e5, Wt = 100, q = 1, Gt = 1e3, Kt = 3e4, qt = 1e3, Jt = {
|
|
1881
1917
|
inline: "PRESENTATION_INLINE",
|
|
1882
1918
|
fullscreen: "PRESENTATION_FULLSCREEN",
|
|
1883
1919
|
pip: "PRESENTATION_PIP"
|
|
1884
|
-
},
|
|
1920
|
+
}, Yt = {
|
|
1885
1921
|
widevine: "KEY_SYSTEM_WIDEVINE",
|
|
1886
1922
|
fairplay: "KEY_SYSTEM_FAIRPLAY",
|
|
1887
1923
|
none: "KEY_SYSTEM_NONE"
|
|
1888
1924
|
};
|
|
1889
|
-
function
|
|
1925
|
+
function Xt(e, t) {
|
|
1890
1926
|
return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
|
|
1891
1927
|
}
|
|
1892
|
-
var
|
|
1928
|
+
var Zt = /* @__PURE__ */ new Set([
|
|
1893
1929
|
"INVALID_URN",
|
|
1894
1930
|
"NOT_FOUND",
|
|
1895
1931
|
"GONE",
|
|
@@ -1909,7 +1945,7 @@ var Yt = /* @__PURE__ */ new Set([
|
|
|
1909
1945
|
ended: "PLAYER_STATE_ENDED",
|
|
1910
1946
|
error: "PLAYER_STATE_ERROR"
|
|
1911
1947
|
};
|
|
1912
|
-
function
|
|
1948
|
+
function Qt(e) {
|
|
1913
1949
|
try {
|
|
1914
1950
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
1915
1951
|
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);
|
|
@@ -1917,8 +1953,8 @@ function Xt(e) {
|
|
|
1917
1953
|
return;
|
|
1918
1954
|
}
|
|
1919
1955
|
}
|
|
1920
|
-
var
|
|
1921
|
-
function
|
|
1956
|
+
var $t = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), en = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), tn = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
|
|
1957
|
+
function nn(e) {
|
|
1922
1958
|
if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
|
|
1923
1959
|
let t;
|
|
1924
1960
|
try {
|
|
@@ -1927,19 +1963,19 @@ function en(e) {
|
|
|
1927
1963
|
} catch {
|
|
1928
1964
|
return;
|
|
1929
1965
|
}
|
|
1930
|
-
if (
|
|
1931
|
-
Y.add(t), g(
|
|
1966
|
+
if (en.has(t) && !Y.has(t)) {
|
|
1967
|
+
Y.add(t), g(tn(new URL(t).origin));
|
|
1932
1968
|
for (let e of X) e.noteCspBlocked();
|
|
1933
1969
|
}
|
|
1934
1970
|
}
|
|
1935
|
-
function
|
|
1971
|
+
function rn(e, t) {
|
|
1936
1972
|
return g(t, e), { disabledReason: t };
|
|
1937
1973
|
}
|
|
1938
|
-
function
|
|
1939
|
-
if (n) return t &&
|
|
1974
|
+
function an(e, t, n) {
|
|
1975
|
+
if (n) return t && !$t(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
|
|
1940
1976
|
if (t) return { endpoint: t };
|
|
1941
|
-
if (t !== void 0) return
|
|
1942
|
-
let r =
|
|
1977
|
+
if (t !== void 0) return rn("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).");
|
|
1978
|
+
let r = Qt(e);
|
|
1943
1979
|
if (r) return { endpoint: r };
|
|
1944
1980
|
let i;
|
|
1945
1981
|
try {
|
|
@@ -1947,9 +1983,9 @@ function nn(e, t, n) {
|
|
|
1947
1983
|
} catch {
|
|
1948
1984
|
i = e;
|
|
1949
1985
|
}
|
|
1950
|
-
return
|
|
1986
|
+
return rn(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).`);
|
|
1951
1987
|
}
|
|
1952
|
-
var
|
|
1988
|
+
var on = class {
|
|
1953
1989
|
opts;
|
|
1954
1990
|
url;
|
|
1955
1991
|
cspKey;
|
|
@@ -2031,8 +2067,8 @@ var rn = class {
|
|
|
2031
2067
|
constructor(e) {
|
|
2032
2068
|
this.opts = {
|
|
2033
2069
|
...e,
|
|
2034
|
-
heartbeatMs: e.heartbeatMs ??
|
|
2035
|
-
idleMs: e.idleMs ??
|
|
2070
|
+
heartbeatMs: e.heartbeatMs ?? Vt,
|
|
2071
|
+
idleMs: e.idleMs ?? Ht
|
|
2036
2072
|
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
|
|
2037
2073
|
try {
|
|
2038
2074
|
let e = new URL(this.url);
|
|
@@ -2049,11 +2085,11 @@ var rn = class {
|
|
|
2049
2085
|
sdkVersion: this.opts.sdkVersion,
|
|
2050
2086
|
...this.opts.environment
|
|
2051
2087
|
};
|
|
2052
|
-
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(),
|
|
2088
|
+
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Gt), 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 && en.add(this.cspKey), document.addEventListener("securitypolicyviolation", nn), X.add(this), this.noteCspBlocked(), this.onVisibility());
|
|
2053
2089
|
}
|
|
2054
2090
|
checkSuspension(e) {
|
|
2055
2091
|
if (this.endedFlag || !this.opts.idleMs) return !1;
|
|
2056
|
-
let t = Math.max(this.opts.idleMs,
|
|
2092
|
+
let t = Math.max(this.opts.idleMs, Ut);
|
|
2057
2093
|
return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
|
|
2058
2094
|
}
|
|
2059
2095
|
syncIdle(e) {
|
|
@@ -2076,12 +2112,12 @@ var rn = class {
|
|
|
2076
2112
|
let a = {
|
|
2077
2113
|
fromState: J[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2078
2114
|
toState: J[t] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2079
|
-
presentation:
|
|
2115
|
+
presentation: Jt[this.presentation]
|
|
2080
2116
|
}, o = this.causeOf(e, t, i);
|
|
2081
2117
|
o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
2082
2118
|
}
|
|
2083
2119
|
seekInduced(e) {
|
|
2084
|
-
return this.lastSeekMs >= 0 && e - this.lastSeekMs <
|
|
2120
|
+
return this.lastSeekMs >= 0 && e - this.lastSeekMs < qt;
|
|
2085
2121
|
}
|
|
2086
2122
|
causeOf(e, t, n) {
|
|
2087
2123
|
if (t === "error") return "TRANSITION_CAUSE_ERROR";
|
|
@@ -2155,7 +2191,7 @@ var rn = class {
|
|
|
2155
2191
|
let r = n ?? "";
|
|
2156
2192
|
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";
|
|
2157
2193
|
if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
|
|
2158
|
-
if (
|
|
2194
|
+
if (Zt.has(e)) return "ERROR_STAGE_RESOLVE";
|
|
2159
2195
|
let i = t ?? "";
|
|
2160
2196
|
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";
|
|
2161
2197
|
}
|
|
@@ -2202,14 +2238,14 @@ var rn = class {
|
|
|
2202
2238
|
if (this.lastRequestCount = g, _ > 0) {
|
|
2203
2239
|
o.requestCountDelta = _;
|
|
2204
2240
|
let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
|
|
2205
|
-
n.length > 0 && (o.requestTimeP50Ms =
|
|
2241
|
+
n.length > 0 && (o.requestTimeP50Ms = Xt(n, 50), o.requestTimeP95Ms = Xt(n, 95));
|
|
2206
2242
|
}
|
|
2207
2243
|
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();
|
|
2208
2244
|
}
|
|
2209
2245
|
maybeEmitMediaInfo(e) {
|
|
2210
2246
|
if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
|
|
2211
2247
|
let t = {};
|
|
2212
|
-
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem =
|
|
2248
|
+
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = Yt[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);
|
|
2213
2249
|
let n = JSON.stringify(t);
|
|
2214
2250
|
n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
|
|
2215
2251
|
}
|
|
@@ -2229,7 +2265,7 @@ var rn = class {
|
|
|
2229
2265
|
let c = r?.positionMs ?? 0;
|
|
2230
2266
|
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));
|
|
2231
2267
|
let l = e !== "END_REASON_ENDED";
|
|
2232
|
-
l && this.lastStallMs > 0 && n - this.lastStallMs <=
|
|
2268
|
+
l && this.lastStallMs > 0 && n - this.lastStallMs <= Kt && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Kt && (i.abandonAfterErrorMs = Math.max(q, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
|
|
2233
2269
|
let u = r?.decodedFrames ?? this.lastDecoded;
|
|
2234
2270
|
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");
|
|
2235
2271
|
}
|
|
@@ -2249,13 +2285,13 @@ var rn = class {
|
|
|
2249
2285
|
};
|
|
2250
2286
|
}
|
|
2251
2287
|
noteCspBlocked() {
|
|
2252
|
-
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(
|
|
2288
|
+
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(tn(new URL(this.url).origin)));
|
|
2253
2289
|
}
|
|
2254
2290
|
cspBlocked() {
|
|
2255
2291
|
return !!this.cspKey && Y.has(this.cspKey);
|
|
2256
2292
|
}
|
|
2257
2293
|
enqueue(e) {
|
|
2258
|
-
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length >
|
|
2294
|
+
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Wt;) {
|
|
2259
2295
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
2260
2296
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
2261
2297
|
}
|
|
@@ -2282,7 +2318,7 @@ var rn = class {
|
|
|
2282
2318
|
};
|
|
2283
2319
|
//#endregion
|
|
2284
2320
|
//#region src/core/environment.ts
|
|
2285
|
-
function
|
|
2321
|
+
function sn() {
|
|
2286
2322
|
if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
|
|
2287
2323
|
let e;
|
|
2288
2324
|
try {
|
|
@@ -2307,14 +2343,14 @@ function an() {
|
|
|
2307
2343
|
integration: "INTEGRATION_KIND_IFRAME"
|
|
2308
2344
|
};
|
|
2309
2345
|
}
|
|
2310
|
-
function
|
|
2346
|
+
function cn() {
|
|
2311
2347
|
if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
|
|
2312
2348
|
let e = navigator.userAgentData, t = e?.platform ?? "";
|
|
2313
2349
|
if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
|
|
2314
2350
|
let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
|
|
2315
2351
|
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";
|
|
2316
2352
|
}
|
|
2317
|
-
function
|
|
2353
|
+
function ln() {
|
|
2318
2354
|
let e = typeof navigator < "u" ? navigator.connection : void 0;
|
|
2319
2355
|
if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
|
|
2320
2356
|
let t = {
|
|
@@ -2333,17 +2369,17 @@ function sn() {
|
|
|
2333
2369
|
}
|
|
2334
2370
|
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;
|
|
2335
2371
|
}
|
|
2336
|
-
function
|
|
2337
|
-
let t =
|
|
2338
|
-
deviceClass:
|
|
2372
|
+
function un(e) {
|
|
2373
|
+
let t = sn(), n = {
|
|
2374
|
+
deviceClass: cn(),
|
|
2339
2375
|
integration: t.integration,
|
|
2340
|
-
...
|
|
2376
|
+
...ln()
|
|
2341
2377
|
};
|
|
2342
2378
|
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);
|
|
2343
2379
|
let r = e.getBoundingClientRect?.();
|
|
2344
2380
|
return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
|
|
2345
2381
|
}
|
|
2346
|
-
async function
|
|
2382
|
+
async function dn() {
|
|
2347
2383
|
let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
|
|
2348
2384
|
if (!e?.getHighEntropyValues) return {};
|
|
2349
2385
|
try {
|
|
@@ -2355,7 +2391,7 @@ async function ln() {
|
|
|
2355
2391
|
}
|
|
2356
2392
|
//#endregion
|
|
2357
2393
|
//#region src/core/version.ts
|
|
2358
|
-
var
|
|
2394
|
+
var fn = "2.16.1", pn = {
|
|
2359
2395
|
accent: "#E1B600",
|
|
2360
2396
|
accentText: "#1B1C23",
|
|
2361
2397
|
background: "#0e0f13",
|
|
@@ -2366,7 +2402,7 @@ var un = "2.15.6", dn = {
|
|
|
2366
2402
|
border: "rgba(255, 255, 255, 0.1)",
|
|
2367
2403
|
radius: "8px",
|
|
2368
2404
|
fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
|
|
2369
|
-
},
|
|
2405
|
+
}, mn = {
|
|
2370
2406
|
accent: "--havik-accent",
|
|
2371
2407
|
accentText: "--havik-accent-text",
|
|
2372
2408
|
background: "--havik-bg",
|
|
@@ -2378,26 +2414,26 @@ var un = "2.15.6", dn = {
|
|
|
2378
2414
|
radius: "--havik-radius",
|
|
2379
2415
|
fontFamily: "--havik-font"
|
|
2380
2416
|
};
|
|
2381
|
-
function
|
|
2417
|
+
function hn(e, t) {
|
|
2382
2418
|
let n = {
|
|
2383
|
-
...
|
|
2419
|
+
...pn,
|
|
2384
2420
|
...t
|
|
2385
2421
|
};
|
|
2386
|
-
for (let t of Object.keys(
|
|
2422
|
+
for (let t of Object.keys(mn)) e.style.setProperty(mn[t], n[t]);
|
|
2387
2423
|
n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
|
|
2388
2424
|
}
|
|
2389
2425
|
//#endregion
|
|
2390
2426
|
//#region src/ui/styles.ts
|
|
2391
|
-
var
|
|
2392
|
-
function
|
|
2393
|
-
let n = e.querySelector(`style#${
|
|
2427
|
+
var gn = "havik-player-styles", _n = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer;\n touch-action:manipulation}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n/* Absolutely centred, NOT a flex sibling of .havik-center: the hidden center\n button (.havik-gone) still occupies its 74px in the row, which pushed an\n in-flow spinner 37px right of centre. */\n.havik-spinner{position:absolute;inset:0;margin:auto;width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n", Z = /* @__PURE__ */ new WeakMap();
|
|
2428
|
+
function vn(e = document, t) {
|
|
2429
|
+
let n = e.querySelector(`style#${gn}`);
|
|
2394
2430
|
if (n && (!t || Z.get(n) === t)) return;
|
|
2395
2431
|
let r = e.createElement("style");
|
|
2396
|
-
r.id =
|
|
2432
|
+
r.id = gn, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = _n, Z.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
|
|
2397
2433
|
}
|
|
2398
2434
|
//#endregion
|
|
2399
2435
|
//#region src/ui/icons.ts
|
|
2400
|
-
var
|
|
2436
|
+
var yn = {
|
|
2401
2437
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
2402
2438
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
2403
2439
|
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\"/>",
|
|
@@ -2411,20 +2447,20 @@ var _n = {
|
|
|
2411
2447
|
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\"/>"
|
|
2412
2448
|
};
|
|
2413
2449
|
function Q(e) {
|
|
2414
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
2450
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${yn[e]}</svg>`;
|
|
2415
2451
|
}
|
|
2416
2452
|
//#endregion
|
|
2417
2453
|
//#region src/ui/controls.ts
|
|
2418
|
-
var
|
|
2454
|
+
var bn = 3e3, xn = 250, Sn = /* @__PURE__ */ new Set([
|
|
2419
2455
|
"GONE",
|
|
2420
2456
|
"NOT_FOUND",
|
|
2421
2457
|
"INVALID_URN",
|
|
2422
2458
|
"UNAUTHORIZED"
|
|
2423
2459
|
]);
|
|
2424
|
-
function
|
|
2425
|
-
return new
|
|
2460
|
+
function Cn(e) {
|
|
2461
|
+
return new wn(e);
|
|
2426
2462
|
}
|
|
2427
|
-
var
|
|
2463
|
+
var wn = class {
|
|
2428
2464
|
root;
|
|
2429
2465
|
video;
|
|
2430
2466
|
player;
|
|
@@ -2470,7 +2506,7 @@ var Sn = class {
|
|
|
2470
2506
|
scrubbing = !1;
|
|
2471
2507
|
offFns = [];
|
|
2472
2508
|
constructor(e) {
|
|
2473
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
2509
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? bn, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, vn(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");
|
|
2474
2510
|
let t = (e, t, n) => {
|
|
2475
2511
|
let r = this.doc.createElement(e);
|
|
2476
2512
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -2556,7 +2592,7 @@ var Sn = class {
|
|
|
2556
2592
|
let t = this.surfaceWasHidden;
|
|
2557
2593
|
this.tapTimer = setTimeout(() => {
|
|
2558
2594
|
this.tapTimer = void 0, this.toggleBar(t);
|
|
2559
|
-
},
|
|
2595
|
+
}, xn);
|
|
2560
2596
|
}
|
|
2561
2597
|
toggleBar(e) {
|
|
2562
2598
|
e ? this.poke() : this.hideIfIdle();
|
|
@@ -2591,7 +2627,7 @@ var Sn = class {
|
|
|
2591
2627
|
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);
|
|
2592
2628
|
} else {
|
|
2593
2629
|
let r = this.doc.createElement("div");
|
|
2594
|
-
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !
|
|
2630
|
+
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Sn.has(this.lastError.code)) {
|
|
2595
2631
|
let e = this.doc.createElement("button");
|
|
2596
2632
|
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);
|
|
2597
2633
|
}
|
|
@@ -2632,7 +2668,7 @@ var Sn = class {
|
|
|
2632
2668
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
2633
2669
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
2634
2670
|
}
|
|
2635
|
-
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${
|
|
2671
|
+
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Tn(this.video.currentTime)} / ${Tn(this.video.duration)}`);
|
|
2636
2672
|
}
|
|
2637
2673
|
syncLive() {
|
|
2638
2674
|
let e = this.player.getStats(), t = e.isLive !== !1;
|
|
@@ -2682,17 +2718,17 @@ var Sn = class {
|
|
|
2682
2718
|
renderQualityMenu() {
|
|
2683
2719
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
2684
2720
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
2685
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
2721
|
+
for (let n of e) this.menu.append(this.menuItem(En(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
2686
2722
|
}
|
|
2687
2723
|
renderAudioMenu() {
|
|
2688
2724
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
2689
2725
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
2690
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2726
|
+
for (let t of e) this.menu.append(this.menuItem(Dn(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
2691
2727
|
}
|
|
2692
2728
|
renderCcMenu() {
|
|
2693
2729
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
2694
2730
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
2695
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2731
|
+
for (let t of e) this.menu.append(this.menuItem(On(t), !1, () => this.player.setTextTrack(t.id)));
|
|
2696
2732
|
}
|
|
2697
2733
|
onTracksChanged() {
|
|
2698
2734
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -2793,41 +2829,41 @@ var Sn = class {
|
|
|
2793
2829
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
2794
2830
|
}
|
|
2795
2831
|
};
|
|
2796
|
-
function
|
|
2832
|
+
function Tn(e) {
|
|
2797
2833
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
2798
2834
|
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");
|
|
2799
2835
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
2800
2836
|
}
|
|
2801
|
-
function
|
|
2837
|
+
function En(e) {
|
|
2802
2838
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
2803
2839
|
}
|
|
2804
|
-
function
|
|
2840
|
+
function Dn(e) {
|
|
2805
2841
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2806
2842
|
}
|
|
2807
|
-
function
|
|
2843
|
+
function On(e) {
|
|
2808
2844
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2809
2845
|
}
|
|
2810
2846
|
//#endregion
|
|
2811
2847
|
//#region src/managed/index.ts
|
|
2812
|
-
var
|
|
2813
|
-
function
|
|
2848
|
+
var kn = 6e3, An = 45e3, jn = 2e3, Mn = 3, Nn = 2e3, Pn = 48e4;
|
|
2849
|
+
function Fn(e) {
|
|
2814
2850
|
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)})`);
|
|
2815
2851
|
if (e.env !== void 0) return B(e.env);
|
|
2816
2852
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
|
|
2817
2853
|
return e.baseUrl;
|
|
2818
2854
|
}
|
|
2819
|
-
async function
|
|
2855
|
+
async function In(e) {
|
|
2820
2856
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
2821
|
-
let t =
|
|
2857
|
+
let t = Fn(e);
|
|
2822
2858
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
2823
2859
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
2824
|
-
let r = new
|
|
2860
|
+
let r = new Ln({
|
|
2825
2861
|
...e,
|
|
2826
2862
|
baseUrl: t
|
|
2827
2863
|
});
|
|
2828
2864
|
return await r.start(), r;
|
|
2829
2865
|
}
|
|
2830
|
-
var
|
|
2866
|
+
var Ln = class {
|
|
2831
2867
|
opts;
|
|
2832
2868
|
abort = new AbortController();
|
|
2833
2869
|
listeners = {};
|
|
@@ -2915,7 +2951,7 @@ var Fn = class {
|
|
|
2915
2951
|
setTimeout(() => {
|
|
2916
2952
|
a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
2917
2953
|
phase: i ? "unavailable" : "tooEarly",
|
|
2918
|
-
retryInMs:
|
|
2954
|
+
retryInMs: An,
|
|
2919
2955
|
attempt: 1,
|
|
2920
2956
|
elapsedMs: 0,
|
|
2921
2957
|
...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
|
|
@@ -2954,13 +2990,13 @@ var Fn = class {
|
|
|
2954
2990
|
!a && !p() && h();
|
|
2955
2991
|
}, e);
|
|
2956
2992
|
};
|
|
2957
|
-
_(
|
|
2993
|
+
_(kn), this.armingSub = E({
|
|
2958
2994
|
eventsBaseUrl: t,
|
|
2959
2995
|
matchUrn: this.opts.matchUrn,
|
|
2960
2996
|
credential: this.opts.credential,
|
|
2961
|
-
onAlive: () => _(
|
|
2997
|
+
onAlive: () => _(An),
|
|
2962
2998
|
onState: (e) => {
|
|
2963
|
-
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() *
|
|
2999
|
+
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * jn);
|
|
2964
3000
|
},
|
|
2965
3001
|
onError: () => h()
|
|
2966
3002
|
});
|
|
@@ -3005,19 +3041,19 @@ var Fn = class {
|
|
|
3005
3041
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
|
|
3006
3042
|
let i = e.analytics?.sid;
|
|
3007
3043
|
if (!i) return;
|
|
3008
|
-
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } =
|
|
3044
|
+
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = an(this.opts.baseUrl, a, e.analytics?.endpoint);
|
|
3009
3045
|
if (!o) {
|
|
3010
3046
|
s && setTimeout(() => {
|
|
3011
3047
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
|
|
3012
3048
|
}, 0);
|
|
3013
3049
|
return;
|
|
3014
3050
|
}
|
|
3015
|
-
let c = this.opts.video, l = new
|
|
3051
|
+
let c = this.opts.video, l = new on({
|
|
3016
3052
|
endpoint: o,
|
|
3017
3053
|
sid: i,
|
|
3018
3054
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
3019
|
-
sdkVersion:
|
|
3020
|
-
environment:
|
|
3055
|
+
sdkVersion: fn,
|
|
3056
|
+
environment: un(c),
|
|
3021
3057
|
idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
|
|
3022
3058
|
onIdle: () => this.onAnalyticsIdle(t),
|
|
3023
3059
|
onBlocked: (e) => setTimeout(() => {
|
|
@@ -3038,7 +3074,7 @@ var Fn = class {
|
|
|
3038
3074
|
let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
|
|
3039
3075
|
c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
|
|
3040
3076
|
c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
|
|
3041
|
-
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()),
|
|
3077
|
+
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), dn().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
|
|
3042
3078
|
}
|
|
3043
3079
|
currentPresentation() {
|
|
3044
3080
|
let e = this.opts.video;
|
|
@@ -3064,9 +3100,9 @@ var Fn = class {
|
|
|
3064
3100
|
emit: (e) => this.onEngineEvent(e)
|
|
3065
3101
|
}, o = this.opts.engine ?? "auto";
|
|
3066
3102
|
if (o === "native") return new K(a);
|
|
3067
|
-
if (o === "hls") return new
|
|
3068
|
-
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && W(this.opts.video) && G() || !e.drmEnabled &&
|
|
3069
|
-
if (
|
|
3103
|
+
if (o === "hls") return new Bt(a);
|
|
3104
|
+
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && W(this.opts.video) && G() || !e.drmEnabled && Ze() && W(this.opts.video)) return new K(a);
|
|
3105
|
+
if (ct()) return new Bt(a);
|
|
3070
3106
|
if (W(this.opts.video)) return new K(a);
|
|
3071
3107
|
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
3072
3108
|
}
|
|
@@ -3119,7 +3155,7 @@ var Fn = class {
|
|
|
3119
3155
|
r = 0, i = !1;
|
|
3120
3156
|
},
|
|
3121
3157
|
onError: () => {
|
|
3122
|
-
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >=
|
|
3158
|
+
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= Mn && (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.`))));
|
|
3123
3159
|
}
|
|
3124
3160
|
});
|
|
3125
3161
|
}
|
|
@@ -3141,7 +3177,7 @@ var Fn = class {
|
|
|
3141
3177
|
scheduleRejoin(e) {
|
|
3142
3178
|
this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
|
|
3143
3179
|
this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
|
|
3144
|
-
}, Math.random() *
|
|
3180
|
+
}, Math.random() * jn));
|
|
3145
3181
|
}
|
|
3146
3182
|
cancelRejoin() {
|
|
3147
3183
|
this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
|
|
@@ -3165,7 +3201,7 @@ var Fn = class {
|
|
|
3165
3201
|
}
|
|
3166
3202
|
t.controls = !1;
|
|
3167
3203
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
3168
|
-
r && r.insertBefore(n, t), n.appendChild(t),
|
|
3204
|
+
r && r.insertBefore(n, t), n.appendChild(t), hn(n, this.opts.theme), this.container = n, this.controlBar = Cn({
|
|
3169
3205
|
root: n,
|
|
3170
3206
|
video: t,
|
|
3171
3207
|
player: this,
|
|
@@ -3196,7 +3232,7 @@ var Fn = class {
|
|
|
3196
3232
|
}
|
|
3197
3233
|
startStats() {
|
|
3198
3234
|
this.stopStats();
|
|
3199
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
3235
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? Nn);
|
|
3200
3236
|
this.statsTimer = setInterval(() => {
|
|
3201
3237
|
if (!this.engine) return;
|
|
3202
3238
|
let e = this.engine.getStats();
|
|
@@ -3208,7 +3244,7 @@ var Fn = class {
|
|
|
3208
3244
|
}
|
|
3209
3245
|
scheduleLicenseRefresh() {
|
|
3210
3246
|
this.stopRefresh();
|
|
3211
|
-
let e = this.opts.licenseRefreshMs ??
|
|
3247
|
+
let e = this.opts.licenseRefreshMs ?? Pn;
|
|
3212
3248
|
e && this._descriptor?.drmEnabled && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
3213
3249
|
}
|
|
3214
3250
|
stopRefresh() {
|
|
@@ -3363,7 +3399,7 @@ function $(e) {
|
|
|
3363
3399
|
}
|
|
3364
3400
|
//#endregion
|
|
3365
3401
|
//#region src/embed/host.ts
|
|
3366
|
-
function
|
|
3402
|
+
function Rn(e) {
|
|
3367
3403
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
3368
3404
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
3369
3405
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -3422,15 +3458,15 @@ function In(e) {
|
|
|
3422
3458
|
}
|
|
3423
3459
|
//#endregion
|
|
3424
3460
|
//#region src/embed/page.ts
|
|
3425
|
-
var
|
|
3426
|
-
function
|
|
3461
|
+
var zn = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
3462
|
+
function Bn(e) {
|
|
3427
3463
|
if (typeof e == "boolean") return e;
|
|
3428
3464
|
if (typeof e == "object" && e) {
|
|
3429
3465
|
let t = e.endpoint;
|
|
3430
3466
|
return typeof t == "string" ? { endpoint: t } : {};
|
|
3431
3467
|
}
|
|
3432
3468
|
}
|
|
3433
|
-
function
|
|
3469
|
+
function Vn() {
|
|
3434
3470
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
3435
3471
|
if (e) return {
|
|
3436
3472
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -3440,7 +3476,7 @@ function zn() {
|
|
|
3440
3476
|
autoplay: e.autoplay ?? !0,
|
|
3441
3477
|
muted: e.muted ?? !0,
|
|
3442
3478
|
waitForLive: e.waitForLive ?? !0,
|
|
3443
|
-
analytics:
|
|
3479
|
+
analytics: Bn(e.analytics)
|
|
3444
3480
|
};
|
|
3445
3481
|
let t = new URLSearchParams(location.search);
|
|
3446
3482
|
return {
|
|
@@ -3453,9 +3489,9 @@ function zn() {
|
|
|
3453
3489
|
waitForLive: !0
|
|
3454
3490
|
};
|
|
3455
3491
|
}
|
|
3456
|
-
async function
|
|
3457
|
-
let e =
|
|
3458
|
-
|
|
3492
|
+
async function Hn() {
|
|
3493
|
+
let e = Vn();
|
|
3494
|
+
Wn();
|
|
3459
3495
|
let t = document.createElement("video");
|
|
3460
3496
|
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);
|
|
3461
3497
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -3510,12 +3546,12 @@ async function Bn() {
|
|
|
3510
3546
|
code: e.code,
|
|
3511
3547
|
message: e.message
|
|
3512
3548
|
})), e.on("autoplayblocked", () => {
|
|
3513
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
3549
|
+
i({ type: "oddin:autoplayblocked" }), Un(t, e);
|
|
3514
3550
|
});
|
|
3515
3551
|
}, s = async (r) => {
|
|
3516
3552
|
a?.destroy(), a = null;
|
|
3517
3553
|
try {
|
|
3518
|
-
let n = await
|
|
3554
|
+
let n = await In({
|
|
3519
3555
|
video: t,
|
|
3520
3556
|
baseUrl: e.baseUrl,
|
|
3521
3557
|
matchUrn: r,
|
|
@@ -3577,7 +3613,7 @@ async function Bn() {
|
|
|
3577
3613
|
a?.retry();
|
|
3578
3614
|
break;
|
|
3579
3615
|
case "oddin:load":
|
|
3580
|
-
typeof e.matchUrn == "string" &&
|
|
3616
|
+
typeof e.matchUrn == "string" && zn.test(e.matchUrn) && s(e.matchUrn);
|
|
3581
3617
|
break;
|
|
3582
3618
|
case "oddin:destroy": c();
|
|
3583
3619
|
}
|
|
@@ -3589,18 +3625,18 @@ async function Bn() {
|
|
|
3589
3625
|
protocol: 1
|
|
3590
3626
|
});
|
|
3591
3627
|
}
|
|
3592
|
-
function
|
|
3628
|
+
function Un(e, t) {
|
|
3593
3629
|
if (document.getElementById("havik-tap")) return;
|
|
3594
3630
|
let n = document.createElement("button");
|
|
3595
3631
|
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", () => {
|
|
3596
3632
|
n.remove(), t.play();
|
|
3597
3633
|
}), document.body.appendChild(n);
|
|
3598
3634
|
}
|
|
3599
|
-
function
|
|
3635
|
+
function Wn() {
|
|
3600
3636
|
let e = document.createElement("style");
|
|
3601
3637
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
3602
3638
|
}
|
|
3603
3639
|
//#endregion
|
|
3604
|
-
export {
|
|
3640
|
+
export { pn as ODDIN_THEME, n as PlaybackError, hn as applyTheme, B as baseUrlForEnv, Hn as bootEmbed, we as clearDeviceId, In as createPlayer, D as deriveEventsBaseUrl, Ve as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, ge as fetchCatalog, ve as fetchTournament, be as flattenMatches, A as getDeviceId, Ue as isLowLatencyManifest, $ as isOddinMessage, Ee as licenseRequestHeaders, Rn as mountEmbed, v as pollToLive, b as resolveStream, E as subscribeLiveState, C as videoFullscreenActive, Se as watchStatus };
|
|
3605
3641
|
|
|
3606
3642
|
//# sourceMappingURL=index.js.map
|