@oddin-gg/havik-player 2.16.0 → 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 +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.js +182 -154
- package/dist/index.js.map +1 -1
- package/docs/API.md +1 -1
- 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],
|
|
@@ -1053,7 +1057,31 @@ var K = class {
|
|
|
1053
1057
|
this.deps.video.pause();
|
|
1054
1058
|
} catch {}
|
|
1055
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
|
+
}
|
|
1056
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);
|
|
1057
1085
|
let { video: e } = this.deps;
|
|
1058
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;
|
|
1059
1087
|
try {
|
|
@@ -1065,13 +1093,13 @@ var K = class {
|
|
|
1065
1093
|
} catch {}
|
|
1066
1094
|
}
|
|
1067
1095
|
};
|
|
1068
|
-
function
|
|
1096
|
+
function Qe(e, t) {
|
|
1069
1097
|
return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
|
|
1070
1098
|
}
|
|
1071
1099
|
//#endregion
|
|
1072
1100
|
//#region src/core/engine/prefetch.ts
|
|
1073
|
-
var
|
|
1074
|
-
function
|
|
1101
|
+
var $e = 15e3, et = 5e3, tt = 6;
|
|
1102
|
+
function nt(e) {
|
|
1075
1103
|
try {
|
|
1076
1104
|
let t = new URL(e);
|
|
1077
1105
|
return t.searchParams.delete("CMCD"), t.toString();
|
|
@@ -1079,7 +1107,7 @@ function et(e) {
|
|
|
1079
1107
|
return e;
|
|
1080
1108
|
}
|
|
1081
1109
|
}
|
|
1082
|
-
var
|
|
1110
|
+
var rt = class {
|
|
1083
1111
|
cmcd;
|
|
1084
1112
|
entries = /* @__PURE__ */ new Map();
|
|
1085
1113
|
keyed = /* @__PURE__ */ new Set();
|
|
@@ -1102,10 +1130,10 @@ var tt = class {
|
|
|
1102
1130
|
}
|
|
1103
1131
|
prefetch(e, t, n) {
|
|
1104
1132
|
if (!this.isActive(t)) return;
|
|
1105
|
-
let r =
|
|
1133
|
+
let r = nt(e);
|
|
1106
1134
|
if (this.entries.has(r)) return;
|
|
1107
1135
|
let i = this.perTrack.get(t) ?? 0;
|
|
1108
|
-
if (i >=
|
|
1136
|
+
if (i >= tt) return;
|
|
1109
1137
|
this.perTrack.set(t, i + 1);
|
|
1110
1138
|
let a = new AbortController(), o = {
|
|
1111
1139
|
started: performance.now(),
|
|
@@ -1119,10 +1147,10 @@ var tt = class {
|
|
|
1119
1147
|
signal: a.signal
|
|
1120
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(() => {
|
|
1121
1149
|
this.entries.get(r) === o && (this.entries.delete(r), a.abort(), this.stats.expired += 1);
|
|
1122
|
-
},
|
|
1150
|
+
}, $e);
|
|
1123
1151
|
}
|
|
1124
1152
|
take(e) {
|
|
1125
|
-
let t =
|
|
1153
|
+
let t = nt(e), n = this.entries.get(t);
|
|
1126
1154
|
return n && this.entries.delete(t), n;
|
|
1127
1155
|
}
|
|
1128
1156
|
destroy() {
|
|
@@ -1142,13 +1170,13 @@ var tt = class {
|
|
|
1142
1170
|
}
|
|
1143
1171
|
}
|
|
1144
1172
|
};
|
|
1145
|
-
function
|
|
1173
|
+
function it(t) {
|
|
1146
1174
|
let n = e.DefaultConfig?.loader;
|
|
1147
1175
|
if (typeof n != "function") return;
|
|
1148
1176
|
class r extends n {
|
|
1149
1177
|
served = !1;
|
|
1150
1178
|
cancelled = !1;
|
|
1151
|
-
stats =
|
|
1179
|
+
stats = at();
|
|
1152
1180
|
load(e, n, r) {
|
|
1153
1181
|
let i = e.rangeEnd ? void 0 : t.take(e.url);
|
|
1154
1182
|
if (!i) {
|
|
@@ -1156,7 +1184,7 @@ function nt(t) {
|
|
|
1156
1184
|
return;
|
|
1157
1185
|
}
|
|
1158
1186
|
this.served = !0;
|
|
1159
|
-
let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs ||
|
|
1187
|
+
let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || et, s = setTimeout(() => {
|
|
1160
1188
|
!this.cancelled && this.served && (i.abort.abort(), t.stats.failed += 1, this.served = !1, super.load(e, n, r));
|
|
1161
1189
|
}, o);
|
|
1162
1190
|
i.bytes.then((o) => {
|
|
@@ -1183,7 +1211,7 @@ function nt(t) {
|
|
|
1183
1211
|
}
|
|
1184
1212
|
return r;
|
|
1185
1213
|
}
|
|
1186
|
-
function
|
|
1214
|
+
function at() {
|
|
1187
1215
|
return {
|
|
1188
1216
|
aborted: !1,
|
|
1189
1217
|
loaded: 0,
|
|
@@ -1207,10 +1235,10 @@ function rt() {
|
|
|
1207
1235
|
}
|
|
1208
1236
|
};
|
|
1209
1237
|
}
|
|
1210
|
-
function
|
|
1238
|
+
function ot(e) {
|
|
1211
1239
|
return e === "audio" ? "audio" : "main";
|
|
1212
1240
|
}
|
|
1213
|
-
function
|
|
1241
|
+
function st(e, t) {
|
|
1214
1242
|
let n = [];
|
|
1215
1243
|
t.initSegment?.url && !t.initSegment.data && n.push({
|
|
1216
1244
|
url: t.initSegment.url,
|
|
@@ -1229,24 +1257,24 @@ function at(e, t) {
|
|
|
1229
1257
|
}
|
|
1230
1258
|
//#endregion
|
|
1231
1259
|
//#region src/core/engine/hls.ts
|
|
1232
|
-
function
|
|
1260
|
+
function ct() {
|
|
1233
1261
|
return e.isSupported();
|
|
1234
1262
|
}
|
|
1235
|
-
var
|
|
1236
|
-
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) {
|
|
1237
1265
|
if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
|
|
1238
1266
|
delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
|
|
1239
1267
|
return;
|
|
1240
1268
|
}
|
|
1241
|
-
e.liveSyncDuration ??=
|
|
1242
|
-
let t = Math.max(12, e.liveSyncDuration +
|
|
1243
|
-
(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);
|
|
1244
1272
|
}
|
|
1245
|
-
function
|
|
1273
|
+
function zt(e, t) {
|
|
1246
1274
|
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
1247
1275
|
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
1248
1276
|
}
|
|
1249
|
-
var
|
|
1277
|
+
var Bt = class {
|
|
1250
1278
|
name = "hls";
|
|
1251
1279
|
hls = null;
|
|
1252
1280
|
deps;
|
|
@@ -1359,7 +1387,7 @@ var Rt = class {
|
|
|
1359
1387
|
}
|
|
1360
1388
|
this.loadSuspended = !0;
|
|
1361
1389
|
}
|
|
1362
|
-
},
|
|
1390
|
+
}, xt));
|
|
1363
1391
|
}
|
|
1364
1392
|
resumeLoading() {
|
|
1365
1393
|
if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
|
|
@@ -1391,7 +1419,7 @@ var Rt = class {
|
|
|
1391
1419
|
let t = e.liveSyncPosition;
|
|
1392
1420
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
1393
1421
|
let { video: n } = this.deps;
|
|
1394
|
-
n.currentTime <= t +
|
|
1422
|
+
n.currentTime <= t + It || (n.currentTime = t);
|
|
1395
1423
|
}
|
|
1396
1424
|
startHls() {
|
|
1397
1425
|
let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
|
|
@@ -1432,20 +1460,20 @@ var Rt = class {
|
|
|
1432
1460
|
...c
|
|
1433
1461
|
};
|
|
1434
1462
|
if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !d.fLoader) {
|
|
1435
|
-
let e = new
|
|
1463
|
+
let e = new rt({
|
|
1436
1464
|
sessionId: n.analytics?.sid,
|
|
1437
1465
|
contentId: n.matchUrn
|
|
1438
|
-
}), t =
|
|
1466
|
+
}), t = it(e);
|
|
1439
1467
|
t && (this.prefetch = e, d.fLoader = t);
|
|
1440
1468
|
}
|
|
1441
|
-
|
|
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;
|
|
1442
1470
|
let f = new e(d);
|
|
1443
1471
|
if (this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
|
|
1444
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" });
|
|
1445
1473
|
}), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
|
|
1446
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(() => {
|
|
1447
1475
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
|
|
1448
|
-
},
|
|
1476
|
+
}, ft)));
|
|
1449
1477
|
}), f.on(e.Events.FRAG_LOADING, (e, t) => {
|
|
1450
1478
|
t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
|
|
1451
1479
|
}), f.on(e.Events.FRAG_LOADED, (e, t) => {
|
|
@@ -1453,7 +1481,7 @@ var Rt = class {
|
|
|
1453
1481
|
let n = t?.frag?.stats, r = n?.loaded;
|
|
1454
1482
|
typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
|
|
1455
1483
|
let i = n?.loading;
|
|
1456
|
-
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());
|
|
1457
1485
|
let a = t?.frag?.url;
|
|
1458
1486
|
if (a) {
|
|
1459
1487
|
let e = H(a);
|
|
@@ -1470,15 +1498,15 @@ var Rt = class {
|
|
|
1470
1498
|
}), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
|
|
1471
1499
|
let t = this.prefetch;
|
|
1472
1500
|
f.on(e.Events.KEY_LOADING, (e, n) => {
|
|
1473
|
-
let r = n?.frag, i =
|
|
1474
|
-
if (r && t.isActive(i)) for (let e of
|
|
1475
|
-
}), 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)));
|
|
1476
1504
|
}
|
|
1477
1505
|
f.on(e.Events.KEY_LOADED, () => {
|
|
1478
1506
|
u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
|
|
1479
1507
|
}), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
|
|
1480
1508
|
this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.checkFrameDrops();
|
|
1481
|
-
},
|
|
1509
|
+
}, mt), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
1482
1510
|
this.renditionSwitches += 1;
|
|
1483
1511
|
let n = this.lastLevelIndex >= 0 ? f.levels[this.lastLevelIndex] : void 0, r = f.levels[t.level];
|
|
1484
1512
|
n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
|
|
@@ -1542,7 +1570,7 @@ var Rt = class {
|
|
|
1542
1570
|
return;
|
|
1543
1571
|
}
|
|
1544
1572
|
this.capTimer && clearTimeout(this.capTimer);
|
|
1545
|
-
let t = e > this.sizeCapLevel ?
|
|
1573
|
+
let t = e > this.sizeCapLevel ? kt : At;
|
|
1546
1574
|
this.capTimer = setTimeout(() => {
|
|
1547
1575
|
this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
|
|
1548
1576
|
}, t);
|
|
@@ -1663,7 +1691,7 @@ var Rt = class {
|
|
|
1663
1691
|
return;
|
|
1664
1692
|
}
|
|
1665
1693
|
let e = Date.now() - this.lastAdvanceMs;
|
|
1666
|
-
!this.chaseSuspended && e >
|
|
1694
|
+
!this.chaseSuspended && e > ht && this.suspendChasing(), e > pt && this.emitEnded("stalled");
|
|
1667
1695
|
}
|
|
1668
1696
|
resetStarvationWindow() {
|
|
1669
1697
|
this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
|
|
@@ -1678,7 +1706,7 @@ var Rt = class {
|
|
|
1678
1706
|
this.resetStarvationWindow();
|
|
1679
1707
|
return;
|
|
1680
1708
|
}
|
|
1681
|
-
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;
|
|
1682
1710
|
if (this.starvedFrames = c, !a || l) {
|
|
1683
1711
|
(t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
|
|
1684
1712
|
return;
|
|
@@ -1687,12 +1715,12 @@ var Rt = class {
|
|
|
1687
1715
|
this.resetStarvationWindow();
|
|
1688
1716
|
return;
|
|
1689
1717
|
}
|
|
1690
|
-
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)) {
|
|
1691
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");
|
|
1692
1720
|
return;
|
|
1693
1721
|
}
|
|
1694
|
-
let u = i && this.starvedTicks >=
|
|
1695
|
-
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))) {
|
|
1696
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");
|
|
1697
1725
|
try {
|
|
1698
1726
|
e.stopLoad(), e.startLoad(-1);
|
|
@@ -1707,7 +1735,7 @@ var Rt = class {
|
|
|
1707
1735
|
let t = e.latency, n = e.targetLatency;
|
|
1708
1736
|
if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
|
|
1709
1737
|
let r = t - n;
|
|
1710
|
-
!this.catchUpEngaged && r >
|
|
1738
|
+
!this.catchUpEngaged && r > gt ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= gt && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
|
|
1711
1739
|
let i = this.catchUpEngaged ? this.catchUpRate : 1;
|
|
1712
1740
|
e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
|
|
1713
1741
|
}
|
|
@@ -1729,15 +1757,15 @@ var Rt = class {
|
|
|
1729
1757
|
return;
|
|
1730
1758
|
}
|
|
1731
1759
|
let { totalFrames: n, dropped: r } = U(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
|
|
1732
|
-
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a <
|
|
1760
|
+
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Mt || o < 0) {
|
|
1733
1761
|
this.fpsBadTicks = 0;
|
|
1734
1762
|
return;
|
|
1735
1763
|
}
|
|
1736
|
-
if (o <=
|
|
1764
|
+
if (o <= jt * a) {
|
|
1737
1765
|
this.fpsBadTicks = 0;
|
|
1738
1766
|
return;
|
|
1739
1767
|
}
|
|
1740
|
-
if (this.fpsBadTicks += 1, this.fpsBadTicks <
|
|
1768
|
+
if (this.fpsBadTicks += 1, this.fpsBadTicks < Nt) return;
|
|
1741
1769
|
this.fpsBadTicks = 0;
|
|
1742
1770
|
let s = e.levels, c = s[e.currentLevel];
|
|
1743
1771
|
if (!c) return;
|
|
@@ -1754,20 +1782,20 @@ var Rt = class {
|
|
|
1754
1782
|
return;
|
|
1755
1783
|
}
|
|
1756
1784
|
let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
|
|
1757
|
-
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))) {
|
|
1758
1786
|
this.resetChaseWindow();
|
|
1759
1787
|
return;
|
|
1760
1788
|
}
|
|
1761
|
-
if (this.chaseLatency < 0 || this.chaseLatency - n >=
|
|
1789
|
+
if (this.chaseLatency < 0 || this.chaseLatency - n >= vt) {
|
|
1762
1790
|
this.chaseLatency = n, this.chaseTicks = 0;
|
|
1763
1791
|
return;
|
|
1764
1792
|
}
|
|
1765
|
-
if (this.chaseTicks += 1, this.chaseTicks <
|
|
1793
|
+
if (this.chaseTicks += 1, this.chaseTicks < _t) return;
|
|
1766
1794
|
this.resetChaseWindow();
|
|
1767
1795
|
let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
|
|
1768
1796
|
if (!(a > 1)) return;
|
|
1769
1797
|
let o = typeof e.targetLatency == "number" ? e.targetLatency : 0, s = Math.min(n, a - 1);
|
|
1770
|
-
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);
|
|
1771
1799
|
}
|
|
1772
1800
|
suspendChasing() {
|
|
1773
1801
|
let e = this.hls;
|
|
@@ -1812,7 +1840,7 @@ var Rt = class {
|
|
|
1812
1840
|
scheduleLicenseRetry(t) {
|
|
1813
1841
|
if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
|
|
1814
1842
|
let n = t.response?.code ?? 0;
|
|
1815
|
-
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;
|
|
1816
1844
|
this.licenseRecoveries += 1;
|
|
1817
1845
|
let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
|
|
1818
1846
|
return this.licenseRetryTimer = setTimeout(() => {
|
|
@@ -1844,7 +1872,7 @@ var Rt = class {
|
|
|
1844
1872
|
return;
|
|
1845
1873
|
}
|
|
1846
1874
|
if (t.type === e.ErrorTypes.NETWORK_ERROR) {
|
|
1847
|
-
if (this.networkRecoveries <
|
|
1875
|
+
if (this.networkRecoveries < ut) {
|
|
1848
1876
|
this.networkRecoveries += 1;
|
|
1849
1877
|
let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
|
|
1850
1878
|
this.networkRetryTimer = setTimeout(() => {
|
|
@@ -1861,7 +1889,7 @@ var Rt = class {
|
|
|
1861
1889
|
return;
|
|
1862
1890
|
}
|
|
1863
1891
|
if (t.type === e.ErrorTypes.MEDIA_ERROR) {
|
|
1864
|
-
if (this.mediaRecoveries <
|
|
1892
|
+
if (this.mediaRecoveries < lt) {
|
|
1865
1893
|
this.mediaRecoveries += 1, n.recoverMediaError();
|
|
1866
1894
|
return;
|
|
1867
1895
|
}
|
|
@@ -1885,19 +1913,19 @@ var Rt = class {
|
|
|
1885
1913
|
let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
|
|
1886
1914
|
return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
|
|
1887
1915
|
}
|
|
1888
|
-
},
|
|
1916
|
+
}, Vt = 15e3, Ht = 6e5, Ut = 3e5, Wt = 100, q = 1, Gt = 1e3, Kt = 3e4, qt = 1e3, Jt = {
|
|
1889
1917
|
inline: "PRESENTATION_INLINE",
|
|
1890
1918
|
fullscreen: "PRESENTATION_FULLSCREEN",
|
|
1891
1919
|
pip: "PRESENTATION_PIP"
|
|
1892
|
-
},
|
|
1920
|
+
}, Yt = {
|
|
1893
1921
|
widevine: "KEY_SYSTEM_WIDEVINE",
|
|
1894
1922
|
fairplay: "KEY_SYSTEM_FAIRPLAY",
|
|
1895
1923
|
none: "KEY_SYSTEM_NONE"
|
|
1896
1924
|
};
|
|
1897
|
-
function
|
|
1925
|
+
function Xt(e, t) {
|
|
1898
1926
|
return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
|
|
1899
1927
|
}
|
|
1900
|
-
var
|
|
1928
|
+
var Zt = /* @__PURE__ */ new Set([
|
|
1901
1929
|
"INVALID_URN",
|
|
1902
1930
|
"NOT_FOUND",
|
|
1903
1931
|
"GONE",
|
|
@@ -1917,7 +1945,7 @@ var Yt = /* @__PURE__ */ new Set([
|
|
|
1917
1945
|
ended: "PLAYER_STATE_ENDED",
|
|
1918
1946
|
error: "PLAYER_STATE_ERROR"
|
|
1919
1947
|
};
|
|
1920
|
-
function
|
|
1948
|
+
function Qt(e) {
|
|
1921
1949
|
try {
|
|
1922
1950
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
1923
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);
|
|
@@ -1925,8 +1953,8 @@ function Xt(e) {
|
|
|
1925
1953
|
return;
|
|
1926
1954
|
}
|
|
1927
1955
|
}
|
|
1928
|
-
var
|
|
1929
|
-
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) {
|
|
1930
1958
|
if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
|
|
1931
1959
|
let t;
|
|
1932
1960
|
try {
|
|
@@ -1935,19 +1963,19 @@ function en(e) {
|
|
|
1935
1963
|
} catch {
|
|
1936
1964
|
return;
|
|
1937
1965
|
}
|
|
1938
|
-
if (
|
|
1939
|
-
Y.add(t), g(
|
|
1966
|
+
if (en.has(t) && !Y.has(t)) {
|
|
1967
|
+
Y.add(t), g(tn(new URL(t).origin));
|
|
1940
1968
|
for (let e of X) e.noteCspBlocked();
|
|
1941
1969
|
}
|
|
1942
1970
|
}
|
|
1943
|
-
function
|
|
1971
|
+
function rn(e, t) {
|
|
1944
1972
|
return g(t, e), { disabledReason: t };
|
|
1945
1973
|
}
|
|
1946
|
-
function
|
|
1947
|
-
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 };
|
|
1948
1976
|
if (t) return { endpoint: t };
|
|
1949
|
-
if (t !== void 0) return
|
|
1950
|
-
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);
|
|
1951
1979
|
if (r) return { endpoint: r };
|
|
1952
1980
|
let i;
|
|
1953
1981
|
try {
|
|
@@ -1955,9 +1983,9 @@ function nn(e, t, n) {
|
|
|
1955
1983
|
} catch {
|
|
1956
1984
|
i = e;
|
|
1957
1985
|
}
|
|
1958
|
-
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).`);
|
|
1959
1987
|
}
|
|
1960
|
-
var
|
|
1988
|
+
var on = class {
|
|
1961
1989
|
opts;
|
|
1962
1990
|
url;
|
|
1963
1991
|
cspKey;
|
|
@@ -2039,8 +2067,8 @@ var rn = class {
|
|
|
2039
2067
|
constructor(e) {
|
|
2040
2068
|
this.opts = {
|
|
2041
2069
|
...e,
|
|
2042
|
-
heartbeatMs: e.heartbeatMs ??
|
|
2043
|
-
idleMs: e.idleMs ??
|
|
2070
|
+
heartbeatMs: e.heartbeatMs ?? Vt,
|
|
2071
|
+
idleMs: e.idleMs ?? Ht
|
|
2044
2072
|
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
|
|
2045
2073
|
try {
|
|
2046
2074
|
let e = new URL(this.url);
|
|
@@ -2057,11 +2085,11 @@ var rn = class {
|
|
|
2057
2085
|
sdkVersion: this.opts.sdkVersion,
|
|
2058
2086
|
...this.opts.environment
|
|
2059
2087
|
};
|
|
2060
|
-
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());
|
|
2061
2089
|
}
|
|
2062
2090
|
checkSuspension(e) {
|
|
2063
2091
|
if (this.endedFlag || !this.opts.idleMs) return !1;
|
|
2064
|
-
let t = Math.max(this.opts.idleMs,
|
|
2092
|
+
let t = Math.max(this.opts.idleMs, Ut);
|
|
2065
2093
|
return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
|
|
2066
2094
|
}
|
|
2067
2095
|
syncIdle(e) {
|
|
@@ -2084,12 +2112,12 @@ var rn = class {
|
|
|
2084
2112
|
let a = {
|
|
2085
2113
|
fromState: J[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2086
2114
|
toState: J[t] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2087
|
-
presentation:
|
|
2115
|
+
presentation: Jt[this.presentation]
|
|
2088
2116
|
}, o = this.causeOf(e, t, i);
|
|
2089
2117
|
o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
2090
2118
|
}
|
|
2091
2119
|
seekInduced(e) {
|
|
2092
|
-
return this.lastSeekMs >= 0 && e - this.lastSeekMs <
|
|
2120
|
+
return this.lastSeekMs >= 0 && e - this.lastSeekMs < qt;
|
|
2093
2121
|
}
|
|
2094
2122
|
causeOf(e, t, n) {
|
|
2095
2123
|
if (t === "error") return "TRANSITION_CAUSE_ERROR";
|
|
@@ -2163,7 +2191,7 @@ var rn = class {
|
|
|
2163
2191
|
let r = n ?? "";
|
|
2164
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";
|
|
2165
2193
|
if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
|
|
2166
|
-
if (
|
|
2194
|
+
if (Zt.has(e)) return "ERROR_STAGE_RESOLVE";
|
|
2167
2195
|
let i = t ?? "";
|
|
2168
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";
|
|
2169
2197
|
}
|
|
@@ -2210,14 +2238,14 @@ var rn = class {
|
|
|
2210
2238
|
if (this.lastRequestCount = g, _ > 0) {
|
|
2211
2239
|
o.requestCountDelta = _;
|
|
2212
2240
|
let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
|
|
2213
|
-
n.length > 0 && (o.requestTimeP50Ms =
|
|
2241
|
+
n.length > 0 && (o.requestTimeP50Ms = Xt(n, 50), o.requestTimeP95Ms = Xt(n, 95));
|
|
2214
2242
|
}
|
|
2215
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();
|
|
2216
2244
|
}
|
|
2217
2245
|
maybeEmitMediaInfo(e) {
|
|
2218
2246
|
if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
|
|
2219
2247
|
let t = {};
|
|
2220
|
-
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);
|
|
2221
2249
|
let n = JSON.stringify(t);
|
|
2222
2250
|
n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
|
|
2223
2251
|
}
|
|
@@ -2237,7 +2265,7 @@ var rn = class {
|
|
|
2237
2265
|
let c = r?.positionMs ?? 0;
|
|
2238
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));
|
|
2239
2267
|
let l = e !== "END_REASON_ENDED";
|
|
2240
|
-
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);
|
|
2241
2269
|
let u = r?.decodedFrames ?? this.lastDecoded;
|
|
2242
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");
|
|
2243
2271
|
}
|
|
@@ -2257,13 +2285,13 @@ var rn = class {
|
|
|
2257
2285
|
};
|
|
2258
2286
|
}
|
|
2259
2287
|
noteCspBlocked() {
|
|
2260
|
-
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)));
|
|
2261
2289
|
}
|
|
2262
2290
|
cspBlocked() {
|
|
2263
2291
|
return !!this.cspKey && Y.has(this.cspKey);
|
|
2264
2292
|
}
|
|
2265
2293
|
enqueue(e) {
|
|
2266
|
-
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;) {
|
|
2267
2295
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
2268
2296
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
2269
2297
|
}
|
|
@@ -2290,7 +2318,7 @@ var rn = class {
|
|
|
2290
2318
|
};
|
|
2291
2319
|
//#endregion
|
|
2292
2320
|
//#region src/core/environment.ts
|
|
2293
|
-
function
|
|
2321
|
+
function sn() {
|
|
2294
2322
|
if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
|
|
2295
2323
|
let e;
|
|
2296
2324
|
try {
|
|
@@ -2315,14 +2343,14 @@ function an() {
|
|
|
2315
2343
|
integration: "INTEGRATION_KIND_IFRAME"
|
|
2316
2344
|
};
|
|
2317
2345
|
}
|
|
2318
|
-
function
|
|
2346
|
+
function cn() {
|
|
2319
2347
|
if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
|
|
2320
2348
|
let e = navigator.userAgentData, t = e?.platform ?? "";
|
|
2321
2349
|
if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
|
|
2322
2350
|
let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
|
|
2323
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";
|
|
2324
2352
|
}
|
|
2325
|
-
function
|
|
2353
|
+
function ln() {
|
|
2326
2354
|
let e = typeof navigator < "u" ? navigator.connection : void 0;
|
|
2327
2355
|
if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
|
|
2328
2356
|
let t = {
|
|
@@ -2341,17 +2369,17 @@ function sn() {
|
|
|
2341
2369
|
}
|
|
2342
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;
|
|
2343
2371
|
}
|
|
2344
|
-
function
|
|
2345
|
-
let t =
|
|
2346
|
-
deviceClass:
|
|
2372
|
+
function un(e) {
|
|
2373
|
+
let t = sn(), n = {
|
|
2374
|
+
deviceClass: cn(),
|
|
2347
2375
|
integration: t.integration,
|
|
2348
|
-
...
|
|
2376
|
+
...ln()
|
|
2349
2377
|
};
|
|
2350
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);
|
|
2351
2379
|
let r = e.getBoundingClientRect?.();
|
|
2352
2380
|
return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
|
|
2353
2381
|
}
|
|
2354
|
-
async function
|
|
2382
|
+
async function dn() {
|
|
2355
2383
|
let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
|
|
2356
2384
|
if (!e?.getHighEntropyValues) return {};
|
|
2357
2385
|
try {
|
|
@@ -2363,7 +2391,7 @@ async function ln() {
|
|
|
2363
2391
|
}
|
|
2364
2392
|
//#endregion
|
|
2365
2393
|
//#region src/core/version.ts
|
|
2366
|
-
var
|
|
2394
|
+
var fn = "2.16.1", pn = {
|
|
2367
2395
|
accent: "#E1B600",
|
|
2368
2396
|
accentText: "#1B1C23",
|
|
2369
2397
|
background: "#0e0f13",
|
|
@@ -2374,7 +2402,7 @@ var un = "2.16.0", dn = {
|
|
|
2374
2402
|
border: "rgba(255, 255, 255, 0.1)",
|
|
2375
2403
|
radius: "8px",
|
|
2376
2404
|
fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
|
|
2377
|
-
},
|
|
2405
|
+
}, mn = {
|
|
2378
2406
|
accent: "--havik-accent",
|
|
2379
2407
|
accentText: "--havik-accent-text",
|
|
2380
2408
|
background: "--havik-bg",
|
|
@@ -2386,26 +2414,26 @@ var un = "2.16.0", dn = {
|
|
|
2386
2414
|
radius: "--havik-radius",
|
|
2387
2415
|
fontFamily: "--havik-font"
|
|
2388
2416
|
};
|
|
2389
|
-
function
|
|
2417
|
+
function hn(e, t) {
|
|
2390
2418
|
let n = {
|
|
2391
|
-
...
|
|
2419
|
+
...pn,
|
|
2392
2420
|
...t
|
|
2393
2421
|
};
|
|
2394
|
-
for (let t of Object.keys(
|
|
2422
|
+
for (let t of Object.keys(mn)) e.style.setProperty(mn[t], n[t]);
|
|
2395
2423
|
n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
|
|
2396
2424
|
}
|
|
2397
2425
|
//#endregion
|
|
2398
2426
|
//#region src/ui/styles.ts
|
|
2399
|
-
var
|
|
2400
|
-
function
|
|
2401
|
-
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}`);
|
|
2402
2430
|
if (n && (!t || Z.get(n) === t)) return;
|
|
2403
2431
|
let r = e.createElement("style");
|
|
2404
|
-
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);
|
|
2405
2433
|
}
|
|
2406
2434
|
//#endregion
|
|
2407
2435
|
//#region src/ui/icons.ts
|
|
2408
|
-
var
|
|
2436
|
+
var yn = {
|
|
2409
2437
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
2410
2438
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
2411
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\"/>",
|
|
@@ -2419,20 +2447,20 @@ var _n = {
|
|
|
2419
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\"/>"
|
|
2420
2448
|
};
|
|
2421
2449
|
function Q(e) {
|
|
2422
|
-
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>`;
|
|
2423
2451
|
}
|
|
2424
2452
|
//#endregion
|
|
2425
2453
|
//#region src/ui/controls.ts
|
|
2426
|
-
var
|
|
2454
|
+
var bn = 3e3, xn = 250, Sn = /* @__PURE__ */ new Set([
|
|
2427
2455
|
"GONE",
|
|
2428
2456
|
"NOT_FOUND",
|
|
2429
2457
|
"INVALID_URN",
|
|
2430
2458
|
"UNAUTHORIZED"
|
|
2431
2459
|
]);
|
|
2432
|
-
function
|
|
2433
|
-
return new
|
|
2460
|
+
function Cn(e) {
|
|
2461
|
+
return new wn(e);
|
|
2434
2462
|
}
|
|
2435
|
-
var
|
|
2463
|
+
var wn = class {
|
|
2436
2464
|
root;
|
|
2437
2465
|
video;
|
|
2438
2466
|
player;
|
|
@@ -2478,7 +2506,7 @@ var Sn = class {
|
|
|
2478
2506
|
scrubbing = !1;
|
|
2479
2507
|
offFns = [];
|
|
2480
2508
|
constructor(e) {
|
|
2481
|
-
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");
|
|
2482
2510
|
let t = (e, t, n) => {
|
|
2483
2511
|
let r = this.doc.createElement(e);
|
|
2484
2512
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -2564,7 +2592,7 @@ var Sn = class {
|
|
|
2564
2592
|
let t = this.surfaceWasHidden;
|
|
2565
2593
|
this.tapTimer = setTimeout(() => {
|
|
2566
2594
|
this.tapTimer = void 0, this.toggleBar(t);
|
|
2567
|
-
},
|
|
2595
|
+
}, xn);
|
|
2568
2596
|
}
|
|
2569
2597
|
toggleBar(e) {
|
|
2570
2598
|
e ? this.poke() : this.hideIfIdle();
|
|
@@ -2599,7 +2627,7 @@ var Sn = class {
|
|
|
2599
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);
|
|
2600
2628
|
} else {
|
|
2601
2629
|
let r = this.doc.createElement("div");
|
|
2602
|
-
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)) {
|
|
2603
2631
|
let e = this.doc.createElement("button");
|
|
2604
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);
|
|
2605
2633
|
}
|
|
@@ -2640,7 +2668,7 @@ var Sn = class {
|
|
|
2640
2668
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
2641
2669
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
2642
2670
|
}
|
|
2643
|
-
!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)}`);
|
|
2644
2672
|
}
|
|
2645
2673
|
syncLive() {
|
|
2646
2674
|
let e = this.player.getStats(), t = e.isLive !== !1;
|
|
@@ -2690,17 +2718,17 @@ var Sn = class {
|
|
|
2690
2718
|
renderQualityMenu() {
|
|
2691
2719
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
2692
2720
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
2693
|
-
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)));
|
|
2694
2722
|
}
|
|
2695
2723
|
renderAudioMenu() {
|
|
2696
2724
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
2697
2725
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
2698
|
-
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)));
|
|
2699
2727
|
}
|
|
2700
2728
|
renderCcMenu() {
|
|
2701
2729
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
2702
2730
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
2703
|
-
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)));
|
|
2704
2732
|
}
|
|
2705
2733
|
onTracksChanged() {
|
|
2706
2734
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -2801,41 +2829,41 @@ var Sn = class {
|
|
|
2801
2829
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
2802
2830
|
}
|
|
2803
2831
|
};
|
|
2804
|
-
function
|
|
2832
|
+
function Tn(e) {
|
|
2805
2833
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
2806
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");
|
|
2807
2835
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
2808
2836
|
}
|
|
2809
|
-
function
|
|
2837
|
+
function En(e) {
|
|
2810
2838
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
2811
2839
|
}
|
|
2812
|
-
function
|
|
2840
|
+
function Dn(e) {
|
|
2813
2841
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2814
2842
|
}
|
|
2815
|
-
function
|
|
2843
|
+
function On(e) {
|
|
2816
2844
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2817
2845
|
}
|
|
2818
2846
|
//#endregion
|
|
2819
2847
|
//#region src/managed/index.ts
|
|
2820
|
-
var
|
|
2821
|
-
function
|
|
2848
|
+
var kn = 6e3, An = 45e3, jn = 2e3, Mn = 3, Nn = 2e3, Pn = 48e4;
|
|
2849
|
+
function Fn(e) {
|
|
2822
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)})`);
|
|
2823
2851
|
if (e.env !== void 0) return B(e.env);
|
|
2824
2852
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
|
|
2825
2853
|
return e.baseUrl;
|
|
2826
2854
|
}
|
|
2827
|
-
async function
|
|
2855
|
+
async function In(e) {
|
|
2828
2856
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
2829
|
-
let t =
|
|
2857
|
+
let t = Fn(e);
|
|
2830
2858
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
2831
2859
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
2832
|
-
let r = new
|
|
2860
|
+
let r = new Ln({
|
|
2833
2861
|
...e,
|
|
2834
2862
|
baseUrl: t
|
|
2835
2863
|
});
|
|
2836
2864
|
return await r.start(), r;
|
|
2837
2865
|
}
|
|
2838
|
-
var
|
|
2866
|
+
var Ln = class {
|
|
2839
2867
|
opts;
|
|
2840
2868
|
abort = new AbortController();
|
|
2841
2869
|
listeners = {};
|
|
@@ -2923,7 +2951,7 @@ var Fn = class {
|
|
|
2923
2951
|
setTimeout(() => {
|
|
2924
2952
|
a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
2925
2953
|
phase: i ? "unavailable" : "tooEarly",
|
|
2926
|
-
retryInMs:
|
|
2954
|
+
retryInMs: An,
|
|
2927
2955
|
attempt: 1,
|
|
2928
2956
|
elapsedMs: 0,
|
|
2929
2957
|
...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
|
|
@@ -2962,13 +2990,13 @@ var Fn = class {
|
|
|
2962
2990
|
!a && !p() && h();
|
|
2963
2991
|
}, e);
|
|
2964
2992
|
};
|
|
2965
|
-
_(
|
|
2993
|
+
_(kn), this.armingSub = E({
|
|
2966
2994
|
eventsBaseUrl: t,
|
|
2967
2995
|
matchUrn: this.opts.matchUrn,
|
|
2968
2996
|
credential: this.opts.credential,
|
|
2969
|
-
onAlive: () => _(
|
|
2997
|
+
onAlive: () => _(An),
|
|
2970
2998
|
onState: (e) => {
|
|
2971
|
-
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);
|
|
2972
3000
|
},
|
|
2973
3001
|
onError: () => h()
|
|
2974
3002
|
});
|
|
@@ -3013,19 +3041,19 @@ var Fn = class {
|
|
|
3013
3041
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
|
|
3014
3042
|
let i = e.analytics?.sid;
|
|
3015
3043
|
if (!i) return;
|
|
3016
|
-
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);
|
|
3017
3045
|
if (!o) {
|
|
3018
3046
|
s && setTimeout(() => {
|
|
3019
3047
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
|
|
3020
3048
|
}, 0);
|
|
3021
3049
|
return;
|
|
3022
3050
|
}
|
|
3023
|
-
let c = this.opts.video, l = new
|
|
3051
|
+
let c = this.opts.video, l = new on({
|
|
3024
3052
|
endpoint: o,
|
|
3025
3053
|
sid: i,
|
|
3026
3054
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
3027
|
-
sdkVersion:
|
|
3028
|
-
environment:
|
|
3055
|
+
sdkVersion: fn,
|
|
3056
|
+
environment: un(c),
|
|
3029
3057
|
idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
|
|
3030
3058
|
onIdle: () => this.onAnalyticsIdle(t),
|
|
3031
3059
|
onBlocked: (e) => setTimeout(() => {
|
|
@@ -3046,7 +3074,7 @@ var Fn = class {
|
|
|
3046
3074
|
let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
|
|
3047
3075
|
c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
|
|
3048
3076
|
c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
|
|
3049
|
-
}, 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");
|
|
3050
3078
|
}
|
|
3051
3079
|
currentPresentation() {
|
|
3052
3080
|
let e = this.opts.video;
|
|
@@ -3072,9 +3100,9 @@ var Fn = class {
|
|
|
3072
3100
|
emit: (e) => this.onEngineEvent(e)
|
|
3073
3101
|
}, o = this.opts.engine ?? "auto";
|
|
3074
3102
|
if (o === "native") return new K(a);
|
|
3075
|
-
if (o === "hls") return new
|
|
3076
|
-
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && W(this.opts.video) && G() || !e.drmEnabled &&
|
|
3077
|
-
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);
|
|
3078
3106
|
if (W(this.opts.video)) return new K(a);
|
|
3079
3107
|
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
3080
3108
|
}
|
|
@@ -3127,7 +3155,7 @@ var Fn = class {
|
|
|
3127
3155
|
r = 0, i = !1;
|
|
3128
3156
|
},
|
|
3129
3157
|
onError: () => {
|
|
3130
|
-
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.`))));
|
|
3131
3159
|
}
|
|
3132
3160
|
});
|
|
3133
3161
|
}
|
|
@@ -3149,7 +3177,7 @@ var Fn = class {
|
|
|
3149
3177
|
scheduleRejoin(e) {
|
|
3150
3178
|
this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
|
|
3151
3179
|
this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
|
|
3152
|
-
}, Math.random() *
|
|
3180
|
+
}, Math.random() * jn));
|
|
3153
3181
|
}
|
|
3154
3182
|
cancelRejoin() {
|
|
3155
3183
|
this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
|
|
@@ -3173,7 +3201,7 @@ var Fn = class {
|
|
|
3173
3201
|
}
|
|
3174
3202
|
t.controls = !1;
|
|
3175
3203
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
3176
|
-
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({
|
|
3177
3205
|
root: n,
|
|
3178
3206
|
video: t,
|
|
3179
3207
|
player: this,
|
|
@@ -3204,7 +3232,7 @@ var Fn = class {
|
|
|
3204
3232
|
}
|
|
3205
3233
|
startStats() {
|
|
3206
3234
|
this.stopStats();
|
|
3207
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
3235
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? Nn);
|
|
3208
3236
|
this.statsTimer = setInterval(() => {
|
|
3209
3237
|
if (!this.engine) return;
|
|
3210
3238
|
let e = this.engine.getStats();
|
|
@@ -3216,7 +3244,7 @@ var Fn = class {
|
|
|
3216
3244
|
}
|
|
3217
3245
|
scheduleLicenseRefresh() {
|
|
3218
3246
|
this.stopRefresh();
|
|
3219
|
-
let e = this.opts.licenseRefreshMs ??
|
|
3247
|
+
let e = this.opts.licenseRefreshMs ?? Pn;
|
|
3220
3248
|
e && this._descriptor?.drmEnabled && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
3221
3249
|
}
|
|
3222
3250
|
stopRefresh() {
|
|
@@ -3371,7 +3399,7 @@ function $(e) {
|
|
|
3371
3399
|
}
|
|
3372
3400
|
//#endregion
|
|
3373
3401
|
//#region src/embed/host.ts
|
|
3374
|
-
function
|
|
3402
|
+
function Rn(e) {
|
|
3375
3403
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
3376
3404
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
3377
3405
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -3430,15 +3458,15 @@ function In(e) {
|
|
|
3430
3458
|
}
|
|
3431
3459
|
//#endregion
|
|
3432
3460
|
//#region src/embed/page.ts
|
|
3433
|
-
var
|
|
3434
|
-
function
|
|
3461
|
+
var zn = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
3462
|
+
function Bn(e) {
|
|
3435
3463
|
if (typeof e == "boolean") return e;
|
|
3436
3464
|
if (typeof e == "object" && e) {
|
|
3437
3465
|
let t = e.endpoint;
|
|
3438
3466
|
return typeof t == "string" ? { endpoint: t } : {};
|
|
3439
3467
|
}
|
|
3440
3468
|
}
|
|
3441
|
-
function
|
|
3469
|
+
function Vn() {
|
|
3442
3470
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
3443
3471
|
if (e) return {
|
|
3444
3472
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -3448,7 +3476,7 @@ function zn() {
|
|
|
3448
3476
|
autoplay: e.autoplay ?? !0,
|
|
3449
3477
|
muted: e.muted ?? !0,
|
|
3450
3478
|
waitForLive: e.waitForLive ?? !0,
|
|
3451
|
-
analytics:
|
|
3479
|
+
analytics: Bn(e.analytics)
|
|
3452
3480
|
};
|
|
3453
3481
|
let t = new URLSearchParams(location.search);
|
|
3454
3482
|
return {
|
|
@@ -3461,9 +3489,9 @@ function zn() {
|
|
|
3461
3489
|
waitForLive: !0
|
|
3462
3490
|
};
|
|
3463
3491
|
}
|
|
3464
|
-
async function
|
|
3465
|
-
let e =
|
|
3466
|
-
|
|
3492
|
+
async function Hn() {
|
|
3493
|
+
let e = Vn();
|
|
3494
|
+
Wn();
|
|
3467
3495
|
let t = document.createElement("video");
|
|
3468
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);
|
|
3469
3497
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -3518,12 +3546,12 @@ async function Bn() {
|
|
|
3518
3546
|
code: e.code,
|
|
3519
3547
|
message: e.message
|
|
3520
3548
|
})), e.on("autoplayblocked", () => {
|
|
3521
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
3549
|
+
i({ type: "oddin:autoplayblocked" }), Un(t, e);
|
|
3522
3550
|
});
|
|
3523
3551
|
}, s = async (r) => {
|
|
3524
3552
|
a?.destroy(), a = null;
|
|
3525
3553
|
try {
|
|
3526
|
-
let n = await
|
|
3554
|
+
let n = await In({
|
|
3527
3555
|
video: t,
|
|
3528
3556
|
baseUrl: e.baseUrl,
|
|
3529
3557
|
matchUrn: r,
|
|
@@ -3585,7 +3613,7 @@ async function Bn() {
|
|
|
3585
3613
|
a?.retry();
|
|
3586
3614
|
break;
|
|
3587
3615
|
case "oddin:load":
|
|
3588
|
-
typeof e.matchUrn == "string" &&
|
|
3616
|
+
typeof e.matchUrn == "string" && zn.test(e.matchUrn) && s(e.matchUrn);
|
|
3589
3617
|
break;
|
|
3590
3618
|
case "oddin:destroy": c();
|
|
3591
3619
|
}
|
|
@@ -3597,18 +3625,18 @@ async function Bn() {
|
|
|
3597
3625
|
protocol: 1
|
|
3598
3626
|
});
|
|
3599
3627
|
}
|
|
3600
|
-
function
|
|
3628
|
+
function Un(e, t) {
|
|
3601
3629
|
if (document.getElementById("havik-tap")) return;
|
|
3602
3630
|
let n = document.createElement("button");
|
|
3603
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", () => {
|
|
3604
3632
|
n.remove(), t.play();
|
|
3605
3633
|
}), document.body.appendChild(n);
|
|
3606
3634
|
}
|
|
3607
|
-
function
|
|
3635
|
+
function Wn() {
|
|
3608
3636
|
let e = document.createElement("style");
|
|
3609
3637
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
3610
3638
|
}
|
|
3611
3639
|
//#endregion
|
|
3612
|
-
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 };
|
|
3613
3641
|
|
|
3614
3642
|
//# sourceMappingURL=index.js.map
|