@oddin-gg/havik-player 2.27.2 → 2.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/havik-player.global.js +3 -3
- package/dist/havik-player.global.js.map +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +302 -228
- package/dist/index.js.map +1 -1
- package/docs/API.md +48 -23
- package/embed/index.html +1 -1
- package/examples/vanilla.html +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8,8 +8,9 @@ var n = class extends Error {
|
|
|
8
8
|
serverCode;
|
|
9
9
|
liveStartsAtMs;
|
|
10
10
|
country;
|
|
11
|
+
detail;
|
|
11
12
|
constructor(e, t, n, r) {
|
|
12
|
-
super(n), this.name = "PlaybackError", this.code = e, this.httpStatus = t, this.retryAfterMs = r?.retryAfterMs, this.requestId = r?.requestId, this.serverCode = r?.serverCode, this.liveStartsAtMs = r?.liveStartsAtMs, this.country = r?.country, r?.cause !== void 0 && (this.cause = r.cause);
|
|
13
|
+
super(n), this.name = "PlaybackError", this.code = e, this.httpStatus = t, this.retryAfterMs = r?.retryAfterMs, this.requestId = r?.requestId, this.serverCode = r?.serverCode, this.liveStartsAtMs = r?.liveStartsAtMs, this.country = r?.country, this.detail = r?.detail, r?.cause !== void 0 && (this.cause = r.cause);
|
|
13
14
|
}
|
|
14
15
|
};
|
|
15
16
|
function r(e) {
|
|
@@ -1010,8 +1011,8 @@ function vt(e, t) {
|
|
|
1010
1011
|
}
|
|
1011
1012
|
//#endregion
|
|
1012
1013
|
//#region src/core/engine/native.ts
|
|
1013
|
-
var yt = 2e3, bt = 3, z = 500, xt = 6e3, St = .25, Ct = 250, wt = .05, Tt = 4, Et = 12e3, Dt = .25, Ot = 1e3;
|
|
1014
|
-
function
|
|
1014
|
+
var yt = 2e3, bt = 3, z = 500, xt = 6e3, St = .25, Ct = 250, wt = .05, Tt = 4, Et = 12e3, Dt = .25, Ot = 1e3, kt = 8e3, At = .05, jt = 2, Mt = 3e4;
|
|
1015
|
+
function Nt(e) {
|
|
1015
1016
|
try {
|
|
1016
1017
|
let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
|
|
1017
1018
|
return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
|
|
@@ -1027,7 +1028,7 @@ function V() {
|
|
|
1027
1028
|
let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
|
|
1028
1029
|
return e || t;
|
|
1029
1030
|
}
|
|
1030
|
-
function
|
|
1031
|
+
function Pt() {
|
|
1031
1032
|
if (typeof navigator > "u" || !V()) return !1;
|
|
1032
1033
|
let e = navigator.userAgent ?? "";
|
|
1033
1034
|
return /iPhone|iPad|iPod/.test(e) ? !0 : /Macintosh/.test(e) && typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1;
|
|
@@ -1053,6 +1054,11 @@ var H = class {
|
|
|
1053
1054
|
edgeStampedAt = null;
|
|
1054
1055
|
lastTickAt = null;
|
|
1055
1056
|
endedEmitted = !1;
|
|
1057
|
+
lastPlayhead = null;
|
|
1058
|
+
playheadStampedAt = null;
|
|
1059
|
+
movingSince = null;
|
|
1060
|
+
stuckReloads = 0;
|
|
1061
|
+
stuckReloadsTotal = 0;
|
|
1056
1062
|
fairplayKeyIV;
|
|
1057
1063
|
loadStarted;
|
|
1058
1064
|
preloadTouched = !1;
|
|
@@ -1083,7 +1089,7 @@ var H = class {
|
|
|
1083
1089
|
type: "error",
|
|
1084
1090
|
error: L() ? new n("INTERNAL", 0, "native HLS playback error") : new n("NETWORK", 0, "native HLS playback error while offline"),
|
|
1085
1091
|
fatal: !0
|
|
1086
|
-
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src =
|
|
1092
|
+
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = It(t.manifestUrl, t.analytics?.sid), e.load();
|
|
1087
1093
|
}
|
|
1088
1094
|
startLoad() {
|
|
1089
1095
|
this.loadStarted || (this.loadStarted = !0, this.restorePreload());
|
|
@@ -1111,7 +1117,7 @@ var H = class {
|
|
|
1111
1117
|
};
|
|
1112
1118
|
this.onEncrypted = (n) => {
|
|
1113
1119
|
let a = n;
|
|
1114
|
-
a.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV =
|
|
1120
|
+
a.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = Nt(a.initData), (async () => {
|
|
1115
1121
|
try {
|
|
1116
1122
|
let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
|
|
1117
1123
|
initDataTypes: [a.initDataType],
|
|
@@ -1211,7 +1217,7 @@ var H = class {
|
|
|
1211
1217
|
droppedFrames: t.dropped,
|
|
1212
1218
|
decodedFrames: t.totalFrames
|
|
1213
1219
|
};
|
|
1214
|
-
if (this.cdnHost ||= mt(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity) {
|
|
1220
|
+
if (this.cdnHost ||= mt(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), n.stuckReloads = this.stuckReloadsTotal, e.duration === Infinity) {
|
|
1215
1221
|
n.isLive = !0;
|
|
1216
1222
|
let t = this.liveEdgeEstimate(), r = t == null ? NaN : t - e.currentTime;
|
|
1217
1223
|
Number.isFinite(r) && (n.atLiveEdge = r <= Tt, !e.paused && r >= 0 && (n.latencySeconds = r));
|
|
@@ -1258,18 +1264,17 @@ var H = class {
|
|
|
1258
1264
|
if (this.edgeTimer != null) return;
|
|
1259
1265
|
let { video: e } = this.deps;
|
|
1260
1266
|
this.onEdgeReset = (e) => {
|
|
1261
|
-
this.lastBufferedEnd = null, this.bufferedAdvancedAt = null, e.type === "emptied" && this.resetEndStale();
|
|
1267
|
+
this.lastBufferedEnd = null, this.bufferedAdvancedAt = null, this.resetStuck(), e.type === "emptied" && this.resetEndStale();
|
|
1262
1268
|
}, e.addEventListener("seeking", this.onEdgeReset), e.addEventListener("emptied", this.onEdgeReset), this.edgeTimer = setInterval(() => {
|
|
1263
1269
|
if (e.duration !== Infinity) return;
|
|
1264
|
-
this.
|
|
1265
|
-
|
|
1266
|
-
|
|
1270
|
+
let t = U(), n = this.lastTickAt == null ? 0 : t - this.lastTickAt;
|
|
1271
|
+
this.lastTickAt = t;
|
|
1272
|
+
let r = Ft(e, e.currentTime);
|
|
1273
|
+
r != null && ((this.lastBufferedEnd == null || Math.abs(r - this.lastBufferedEnd) >= wt) && (this.bufferedAdvancedAt = t), this.lastBufferedEnd = r), this.checkEndStale(t, n), this.checkStuck(t, n);
|
|
1267
1274
|
}, Ct);
|
|
1268
1275
|
}
|
|
1269
|
-
checkEndStale() {
|
|
1276
|
+
checkEndStale(e, t) {
|
|
1270
1277
|
if (this.endedEmitted) return;
|
|
1271
|
-
let e = U(), t = this.lastTickAt == null ? 0 : e - this.lastTickAt;
|
|
1272
|
-
this.lastTickAt = e;
|
|
1273
1278
|
let n = this.liveEnd();
|
|
1274
1279
|
if (n == null) return;
|
|
1275
1280
|
let r = this.lastSeekableEnd == null || Math.abs(n - this.lastSeekableEnd) >= Dt;
|
|
@@ -1287,13 +1292,44 @@ var H = class {
|
|
|
1287
1292
|
resetEndStale() {
|
|
1288
1293
|
this.lastSeekableEnd = null, this.edgeStampedAt = null, this.lastTickAt = null;
|
|
1289
1294
|
}
|
|
1295
|
+
checkStuck(e, t) {
|
|
1296
|
+
if (this.deps.stuckReload === !1 || this.endedEmitted) return;
|
|
1297
|
+
let n = this.deps.video, r = n.currentTime, i = this.lastPlayhead == null || !Number.isFinite(r) || Math.abs(r - this.lastPlayhead) >= At;
|
|
1298
|
+
this.lastPlayhead = Number.isFinite(r) ? r : null;
|
|
1299
|
+
let a = typeof document < "u" && document.visibilityState === "hidden", o = t > Ot || a || n.paused || n.seeking || n.readyState < HTMLMediaElement.HAVE_CURRENT_DATA || !L();
|
|
1300
|
+
if (i || o) {
|
|
1301
|
+
this.playheadStampedAt = e, i && !o ? (this.movingSince ??= e, this.stuckReloads > 0 && e - this.movingSince >= Mt && (this.stuckReloads = 0)) : this.movingSince = null;
|
|
1302
|
+
return;
|
|
1303
|
+
}
|
|
1304
|
+
this.movingSince = null;
|
|
1305
|
+
let s = e - (this.playheadStampedAt ?? e), c = this.bufferedAdvancedAt == null ? Infinity : e - this.bufferedAdvancedAt;
|
|
1306
|
+
s <= kt || c <= kt || (this.playheadStampedAt = e, !(this.stuckReloads >= jt) && this.reloadStuck());
|
|
1307
|
+
}
|
|
1308
|
+
resetStuck() {
|
|
1309
|
+
this.lastPlayhead = null, this.playheadStampedAt = null, this.movingSince = null;
|
|
1310
|
+
}
|
|
1311
|
+
reloadStuck() {
|
|
1312
|
+
let { video: e, descriptor: t } = this.deps;
|
|
1313
|
+
this.stuckReloads += 1, this.stuckReloadsTotal += 1;
|
|
1314
|
+
let n = !e.paused;
|
|
1315
|
+
console.warn("havik-player: native playback frozen, buffer not growing: reloading at live");
|
|
1316
|
+
try {
|
|
1317
|
+
e.src = It(t.manifestUrl, t.analytics?.sid), e.load();
|
|
1318
|
+
} catch (e) {
|
|
1319
|
+
console.warn("havik-player: reload failed", e);
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
n && Promise.resolve(e.play()).catch((e) => {
|
|
1323
|
+
console.warn("havik-player: play() after the reload was refused", e);
|
|
1324
|
+
});
|
|
1325
|
+
}
|
|
1290
1326
|
unwatchBufferedEnd() {
|
|
1291
|
-
this.edgeTimer != null && clearInterval(this.edgeTimer), this.edgeTimer = null, this.onEdgeReset &&= (this.deps.video.removeEventListener("seeking", this.onEdgeReset), this.deps.video.removeEventListener("emptied", this.onEdgeReset), null), this.resetEndStale(), this.lastBufferedEnd = null, this.bufferedAdvancedAt = null;
|
|
1327
|
+
this.edgeTimer != null && clearInterval(this.edgeTimer), this.edgeTimer = null, this.onEdgeReset &&= (this.deps.video.removeEventListener("seeking", this.onEdgeReset), this.deps.video.removeEventListener("emptied", this.onEdgeReset), null), this.resetEndStale(), this.resetStuck(), this.lastBufferedEnd = null, this.bufferedAdvancedAt = null;
|
|
1292
1328
|
}
|
|
1293
1329
|
liveEdgeEstimate() {
|
|
1294
1330
|
let e = this.deps.video;
|
|
1295
1331
|
if (e.duration !== Infinity) return null;
|
|
1296
|
-
let t = this.liveEnd(), n =
|
|
1332
|
+
let t = this.liveEnd(), n = Ft(e, e.currentTime) ?? this.lastBufferedEnd;
|
|
1297
1333
|
if (n != null) {
|
|
1298
1334
|
let e = this.bufferedAdvancedAt, r = n + (e == null ? 0 : Math.max(0, (U() - e) / 1e3));
|
|
1299
1335
|
(t == null || r > t) && (t = r);
|
|
@@ -1330,7 +1366,7 @@ var H = class {
|
|
|
1330
1366
|
function U() {
|
|
1331
1367
|
return typeof performance < "u" ? performance.now() : Date.now();
|
|
1332
1368
|
}
|
|
1333
|
-
function
|
|
1369
|
+
function Ft(e, t) {
|
|
1334
1370
|
let n = e.buffered;
|
|
1335
1371
|
if (!n || !Number.isFinite(t)) return null;
|
|
1336
1372
|
for (let e = 0; e < n.length; e += 1) if (n.start(e) <= t + .1 && n.end(e) > t) {
|
|
@@ -1339,7 +1375,7 @@ function jt(e, t) {
|
|
|
1339
1375
|
}
|
|
1340
1376
|
return null;
|
|
1341
1377
|
}
|
|
1342
|
-
function
|
|
1378
|
+
function It(e, t) {
|
|
1343
1379
|
return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
|
|
1344
1380
|
}
|
|
1345
1381
|
//#endregion
|
|
@@ -1356,13 +1392,13 @@ function W(e, t = Date.now()) {
|
|
|
1356
1392
|
}
|
|
1357
1393
|
//#endregion
|
|
1358
1394
|
//#region src/core/drm/xhrBody.ts
|
|
1359
|
-
var
|
|
1360
|
-
function
|
|
1395
|
+
var Lt = 4096;
|
|
1396
|
+
function Rt(e) {
|
|
1361
1397
|
if (!e || typeof e != "object") return;
|
|
1362
1398
|
let { response: t } = e;
|
|
1363
1399
|
if (typeof t == "string") return t;
|
|
1364
1400
|
let n;
|
|
1365
|
-
if (Object.prototype.toString.call(t) === "[object ArrayBuffer]" ? n = new Uint8Array(t) : ArrayBuffer.isView(t) && (n = new Uint8Array(t.buffer, t.byteOffset, t.byteLength)), !(!n || n.byteLength === 0 || n.byteLength >
|
|
1401
|
+
if (Object.prototype.toString.call(t) === "[object ArrayBuffer]" ? n = new Uint8Array(t) : ArrayBuffer.isView(t) && (n = new Uint8Array(t.buffer, t.byteOffset, t.byteLength)), !(!n || n.byteLength === 0 || n.byteLength > Lt)) try {
|
|
1366
1402
|
return new TextDecoder().decode(n);
|
|
1367
1403
|
} catch {
|
|
1368
1404
|
return;
|
|
@@ -1370,7 +1406,7 @@ function Pt(e) {
|
|
|
1370
1406
|
}
|
|
1371
1407
|
//#endregion
|
|
1372
1408
|
//#region src/core/engine/prefetch.ts
|
|
1373
|
-
var
|
|
1409
|
+
var zt = 15e3, Bt = 5e3, Vt = 6, Ht = 4e3, Ut = 2;
|
|
1374
1410
|
function G(e) {
|
|
1375
1411
|
try {
|
|
1376
1412
|
let t = new URL(e);
|
|
@@ -1379,7 +1415,7 @@ function G(e) {
|
|
|
1379
1415
|
return e;
|
|
1380
1416
|
}
|
|
1381
1417
|
}
|
|
1382
|
-
var
|
|
1418
|
+
var Wt = class {
|
|
1383
1419
|
cmcd;
|
|
1384
1420
|
entries = /* @__PURE__ */ new Map();
|
|
1385
1421
|
keyed = /* @__PURE__ */ new Set();
|
|
@@ -1411,17 +1447,17 @@ var Bt = class {
|
|
|
1411
1447
|
let r = G(e);
|
|
1412
1448
|
if (this.entries.has(r)) return;
|
|
1413
1449
|
let i = this.perTrack.get(t) ?? 0;
|
|
1414
|
-
i >=
|
|
1450
|
+
i >= Vt || (this.perTrack.set(t, i + 1), this.start(r, this.withCmcd(e, t, n), !1, zt), this.stats.started += 1);
|
|
1415
1451
|
}
|
|
1416
1452
|
prefetchHint(e, t) {
|
|
1417
1453
|
let n = G(e);
|
|
1418
1454
|
if (this.entries.has(n)) return;
|
|
1419
1455
|
let r = this.hints.get(t) ?? [];
|
|
1420
|
-
for (; r.length >=
|
|
1456
|
+
for (; r.length >= Ut;) {
|
|
1421
1457
|
let e = r.shift();
|
|
1422
1458
|
e !== void 0 && this.drop(e) && (this.stats.hintDropped += 1);
|
|
1423
1459
|
}
|
|
1424
|
-
r.push(n), this.hints.set(t, r), this.start(n, this.withCmcd(e, t, "media"), !0,
|
|
1460
|
+
r.push(n), this.hints.set(t, r), this.start(n, this.withCmcd(e, t, "media"), !0, Ht), this.stats.hintStarted += 1;
|
|
1425
1461
|
}
|
|
1426
1462
|
dropHints(e) {
|
|
1427
1463
|
for (let t of this.hints.get(e) ?? []) this.drop(t) && (this.stats.hintDropped += 1);
|
|
@@ -1474,14 +1510,14 @@ var Bt = class {
|
|
|
1474
1510
|
}
|
|
1475
1511
|
}
|
|
1476
1512
|
};
|
|
1477
|
-
function
|
|
1513
|
+
function Gt(t, n) {
|
|
1478
1514
|
let r = typeof n == "function" ? n : e.DefaultConfig?.loader;
|
|
1479
1515
|
if (typeof r != "function") return;
|
|
1480
1516
|
class i extends r {
|
|
1481
1517
|
served = !1;
|
|
1482
1518
|
cancelled = !1;
|
|
1483
1519
|
entry;
|
|
1484
|
-
stats =
|
|
1520
|
+
stats = Kt();
|
|
1485
1521
|
load(e, n, r) {
|
|
1486
1522
|
let i = e.rangeEnd ? void 0 : t.take(e.url);
|
|
1487
1523
|
if (!i) {
|
|
@@ -1493,7 +1529,7 @@ function Vt(t, n) {
|
|
|
1493
1529
|
i.hint ? t.stats.hintFailed += 1 : t.stats.failed += 1;
|
|
1494
1530
|
}, s = () => {
|
|
1495
1531
|
!this.cancelled && this.served && (i.abort.abort(), o(), this.served = !1, this.entry = void 0, super.load(e, n, r));
|
|
1496
|
-
}, c = n?.loadPolicy, l = c?.maxTimeToFirstByteMs ||
|
|
1532
|
+
}, c = n?.loadPolicy, l = c?.maxTimeToFirstByteMs || Bt, u = setTimeout(s, l);
|
|
1497
1533
|
i.headers.then(() => {
|
|
1498
1534
|
clearTimeout(u);
|
|
1499
1535
|
let e = c?.maxLoadTimeMs;
|
|
@@ -1526,7 +1562,7 @@ function Vt(t, n) {
|
|
|
1526
1562
|
}
|
|
1527
1563
|
return i;
|
|
1528
1564
|
}
|
|
1529
|
-
function
|
|
1565
|
+
function Kt() {
|
|
1530
1566
|
return {
|
|
1531
1567
|
aborted: !1,
|
|
1532
1568
|
loaded: 0,
|
|
@@ -1550,10 +1586,10 @@ function Ht() {
|
|
|
1550
1586
|
}
|
|
1551
1587
|
};
|
|
1552
1588
|
}
|
|
1553
|
-
function
|
|
1589
|
+
function qt(e) {
|
|
1554
1590
|
return e === "audio" ? "audio" : "main";
|
|
1555
1591
|
}
|
|
1556
|
-
function
|
|
1592
|
+
function Jt(e, t) {
|
|
1557
1593
|
let n = [];
|
|
1558
1594
|
t.initSegment?.url && !t.initSegment.data && n.push({
|
|
1559
1595
|
url: t.initSegment.url,
|
|
@@ -1570,7 +1606,7 @@ function Wt(e, t) {
|
|
|
1570
1606
|
});
|
|
1571
1607
|
return n;
|
|
1572
1608
|
}
|
|
1573
|
-
function
|
|
1609
|
+
function Yt(e) {
|
|
1574
1610
|
let t = e, n = t?.preloadHint;
|
|
1575
1611
|
if (!n || !t?.url || n.TYPE !== "PART" || n["BYTERANGE-START"] !== void 0 || n["BYTERANGE-LENGTH"] !== void 0) return null;
|
|
1576
1612
|
let r = n.URI;
|
|
@@ -1588,15 +1624,15 @@ function K(e, t) {
|
|
|
1588
1624
|
}
|
|
1589
1625
|
//#endregion
|
|
1590
1626
|
//#region src/core/engine/hls.ts
|
|
1591
|
-
function
|
|
1627
|
+
function Xt() {
|
|
1592
1628
|
return e.isSupported();
|
|
1593
1629
|
}
|
|
1594
|
-
var
|
|
1595
|
-
function
|
|
1630
|
+
var Zt = 3, Qt = 1e6, $t = 20, en = 1e4, tn = 3, nn = 5, rn = 3, an = 1e4, on = 3e4, sn = 12e3, cn = 3e3, ln = .02, un = 6e3, dn = .5, fn = 3, pn = .5, mn = 1.1, hn = .25, gn = 5e3, _n = 4e3, vn = 2, yn = 5, bn = 2, xn = 2, Sn = 4, Cn = 4, wn = 2e3, Tn = 3e4, En = 1, Dn = 2, On = .5, kn = .6, An = 2, jn = 1.5, Mn = 1e4, Nn = 18e4, Pn = .5, Fn = 2;
|
|
1631
|
+
function In(e) {
|
|
1596
1632
|
let t = e.config ?? {};
|
|
1597
1633
|
return t.capLevelToPlayerSize === !0 || t.capLevelOnFPSDrop === !0;
|
|
1598
1634
|
}
|
|
1599
|
-
var q = 8,
|
|
1635
|
+
var q = 8, Ln = 12e4, Rn = 6e4;
|
|
1600
1636
|
function J(e, t, n) {
|
|
1601
1637
|
if (n <= 0 || t < 0 || t >= e.length) return t;
|
|
1602
1638
|
let r = (t, n) => e[t].width === e[n].width && e[t].height === e[n].height, i = (t) => {
|
|
@@ -1609,11 +1645,11 @@ function J(e, t, n) {
|
|
|
1609
1645
|
function Y() {
|
|
1610
1646
|
return typeof self < "u" && self.devicePixelRatio > 0 ? self.devicePixelRatio : 1;
|
|
1611
1647
|
}
|
|
1612
|
-
var
|
|
1613
|
-
function
|
|
1648
|
+
var zn = .2, Bn = 30, Vn = 2, Hn = 2, Un = 2, Wn = 9, Gn = .5, Kn = 64, qn = 1e4, Jn = 8, Yn = .6, Xn = .4, Zn = .4, Qn = 2, $n = 6e4, X = .5, er = 3.5, tr = 300;
|
|
1649
|
+
function nr(e) {
|
|
1614
1650
|
return (e?.part ?? e?.frag)?.stats;
|
|
1615
1651
|
}
|
|
1616
|
-
function
|
|
1652
|
+
function rr() {
|
|
1617
1653
|
if (typeof navigator > "u") return 0;
|
|
1618
1654
|
try {
|
|
1619
1655
|
let e = navigator.connection?.rtt;
|
|
@@ -1622,20 +1658,20 @@ function $n() {
|
|
|
1622
1658
|
return 0;
|
|
1623
1659
|
}
|
|
1624
1660
|
}
|
|
1625
|
-
function
|
|
1661
|
+
function ir(e) {
|
|
1626
1662
|
if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
|
|
1627
1663
|
delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
|
|
1628
1664
|
return;
|
|
1629
1665
|
}
|
|
1630
|
-
e.liveSyncDuration ??=
|
|
1631
|
-
let t = Math.max(12, e.liveSyncDuration +
|
|
1632
|
-
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t),
|
|
1666
|
+
e.liveSyncDuration ??= Un;
|
|
1667
|
+
let t = Math.max(12, e.liveSyncDuration + Wn);
|
|
1668
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), ar(e, e.liveSyncDuration);
|
|
1633
1669
|
}
|
|
1634
|
-
function
|
|
1670
|
+
function ar(e, t) {
|
|
1635
1671
|
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
1636
1672
|
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
1637
1673
|
}
|
|
1638
|
-
var
|
|
1674
|
+
var or = class {
|
|
1639
1675
|
name = "hls";
|
|
1640
1676
|
hls = null;
|
|
1641
1677
|
deps;
|
|
@@ -1788,7 +1824,7 @@ var nr = class {
|
|
|
1788
1824
|
}
|
|
1789
1825
|
this.loadSuspended = !0;
|
|
1790
1826
|
}
|
|
1791
|
-
},
|
|
1827
|
+
}, gn));
|
|
1792
1828
|
}
|
|
1793
1829
|
resumeLoading() {
|
|
1794
1830
|
if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
|
|
@@ -1820,7 +1856,7 @@ var nr = class {
|
|
|
1820
1856
|
let t = e.liveSyncPosition;
|
|
1821
1857
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
1822
1858
|
let { video: n } = this.deps;
|
|
1823
|
-
n.currentTime <= t +
|
|
1859
|
+
n.currentTime <= t + Gn || (n.currentTime = t);
|
|
1824
1860
|
}
|
|
1825
1861
|
reanchorPartTimeline(e, t) {
|
|
1826
1862
|
let { frag: n, part: r } = t;
|
|
@@ -1832,7 +1868,7 @@ var nr = class {
|
|
|
1832
1868
|
let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
|
|
1833
1869
|
if (!s) return;
|
|
1834
1870
|
let c = a.startPTS - s.start;
|
|
1835
|
-
if (!(!Number.isFinite(c) || Math.abs(c) <
|
|
1871
|
+
if (!(!Number.isFinite(c) || Math.abs(c) < ln)) {
|
|
1836
1872
|
for (let e of i.fragments) e && e.setStart(e.start + c);
|
|
1837
1873
|
i.fragmentHint?.setStart(i.fragmentHint.start + c), this.deps.debug === !0 && console.info(`havik-player: LL-HLS timeline re-anchored by ${c >= 0 ? "+" : ""}${c.toFixed(3)}s at sn ${n.sn} (level ${n.level})`);
|
|
1838
1874
|
}
|
|
@@ -1872,7 +1908,7 @@ var nr = class {
|
|
|
1872
1908
|
return;
|
|
1873
1909
|
}
|
|
1874
1910
|
let l = this.hls, u, d = new Promise((e) => {
|
|
1875
|
-
u = setTimeout(() => e(void 0),
|
|
1911
|
+
u = setTimeout(() => e(void 0), an);
|
|
1876
1912
|
});
|
|
1877
1913
|
return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
|
|
1878
1914
|
if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
|
|
@@ -1890,28 +1926,28 @@ var nr = class {
|
|
|
1890
1926
|
this.prefetch?.destroy(), this.prefetch = null;
|
|
1891
1927
|
let p = !1, m = !1, h = u && this.deps.mediaDuringKey !== !1, g = this.deps.preloadHints !== !1;
|
|
1892
1928
|
if ((h || g) && !f.fLoader) {
|
|
1893
|
-
let e = new
|
|
1929
|
+
let e = new Wt({
|
|
1894
1930
|
sessionId: n.analytics?.sid,
|
|
1895
1931
|
contentId: n.matchUrn
|
|
1896
|
-
}), t =
|
|
1932
|
+
}), t = Gt(e, f.loader);
|
|
1897
1933
|
t && (this.prefetch = e, p = h, m = g, f.fLoader = t);
|
|
1898
1934
|
}
|
|
1899
|
-
|
|
1935
|
+
ir(f), this.catchUpRate = typeof f.maxLiveSyncPlaybackRate == "number" ? f.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (f.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = f.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = f.autoStartLoad !== !1;
|
|
1900
1936
|
let _ = new e(f);
|
|
1901
1937
|
if (this.hls = _, this.armHoldBack(_, f), _.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(_, t)), _.on(e.Events.MANIFEST_PARSED, () => {
|
|
1902
1938
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(_), this.measureLadder(_), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
|
|
1903
1939
|
}), _.on(e.Events.FRAG_BUFFERED, (e, t) => {
|
|
1904
1940
|
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(() => {
|
|
1905
1941
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
|
|
1906
|
-
},
|
|
1942
|
+
}, on)));
|
|
1907
1943
|
}), _.on(e.Events.FRAG_LOADING, (e, t) => {
|
|
1908
1944
|
t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
|
|
1909
1945
|
}), _.on(e.Events.FRAG_LOADED, (e, t) => {
|
|
1910
1946
|
t?.frag?.type === "main" && (this.mainFragsSinceTick += 1, this.bwFragsLoaded += 1, this.maybeRememberBandwidth(!1));
|
|
1911
|
-
let n = t?.frag, r =
|
|
1947
|
+
let n = t?.frag, r = nr(t), i = r?.loaded;
|
|
1912
1948
|
typeof i == "number" && (this.bytesLoaded += i), !this.reportedFirstBytes && typeof i == "number" && i > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
|
|
1913
1949
|
let a = r?.loading;
|
|
1914
|
-
a && a.end > 0 && a.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(a.end - a.start))), this.requestTimesMs.length >
|
|
1950
|
+
a && a.end > 0 && a.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(a.end - a.start))), this.requestTimesMs.length > Kn && this.requestTimesMs.shift()), this.sampleHoldBack(t), this.sampleHeadroom(t);
|
|
1915
1951
|
let o = n?.url;
|
|
1916
1952
|
if (o) {
|
|
1917
1953
|
let e = ft(o);
|
|
@@ -1931,8 +1967,8 @@ var nr = class {
|
|
|
1931
1967
|
let i = e;
|
|
1932
1968
|
if (!i?.live || !i.partList?.length || typeof i.edge != "number") return;
|
|
1933
1969
|
let a = n.buffered, o = a.length ? a.end(a.length - 1) : 0;
|
|
1934
|
-
if (i.edge - o >
|
|
1935
|
-
let s =
|
|
1970
|
+
if (i.edge - o > Zt * (i.partTarget || .5)) return;
|
|
1971
|
+
let s = Yt(e);
|
|
1936
1972
|
s && t.prefetchHint(s, r);
|
|
1937
1973
|
};
|
|
1938
1974
|
_.on(e.Events.LEVEL_LOADED, (e, t) => {
|
|
@@ -1944,15 +1980,15 @@ var nr = class {
|
|
|
1944
1980
|
if (this.prefetch && p) {
|
|
1945
1981
|
let t = this.prefetch;
|
|
1946
1982
|
_.on(e.Events.KEY_LOADING, (e, n) => {
|
|
1947
|
-
let r = n?.frag, i =
|
|
1948
|
-
if (r && t.isActive(i)) for (let e of
|
|
1949
|
-
}), _.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(
|
|
1983
|
+
let r = n?.frag, i = qt(r?.type);
|
|
1984
|
+
if (r && t.isActive(i)) for (let e of Jt(_, r)) t.prefetch(e.url, i, e.kind);
|
|
1985
|
+
}), _.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(qt(n?.frag?.type)));
|
|
1950
1986
|
}
|
|
1951
1987
|
_.on(e.Events.KEY_LOADED, () => {
|
|
1952
1988
|
u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
|
|
1953
1989
|
}), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
|
|
1954
1990
|
this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.adaptHoldBack(), this.reviewSizeCapHeadroom(), this.releaseStallCap(), this.checkFrameDrops();
|
|
1955
|
-
},
|
|
1991
|
+
}, cn), _.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
1956
1992
|
this.renditionSwitches += 1;
|
|
1957
1993
|
let n = this.lastLevelIndex >= 0 ? _.levels[this.lastLevelIndex] : void 0, r = _.levels[t.level];
|
|
1958
1994
|
n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, this.armFrameDropGrace(), l({
|
|
@@ -2013,8 +2049,8 @@ var nr = class {
|
|
|
2013
2049
|
let e = this.hls, t = this.sizeCapCover();
|
|
2014
2050
|
if (!e || !t) return null;
|
|
2015
2051
|
let { cover: n, deviceRatio: r } = t, i = this.deps.sizeCapHeadroom, a = i == null || Number.isNaN(i);
|
|
2016
|
-
if (a && r >=
|
|
2017
|
-
if (a) return this.headroomUngated || this.headroomGranted ? J(e.levels, n,
|
|
2052
|
+
if (a && r >= Dn) return n;
|
|
2053
|
+
if (a) return this.headroomUngated || this.headroomGranted ? J(e.levels, n, En) : n;
|
|
2018
2054
|
let o = i === Infinity ? e.levels.length : Math.max(0, Math.floor(i));
|
|
2019
2055
|
return J(e.levels, n, o);
|
|
2020
2056
|
}
|
|
@@ -2031,11 +2067,11 @@ var nr = class {
|
|
|
2031
2067
|
return;
|
|
2032
2068
|
}
|
|
2033
2069
|
this.capTimer && clearTimeout(this.capTimer);
|
|
2034
|
-
let t = e > this.sizeCapLevel ?
|
|
2070
|
+
let t = e > this.sizeCapLevel ? wn : Tn;
|
|
2035
2071
|
this.capTimer = setTimeout(() => {
|
|
2036
2072
|
this.capTimer = null;
|
|
2037
2073
|
let n = this.computeSizeCapTarget();
|
|
2038
|
-
n === e || t ===
|
|
2074
|
+
n === e || t === Tn && n != null && n < e ? this.applySizeCap() : this.onMediaResize();
|
|
2039
2075
|
}, t);
|
|
2040
2076
|
}
|
|
2041
2077
|
measureLadder(e) {
|
|
@@ -2062,7 +2098,7 @@ var nr = class {
|
|
|
2062
2098
|
}
|
|
2063
2099
|
defaultHeadroomApplies() {
|
|
2064
2100
|
let e = this.deps.sizeCapHeadroom;
|
|
2065
|
-
return e != null && !Number.isNaN(e) || this.headroomUngated ? !1 : Y() <
|
|
2101
|
+
return e != null && !Number.isNaN(e) || this.headroomUngated ? !1 : Y() < Dn;
|
|
2066
2102
|
}
|
|
2067
2103
|
applySizeCapUnlessPending() {
|
|
2068
2104
|
this.capTimer || this.applySizeCap();
|
|
@@ -2071,7 +2107,7 @@ var nr = class {
|
|
|
2071
2107
|
if (!this.sizeCapManaged || !this.defaultHeadroomApplies() || e.frag?.type !== "main" || typeof e.frag.level != "number" || typeof document < "u" && document.hidden) return;
|
|
2072
2108
|
let t = e.part ? e.part.duration : this.detectedLowLatency ? 0 : e.frag.duration;
|
|
2073
2109
|
if (typeof t != "number" || !(t > 0)) return;
|
|
2074
|
-
let n =
|
|
2110
|
+
let n = nr(e)?.loading;
|
|
2075
2111
|
if (!n || !(n.start > 0) || !(n.end >= n.start)) return;
|
|
2076
2112
|
let r = this.hls?.levels?.[e.frag.level]?.bitrate;
|
|
2077
2113
|
if (!(typeof r == "number" && r > 0)) return;
|
|
@@ -2084,7 +2120,7 @@ var nr = class {
|
|
|
2084
2120
|
}
|
|
2085
2121
|
onPlaybackStall(e) {
|
|
2086
2122
|
let t = Date.now();
|
|
2087
|
-
this.deps.video.seeking || !this.playingSince || t - this.playingSince <
|
|
2123
|
+
this.deps.video.seeking || !this.playingSince || t - this.playingSince < Mn || (this.lastStallAt = t, this.stepStallCapDown(t, e), this.headroomGranted && (this.headroomGranted = !1, this.applySizeCapUnlessPending()));
|
|
2088
2124
|
}
|
|
2089
2125
|
stallCapLevel(e) {
|
|
2090
2126
|
if (this.stallCapBitrate == null) return -1;
|
|
@@ -2095,7 +2131,7 @@ var nr = class {
|
|
|
2095
2131
|
}
|
|
2096
2132
|
stepStallCapDown(e, t) {
|
|
2097
2133
|
let n = this.hls;
|
|
2098
|
-
if (!n || !this.stallCapEnabled ||
|
|
2134
|
+
if (!n || !this.stallCapEnabled || In(n) || !n.autoLevelEnabled || typeof t == "number" && t >= Pn || this.isLiveEdgeWait(n, t ?? 0)) return;
|
|
2099
2135
|
this.stallCapBitrate != null && (this.stallCapSince = e);
|
|
2100
2136
|
let r = Math.max(n.levels[n.currentLevel]?.bitrate ?? 0, n.levels[n.loadLevel]?.bitrate ?? 0);
|
|
2101
2137
|
if (!(r > 0)) return;
|
|
@@ -2106,7 +2142,7 @@ var nr = class {
|
|
|
2106
2142
|
let n = e.latestLevelDetails;
|
|
2107
2143
|
if (!n?.live) return !1;
|
|
2108
2144
|
let r = n.partTarget || n.targetduration;
|
|
2109
|
-
return !(r > 0) || !(n.edge > 0) ? !1 : n.edge - (this.deps.video.currentTime + t) <
|
|
2145
|
+
return !(r > 0) || !(n.edge > 0) ? !1 : n.edge - (this.deps.video.currentTime + t) < Fn * r;
|
|
2110
2146
|
}
|
|
2111
2147
|
releaseStallCap() {
|
|
2112
2148
|
let e = this.hls, t = Date.now(), n = this.stallCapTickAt;
|
|
@@ -2115,7 +2151,7 @@ var nr = class {
|
|
|
2115
2151
|
n && (this.stallCapSince += t - Math.max(n, this.stallCapSince));
|
|
2116
2152
|
return;
|
|
2117
2153
|
}
|
|
2118
|
-
if (t - this.stallCapSince <
|
|
2154
|
+
if (t - this.stallCapSince < Nn) return;
|
|
2119
2155
|
let r = this.stallCapBitrate, i = e.levels.map((e) => e.bitrate).filter((e) => e > r).sort((e, t) => e - t)[0];
|
|
2120
2156
|
this.stallCapBitrate = i ?? null, this.stallCapSince = t, this.pushCap();
|
|
2121
2157
|
}
|
|
@@ -2128,26 +2164,26 @@ var nr = class {
|
|
|
2128
2164
|
this.headroomGranted = !1, this.headroomSamples = [];
|
|
2129
2165
|
return;
|
|
2130
2166
|
}
|
|
2131
|
-
this.headroomSamples = this.headroomSamples.filter((t) => t.t >= e -
|
|
2167
|
+
this.headroomSamples = this.headroomSamples.filter((t) => t.t >= e - qn);
|
|
2132
2168
|
let r = this.headroomEarned(n, e);
|
|
2133
|
-
r !== this.headroomGranted && (r || (this.headroomRegrantAt = e +
|
|
2169
|
+
r !== this.headroomGranted && (r || (this.headroomRegrantAt = e + Rn), this.headroomGranted = r, this.applySizeCapUnlessPending());
|
|
2134
2170
|
}
|
|
2135
2171
|
headroomEarned(e, t) {
|
|
2136
|
-
if (t - this.lastStallAt <
|
|
2172
|
+
if (t - this.lastStallAt < Ln || !this.headroomGranted && t < this.headroomRegrantAt || !this.headroomGranted && this.headroomSamples.length < q) return !1;
|
|
2137
2173
|
let n = e.levels, r = this.sizeCapCoverLevel();
|
|
2138
2174
|
if (r == null) return this.headroomGranted;
|
|
2139
|
-
let i = J(n, r,
|
|
2175
|
+
let i = J(n, r, En);
|
|
2140
2176
|
if (i === r) return this.headroomGranted;
|
|
2141
|
-
let a = n[i]?.bitrate, o = e.bandwidthEstimate, s = this.headroomGranted ?
|
|
2177
|
+
let a = n[i]?.bitrate, o = e.bandwidthEstimate, s = this.headroomGranted ? jn : An;
|
|
2142
2178
|
if (!(a > 0) || !(o >= s * a)) return !1;
|
|
2143
2179
|
let c = (e) => K([...e].sort((e, t) => e - t), 90);
|
|
2144
2180
|
if (this.headroomGranted) {
|
|
2145
2181
|
let e = this.headroomSamples.filter((e) => e.bitrate >= a).map((e) => e.ratio);
|
|
2146
|
-
return e.length < q || c(e) <=
|
|
2182
|
+
return e.length < q || c(e) <= kn;
|
|
2147
2183
|
}
|
|
2148
2184
|
let l = [];
|
|
2149
2185
|
for (let e of this.headroomSamples) e.bitrate < a && l.push(e.ratio * (a / e.bitrate));
|
|
2150
|
-
return l.length >= q && c(l) <=
|
|
2186
|
+
return l.length >= q && c(l) <= On;
|
|
2151
2187
|
}
|
|
2152
2188
|
applySizeCap() {
|
|
2153
2189
|
if (!this.sizeCapManaged) return;
|
|
@@ -2222,7 +2258,7 @@ var nr = class {
|
|
|
2222
2258
|
let t = e.currentLevel >= 0 ? e.levels[e.currentLevel] : void 0;
|
|
2223
2259
|
t && (n.levelHeight = t.height);
|
|
2224
2260
|
let r = e.autoLevelCapping, i = r >= 0 ? e.levels[r] : void 0;
|
|
2225
|
-
i && i.height > 0 && (n.maxLevelHeight = i.height, !
|
|
2261
|
+
i && i.height > 0 && (n.maxLevelHeight = i.height, !In(e) && r === this.pushedCapLevel && this.pushedCapReason && (n.capReason = this.pushedCapReason)), t?.videoCodec && (n.videoCodec = t.videoCodec), t?.audioCodec && (n.audioCodec = t.audioCodec), t && typeof t.bitrate == "number" && (n.renditionBitrateKbps = Math.round(t.bitrate / 1e3)), typeof t?.details?.live == "boolean" && (n.isLive = t.details.live, typeof e.liveSyncPosition == "number" && (n.atLiveEdge = this.deps.video.currentTime >= e.liveSyncPosition - 1.5));
|
|
2226
2262
|
}
|
|
2227
2263
|
return n;
|
|
2228
2264
|
}
|
|
@@ -2250,7 +2286,7 @@ var nr = class {
|
|
|
2250
2286
|
return;
|
|
2251
2287
|
}
|
|
2252
2288
|
let e = Date.now() - this.lastAdvanceMs;
|
|
2253
|
-
!this.chaseSuspended && e >
|
|
2289
|
+
!this.chaseSuspended && e > un && this.suspendChasing(), e > sn && this.emitEnded("stalled");
|
|
2254
2290
|
}
|
|
2255
2291
|
resetStarvationWindow() {
|
|
2256
2292
|
this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
|
|
@@ -2265,7 +2301,7 @@ var nr = class {
|
|
|
2265
2301
|
this.resetStarvationWindow();
|
|
2266
2302
|
return;
|
|
2267
2303
|
}
|
|
2268
|
-
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs <
|
|
2304
|
+
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < un, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > _n, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = R(t), c = o - s, l = c !== this.starvedFrames;
|
|
2269
2305
|
if (this.starvedFrames = c, !a || l) {
|
|
2270
2306
|
(t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
|
|
2271
2307
|
return;
|
|
@@ -2274,12 +2310,12 @@ var nr = class {
|
|
|
2274
2310
|
this.resetStarvationWindow();
|
|
2275
2311
|
return;
|
|
2276
2312
|
}
|
|
2277
|
-
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 >
|
|
2313
|
+
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 > Sn && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= bn && (this.clearKick(), this.starvationRebuilds < xn)) {
|
|
2278
2314
|
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");
|
|
2279
2315
|
return;
|
|
2280
2316
|
}
|
|
2281
|
-
let u = i && this.starvedTicks >=
|
|
2282
|
-
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >=
|
|
2317
|
+
let u = i && this.starvedTicks >= vn, d = !i && this.deadTicks >= Sn && this.recentMainFrags.reduce((e, t) => e + t, 0) >= Cn;
|
|
2318
|
+
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= yn))) {
|
|
2283
2319
|
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");
|
|
2284
2320
|
try {
|
|
2285
2321
|
e.stopLoad(), e.startLoad(-1);
|
|
@@ -2294,7 +2330,7 @@ var nr = class {
|
|
|
2294
2330
|
let t = e.latency, n = e.targetLatency;
|
|
2295
2331
|
if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
|
|
2296
2332
|
let r = t - n;
|
|
2297
|
-
!this.catchUpEngaged && r >
|
|
2333
|
+
!this.catchUpEngaged && r > dn ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= dn && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
|
|
2298
2334
|
let i = this.catchUpEngaged ? this.catchUpRate : 1;
|
|
2299
2335
|
e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
|
|
2300
2336
|
}
|
|
@@ -2307,7 +2343,7 @@ var nr = class {
|
|
|
2307
2343
|
}), n < 0 ? 0 : n;
|
|
2308
2344
|
}
|
|
2309
2345
|
armFrameDropGrace() {
|
|
2310
|
-
this.fpsGraceTicks > 0 || (this.fpsGraceTicks =
|
|
2346
|
+
this.fpsGraceTicks > 0 || (this.fpsGraceTicks = Hn, this.fpsBadTicks = 0);
|
|
2311
2347
|
}
|
|
2312
2348
|
resetFrameDropWindow() {
|
|
2313
2349
|
this.fpsLastFrames = -1, this.fpsLastDropped = -1, this.fpsBadTicks = 0;
|
|
@@ -2319,7 +2355,7 @@ var nr = class {
|
|
|
2319
2355
|
return;
|
|
2320
2356
|
}
|
|
2321
2357
|
let { totalFrames: n, dropped: r } = R(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
|
|
2322
|
-
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a <
|
|
2358
|
+
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Bn || o < 0) {
|
|
2323
2359
|
this.fpsBadTicks = 0;
|
|
2324
2360
|
return;
|
|
2325
2361
|
}
|
|
@@ -2327,11 +2363,11 @@ var nr = class {
|
|
|
2327
2363
|
--this.fpsGraceTicks, this.fpsBadTicks = 0;
|
|
2328
2364
|
return;
|
|
2329
2365
|
}
|
|
2330
|
-
if (o <=
|
|
2366
|
+
if (o <= zn * a) {
|
|
2331
2367
|
this.fpsBadTicks = 0;
|
|
2332
2368
|
return;
|
|
2333
2369
|
}
|
|
2334
|
-
if (this.fpsBadTicks += 1, this.fpsBadTicks <
|
|
2370
|
+
if (this.fpsBadTicks += 1, this.fpsBadTicks < Vn) return;
|
|
2335
2371
|
this.fpsBadTicks = 0;
|
|
2336
2372
|
let s = e.levels, c = s[e.currentLevel];
|
|
2337
2373
|
if (!c) return;
|
|
@@ -2348,22 +2384,22 @@ var nr = class {
|
|
|
2348
2384
|
return;
|
|
2349
2385
|
}
|
|
2350
2386
|
let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
|
|
2351
|
-
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(
|
|
2387
|
+
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(mn, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
|
|
2352
2388
|
this.resetChaseWindow();
|
|
2353
2389
|
return;
|
|
2354
2390
|
}
|
|
2355
|
-
if (this.chaseLatency < 0 || this.chaseLatency - n >=
|
|
2391
|
+
if (this.chaseLatency < 0 || this.chaseLatency - n >= pn) {
|
|
2356
2392
|
this.chaseLatency = n, this.chaseTicks = 0;
|
|
2357
2393
|
return;
|
|
2358
2394
|
}
|
|
2359
|
-
if (this.chaseTicks += 1, this.chaseTicks <
|
|
2395
|
+
if (this.chaseTicks += 1, this.chaseTicks < fn) return;
|
|
2360
2396
|
this.resetChaseWindow();
|
|
2361
2397
|
let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
|
|
2362
2398
|
if (!(a > 1)) return;
|
|
2363
2399
|
let o = e.targetLatency;
|
|
2364
2400
|
if (typeof o != "number" || !(o > 0)) return;
|
|
2365
2401
|
let s = Math.min(n, a - 1);
|
|
2366
|
-
s < o +
|
|
2402
|
+
s < o + hn || (console.warn(`havik-player: catch-up at ${r}x not gaining on the live edge (latency ${n.toFixed(1)}s); holding at ${s.toFixed(1)}s`), this.liveRetargets += 1, e.targetLatency = s, this.deps.emit({
|
|
2367
2403
|
type: "livetargetchange",
|
|
2368
2404
|
change: {
|
|
2369
2405
|
targetSeconds: s,
|
|
@@ -2380,13 +2416,13 @@ var nr = class {
|
|
|
2380
2416
|
if (!this.holdBackEnabled || this.holdBackPriorChecked || !e || (this.holdBackPriorChecked = !0, this.holdBackApplied > 0 || this.holdBackStepCount > 0)) return;
|
|
2381
2417
|
let t = e.targetLatency;
|
|
2382
2418
|
if (this.holdBackBase < 0 && typeof t == "number" && t > 0 && (this.holdBackBase = t), this.holdBackBase < 0) return;
|
|
2383
|
-
let n =
|
|
2384
|
-
if (!(n >=
|
|
2419
|
+
let n = rr();
|
|
2420
|
+
if (!(n >= tr)) return;
|
|
2385
2421
|
let r = typeof t == "number" && t > 0 ? t : this.holdBackBase, i = Math.min(this.holdBackCeiling(e), this.holdBackBase + X);
|
|
2386
2422
|
i > r && (this.holdBackStepCount = 1, this.moveHoldBack(e, r, i, "connection-rtt", `connection rtt ${n} ms`));
|
|
2387
2423
|
}
|
|
2388
2424
|
holdBackCeiling(e) {
|
|
2389
|
-
let t = this.deps.adaptiveHoldBackCeiling, n = typeof t == "number" && Number.isFinite(t) ? t :
|
|
2425
|
+
let t = this.deps.adaptiveHoldBackCeiling, n = typeof t == "number" && Number.isFinite(t) ? t : er, r = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
|
|
2390
2426
|
return r > 1 ? Math.min(n, r - 1) : n;
|
|
2391
2427
|
}
|
|
2392
2428
|
sampleHoldBack(e) {
|
|
@@ -2395,7 +2431,7 @@ var nr = class {
|
|
|
2395
2431
|
if (t !== "main" && t !== "audio") return;
|
|
2396
2432
|
let n = e.part ? e.part.duration : this.detectedLowLatency ? 0 : e.frag?.duration;
|
|
2397
2433
|
if (typeof n != "number" || !(n > 0)) return;
|
|
2398
|
-
let r =
|
|
2434
|
+
let r = nr(e)?.loading;
|
|
2399
2435
|
if (!r || !(r.start > 0) || !(r.end > 0)) return;
|
|
2400
2436
|
let i = r.first > r.start ? r.first : r.end, a = Math.max(0, i - r.start) / (n * 1e3);
|
|
2401
2437
|
this.holdBackSamples.push({
|
|
@@ -2410,20 +2446,20 @@ var nr = class {
|
|
|
2410
2446
|
this.holdBackSlowTicks = 0, this.holdBackFastSince = 0, this.holdBackSamples = [];
|
|
2411
2447
|
return;
|
|
2412
2448
|
}
|
|
2413
|
-
let t = Date.now(), n = t -
|
|
2449
|
+
let t = Date.now(), n = t - qn, r = this.holdBackSamples, i = 0;
|
|
2414
2450
|
for (; i < r.length && r[i].t < n;) i += 1;
|
|
2415
2451
|
i > 0 && r.splice(0, i);
|
|
2416
2452
|
let a = e.targetLatency;
|
|
2417
2453
|
if (typeof a != "number" || !(a > 0)) return;
|
|
2418
2454
|
this.holdBackBase < 0 && (this.holdBackBase = a);
|
|
2419
2455
|
let o = this.holdBackBase, s = this.holdBackCeiling(e);
|
|
2420
|
-
if (r.length <
|
|
2456
|
+
if (r.length < Jn) {
|
|
2421
2457
|
this.holdBackSlowTicks = 0;
|
|
2422
2458
|
return;
|
|
2423
2459
|
}
|
|
2424
2460
|
let c = r.map((e) => e.ratio).sort((e, t) => e - t), l = K(c, 95), u = K(c, 50), d = Math.round(l * 1e3);
|
|
2425
|
-
if (l >=
|
|
2426
|
-
if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks <
|
|
2461
|
+
if (l >= Yn && u >= Xn) {
|
|
2462
|
+
if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks < Qn) return;
|
|
2427
2463
|
this.holdBackSlowTicks = 0;
|
|
2428
2464
|
let t = Math.ceil((s - o) / X), n = Math.ceil((a - o) / X - 1e-9);
|
|
2429
2465
|
if (n > this.holdBackStepCount && (this.holdBackStepCount = n), this.holdBackStepCount >= t) return;
|
|
@@ -2433,7 +2469,7 @@ var nr = class {
|
|
|
2433
2469
|
this.moveHoldBack(e, a, r, "slow-fetches", `part fetches slow (first byte p50 ${Math.round(u * 1e3)} / p95 ${d} ms per 1 s of media)`);
|
|
2434
2470
|
return;
|
|
2435
2471
|
}
|
|
2436
|
-
if (this.holdBackSlowTicks = 0, l >=
|
|
2472
|
+
if (this.holdBackSlowTicks = 0, l >= Zn) {
|
|
2437
2473
|
this.holdBackFastSince = 0;
|
|
2438
2474
|
return;
|
|
2439
2475
|
}
|
|
@@ -2441,7 +2477,7 @@ var nr = class {
|
|
|
2441
2477
|
this.holdBackFastSince = t;
|
|
2442
2478
|
return;
|
|
2443
2479
|
}
|
|
2444
|
-
if (t - this.holdBackFastSince <
|
|
2480
|
+
if (t - this.holdBackFastSince < $n || (this.holdBackFastSince = t, this.holdBackStepCount === 0 || a !== this.holdBackApplied)) return;
|
|
2445
2481
|
--this.holdBackStepCount;
|
|
2446
2482
|
let f = Math.max(o, o + this.holdBackStepCount * X);
|
|
2447
2483
|
f >= a || this.moveHoldBack(e, a, f, "fast-fetches", `part fetches fast again (p95 first byte ${d} ms per 1 s of media)`);
|
|
@@ -2484,12 +2520,12 @@ var nr = class {
|
|
|
2484
2520
|
} catch {}
|
|
2485
2521
|
}
|
|
2486
2522
|
startEstimate() {
|
|
2487
|
-
return this.deps.rememberBandwidth === !1 ?
|
|
2523
|
+
return this.deps.rememberBandwidth === !1 ? Qt : Be() ?? Qt;
|
|
2488
2524
|
}
|
|
2489
2525
|
maybeRememberBandwidth(e) {
|
|
2490
|
-
if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded <
|
|
2526
|
+
if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < $t) return;
|
|
2491
2527
|
let t = Date.now();
|
|
2492
|
-
if (!e && t - this.bwSavedAt <
|
|
2528
|
+
if (!e && t - this.bwSavedAt < en) return;
|
|
2493
2529
|
let n = this.hls?.bandwidthEstimate;
|
|
2494
2530
|
typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Ve(n));
|
|
2495
2531
|
}
|
|
@@ -2509,7 +2545,7 @@ var nr = class {
|
|
|
2509
2545
|
scheduleLicenseRetry(t) {
|
|
2510
2546
|
if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
|
|
2511
2547
|
let n = t.response?.code ?? 0;
|
|
2512
|
-
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >=
|
|
2548
|
+
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= rn) return !1;
|
|
2513
2549
|
this.licenseRecoveries += 1;
|
|
2514
2550
|
let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
|
|
2515
2551
|
return this.licenseRetryTimer = setTimeout(() => {
|
|
@@ -2545,7 +2581,7 @@ var nr = class {
|
|
|
2545
2581
|
this.offlineHold = !0, this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null);
|
|
2546
2582
|
return;
|
|
2547
2583
|
}
|
|
2548
|
-
if (this.networkRecoveries <
|
|
2584
|
+
if (this.networkRecoveries < nn) {
|
|
2549
2585
|
this.networkRecoveries += 1;
|
|
2550
2586
|
let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
|
|
2551
2587
|
this.networkRetryTimer = setTimeout(() => {
|
|
@@ -2562,7 +2598,7 @@ var nr = class {
|
|
|
2562
2598
|
return;
|
|
2563
2599
|
}
|
|
2564
2600
|
if (t.type === e.ErrorTypes.MEDIA_ERROR) {
|
|
2565
|
-
if (this.mediaRecoveries <
|
|
2601
|
+
if (this.mediaRecoveries < tn) {
|
|
2566
2602
|
this.mediaRecoveries += 1, n.recoverMediaError();
|
|
2567
2603
|
return;
|
|
2568
2604
|
}
|
|
@@ -2583,18 +2619,21 @@ var nr = class {
|
|
|
2583
2619
|
}
|
|
2584
2620
|
}
|
|
2585
2621
|
toError(t, r = "PLAYBACK") {
|
|
2586
|
-
let o = t.response?.code ?? 0, s = t.details ?? t.type, c = t.reason ?? t.error?.message ?? "", l = r === "DRM" && o === 403 && t.details === e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED ? i(
|
|
2587
|
-
return new n(r === "DRM" ? a(o, l) : r === "NETWORK" && o === 0 ? "NETWORK" : o === 401 ? "UNAUTHORIZED" : o === 403 ? "FORBIDDEN" : "INTERNAL", o, `${r} error: ${s}${c ? ` (${c})` : ""}`,
|
|
2622
|
+
let o = t.response?.code ?? 0, s = t.details ?? t.type, c = t.reason ?? t.error?.message ?? "", l = r === "DRM" && o === 403 && t.details === e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED ? i(Rt(t.networkDetails)) : void 0;
|
|
2623
|
+
return new n(r === "DRM" ? a(o, l) : r === "NETWORK" && o === 0 ? "NETWORK" : o === 401 ? "UNAUTHORIZED" : o === 403 ? "FORBIDDEN" : "INTERNAL", o, `${r} error: ${s}${c ? ` (${c})` : ""}`, {
|
|
2624
|
+
detail: s,
|
|
2625
|
+
...l ? { serverCode: l } : {}
|
|
2626
|
+
});
|
|
2588
2627
|
}
|
|
2589
|
-
},
|
|
2628
|
+
}, sr = 15e3, cr = 6e5, lr = 3e5, ur = 100, Z = 1, dr = 1e3, fr = 3e4, pr = 1e3, mr = {
|
|
2590
2629
|
inline: "PRESENTATION_INLINE",
|
|
2591
2630
|
fullscreen: "PRESENTATION_FULLSCREEN",
|
|
2592
2631
|
pip: "PRESENTATION_PIP"
|
|
2593
|
-
},
|
|
2632
|
+
}, hr = {
|
|
2594
2633
|
widevine: "KEY_SYSTEM_WIDEVINE",
|
|
2595
2634
|
fairplay: "KEY_SYSTEM_FAIRPLAY",
|
|
2596
2635
|
none: "KEY_SYSTEM_NONE"
|
|
2597
|
-
},
|
|
2636
|
+
}, gr = /* @__PURE__ */ new Set([
|
|
2598
2637
|
"INVALID_URN",
|
|
2599
2638
|
"NOT_FOUND",
|
|
2600
2639
|
"GEO_DENIED",
|
|
@@ -2605,7 +2644,7 @@ var nr = class {
|
|
|
2605
2644
|
"FORBIDDEN",
|
|
2606
2645
|
"RATE_LIMITED",
|
|
2607
2646
|
"TIMEOUT"
|
|
2608
|
-
]),
|
|
2647
|
+
]), _r = {
|
|
2609
2648
|
idle: "PLAYER_STATE_IDLE",
|
|
2610
2649
|
waiting: "PLAYER_STATE_WAITING",
|
|
2611
2650
|
loading: "PLAYER_STATE_LOADING",
|
|
@@ -2615,7 +2654,7 @@ var nr = class {
|
|
|
2615
2654
|
ended: "PLAYER_STATE_ENDED",
|
|
2616
2655
|
error: "PLAYER_STATE_ERROR"
|
|
2617
2656
|
};
|
|
2618
|
-
function
|
|
2657
|
+
function vr(e) {
|
|
2619
2658
|
try {
|
|
2620
2659
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
2621
2660
|
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);
|
|
@@ -2623,8 +2662,8 @@ function mr(e) {
|
|
|
2623
2662
|
return;
|
|
2624
2663
|
}
|
|
2625
2664
|
}
|
|
2626
|
-
var
|
|
2627
|
-
function
|
|
2665
|
+
var yr = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), br = /* @__PURE__ */ new Set(), xr = /* @__PURE__ */ new Set(), Sr = /* @__PURE__ */ new Set(), Cr = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
|
|
2666
|
+
function wr(e) {
|
|
2628
2667
|
if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
|
|
2629
2668
|
let t;
|
|
2630
2669
|
try {
|
|
@@ -2633,19 +2672,19 @@ function br(e) {
|
|
|
2633
2672
|
} catch {
|
|
2634
2673
|
return;
|
|
2635
2674
|
}
|
|
2636
|
-
if (
|
|
2637
|
-
|
|
2638
|
-
for (let e of
|
|
2675
|
+
if (br.has(t) && !xr.has(t)) {
|
|
2676
|
+
xr.add(t), _(Cr(new URL(t).origin));
|
|
2677
|
+
for (let e of Sr) e.noteCspBlocked();
|
|
2639
2678
|
}
|
|
2640
2679
|
}
|
|
2641
|
-
function
|
|
2680
|
+
function Tr(e, t) {
|
|
2642
2681
|
return _(t, e), { disabledReason: t };
|
|
2643
2682
|
}
|
|
2644
|
-
function
|
|
2645
|
-
if (n) return t && !
|
|
2683
|
+
function Er(e, t, n) {
|
|
2684
|
+
if (n) return t && !yr(t, n) && _(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
|
|
2646
2685
|
if (t) return { endpoint: t };
|
|
2647
|
-
if (t !== void 0) return
|
|
2648
|
-
let r =
|
|
2686
|
+
if (t !== void 0) return Tr("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).");
|
|
2687
|
+
let r = vr(e);
|
|
2649
2688
|
if (r) return { endpoint: r };
|
|
2650
2689
|
let i;
|
|
2651
2690
|
try {
|
|
@@ -2653,9 +2692,9 @@ function Sr(e, t, n) {
|
|
|
2653
2692
|
} catch {
|
|
2654
2693
|
i = e;
|
|
2655
2694
|
}
|
|
2656
|
-
return
|
|
2695
|
+
return Tr(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).`);
|
|
2657
2696
|
}
|
|
2658
|
-
var
|
|
2697
|
+
var Dr = class {
|
|
2659
2698
|
opts;
|
|
2660
2699
|
url;
|
|
2661
2700
|
cspKey;
|
|
@@ -2737,8 +2776,8 @@ var Cr = class {
|
|
|
2737
2776
|
constructor(e) {
|
|
2738
2777
|
this.opts = {
|
|
2739
2778
|
...e,
|
|
2740
|
-
heartbeatMs: e.heartbeatMs ??
|
|
2741
|
-
idleMs: e.idleMs ??
|
|
2779
|
+
heartbeatMs: e.heartbeatMs ?? sr,
|
|
2780
|
+
idleMs: e.idleMs ?? cr
|
|
2742
2781
|
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
|
|
2743
2782
|
try {
|
|
2744
2783
|
let e = new URL(this.url);
|
|
@@ -2755,11 +2794,11 @@ var Cr = class {
|
|
|
2755
2794
|
sdkVersion: this.opts.sdkVersion,
|
|
2756
2795
|
...this.opts.environment
|
|
2757
2796
|
};
|
|
2758
|
-
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(),
|
|
2797
|
+
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), dr), 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 && br.add(this.cspKey), document.addEventListener("securitypolicyviolation", wr), Sr.add(this), this.noteCspBlocked(), this.onVisibility());
|
|
2759
2798
|
}
|
|
2760
2799
|
checkSuspension(e) {
|
|
2761
2800
|
if (this.endedFlag || !this.opts.idleMs) return !1;
|
|
2762
|
-
let t = Math.max(this.opts.idleMs,
|
|
2801
|
+
let t = Math.max(this.opts.idleMs, lr);
|
|
2763
2802
|
return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
|
|
2764
2803
|
}
|
|
2765
2804
|
syncIdle(e) {
|
|
@@ -2780,14 +2819,14 @@ var Cr = class {
|
|
|
2780
2819
|
} else e === "buffering" && (this.isBuffering = !1, this.stallIsSeekInduced = !1);
|
|
2781
2820
|
this.syncBuffering(), t === "paused" && (this.pauseCount += 1), this.syncIdle(t);
|
|
2782
2821
|
let a = {
|
|
2783
|
-
fromState:
|
|
2784
|
-
toState:
|
|
2785
|
-
presentation:
|
|
2822
|
+
fromState: _r[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2823
|
+
toState: _r[t] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2824
|
+
presentation: mr[this.presentation]
|
|
2786
2825
|
}, o = this.causeOf(e, t, i);
|
|
2787
2826
|
o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
2788
2827
|
}
|
|
2789
2828
|
seekInduced(e) {
|
|
2790
|
-
return this.lastSeekMs >= 0 && e - this.lastSeekMs <
|
|
2829
|
+
return this.lastSeekMs >= 0 && e - this.lastSeekMs < pr;
|
|
2791
2830
|
}
|
|
2792
2831
|
causeOf(e, t, n) {
|
|
2793
2832
|
if (t === "error") return "TRANSITION_CAUSE_ERROR";
|
|
@@ -2861,7 +2900,7 @@ var Cr = class {
|
|
|
2861
2900
|
let r = n ?? "";
|
|
2862
2901
|
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";
|
|
2863
2902
|
if (e === "DRM_CLIENT" || e === "DRM_DEVICE_REVOKED") return "ERROR_STAGE_DRM";
|
|
2864
|
-
if (
|
|
2903
|
+
if (gr.has(e)) return "ERROR_STAGE_RESOLVE";
|
|
2865
2904
|
let i = t ?? "";
|
|
2866
2905
|
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";
|
|
2867
2906
|
}
|
|
@@ -2893,7 +2932,7 @@ var Cr = class {
|
|
|
2893
2932
|
let l = t.droppedFrames ?? 0;
|
|
2894
2933
|
l > this.lastDropped && (o.droppedFramesDelta = l - this.lastDropped), this.lastDropped = l;
|
|
2895
2934
|
let u = t.renditionSwitches ?? 0;
|
|
2896
|
-
u > this.lastSwitches && (o.renditionSwitchesDelta = u - this.lastSwitches), this.lastSwitches = u, n > this.lastHbPlayingMs && (o.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (o.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, i > this.lastHbRebufferMs && (o.rebufferMsDelta = Math.round(i - this.lastHbRebufferMs)), this.lastHbRebufferMs = i, this.rebufferCount > this.lastHbRebufferCount && (o.rebufferCountDelta = this.rebufferCount - this.lastHbRebufferCount), this.lastHbRebufferCount = this.rebufferCount, a > this.lastHbActiveMs && (o.activeMsDelta = Math.round(a - this.lastHbActiveMs)), this.lastHbActiveMs = a, typeof t.latencySeconds == "number" && (o.latencyMs = Math.round(t.latencySeconds * 1e3)), typeof t.targetLatencySeconds == "number" && (o.targetLatencyMs = Math.round(t.targetLatencySeconds * 1e3)), typeof t.bandwidthKbps == "number" && (o.bandwidthEstKbps = t.bandwidthKbps), typeof t.levelHeight == "number" && (o.renditionHeight = t.levelHeight), typeof t.renditionBitrateKbps == "number" && (o.renditionBitrateKbps = t.renditionBitrateKbps), t.atLiveEdge === !0 && (o.atLiveEdge = !0), typeof t.bufferedMs == "number" && t.bufferedMs > 0 && (o.bufferedMs = Math.round(t.bufferedMs)), o.playerState =
|
|
2935
|
+
u > this.lastSwitches && (o.renditionSwitchesDelta = u - this.lastSwitches), this.lastSwitches = u, n > this.lastHbPlayingMs && (o.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (o.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, i > this.lastHbRebufferMs && (o.rebufferMsDelta = Math.round(i - this.lastHbRebufferMs)), this.lastHbRebufferMs = i, this.rebufferCount > this.lastHbRebufferCount && (o.rebufferCountDelta = this.rebufferCount - this.lastHbRebufferCount), this.lastHbRebufferCount = this.rebufferCount, a > this.lastHbActiveMs && (o.activeMsDelta = Math.round(a - this.lastHbActiveMs)), this.lastHbActiveMs = a, typeof t.latencySeconds == "number" && (o.latencyMs = Math.round(t.latencySeconds * 1e3)), typeof t.targetLatencySeconds == "number" && (o.targetLatencyMs = Math.round(t.targetLatencySeconds * 1e3)), typeof t.bandwidthKbps == "number" && (o.bandwidthEstKbps = t.bandwidthKbps), typeof t.levelHeight == "number" && (o.renditionHeight = t.levelHeight), typeof t.renditionBitrateKbps == "number" && (o.renditionBitrateKbps = t.renditionBitrateKbps), t.atLiveEdge === !0 && (o.atLiveEdge = !0), typeof t.bufferedMs == "number" && t.bufferedMs > 0 && (o.bufferedMs = Math.round(t.bufferedMs)), o.playerState = _r[t.state] ?? "PLAYER_STATE_UNSPECIFIED";
|
|
2897
2936
|
let d = this.mutedTotalMs;
|
|
2898
2937
|
this.mutedSinceMs !== null && (d += e - this.mutedSinceMs), d > this.lastHbMutedMs && (o.mutedMsDelta = Math.round(d - this.lastHbMutedMs)), this.lastHbMutedMs = d;
|
|
2899
2938
|
let f = t.upshifts ?? 0;
|
|
@@ -2915,13 +2954,13 @@ var Cr = class {
|
|
|
2915
2954
|
maybeEmitMediaInfo(e) {
|
|
2916
2955
|
if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
|
|
2917
2956
|
let t = {};
|
|
2918
|
-
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem =
|
|
2957
|
+
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = hr[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);
|
|
2919
2958
|
let n = JSON.stringify(t);
|
|
2920
2959
|
n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
|
|
2921
2960
|
}
|
|
2922
2961
|
end(e, t) {
|
|
2923
2962
|
if (this.endedFlag) return;
|
|
2924
|
-
this.endedFlag = !0,
|
|
2963
|
+
this.endedFlag = !0, Sr.delete(this);
|
|
2925
2964
|
let n = t ?? this.now();
|
|
2926
2965
|
this.playingSinceMs !== null && (this.playingTotalMs += n - this.playingSinceMs, this.playingSinceMs = null), this.hiddenSinceMs !== null && (this.hiddenTotalMs += n - this.hiddenSinceMs, this.hiddenSinceMs = null), this.bufferingSinceMs !== null && (this.rebufferTotalMs += n - this.bufferingSinceMs, this.bufferingSinceMs = null), this.mutedSinceMs !== null && (this.mutedTotalMs += n - this.mutedSinceMs, this.mutedSinceMs = null), this.waitingSinceMs !== null && (this.waitingTotalMs += n - this.waitingSinceMs, this.waitingSinceMs = null), this.isPlaying = !1, this.syncActive(n), this.closePresentation(n), this.firstFlushTimer &&= (clearTimeout(this.firstFlushTimer), null), this.timer &&= (clearInterval(this.timer), null), this.idleTimer &&= (clearTimeout(this.idleTimer), null), typeof window < "u" && window.removeEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), document.removeEventListener("freeze", this.onFreeze), document.removeEventListener("resume", this.onResume));
|
|
2927
2966
|
let r = this.safeSample();
|
|
@@ -2935,7 +2974,7 @@ var Cr = class {
|
|
|
2935
2974
|
let c = r?.positionMs ?? 0;
|
|
2936
2975
|
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));
|
|
2937
2976
|
let l = e !== "END_REASON_ENDED";
|
|
2938
|
-
l && this.lastStallMs > 0 && n - this.lastStallMs <=
|
|
2977
|
+
l && this.lastStallMs > 0 && n - this.lastStallMs <= fr && (i.abandonAfterStallMs = Math.max(Z, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= fr && (i.abandonAfterErrorMs = Math.max(Z, 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);
|
|
2939
2978
|
let u = r?.decodedFrames ?? this.lastDecoded;
|
|
2940
2979
|
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");
|
|
2941
2980
|
}
|
|
@@ -2955,13 +2994,13 @@ var Cr = class {
|
|
|
2955
2994
|
};
|
|
2956
2995
|
}
|
|
2957
2996
|
noteCspBlocked() {
|
|
2958
|
-
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(
|
|
2997
|
+
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(Cr(new URL(this.url).origin)));
|
|
2959
2998
|
}
|
|
2960
2999
|
cspBlocked() {
|
|
2961
|
-
return !!this.cspKey &&
|
|
3000
|
+
return !!this.cspKey && xr.has(this.cspKey);
|
|
2962
3001
|
}
|
|
2963
3002
|
enqueue(e) {
|
|
2964
|
-
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length >
|
|
3003
|
+
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > ur;) {
|
|
2965
3004
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
2966
3005
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
2967
3006
|
}
|
|
@@ -2988,7 +3027,7 @@ var Cr = class {
|
|
|
2988
3027
|
};
|
|
2989
3028
|
//#endregion
|
|
2990
3029
|
//#region src/core/environment.ts
|
|
2991
|
-
function
|
|
3030
|
+
function Or() {
|
|
2992
3031
|
if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
|
|
2993
3032
|
let e;
|
|
2994
3033
|
try {
|
|
@@ -3013,14 +3052,14 @@ function wr() {
|
|
|
3013
3052
|
integration: "INTEGRATION_KIND_IFRAME"
|
|
3014
3053
|
};
|
|
3015
3054
|
}
|
|
3016
|
-
function
|
|
3055
|
+
function kr() {
|
|
3017
3056
|
if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
|
|
3018
3057
|
let e = navigator.userAgentData, t = e?.platform ?? "";
|
|
3019
3058
|
if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
|
|
3020
3059
|
let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
|
|
3021
3060
|
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";
|
|
3022
3061
|
}
|
|
3023
|
-
function
|
|
3062
|
+
function Ar() {
|
|
3024
3063
|
let e = typeof navigator < "u" ? navigator.connection : void 0;
|
|
3025
3064
|
if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
|
|
3026
3065
|
let t = {
|
|
@@ -3039,17 +3078,17 @@ function Er() {
|
|
|
3039
3078
|
}
|
|
3040
3079
|
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;
|
|
3041
3080
|
}
|
|
3042
|
-
function
|
|
3043
|
-
let t =
|
|
3044
|
-
deviceClass:
|
|
3081
|
+
function jr(e) {
|
|
3082
|
+
let t = Or(), n = {
|
|
3083
|
+
deviceClass: kr(),
|
|
3045
3084
|
integration: t.integration,
|
|
3046
|
-
...
|
|
3085
|
+
...Ar()
|
|
3047
3086
|
};
|
|
3048
3087
|
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);
|
|
3049
3088
|
let r = e.getBoundingClientRect?.();
|
|
3050
3089
|
return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
|
|
3051
3090
|
}
|
|
3052
|
-
async function
|
|
3091
|
+
async function Mr() {
|
|
3053
3092
|
let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
|
|
3054
3093
|
if (!e?.getHighEntropyValues) return {};
|
|
3055
3094
|
try {
|
|
@@ -3061,7 +3100,7 @@ async function Or() {
|
|
|
3061
3100
|
}
|
|
3062
3101
|
//#endregion
|
|
3063
3102
|
//#region src/core/version.ts
|
|
3064
|
-
var
|
|
3103
|
+
var Nr = "2.28.0", Pr = {
|
|
3065
3104
|
accent: "#E1B600",
|
|
3066
3105
|
accentText: "#1B1C23",
|
|
3067
3106
|
background: "#0e0f13",
|
|
@@ -3072,7 +3111,7 @@ var kr = "2.27.2", Ar = {
|
|
|
3072
3111
|
border: "rgba(255, 255, 255, 0.1)",
|
|
3073
3112
|
radius: "8px",
|
|
3074
3113
|
fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
|
|
3075
|
-
},
|
|
3114
|
+
}, Fr = {
|
|
3076
3115
|
accent: "--havik-accent",
|
|
3077
3116
|
accentText: "--havik-accent-text",
|
|
3078
3117
|
background: "--havik-bg",
|
|
@@ -3084,26 +3123,26 @@ var kr = "2.27.2", Ar = {
|
|
|
3084
3123
|
radius: "--havik-radius",
|
|
3085
3124
|
fontFamily: "--havik-font"
|
|
3086
3125
|
};
|
|
3087
|
-
function
|
|
3126
|
+
function Ir(e, t) {
|
|
3088
3127
|
let n = {
|
|
3089
|
-
...
|
|
3128
|
+
...Pr,
|
|
3090
3129
|
...t
|
|
3091
3130
|
};
|
|
3092
|
-
for (let t of Object.keys(
|
|
3131
|
+
for (let t of Object.keys(Fr)) e.style.setProperty(Fr[t], n[t]);
|
|
3093
3132
|
n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
|
|
3094
3133
|
}
|
|
3095
3134
|
//#endregion
|
|
3096
3135
|
//#region src/ui/styles.ts
|
|
3097
|
-
var
|
|
3098
|
-
function
|
|
3099
|
-
let n = e.querySelector(`style#${
|
|
3100
|
-
if (n && (!t ||
|
|
3136
|
+
var Lr = "havik-player-styles", Rr = "\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", zr = /* @__PURE__ */ new WeakMap();
|
|
3137
|
+
function Br(e = document, t) {
|
|
3138
|
+
let n = e.querySelector(`style#${Lr}`);
|
|
3139
|
+
if (n && (!t || zr.get(n) === t)) return;
|
|
3101
3140
|
let r = e.createElement("style");
|
|
3102
|
-
r.id =
|
|
3141
|
+
r.id = Lr, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = Rr, zr.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
|
|
3103
3142
|
}
|
|
3104
3143
|
//#endregion
|
|
3105
3144
|
//#region src/ui/icons.ts
|
|
3106
|
-
var
|
|
3145
|
+
var Vr = {
|
|
3107
3146
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
3108
3147
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
3109
3148
|
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\"/>",
|
|
@@ -3117,11 +3156,11 @@ var Lr = {
|
|
|
3117
3156
|
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\"/>"
|
|
3118
3157
|
};
|
|
3119
3158
|
function Q(e) {
|
|
3120
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
3159
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Vr[e]}</svg>`;
|
|
3121
3160
|
}
|
|
3122
3161
|
//#endregion
|
|
3123
3162
|
//#region src/ui/controls.ts
|
|
3124
|
-
var
|
|
3163
|
+
var Hr = 3e3, Ur = 250, Wr = /* @__PURE__ */ new Set([
|
|
3125
3164
|
"GONE",
|
|
3126
3165
|
"NOT_FOUND",
|
|
3127
3166
|
"GEO_DENIED",
|
|
@@ -3129,15 +3168,19 @@ var Rr = 3e3, zr = 250, Br = /* @__PURE__ */ new Set([
|
|
|
3129
3168
|
"UNAUTHORIZED",
|
|
3130
3169
|
"DRM_DEVICE_REVOKED"
|
|
3131
3170
|
]);
|
|
3132
|
-
function
|
|
3171
|
+
function Gr(e) {
|
|
3133
3172
|
let t = "This match isn't available in your country";
|
|
3134
3173
|
return e ? `${t} (${e})` : t;
|
|
3135
3174
|
}
|
|
3136
|
-
var
|
|
3137
|
-
function
|
|
3138
|
-
return
|
|
3175
|
+
var Kr = "This device can't play protected video";
|
|
3176
|
+
function qr(e) {
|
|
3177
|
+
return `This browser can't play protected video. Allow protected content in its site settings, or use ${e ? "Chrome, Edge or Safari" : "Chrome or Edge"} (Firefox asks when you retry)`;
|
|
3139
3178
|
}
|
|
3140
|
-
var
|
|
3179
|
+
var Jr = "Protected video can't be shown on this display. Use the built-in screen, or an HDCP-capable monitor and cable";
|
|
3180
|
+
function Yr(e) {
|
|
3181
|
+
return new Xr(e);
|
|
3182
|
+
}
|
|
3183
|
+
var Xr = class {
|
|
3141
3184
|
root;
|
|
3142
3185
|
video;
|
|
3143
3186
|
player;
|
|
@@ -3186,7 +3229,7 @@ var Wr = class {
|
|
|
3186
3229
|
scrubbing = !1;
|
|
3187
3230
|
offFns = [];
|
|
3188
3231
|
constructor(e) {
|
|
3189
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
3232
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Hr, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.streamEnded = e.streamEnded ?? (() => !1), this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, this.offlineMessage = e.offlineMessage ?? "No internet connection — waiting to reconnect", Br(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");
|
|
3190
3233
|
let t = (e, t, n) => {
|
|
3191
3234
|
let r = this.doc.createElement(e);
|
|
3192
3235
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -3272,7 +3315,7 @@ var Wr = class {
|
|
|
3272
3315
|
let t = this.surfaceWasHidden;
|
|
3273
3316
|
this.tapTimer = setTimeout(() => {
|
|
3274
3317
|
this.tapTimer = void 0, this.toggleBar(t);
|
|
3275
|
-
},
|
|
3318
|
+
}, Ur);
|
|
3276
3319
|
}
|
|
3277
3320
|
toggleBar(e) {
|
|
3278
3321
|
e ? this.poke() : this.hideIfIdle();
|
|
@@ -3299,7 +3342,20 @@ var Wr = class {
|
|
|
3299
3342
|
this.renderStatus(t);
|
|
3300
3343
|
}
|
|
3301
3344
|
statusMessageFor(e) {
|
|
3302
|
-
|
|
3345
|
+
if (e === "ended") return this.isGone() ? this.endedMessage : this.player.endedReason === "interrupted" ? this.interruptedMessage : this.endedMessage;
|
|
3346
|
+
if (e === "offline") return this.offlineMessage;
|
|
3347
|
+
if (e === "waiting") return this.hasPlayed ? "Reconnecting — please stand by" : "Starting soon…";
|
|
3348
|
+
if (e === "error") {
|
|
3349
|
+
if (this.errorMessage !== void 0) return this.errorMessage;
|
|
3350
|
+
if (this.lastError?.code === "GEO_DENIED") return Gr(this.lastError.country);
|
|
3351
|
+
if (this.lastError?.code === "DRM_DEVICE_REVOKED") return Kr;
|
|
3352
|
+
if (this.lastError?.code === "DRM_CLIENT") {
|
|
3353
|
+
if (this.lastError.detail === "keySystemNoAccess") return qr(!!this.player.descriptor?.drm?.fairplay?.licenseUrl);
|
|
3354
|
+
if (this.lastError.detail === "keySystemStatusOutputRestricted") return Jr;
|
|
3355
|
+
}
|
|
3356
|
+
return this.lastError?.message ?? "Playback unavailable";
|
|
3357
|
+
}
|
|
3358
|
+
return null;
|
|
3303
3359
|
}
|
|
3304
3360
|
renderStatus(e) {
|
|
3305
3361
|
let t = this.statusMessageFor(e);
|
|
@@ -3314,7 +3370,7 @@ var Wr = class {
|
|
|
3314
3370
|
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);
|
|
3315
3371
|
} else {
|
|
3316
3372
|
let r = this.doc.createElement("div");
|
|
3317
|
-
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !
|
|
3373
|
+
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Wr.has(this.lastError.code)) {
|
|
3318
3374
|
let e = this.doc.createElement("button");
|
|
3319
3375
|
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);
|
|
3320
3376
|
}
|
|
@@ -3355,7 +3411,7 @@ var Wr = class {
|
|
|
3355
3411
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
3356
3412
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
3357
3413
|
}
|
|
3358
|
-
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${
|
|
3414
|
+
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Zr(this.video.currentTime)} / ${Zr(this.video.duration)}`);
|
|
3359
3415
|
}
|
|
3360
3416
|
syncLive() {
|
|
3361
3417
|
let e = this.player.getStats(), t = e.isLive !== !1, n = this.isGone(), r = this.player.state === "ended" || n, i = !t && !this.streamEnded() && !n;
|
|
@@ -3405,17 +3461,17 @@ var Wr = class {
|
|
|
3405
3461
|
renderQualityMenu() {
|
|
3406
3462
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
3407
3463
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
3408
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
3464
|
+
for (let n of e) this.menu.append(this.menuItem(Qr(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
3409
3465
|
}
|
|
3410
3466
|
renderAudioMenu() {
|
|
3411
3467
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
3412
3468
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
3413
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
3469
|
+
for (let t of e) this.menu.append(this.menuItem($r(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
3414
3470
|
}
|
|
3415
3471
|
renderCcMenu() {
|
|
3416
3472
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
3417
3473
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
3418
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
3474
|
+
for (let t of e) this.menu.append(this.menuItem(ei(t), !1, () => this.player.setTextTrack(t.id)));
|
|
3419
3475
|
}
|
|
3420
3476
|
onTracksChanged() {
|
|
3421
3477
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -3520,23 +3576,23 @@ var Wr = class {
|
|
|
3520
3576
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
3521
3577
|
}
|
|
3522
3578
|
};
|
|
3523
|
-
function
|
|
3579
|
+
function Zr(e) {
|
|
3524
3580
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
3525
3581
|
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");
|
|
3526
3582
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
3527
3583
|
}
|
|
3528
|
-
function
|
|
3584
|
+
function Qr(e) {
|
|
3529
3585
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
3530
3586
|
}
|
|
3531
|
-
function
|
|
3587
|
+
function $r(e) {
|
|
3532
3588
|
return e.name || e.lang || `Track ${e.id}`;
|
|
3533
3589
|
}
|
|
3534
|
-
function
|
|
3590
|
+
function ei(e) {
|
|
3535
3591
|
return e.name || e.lang || `Track ${e.id}`;
|
|
3536
3592
|
}
|
|
3537
3593
|
//#endregion
|
|
3538
3594
|
//#region src/managed/index.ts
|
|
3539
|
-
var
|
|
3595
|
+
var ti = 6e3, ni = 45e3, ri = 2e3, ii = 3, ai = 6e4, oi = 2, si = 6e5, ci = 5e3, li = 2e3, ui = 48e4, di = "keySystemLicenseRequestFailed", fi = /* @__PURE__ */ new Set([
|
|
3540
3596
|
"GONE",
|
|
3541
3597
|
"NOT_FOUND",
|
|
3542
3598
|
"INVALID_URN",
|
|
@@ -3544,27 +3600,27 @@ var Yr = 6e3, Xr = 45e3, Zr = 2e3, Qr = 3, $r = 5e3, ei = 2e3, ti = 48e4, ni = "
|
|
|
3544
3600
|
"GEO_DENIED",
|
|
3545
3601
|
"DRM_DEVICE_REVOKED"
|
|
3546
3602
|
]);
|
|
3547
|
-
function
|
|
3548
|
-
return !
|
|
3603
|
+
function pi(e) {
|
|
3604
|
+
return !fi.has(e);
|
|
3549
3605
|
}
|
|
3550
|
-
function
|
|
3606
|
+
function mi(e) {
|
|
3551
3607
|
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)})`);
|
|
3552
3608
|
if (e.env !== void 0) return lt(e.env);
|
|
3553
3609
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
|
|
3554
3610
|
return e.baseUrl;
|
|
3555
3611
|
}
|
|
3556
|
-
async function
|
|
3612
|
+
async function hi(e) {
|
|
3557
3613
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
3558
|
-
let t =
|
|
3614
|
+
let t = mi(e);
|
|
3559
3615
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
3560
3616
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
3561
|
-
let r = new
|
|
3617
|
+
let r = new gi({
|
|
3562
3618
|
...e,
|
|
3563
3619
|
baseUrl: t
|
|
3564
3620
|
});
|
|
3565
3621
|
return await r.start(), r;
|
|
3566
3622
|
}
|
|
3567
|
-
var
|
|
3623
|
+
var gi = class {
|
|
3568
3624
|
opts;
|
|
3569
3625
|
abort = new AbortController();
|
|
3570
3626
|
listeners = {};
|
|
@@ -3587,6 +3643,10 @@ var si = class {
|
|
|
3587
3643
|
destroyed = !1;
|
|
3588
3644
|
loadGen = 0;
|
|
3589
3645
|
liveStateSub = null;
|
|
3646
|
+
liveStateLast = null;
|
|
3647
|
+
liveStateAliveAt = 0;
|
|
3648
|
+
staleEndReloads = 0;
|
|
3649
|
+
staleEndWindowAt = 0;
|
|
3590
3650
|
endedHandled = !1;
|
|
3591
3651
|
_endedReason = null;
|
|
3592
3652
|
rejoinTimer = null;
|
|
@@ -3664,7 +3724,7 @@ var si = class {
|
|
|
3664
3724
|
setTimeout(() => {
|
|
3665
3725
|
a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
3666
3726
|
phase: i ? "unavailable" : "tooEarly",
|
|
3667
|
-
retryInMs:
|
|
3727
|
+
retryInMs: ni,
|
|
3668
3728
|
attempt: 1,
|
|
3669
3729
|
elapsedMs: 0,
|
|
3670
3730
|
...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
|
|
@@ -3703,13 +3763,13 @@ var si = class {
|
|
|
3703
3763
|
!a && !p() && h();
|
|
3704
3764
|
}, e);
|
|
3705
3765
|
};
|
|
3706
|
-
_(
|
|
3766
|
+
_(ti), this.armingSub = D({
|
|
3707
3767
|
eventsBaseUrl: t,
|
|
3708
3768
|
matchUrn: this.opts.matchUrn,
|
|
3709
3769
|
credential: this.opts.credential,
|
|
3710
|
-
onAlive: () => _(
|
|
3770
|
+
onAlive: () => _(ni),
|
|
3711
3771
|
onState: (e) => {
|
|
3712
|
-
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() *
|
|
3772
|
+
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * ri);
|
|
3713
3773
|
},
|
|
3714
3774
|
onError: () => h()
|
|
3715
3775
|
});
|
|
@@ -3754,19 +3814,19 @@ var si = class {
|
|
|
3754
3814
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
|
|
3755
3815
|
let i = e.analytics?.sid;
|
|
3756
3816
|
if (!i) return;
|
|
3757
|
-
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } =
|
|
3817
|
+
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = Er(this.opts.baseUrl, a, e.analytics?.endpoint);
|
|
3758
3818
|
if (!o) {
|
|
3759
3819
|
s && setTimeout(() => {
|
|
3760
3820
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
|
|
3761
3821
|
}, 0);
|
|
3762
3822
|
return;
|
|
3763
3823
|
}
|
|
3764
|
-
let c = this.opts.video, l = new
|
|
3824
|
+
let c = this.opts.video, l = new Dr({
|
|
3765
3825
|
endpoint: o,
|
|
3766
3826
|
sid: i,
|
|
3767
3827
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
3768
|
-
sdkVersion:
|
|
3769
|
-
environment:
|
|
3828
|
+
sdkVersion: Nr,
|
|
3829
|
+
environment: jr(c),
|
|
3770
3830
|
idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
|
|
3771
3831
|
onIdle: () => this.onAnalyticsIdle(t),
|
|
3772
3832
|
onBlocked: (e) => setTimeout(() => {
|
|
@@ -3787,7 +3847,7 @@ var si = class {
|
|
|
3787
3847
|
let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
|
|
3788
3848
|
c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
|
|
3789
3849
|
c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
|
|
3790
|
-
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()),
|
|
3850
|
+
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), Mr().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
|
|
3791
3851
|
}
|
|
3792
3852
|
currentPresentation() {
|
|
3793
3853
|
let e = this.opts.video;
|
|
@@ -3811,6 +3871,7 @@ var si = class {
|
|
|
3811
3871
|
adaptiveHoldBack: this.opts.adaptiveHoldBack,
|
|
3812
3872
|
adaptiveHoldBackCeiling: this.opts.adaptiveHoldBackCeiling,
|
|
3813
3873
|
stallCap: this.opts.stallCap,
|
|
3874
|
+
stuckReload: this.opts.stuckReload,
|
|
3814
3875
|
mediaDuringKey: this.opts.mediaDuringKey,
|
|
3815
3876
|
preloadHints: this.opts.preloadHints,
|
|
3816
3877
|
debug: this.opts.debug,
|
|
@@ -3820,9 +3881,9 @@ var si = class {
|
|
|
3820
3881
|
freshLicenseUrl: () => this.refreshLicense()
|
|
3821
3882
|
}, o = this.opts.engine ?? "auto";
|
|
3822
3883
|
if (o === "native") return new H(a);
|
|
3823
|
-
if (o === "hls") return new
|
|
3824
|
-
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && B(this.opts.video) && V() || !e.drmEnabled &&
|
|
3825
|
-
if (
|
|
3884
|
+
if (o === "hls") return new or(a);
|
|
3885
|
+
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && B(this.opts.video) && V() || !e.drmEnabled && Pt() && B(this.opts.video)) return new H(a);
|
|
3886
|
+
if (Xt()) return new or(a);
|
|
3826
3887
|
if (B(this.opts.video)) return new H(a);
|
|
3827
3888
|
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
3828
3889
|
}
|
|
@@ -3856,6 +3917,7 @@ var si = class {
|
|
|
3856
3917
|
this.emit("texttrackchange", e.id);
|
|
3857
3918
|
break;
|
|
3858
3919
|
case "ended":
|
|
3920
|
+
if (e.reason === "stalled" && this.reloadStaleEnd()) break;
|
|
3859
3921
|
this.onStreamEnded();
|
|
3860
3922
|
break;
|
|
3861
3923
|
case "error": {
|
|
@@ -3875,17 +3937,17 @@ var si = class {
|
|
|
3875
3937
|
if (this.opts.liveStateEvents === !1) return;
|
|
3876
3938
|
let t = this.opts.eventsBaseUrl ?? O(this.opts.baseUrl);
|
|
3877
3939
|
if (!t) return;
|
|
3878
|
-
this.closeLiveState();
|
|
3940
|
+
this.closeLiveState(), this.liveStateLast = null, this.liveStateAliveAt = 0;
|
|
3879
3941
|
let i = 0, a = !1;
|
|
3880
3942
|
this.liveStateSub = D({
|
|
3881
3943
|
eventsBaseUrl: t,
|
|
3882
3944
|
matchUrn: this.opts.matchUrn,
|
|
3883
3945
|
credential: this.opts.credential,
|
|
3884
3946
|
onState: (t) => {
|
|
3885
|
-
this.destroyed || e !== this.loadGen || (t.state === "gone" ? this.onStreamEnded(!0, t.reason ?? "match_ended") : t.state === "ended" ? this.onStreamEnded(!1, t.reason) : t.state === "live" && this.endedHandled && this.scheduleRejoin(e));
|
|
3947
|
+
this.destroyed || e !== this.loadGen || (this.liveStateLast = t.state, this.liveStateAliveAt = Date.now(), t.state === "gone" ? this.onStreamEnded(!0, t.reason ?? "match_ended") : t.state === "ended" ? this.onStreamEnded(!1, t.reason) : t.state === "live" && this.endedHandled && this.scheduleRejoin(e));
|
|
3886
3948
|
},
|
|
3887
3949
|
onAlive: () => {
|
|
3888
|
-
i = 0, a = !1;
|
|
3950
|
+
i = 0, a = !1, !this.destroyed && e === this.loadGen && (this.liveStateAliveAt = Date.now());
|
|
3889
3951
|
},
|
|
3890
3952
|
onError: (o) => {
|
|
3891
3953
|
if (!(this.destroyed || e !== this.loadGen || a) && !this.endedHandled) {
|
|
@@ -3893,7 +3955,7 @@ var si = class {
|
|
|
3893
3955
|
a = !0, this.emit("warning", new n(r(o.status), o.status, `live-state events answered HTTP ${o.status} for ${this.opts.matchUrn}: the match is ` + (o.terminal ? "gone, so the subscription stopped" : "not in the catalog (ended and dropped, or not listed yet), so it retries every 5 min") + " — end-of-stream detection falls back to the HLS staleness watchdog."));
|
|
3894
3956
|
return;
|
|
3895
3957
|
}
|
|
3896
|
-
i += 1, i >=
|
|
3958
|
+
i += 1, i >= ii && (a = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${i} 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.`)));
|
|
3897
3959
|
}
|
|
3898
3960
|
}
|
|
3899
3961
|
});
|
|
@@ -3901,6 +3963,18 @@ var si = class {
|
|
|
3901
3963
|
closeLiveState() {
|
|
3902
3964
|
this.liveStateSub?.close(), this.liveStateSub = null;
|
|
3903
3965
|
}
|
|
3966
|
+
reloadStaleEnd() {
|
|
3967
|
+
if (this.destroyed || this.endedHandled || this._state === "error" || this._state === "ended") return !1;
|
|
3968
|
+
let e = Date.now();
|
|
3969
|
+
if (this.liveStateLast !== "live" || e - this.liveStateAliveAt > ai || (e - this.staleEndWindowAt > si && (this.staleEndReloads = 0, this.staleEndWindowAt = e), this.staleEndReloads >= oi)) return !1;
|
|
3970
|
+
this.staleEndReloads += 1;
|
|
3971
|
+
let t = new n("UNAVAILABLE", 0, `live playlist stopped advancing for 12 s while the match is live (live-state push heard ${Math.round((e - this.liveStateAliveAt) / 1e3)} s ago): reloading instead of ending (${this.staleEndReloads} of ${oi} this window)`);
|
|
3972
|
+
this.analyticsSession?.noteError(t.code, t.message, !1, 0, Math.round(this.opts.video.currentTime * 1e3), "staleEndReload");
|
|
3973
|
+
let r = this.loadGen;
|
|
3974
|
+
return this.emit("warning", t), Promise.resolve().then(() => {
|
|
3975
|
+
if (!(this.destroyed || r !== this.loadGen) && this._state !== "error" && this._state !== "ended") return this.reload().catch(() => void 0);
|
|
3976
|
+
}), !0;
|
|
3977
|
+
}
|
|
3904
3978
|
watchConnectivity() {
|
|
3905
3979
|
this.connectivity || (this.connectivity = ut(), this.connectivity.onChange((e) => {
|
|
3906
3980
|
if (this.destroyed) return;
|
|
@@ -3910,7 +3984,7 @@ var si = class {
|
|
|
3910
3984
|
}
|
|
3911
3985
|
if (this.emit("online"), this._state !== "error" || !this._lastError) return;
|
|
3912
3986
|
let t = this._lastError.code;
|
|
3913
|
-
|
|
3987
|
+
pi(t) && (t === "NETWORK" || this.failedWhileOffline) && this.retry().catch(() => void 0);
|
|
3914
3988
|
}));
|
|
3915
3989
|
}
|
|
3916
3990
|
watchReturn() {
|
|
@@ -3920,7 +3994,7 @@ var si = class {
|
|
|
3920
3994
|
return;
|
|
3921
3995
|
}
|
|
3922
3996
|
let e = this.hiddenAtMs;
|
|
3923
|
-
this.hiddenAtMs = null, e != null && Date.now() - e >=
|
|
3997
|
+
this.hiddenAtMs = null, e != null && Date.now() - e >= ci && this.resyncLiveState();
|
|
3924
3998
|
}, this.onReturnPageShow = (e) => {
|
|
3925
3999
|
e.persisted && this.resyncLiveState();
|
|
3926
4000
|
}, document.addEventListener("visibilitychange", this.onReturnVisible), typeof window < "u" && window.addEventListener("pageshow", this.onReturnPageShow));
|
|
@@ -3952,7 +4026,7 @@ var si = class {
|
|
|
3952
4026
|
scheduleRejoin(e) {
|
|
3953
4027
|
this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
|
|
3954
4028
|
this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
|
|
3955
|
-
}, Math.random() *
|
|
4029
|
+
}, Math.random() * ri));
|
|
3956
4030
|
}
|
|
3957
4031
|
cancelRejoin() {
|
|
3958
4032
|
this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
|
|
@@ -3976,7 +4050,7 @@ var si = class {
|
|
|
3976
4050
|
}
|
|
3977
4051
|
t.controls = !1;
|
|
3978
4052
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
3979
|
-
r && r.insertBefore(n, t), n.appendChild(t),
|
|
4053
|
+
r && r.insertBefore(n, t), n.appendChild(t), Ir(n, this.opts.theme), this.container = n, this.controlBar = Yr({
|
|
3980
4054
|
root: n,
|
|
3981
4055
|
video: t,
|
|
3982
4056
|
player: this,
|
|
@@ -4015,7 +4089,7 @@ var si = class {
|
|
|
4015
4089
|
}
|
|
4016
4090
|
startStats() {
|
|
4017
4091
|
this.stopStats();
|
|
4018
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
4092
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? li);
|
|
4019
4093
|
this.statsTimer = setInterval(() => {
|
|
4020
4094
|
if (!this.engine) return;
|
|
4021
4095
|
let e = this.engine.getStats();
|
|
@@ -4026,14 +4100,14 @@ var si = class {
|
|
|
4026
4100
|
this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
|
|
4027
4101
|
}
|
|
4028
4102
|
isStaleLicenseDenial(e) {
|
|
4029
|
-
return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !==
|
|
4103
|
+
return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== di || e.error.httpStatus !== 403 || e.error.code !== "FORBIDDEN" || e.error.serverCode === "license_refused" ? !1 : W(this._descriptor?.drm?.widevine?.licenseUrl);
|
|
4030
4104
|
}
|
|
4031
4105
|
scheduleLicenseRefresh() {
|
|
4032
4106
|
if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
|
|
4033
4107
|
typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
|
|
4034
4108
|
document.visibilityState !== "visible" || this.destroyed || W(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
|
|
4035
4109
|
}, document.addEventListener("visibilitychange", this.onRefocus));
|
|
4036
|
-
let e = this.opts.licenseRefreshMs ??
|
|
4110
|
+
let e = this.opts.licenseRefreshMs ?? ui;
|
|
4037
4111
|
e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
4038
4112
|
}
|
|
4039
4113
|
stopRefresh() {
|
|
@@ -4203,7 +4277,7 @@ function $(e) {
|
|
|
4203
4277
|
}
|
|
4204
4278
|
//#endregion
|
|
4205
4279
|
//#region src/embed/host.ts
|
|
4206
|
-
function
|
|
4280
|
+
function _i(e) {
|
|
4207
4281
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
4208
4282
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
4209
4283
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -4262,15 +4336,15 @@ function ci(e) {
|
|
|
4262
4336
|
}
|
|
4263
4337
|
//#endregion
|
|
4264
4338
|
//#region src/embed/page.ts
|
|
4265
|
-
var
|
|
4266
|
-
function
|
|
4339
|
+
var vi = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
4340
|
+
function yi(e) {
|
|
4267
4341
|
if (typeof e == "boolean") return e;
|
|
4268
4342
|
if (typeof e == "object" && e) {
|
|
4269
4343
|
let t = e.endpoint;
|
|
4270
4344
|
return typeof t == "string" ? { endpoint: t } : {};
|
|
4271
4345
|
}
|
|
4272
4346
|
}
|
|
4273
|
-
function
|
|
4347
|
+
function bi() {
|
|
4274
4348
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
4275
4349
|
if (e) return {
|
|
4276
4350
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -4280,7 +4354,7 @@ function di() {
|
|
|
4280
4354
|
autoplay: e.autoplay ?? !0,
|
|
4281
4355
|
muted: e.muted ?? !0,
|
|
4282
4356
|
waitForLive: e.waitForLive ?? !0,
|
|
4283
|
-
analytics:
|
|
4357
|
+
analytics: yi(e.analytics)
|
|
4284
4358
|
};
|
|
4285
4359
|
let t = new URLSearchParams(location.search);
|
|
4286
4360
|
return {
|
|
@@ -4293,9 +4367,9 @@ function di() {
|
|
|
4293
4367
|
waitForLive: !0
|
|
4294
4368
|
};
|
|
4295
4369
|
}
|
|
4296
|
-
async function
|
|
4297
|
-
let e =
|
|
4298
|
-
|
|
4370
|
+
async function xi() {
|
|
4371
|
+
let e = bi();
|
|
4372
|
+
Ci();
|
|
4299
4373
|
let t = document.createElement("video");
|
|
4300
4374
|
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);
|
|
4301
4375
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -4351,12 +4425,12 @@ async function fi() {
|
|
|
4351
4425
|
message: e.message,
|
|
4352
4426
|
...e.country === void 0 ? {} : { country: e.country }
|
|
4353
4427
|
})), e.on("autoplayblocked", () => {
|
|
4354
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
4428
|
+
i({ type: "oddin:autoplayblocked" }), Si(t, e);
|
|
4355
4429
|
});
|
|
4356
4430
|
}, s = async (r) => {
|
|
4357
4431
|
a?.destroy(), a = null;
|
|
4358
4432
|
try {
|
|
4359
|
-
let n = await
|
|
4433
|
+
let n = await hi({
|
|
4360
4434
|
video: t,
|
|
4361
4435
|
baseUrl: e.baseUrl,
|
|
4362
4436
|
matchUrn: r,
|
|
@@ -4419,7 +4493,7 @@ async function fi() {
|
|
|
4419
4493
|
a?.retry();
|
|
4420
4494
|
break;
|
|
4421
4495
|
case "oddin:load":
|
|
4422
|
-
typeof e.matchUrn == "string" &&
|
|
4496
|
+
typeof e.matchUrn == "string" && vi.test(e.matchUrn) && s(e.matchUrn);
|
|
4423
4497
|
break;
|
|
4424
4498
|
case "oddin:destroy": c();
|
|
4425
4499
|
}
|
|
@@ -4431,18 +4505,18 @@ async function fi() {
|
|
|
4431
4505
|
protocol: 1
|
|
4432
4506
|
});
|
|
4433
4507
|
}
|
|
4434
|
-
function
|
|
4508
|
+
function Si(e, t) {
|
|
4435
4509
|
if (document.getElementById("havik-tap")) return;
|
|
4436
4510
|
let n = document.createElement("button");
|
|
4437
4511
|
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", () => {
|
|
4438
4512
|
n.remove(), t.play();
|
|
4439
4513
|
}), document.body.appendChild(n);
|
|
4440
4514
|
}
|
|
4441
|
-
function
|
|
4515
|
+
function Ci() {
|
|
4442
4516
|
let e = document.createElement("style");
|
|
4443
4517
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
4444
4518
|
}
|
|
4445
4519
|
//#endregion
|
|
4446
|
-
export { E as LiveStateHttpError,
|
|
4520
|
+
export { E as LiveStateHttpError, Pr as ODDIN_THEME, n as PlaybackError, Ir as applyTheme, lt as baseUrlForEnv, xi as bootEmbed, ke as clearDeviceId, He as clearRememberedBandwidth, hi as createPlayer, O as deriveEventsBaseUrl, at as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, ve as fetchCatalog, be as fetchTournament, Se as flattenMatches, C as fullscreenSupported, Oe as getDeviceId, st as isLowLatencyManifest, $ as isOddinMessage, je as licenseRequestHeaders, _i as mountEmbed, fe as pollToLive, y as resolveStream, D as subscribeLiveState, S as videoFullscreenActive, we as watchStatus };
|
|
4447
4521
|
|
|
4448
4522
|
//# sourceMappingURL=index.js.map
|