@oddin-gg/havik-player 2.27.2 → 2.28.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/havik-player.global.js +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 +314 -230
- package/dist/index.js.map +1 -1
- package/docs/API.md +57 -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 = 2, rn = 5, an = 3, on = 1e4, sn = 3e4, cn = 12e3, ln = 3e3, un = .02, dn = 6e3, fn = .5, pn = 3, mn = .5, hn = 1.1, gn = .25, _n = 5e3, vn = 4e3, yn = 2, bn = 5, xn = 2, Sn = 2, Cn = 4, wn = 4, Tn = 2e3, En = 3e4, Dn = 1, On = 2, kn = .5, An = .6, jn = 2, Mn = 1.5, Nn = 1e4, Pn = 18e4, Fn = .5, In = 2;
|
|
1631
|
+
function Ln(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, Rn = 12e4, zn = 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 Bn = .2, Vn = 30, Hn = 2, Un = 2, Wn = 2, Gn = 9, Kn = .5, qn = 64, Jn = 1e4, Yn = 8, Xn = .6, Zn = .4, Qn = .4, $n = 2, er = 6e4, X = .5, tr = 3.5, nr = 300;
|
|
1649
|
+
function rr(e) {
|
|
1614
1650
|
return (e?.part ?? e?.frag)?.stats;
|
|
1615
1651
|
}
|
|
1616
|
-
function
|
|
1652
|
+
function ir() {
|
|
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 ar(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 ??= Wn;
|
|
1667
|
+
let t = Math.max(12, e.liveSyncDuration + Gn);
|
|
1668
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), or(e, e.liveSyncDuration);
|
|
1633
1669
|
}
|
|
1634
|
-
function
|
|
1670
|
+
function or(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 sr = class {
|
|
1639
1675
|
name = "hls";
|
|
1640
1676
|
hls = null;
|
|
1641
1677
|
deps;
|
|
@@ -1660,6 +1696,7 @@ var nr = class {
|
|
|
1660
1696
|
ladderHeights;
|
|
1661
1697
|
ladderTopBitrateKbps = 0;
|
|
1662
1698
|
mediaRecoveries = 0;
|
|
1699
|
+
holeKicks = 0;
|
|
1663
1700
|
networkRecoveries = 0;
|
|
1664
1701
|
licenseRecoveries = 0;
|
|
1665
1702
|
recoveryResetTimer = null;
|
|
@@ -1788,7 +1825,7 @@ var nr = class {
|
|
|
1788
1825
|
}
|
|
1789
1826
|
this.loadSuspended = !0;
|
|
1790
1827
|
}
|
|
1791
|
-
},
|
|
1828
|
+
}, _n));
|
|
1792
1829
|
}
|
|
1793
1830
|
resumeLoading() {
|
|
1794
1831
|
if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
|
|
@@ -1820,7 +1857,7 @@ var nr = class {
|
|
|
1820
1857
|
let t = e.liveSyncPosition;
|
|
1821
1858
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
1822
1859
|
let { video: n } = this.deps;
|
|
1823
|
-
n.currentTime <= t +
|
|
1860
|
+
n.currentTime <= t + Kn || (n.currentTime = t);
|
|
1824
1861
|
}
|
|
1825
1862
|
reanchorPartTimeline(e, t) {
|
|
1826
1863
|
let { frag: n, part: r } = t;
|
|
@@ -1832,7 +1869,7 @@ var nr = class {
|
|
|
1832
1869
|
let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
|
|
1833
1870
|
if (!s) return;
|
|
1834
1871
|
let c = a.startPTS - s.start;
|
|
1835
|
-
if (!(!Number.isFinite(c) || Math.abs(c) <
|
|
1872
|
+
if (!(!Number.isFinite(c) || Math.abs(c) < un)) {
|
|
1836
1873
|
for (let e of i.fragments) e && e.setStart(e.start + c);
|
|
1837
1874
|
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
1875
|
}
|
|
@@ -1872,7 +1909,7 @@ var nr = class {
|
|
|
1872
1909
|
return;
|
|
1873
1910
|
}
|
|
1874
1911
|
let l = this.hls, u, d = new Promise((e) => {
|
|
1875
|
-
u = setTimeout(() => e(void 0),
|
|
1912
|
+
u = setTimeout(() => e(void 0), on);
|
|
1876
1913
|
});
|
|
1877
1914
|
return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
|
|
1878
1915
|
if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
|
|
@@ -1890,28 +1927,28 @@ var nr = class {
|
|
|
1890
1927
|
this.prefetch?.destroy(), this.prefetch = null;
|
|
1891
1928
|
let p = !1, m = !1, h = u && this.deps.mediaDuringKey !== !1, g = this.deps.preloadHints !== !1;
|
|
1892
1929
|
if ((h || g) && !f.fLoader) {
|
|
1893
|
-
let e = new
|
|
1930
|
+
let e = new Wt({
|
|
1894
1931
|
sessionId: n.analytics?.sid,
|
|
1895
1932
|
contentId: n.matchUrn
|
|
1896
|
-
}), t =
|
|
1933
|
+
}), t = Gt(e, f.loader);
|
|
1897
1934
|
t && (this.prefetch = e, p = h, m = g, f.fLoader = t);
|
|
1898
1935
|
}
|
|
1899
|
-
|
|
1936
|
+
ar(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
1937
|
let _ = new e(f);
|
|
1901
1938
|
if (this.hls = _, this.armHoldBack(_, f), _.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(_, t)), _.on(e.Events.MANIFEST_PARSED, () => {
|
|
1902
1939
|
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
1940
|
}), _.on(e.Events.FRAG_BUFFERED, (e, t) => {
|
|
1904
|
-
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
|
-
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
|
|
1906
|
-
},
|
|
1941
|
+
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.holeKicks > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
|
|
1942
|
+
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.holeKicks = 0, this.recoveryResetTimer = null;
|
|
1943
|
+
}, sn)));
|
|
1907
1944
|
}), _.on(e.Events.FRAG_LOADING, (e, t) => {
|
|
1908
1945
|
t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
|
|
1909
1946
|
}), _.on(e.Events.FRAG_LOADED, (e, t) => {
|
|
1910
1947
|
t?.frag?.type === "main" && (this.mainFragsSinceTick += 1, this.bwFragsLoaded += 1, this.maybeRememberBandwidth(!1));
|
|
1911
|
-
let n = t?.frag, r =
|
|
1948
|
+
let n = t?.frag, r = rr(t), i = r?.loaded;
|
|
1912
1949
|
typeof i == "number" && (this.bytesLoaded += i), !this.reportedFirstBytes && typeof i == "number" && i > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
|
|
1913
1950
|
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 >
|
|
1951
|
+
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 > qn && this.requestTimesMs.shift()), this.sampleHoldBack(t), this.sampleHeadroom(t);
|
|
1915
1952
|
let o = n?.url;
|
|
1916
1953
|
if (o) {
|
|
1917
1954
|
let e = ft(o);
|
|
@@ -1931,8 +1968,8 @@ var nr = class {
|
|
|
1931
1968
|
let i = e;
|
|
1932
1969
|
if (!i?.live || !i.partList?.length || typeof i.edge != "number") return;
|
|
1933
1970
|
let a = n.buffered, o = a.length ? a.end(a.length - 1) : 0;
|
|
1934
|
-
if (i.edge - o >
|
|
1935
|
-
let s =
|
|
1971
|
+
if (i.edge - o > Zt * (i.partTarget || .5)) return;
|
|
1972
|
+
let s = Yt(e);
|
|
1936
1973
|
s && t.prefetchHint(s, r);
|
|
1937
1974
|
};
|
|
1938
1975
|
_.on(e.Events.LEVEL_LOADED, (e, t) => {
|
|
@@ -1944,15 +1981,15 @@ var nr = class {
|
|
|
1944
1981
|
if (this.prefetch && p) {
|
|
1945
1982
|
let t = this.prefetch;
|
|
1946
1983
|
_.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(
|
|
1984
|
+
let r = n?.frag, i = qt(r?.type);
|
|
1985
|
+
if (r && t.isActive(i)) for (let e of Jt(_, r)) t.prefetch(e.url, i, e.kind);
|
|
1986
|
+
}), _.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(qt(n?.frag?.type)));
|
|
1950
1987
|
}
|
|
1951
1988
|
_.on(e.Events.KEY_LOADED, () => {
|
|
1952
1989
|
u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
|
|
1953
1990
|
}), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
|
|
1954
1991
|
this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.adaptHoldBack(), this.reviewSizeCapHeadroom(), this.releaseStallCap(), this.checkFrameDrops();
|
|
1955
|
-
},
|
|
1992
|
+
}, ln), _.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
1956
1993
|
this.renditionSwitches += 1;
|
|
1957
1994
|
let n = this.lastLevelIndex >= 0 ? _.levels[this.lastLevelIndex] : void 0, r = _.levels[t.level];
|
|
1958
1995
|
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 +2050,8 @@ var nr = class {
|
|
|
2013
2050
|
let e = this.hls, t = this.sizeCapCover();
|
|
2014
2051
|
if (!e || !t) return null;
|
|
2015
2052
|
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,
|
|
2053
|
+
if (a && r >= On) return n;
|
|
2054
|
+
if (a) return this.headroomUngated || this.headroomGranted ? J(e.levels, n, Dn) : n;
|
|
2018
2055
|
let o = i === Infinity ? e.levels.length : Math.max(0, Math.floor(i));
|
|
2019
2056
|
return J(e.levels, n, o);
|
|
2020
2057
|
}
|
|
@@ -2031,11 +2068,11 @@ var nr = class {
|
|
|
2031
2068
|
return;
|
|
2032
2069
|
}
|
|
2033
2070
|
this.capTimer && clearTimeout(this.capTimer);
|
|
2034
|
-
let t = e > this.sizeCapLevel ?
|
|
2071
|
+
let t = e > this.sizeCapLevel ? Tn : En;
|
|
2035
2072
|
this.capTimer = setTimeout(() => {
|
|
2036
2073
|
this.capTimer = null;
|
|
2037
2074
|
let n = this.computeSizeCapTarget();
|
|
2038
|
-
n === e || t ===
|
|
2075
|
+
n === e || t === En && n != null && n < e ? this.applySizeCap() : this.onMediaResize();
|
|
2039
2076
|
}, t);
|
|
2040
2077
|
}
|
|
2041
2078
|
measureLadder(e) {
|
|
@@ -2062,7 +2099,7 @@ var nr = class {
|
|
|
2062
2099
|
}
|
|
2063
2100
|
defaultHeadroomApplies() {
|
|
2064
2101
|
let e = this.deps.sizeCapHeadroom;
|
|
2065
|
-
return e != null && !Number.isNaN(e) || this.headroomUngated ? !1 : Y() <
|
|
2102
|
+
return e != null && !Number.isNaN(e) || this.headroomUngated ? !1 : Y() < On;
|
|
2066
2103
|
}
|
|
2067
2104
|
applySizeCapUnlessPending() {
|
|
2068
2105
|
this.capTimer || this.applySizeCap();
|
|
@@ -2071,7 +2108,7 @@ var nr = class {
|
|
|
2071
2108
|
if (!this.sizeCapManaged || !this.defaultHeadroomApplies() || e.frag?.type !== "main" || typeof e.frag.level != "number" || typeof document < "u" && document.hidden) return;
|
|
2072
2109
|
let t = e.part ? e.part.duration : this.detectedLowLatency ? 0 : e.frag.duration;
|
|
2073
2110
|
if (typeof t != "number" || !(t > 0)) return;
|
|
2074
|
-
let n =
|
|
2111
|
+
let n = rr(e)?.loading;
|
|
2075
2112
|
if (!n || !(n.start > 0) || !(n.end >= n.start)) return;
|
|
2076
2113
|
let r = this.hls?.levels?.[e.frag.level]?.bitrate;
|
|
2077
2114
|
if (!(typeof r == "number" && r > 0)) return;
|
|
@@ -2084,7 +2121,7 @@ var nr = class {
|
|
|
2084
2121
|
}
|
|
2085
2122
|
onPlaybackStall(e) {
|
|
2086
2123
|
let t = Date.now();
|
|
2087
|
-
this.deps.video.seeking || !this.playingSince || t - this.playingSince <
|
|
2124
|
+
this.deps.video.seeking || !this.playingSince || t - this.playingSince < Nn || (this.lastStallAt = t, this.stepStallCapDown(t, e), this.headroomGranted && (this.headroomGranted = !1, this.applySizeCapUnlessPending()));
|
|
2088
2125
|
}
|
|
2089
2126
|
stallCapLevel(e) {
|
|
2090
2127
|
if (this.stallCapBitrate == null) return -1;
|
|
@@ -2095,7 +2132,7 @@ var nr = class {
|
|
|
2095
2132
|
}
|
|
2096
2133
|
stepStallCapDown(e, t) {
|
|
2097
2134
|
let n = this.hls;
|
|
2098
|
-
if (!n || !this.stallCapEnabled ||
|
|
2135
|
+
if (!n || !this.stallCapEnabled || Ln(n) || !n.autoLevelEnabled || typeof t == "number" && t >= Fn || this.isLiveEdgeWait(n, t ?? 0)) return;
|
|
2099
2136
|
this.stallCapBitrate != null && (this.stallCapSince = e);
|
|
2100
2137
|
let r = Math.max(n.levels[n.currentLevel]?.bitrate ?? 0, n.levels[n.loadLevel]?.bitrate ?? 0);
|
|
2101
2138
|
if (!(r > 0)) return;
|
|
@@ -2106,7 +2143,7 @@ var nr = class {
|
|
|
2106
2143
|
let n = e.latestLevelDetails;
|
|
2107
2144
|
if (!n?.live) return !1;
|
|
2108
2145
|
let r = n.partTarget || n.targetduration;
|
|
2109
|
-
return !(r > 0) || !(n.edge > 0) ? !1 : n.edge - (this.deps.video.currentTime + t) <
|
|
2146
|
+
return !(r > 0) || !(n.edge > 0) ? !1 : n.edge - (this.deps.video.currentTime + t) < In * r;
|
|
2110
2147
|
}
|
|
2111
2148
|
releaseStallCap() {
|
|
2112
2149
|
let e = this.hls, t = Date.now(), n = this.stallCapTickAt;
|
|
@@ -2115,7 +2152,7 @@ var nr = class {
|
|
|
2115
2152
|
n && (this.stallCapSince += t - Math.max(n, this.stallCapSince));
|
|
2116
2153
|
return;
|
|
2117
2154
|
}
|
|
2118
|
-
if (t - this.stallCapSince <
|
|
2155
|
+
if (t - this.stallCapSince < Pn) return;
|
|
2119
2156
|
let r = this.stallCapBitrate, i = e.levels.map((e) => e.bitrate).filter((e) => e > r).sort((e, t) => e - t)[0];
|
|
2120
2157
|
this.stallCapBitrate = i ?? null, this.stallCapSince = t, this.pushCap();
|
|
2121
2158
|
}
|
|
@@ -2128,26 +2165,26 @@ var nr = class {
|
|
|
2128
2165
|
this.headroomGranted = !1, this.headroomSamples = [];
|
|
2129
2166
|
return;
|
|
2130
2167
|
}
|
|
2131
|
-
this.headroomSamples = this.headroomSamples.filter((t) => t.t >= e -
|
|
2168
|
+
this.headroomSamples = this.headroomSamples.filter((t) => t.t >= e - Jn);
|
|
2132
2169
|
let r = this.headroomEarned(n, e);
|
|
2133
|
-
r !== this.headroomGranted && (r || (this.headroomRegrantAt = e +
|
|
2170
|
+
r !== this.headroomGranted && (r || (this.headroomRegrantAt = e + zn), this.headroomGranted = r, this.applySizeCapUnlessPending());
|
|
2134
2171
|
}
|
|
2135
2172
|
headroomEarned(e, t) {
|
|
2136
|
-
if (t - this.lastStallAt <
|
|
2173
|
+
if (t - this.lastStallAt < Rn || !this.headroomGranted && t < this.headroomRegrantAt || !this.headroomGranted && this.headroomSamples.length < q) return !1;
|
|
2137
2174
|
let n = e.levels, r = this.sizeCapCoverLevel();
|
|
2138
2175
|
if (r == null) return this.headroomGranted;
|
|
2139
|
-
let i = J(n, r,
|
|
2176
|
+
let i = J(n, r, Dn);
|
|
2140
2177
|
if (i === r) return this.headroomGranted;
|
|
2141
|
-
let a = n[i]?.bitrate, o = e.bandwidthEstimate, s = this.headroomGranted ?
|
|
2178
|
+
let a = n[i]?.bitrate, o = e.bandwidthEstimate, s = this.headroomGranted ? Mn : jn;
|
|
2142
2179
|
if (!(a > 0) || !(o >= s * a)) return !1;
|
|
2143
2180
|
let c = (e) => K([...e].sort((e, t) => e - t), 90);
|
|
2144
2181
|
if (this.headroomGranted) {
|
|
2145
2182
|
let e = this.headroomSamples.filter((e) => e.bitrate >= a).map((e) => e.ratio);
|
|
2146
|
-
return e.length < q || c(e) <=
|
|
2183
|
+
return e.length < q || c(e) <= An;
|
|
2147
2184
|
}
|
|
2148
2185
|
let l = [];
|
|
2149
2186
|
for (let e of this.headroomSamples) e.bitrate < a && l.push(e.ratio * (a / e.bitrate));
|
|
2150
|
-
return l.length >= q && c(l) <=
|
|
2187
|
+
return l.length >= q && c(l) <= kn;
|
|
2151
2188
|
}
|
|
2152
2189
|
applySizeCap() {
|
|
2153
2190
|
if (!this.sizeCapManaged) return;
|
|
@@ -2222,7 +2259,7 @@ var nr = class {
|
|
|
2222
2259
|
let t = e.currentLevel >= 0 ? e.levels[e.currentLevel] : void 0;
|
|
2223
2260
|
t && (n.levelHeight = t.height);
|
|
2224
2261
|
let r = e.autoLevelCapping, i = r >= 0 ? e.levels[r] : void 0;
|
|
2225
|
-
i && i.height > 0 && (n.maxLevelHeight = i.height, !
|
|
2262
|
+
i && i.height > 0 && (n.maxLevelHeight = i.height, !Ln(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
2263
|
}
|
|
2227
2264
|
return n;
|
|
2228
2265
|
}
|
|
@@ -2250,7 +2287,7 @@ var nr = class {
|
|
|
2250
2287
|
return;
|
|
2251
2288
|
}
|
|
2252
2289
|
let e = Date.now() - this.lastAdvanceMs;
|
|
2253
|
-
!this.chaseSuspended && e >
|
|
2290
|
+
!this.chaseSuspended && e > dn && this.suspendChasing(), e > cn && this.emitEnded("stalled");
|
|
2254
2291
|
}
|
|
2255
2292
|
resetStarvationWindow() {
|
|
2256
2293
|
this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
|
|
@@ -2265,7 +2302,7 @@ var nr = class {
|
|
|
2265
2302
|
this.resetStarvationWindow();
|
|
2266
2303
|
return;
|
|
2267
2304
|
}
|
|
2268
|
-
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs <
|
|
2305
|
+
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < dn, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > vn, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = R(t), c = o - s, l = c !== this.starvedFrames;
|
|
2269
2306
|
if (this.starvedFrames = c, !a || l) {
|
|
2270
2307
|
(t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
|
|
2271
2308
|
return;
|
|
@@ -2274,12 +2311,12 @@ var nr = class {
|
|
|
2274
2311
|
this.resetStarvationWindow();
|
|
2275
2312
|
return;
|
|
2276
2313
|
}
|
|
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 >
|
|
2314
|
+
if (this.kickPending && (this.kickKind === "dead" || i) && (this.kickTicks += 1), this.starvedTicks = i ? this.starvedTicks + 1 : 0, this.deadTicks += 1, this.recentMainFrags.push(this.mainFragsSinceTick), this.mainFragsSinceTick = 0, this.recentMainFrags.length > Cn && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= xn && (this.clearKick(), this.starvationRebuilds < Sn)) {
|
|
2278
2315
|
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
2316
|
return;
|
|
2280
2317
|
}
|
|
2281
|
-
let u = i && this.starvedTicks >=
|
|
2282
|
-
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >=
|
|
2318
|
+
let u = i && this.starvedTicks >= yn, d = !i && this.deadTicks >= Cn && this.recentMainFrags.reduce((e, t) => e + t, 0) >= wn;
|
|
2319
|
+
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= bn))) {
|
|
2283
2320
|
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
2321
|
try {
|
|
2285
2322
|
e.stopLoad(), e.startLoad(-1);
|
|
@@ -2294,7 +2331,7 @@ var nr = class {
|
|
|
2294
2331
|
let t = e.latency, n = e.targetLatency;
|
|
2295
2332
|
if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
|
|
2296
2333
|
let r = t - n;
|
|
2297
|
-
!this.catchUpEngaged && r >
|
|
2334
|
+
!this.catchUpEngaged && r > fn ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= fn && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
|
|
2298
2335
|
let i = this.catchUpEngaged ? this.catchUpRate : 1;
|
|
2299
2336
|
e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
|
|
2300
2337
|
}
|
|
@@ -2307,7 +2344,7 @@ var nr = class {
|
|
|
2307
2344
|
}), n < 0 ? 0 : n;
|
|
2308
2345
|
}
|
|
2309
2346
|
armFrameDropGrace() {
|
|
2310
|
-
this.fpsGraceTicks > 0 || (this.fpsGraceTicks =
|
|
2347
|
+
this.fpsGraceTicks > 0 || (this.fpsGraceTicks = Un, this.fpsBadTicks = 0);
|
|
2311
2348
|
}
|
|
2312
2349
|
resetFrameDropWindow() {
|
|
2313
2350
|
this.fpsLastFrames = -1, this.fpsLastDropped = -1, this.fpsBadTicks = 0;
|
|
@@ -2319,7 +2356,7 @@ var nr = class {
|
|
|
2319
2356
|
return;
|
|
2320
2357
|
}
|
|
2321
2358
|
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 <
|
|
2359
|
+
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Vn || o < 0) {
|
|
2323
2360
|
this.fpsBadTicks = 0;
|
|
2324
2361
|
return;
|
|
2325
2362
|
}
|
|
@@ -2327,11 +2364,11 @@ var nr = class {
|
|
|
2327
2364
|
--this.fpsGraceTicks, this.fpsBadTicks = 0;
|
|
2328
2365
|
return;
|
|
2329
2366
|
}
|
|
2330
|
-
if (o <=
|
|
2367
|
+
if (o <= Bn * a) {
|
|
2331
2368
|
this.fpsBadTicks = 0;
|
|
2332
2369
|
return;
|
|
2333
2370
|
}
|
|
2334
|
-
if (this.fpsBadTicks += 1, this.fpsBadTicks <
|
|
2371
|
+
if (this.fpsBadTicks += 1, this.fpsBadTicks < Hn) return;
|
|
2335
2372
|
this.fpsBadTicks = 0;
|
|
2336
2373
|
let s = e.levels, c = s[e.currentLevel];
|
|
2337
2374
|
if (!c) return;
|
|
@@ -2348,22 +2385,22 @@ var nr = class {
|
|
|
2348
2385
|
return;
|
|
2349
2386
|
}
|
|
2350
2387
|
let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
|
|
2351
|
-
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(
|
|
2388
|
+
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(hn, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
|
|
2352
2389
|
this.resetChaseWindow();
|
|
2353
2390
|
return;
|
|
2354
2391
|
}
|
|
2355
|
-
if (this.chaseLatency < 0 || this.chaseLatency - n >=
|
|
2392
|
+
if (this.chaseLatency < 0 || this.chaseLatency - n >= mn) {
|
|
2356
2393
|
this.chaseLatency = n, this.chaseTicks = 0;
|
|
2357
2394
|
return;
|
|
2358
2395
|
}
|
|
2359
|
-
if (this.chaseTicks += 1, this.chaseTicks <
|
|
2396
|
+
if (this.chaseTicks += 1, this.chaseTicks < pn) return;
|
|
2360
2397
|
this.resetChaseWindow();
|
|
2361
2398
|
let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
|
|
2362
2399
|
if (!(a > 1)) return;
|
|
2363
2400
|
let o = e.targetLatency;
|
|
2364
2401
|
if (typeof o != "number" || !(o > 0)) return;
|
|
2365
2402
|
let s = Math.min(n, a - 1);
|
|
2366
|
-
s < o +
|
|
2403
|
+
s < o + gn || (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
2404
|
type: "livetargetchange",
|
|
2368
2405
|
change: {
|
|
2369
2406
|
targetSeconds: s,
|
|
@@ -2380,13 +2417,13 @@ var nr = class {
|
|
|
2380
2417
|
if (!this.holdBackEnabled || this.holdBackPriorChecked || !e || (this.holdBackPriorChecked = !0, this.holdBackApplied > 0 || this.holdBackStepCount > 0)) return;
|
|
2381
2418
|
let t = e.targetLatency;
|
|
2382
2419
|
if (this.holdBackBase < 0 && typeof t == "number" && t > 0 && (this.holdBackBase = t), this.holdBackBase < 0) return;
|
|
2383
|
-
let n =
|
|
2384
|
-
if (!(n >=
|
|
2420
|
+
let n = ir();
|
|
2421
|
+
if (!(n >= nr)) return;
|
|
2385
2422
|
let r = typeof t == "number" && t > 0 ? t : this.holdBackBase, i = Math.min(this.holdBackCeiling(e), this.holdBackBase + X);
|
|
2386
2423
|
i > r && (this.holdBackStepCount = 1, this.moveHoldBack(e, r, i, "connection-rtt", `connection rtt ${n} ms`));
|
|
2387
2424
|
}
|
|
2388
2425
|
holdBackCeiling(e) {
|
|
2389
|
-
let t = this.deps.adaptiveHoldBackCeiling, n = typeof t == "number" && Number.isFinite(t) ? t :
|
|
2426
|
+
let t = this.deps.adaptiveHoldBackCeiling, n = typeof t == "number" && Number.isFinite(t) ? t : tr, r = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
|
|
2390
2427
|
return r > 1 ? Math.min(n, r - 1) : n;
|
|
2391
2428
|
}
|
|
2392
2429
|
sampleHoldBack(e) {
|
|
@@ -2395,7 +2432,7 @@ var nr = class {
|
|
|
2395
2432
|
if (t !== "main" && t !== "audio") return;
|
|
2396
2433
|
let n = e.part ? e.part.duration : this.detectedLowLatency ? 0 : e.frag?.duration;
|
|
2397
2434
|
if (typeof n != "number" || !(n > 0)) return;
|
|
2398
|
-
let r =
|
|
2435
|
+
let r = rr(e)?.loading;
|
|
2399
2436
|
if (!r || !(r.start > 0) || !(r.end > 0)) return;
|
|
2400
2437
|
let i = r.first > r.start ? r.first : r.end, a = Math.max(0, i - r.start) / (n * 1e3);
|
|
2401
2438
|
this.holdBackSamples.push({
|
|
@@ -2410,20 +2447,20 @@ var nr = class {
|
|
|
2410
2447
|
this.holdBackSlowTicks = 0, this.holdBackFastSince = 0, this.holdBackSamples = [];
|
|
2411
2448
|
return;
|
|
2412
2449
|
}
|
|
2413
|
-
let t = Date.now(), n = t -
|
|
2450
|
+
let t = Date.now(), n = t - Jn, r = this.holdBackSamples, i = 0;
|
|
2414
2451
|
for (; i < r.length && r[i].t < n;) i += 1;
|
|
2415
2452
|
i > 0 && r.splice(0, i);
|
|
2416
2453
|
let a = e.targetLatency;
|
|
2417
2454
|
if (typeof a != "number" || !(a > 0)) return;
|
|
2418
2455
|
this.holdBackBase < 0 && (this.holdBackBase = a);
|
|
2419
2456
|
let o = this.holdBackBase, s = this.holdBackCeiling(e);
|
|
2420
|
-
if (r.length <
|
|
2457
|
+
if (r.length < Yn) {
|
|
2421
2458
|
this.holdBackSlowTicks = 0;
|
|
2422
2459
|
return;
|
|
2423
2460
|
}
|
|
2424
2461
|
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 <
|
|
2462
|
+
if (l >= Xn && u >= Zn) {
|
|
2463
|
+
if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks < $n) return;
|
|
2427
2464
|
this.holdBackSlowTicks = 0;
|
|
2428
2465
|
let t = Math.ceil((s - o) / X), n = Math.ceil((a - o) / X - 1e-9);
|
|
2429
2466
|
if (n > this.holdBackStepCount && (this.holdBackStepCount = n), this.holdBackStepCount >= t) return;
|
|
@@ -2433,7 +2470,7 @@ var nr = class {
|
|
|
2433
2470
|
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
2471
|
return;
|
|
2435
2472
|
}
|
|
2436
|
-
if (this.holdBackSlowTicks = 0, l >=
|
|
2473
|
+
if (this.holdBackSlowTicks = 0, l >= Qn) {
|
|
2437
2474
|
this.holdBackFastSince = 0;
|
|
2438
2475
|
return;
|
|
2439
2476
|
}
|
|
@@ -2441,7 +2478,7 @@ var nr = class {
|
|
|
2441
2478
|
this.holdBackFastSince = t;
|
|
2442
2479
|
return;
|
|
2443
2480
|
}
|
|
2444
|
-
if (t - this.holdBackFastSince <
|
|
2481
|
+
if (t - this.holdBackFastSince < er || (this.holdBackFastSince = t, this.holdBackStepCount === 0 || a !== this.holdBackApplied)) return;
|
|
2445
2482
|
--this.holdBackStepCount;
|
|
2446
2483
|
let f = Math.max(o, o + this.holdBackStepCount * X);
|
|
2447
2484
|
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 +2521,12 @@ var nr = class {
|
|
|
2484
2521
|
} catch {}
|
|
2485
2522
|
}
|
|
2486
2523
|
startEstimate() {
|
|
2487
|
-
return this.deps.rememberBandwidth === !1 ?
|
|
2524
|
+
return this.deps.rememberBandwidth === !1 ? Qt : Be() ?? Qt;
|
|
2488
2525
|
}
|
|
2489
2526
|
maybeRememberBandwidth(e) {
|
|
2490
|
-
if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded <
|
|
2527
|
+
if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < $t) return;
|
|
2491
2528
|
let t = Date.now();
|
|
2492
|
-
if (!e && t - this.bwSavedAt <
|
|
2529
|
+
if (!e && t - this.bwSavedAt < en) return;
|
|
2493
2530
|
let n = this.hls?.bandwidthEstimate;
|
|
2494
2531
|
typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Ve(n));
|
|
2495
2532
|
}
|
|
@@ -2509,7 +2546,7 @@ var nr = class {
|
|
|
2509
2546
|
scheduleLicenseRetry(t) {
|
|
2510
2547
|
if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
|
|
2511
2548
|
let n = t.response?.code ?? 0;
|
|
2512
|
-
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >=
|
|
2549
|
+
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= an) return !1;
|
|
2513
2550
|
this.licenseRecoveries += 1;
|
|
2514
2551
|
let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
|
|
2515
2552
|
return this.licenseRetryTimer = setTimeout(() => {
|
|
@@ -2545,7 +2582,7 @@ var nr = class {
|
|
|
2545
2582
|
this.offlineHold = !0, this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null);
|
|
2546
2583
|
return;
|
|
2547
2584
|
}
|
|
2548
|
-
if (this.networkRecoveries <
|
|
2585
|
+
if (this.networkRecoveries < rn) {
|
|
2549
2586
|
this.networkRecoveries += 1;
|
|
2550
2587
|
let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
|
|
2551
2588
|
this.networkRetryTimer = setTimeout(() => {
|
|
@@ -2562,7 +2599,16 @@ var nr = class {
|
|
|
2562
2599
|
return;
|
|
2563
2600
|
}
|
|
2564
2601
|
if (t.type === e.ErrorTypes.MEDIA_ERROR) {
|
|
2565
|
-
if (this.mediaRecoveries <
|
|
2602
|
+
if (t.details != null && (t.details === e.ErrorDetails.BUFFER_SEEK_OVER_HOLE || t.details === e.ErrorDetails.BUFFER_STALLED_ERROR) && this.sawLive && this.holeKicks < nn && this.mediaRecoveries < tn) {
|
|
2603
|
+
this.holeKicks += 1, this.mediaRecoveries += 1, console.warn("havik-player: playback stuck at a buffer hole hls.js could not nudge across — re-syncing to the live edge");
|
|
2604
|
+
try {
|
|
2605
|
+
n.stopLoad(), n.startLoad(-1);
|
|
2606
|
+
return;
|
|
2607
|
+
} catch (e) {
|
|
2608
|
+
console.warn("havik-player: live re-sync after a buffer hole failed", e);
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
if (this.mediaRecoveries < tn) {
|
|
2566
2612
|
this.mediaRecoveries += 1, n.recoverMediaError();
|
|
2567
2613
|
return;
|
|
2568
2614
|
}
|
|
@@ -2583,18 +2629,21 @@ var nr = class {
|
|
|
2583
2629
|
}
|
|
2584
2630
|
}
|
|
2585
2631
|
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})` : ""}`,
|
|
2632
|
+
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;
|
|
2633
|
+
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})` : ""}`, {
|
|
2634
|
+
detail: s,
|
|
2635
|
+
...l ? { serverCode: l } : {}
|
|
2636
|
+
});
|
|
2588
2637
|
}
|
|
2589
|
-
},
|
|
2638
|
+
}, cr = 15e3, lr = 6e5, ur = 3e5, dr = 100, Z = 1, fr = 1e3, pr = 3e4, mr = 1e3, hr = {
|
|
2590
2639
|
inline: "PRESENTATION_INLINE",
|
|
2591
2640
|
fullscreen: "PRESENTATION_FULLSCREEN",
|
|
2592
2641
|
pip: "PRESENTATION_PIP"
|
|
2593
|
-
},
|
|
2642
|
+
}, gr = {
|
|
2594
2643
|
widevine: "KEY_SYSTEM_WIDEVINE",
|
|
2595
2644
|
fairplay: "KEY_SYSTEM_FAIRPLAY",
|
|
2596
2645
|
none: "KEY_SYSTEM_NONE"
|
|
2597
|
-
},
|
|
2646
|
+
}, _r = /* @__PURE__ */ new Set([
|
|
2598
2647
|
"INVALID_URN",
|
|
2599
2648
|
"NOT_FOUND",
|
|
2600
2649
|
"GEO_DENIED",
|
|
@@ -2605,7 +2654,7 @@ var nr = class {
|
|
|
2605
2654
|
"FORBIDDEN",
|
|
2606
2655
|
"RATE_LIMITED",
|
|
2607
2656
|
"TIMEOUT"
|
|
2608
|
-
]),
|
|
2657
|
+
]), vr = {
|
|
2609
2658
|
idle: "PLAYER_STATE_IDLE",
|
|
2610
2659
|
waiting: "PLAYER_STATE_WAITING",
|
|
2611
2660
|
loading: "PLAYER_STATE_LOADING",
|
|
@@ -2615,7 +2664,7 @@ var nr = class {
|
|
|
2615
2664
|
ended: "PLAYER_STATE_ENDED",
|
|
2616
2665
|
error: "PLAYER_STATE_ERROR"
|
|
2617
2666
|
};
|
|
2618
|
-
function
|
|
2667
|
+
function yr(e) {
|
|
2619
2668
|
try {
|
|
2620
2669
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
2621
2670
|
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 +2672,8 @@ function mr(e) {
|
|
|
2623
2672
|
return;
|
|
2624
2673
|
}
|
|
2625
2674
|
}
|
|
2626
|
-
var
|
|
2627
|
-
function
|
|
2675
|
+
var br = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), xr = /* @__PURE__ */ new Set(), Sr = /* @__PURE__ */ new Set(), Cr = /* @__PURE__ */ new Set(), wr = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
|
|
2676
|
+
function Tr(e) {
|
|
2628
2677
|
if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
|
|
2629
2678
|
let t;
|
|
2630
2679
|
try {
|
|
@@ -2633,19 +2682,19 @@ function br(e) {
|
|
|
2633
2682
|
} catch {
|
|
2634
2683
|
return;
|
|
2635
2684
|
}
|
|
2636
|
-
if (
|
|
2637
|
-
|
|
2638
|
-
for (let e of
|
|
2685
|
+
if (xr.has(t) && !Sr.has(t)) {
|
|
2686
|
+
Sr.add(t), _(wr(new URL(t).origin));
|
|
2687
|
+
for (let e of Cr) e.noteCspBlocked();
|
|
2639
2688
|
}
|
|
2640
2689
|
}
|
|
2641
|
-
function
|
|
2690
|
+
function Er(e, t) {
|
|
2642
2691
|
return _(t, e), { disabledReason: t };
|
|
2643
2692
|
}
|
|
2644
|
-
function
|
|
2645
|
-
if (n) return t && !
|
|
2693
|
+
function Dr(e, t, n) {
|
|
2694
|
+
if (n) return t && !br(t, n) && _(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
|
|
2646
2695
|
if (t) return { endpoint: t };
|
|
2647
|
-
if (t !== void 0) return
|
|
2648
|
-
let r =
|
|
2696
|
+
if (t !== void 0) return Er("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).");
|
|
2697
|
+
let r = yr(e);
|
|
2649
2698
|
if (r) return { endpoint: r };
|
|
2650
2699
|
let i;
|
|
2651
2700
|
try {
|
|
@@ -2653,9 +2702,9 @@ function Sr(e, t, n) {
|
|
|
2653
2702
|
} catch {
|
|
2654
2703
|
i = e;
|
|
2655
2704
|
}
|
|
2656
|
-
return
|
|
2705
|
+
return Er(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
2706
|
}
|
|
2658
|
-
var
|
|
2707
|
+
var Or = class {
|
|
2659
2708
|
opts;
|
|
2660
2709
|
url;
|
|
2661
2710
|
cspKey;
|
|
@@ -2737,8 +2786,8 @@ var Cr = class {
|
|
|
2737
2786
|
constructor(e) {
|
|
2738
2787
|
this.opts = {
|
|
2739
2788
|
...e,
|
|
2740
|
-
heartbeatMs: e.heartbeatMs ??
|
|
2741
|
-
idleMs: e.idleMs ??
|
|
2789
|
+
heartbeatMs: e.heartbeatMs ?? cr,
|
|
2790
|
+
idleMs: e.idleMs ?? lr
|
|
2742
2791
|
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
|
|
2743
2792
|
try {
|
|
2744
2793
|
let e = new URL(this.url);
|
|
@@ -2755,11 +2804,11 @@ var Cr = class {
|
|
|
2755
2804
|
sdkVersion: this.opts.sdkVersion,
|
|
2756
2805
|
...this.opts.environment
|
|
2757
2806
|
};
|
|
2758
|
-
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(),
|
|
2807
|
+
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), fr), 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 && xr.add(this.cspKey), document.addEventListener("securitypolicyviolation", Tr), Cr.add(this), this.noteCspBlocked(), this.onVisibility());
|
|
2759
2808
|
}
|
|
2760
2809
|
checkSuspension(e) {
|
|
2761
2810
|
if (this.endedFlag || !this.opts.idleMs) return !1;
|
|
2762
|
-
let t = Math.max(this.opts.idleMs,
|
|
2811
|
+
let t = Math.max(this.opts.idleMs, ur);
|
|
2763
2812
|
return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
|
|
2764
2813
|
}
|
|
2765
2814
|
syncIdle(e) {
|
|
@@ -2780,14 +2829,14 @@ var Cr = class {
|
|
|
2780
2829
|
} else e === "buffering" && (this.isBuffering = !1, this.stallIsSeekInduced = !1);
|
|
2781
2830
|
this.syncBuffering(), t === "paused" && (this.pauseCount += 1), this.syncIdle(t);
|
|
2782
2831
|
let a = {
|
|
2783
|
-
fromState:
|
|
2784
|
-
toState:
|
|
2785
|
-
presentation:
|
|
2832
|
+
fromState: vr[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2833
|
+
toState: vr[t] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2834
|
+
presentation: hr[this.presentation]
|
|
2786
2835
|
}, o = this.causeOf(e, t, i);
|
|
2787
2836
|
o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
2788
2837
|
}
|
|
2789
2838
|
seekInduced(e) {
|
|
2790
|
-
return this.lastSeekMs >= 0 && e - this.lastSeekMs <
|
|
2839
|
+
return this.lastSeekMs >= 0 && e - this.lastSeekMs < mr;
|
|
2791
2840
|
}
|
|
2792
2841
|
causeOf(e, t, n) {
|
|
2793
2842
|
if (t === "error") return "TRANSITION_CAUSE_ERROR";
|
|
@@ -2861,7 +2910,7 @@ var Cr = class {
|
|
|
2861
2910
|
let r = n ?? "";
|
|
2862
2911
|
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
2912
|
if (e === "DRM_CLIENT" || e === "DRM_DEVICE_REVOKED") return "ERROR_STAGE_DRM";
|
|
2864
|
-
if (
|
|
2913
|
+
if (_r.has(e)) return "ERROR_STAGE_RESOLVE";
|
|
2865
2914
|
let i = t ?? "";
|
|
2866
2915
|
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
2916
|
}
|
|
@@ -2893,7 +2942,7 @@ var Cr = class {
|
|
|
2893
2942
|
let l = t.droppedFrames ?? 0;
|
|
2894
2943
|
l > this.lastDropped && (o.droppedFramesDelta = l - this.lastDropped), this.lastDropped = l;
|
|
2895
2944
|
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 =
|
|
2945
|
+
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 = vr[t.state] ?? "PLAYER_STATE_UNSPECIFIED";
|
|
2897
2946
|
let d = this.mutedTotalMs;
|
|
2898
2947
|
this.mutedSinceMs !== null && (d += e - this.mutedSinceMs), d > this.lastHbMutedMs && (o.mutedMsDelta = Math.round(d - this.lastHbMutedMs)), this.lastHbMutedMs = d;
|
|
2899
2948
|
let f = t.upshifts ?? 0;
|
|
@@ -2915,13 +2964,13 @@ var Cr = class {
|
|
|
2915
2964
|
maybeEmitMediaInfo(e) {
|
|
2916
2965
|
if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
|
|
2917
2966
|
let t = {};
|
|
2918
|
-
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem =
|
|
2967
|
+
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = gr[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
2968
|
let n = JSON.stringify(t);
|
|
2920
2969
|
n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
|
|
2921
2970
|
}
|
|
2922
2971
|
end(e, t) {
|
|
2923
2972
|
if (this.endedFlag) return;
|
|
2924
|
-
this.endedFlag = !0,
|
|
2973
|
+
this.endedFlag = !0, Cr.delete(this);
|
|
2925
2974
|
let n = t ?? this.now();
|
|
2926
2975
|
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
2976
|
let r = this.safeSample();
|
|
@@ -2935,7 +2984,7 @@ var Cr = class {
|
|
|
2935
2984
|
let c = r?.positionMs ?? 0;
|
|
2936
2985
|
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
2986
|
let l = e !== "END_REASON_ENDED";
|
|
2938
|
-
l && this.lastStallMs > 0 && n - this.lastStallMs <=
|
|
2987
|
+
l && this.lastStallMs > 0 && n - this.lastStallMs <= pr && (i.abandonAfterStallMs = Math.max(Z, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= pr && (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
2988
|
let u = r?.decodedFrames ?? this.lastDecoded;
|
|
2940
2989
|
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
2990
|
}
|
|
@@ -2955,13 +3004,13 @@ var Cr = class {
|
|
|
2955
3004
|
};
|
|
2956
3005
|
}
|
|
2957
3006
|
noteCspBlocked() {
|
|
2958
|
-
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(
|
|
3007
|
+
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(wr(new URL(this.url).origin)));
|
|
2959
3008
|
}
|
|
2960
3009
|
cspBlocked() {
|
|
2961
|
-
return !!this.cspKey &&
|
|
3010
|
+
return !!this.cspKey && Sr.has(this.cspKey);
|
|
2962
3011
|
}
|
|
2963
3012
|
enqueue(e) {
|
|
2964
|
-
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length >
|
|
3013
|
+
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > dr;) {
|
|
2965
3014
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
2966
3015
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
2967
3016
|
}
|
|
@@ -2988,7 +3037,7 @@ var Cr = class {
|
|
|
2988
3037
|
};
|
|
2989
3038
|
//#endregion
|
|
2990
3039
|
//#region src/core/environment.ts
|
|
2991
|
-
function
|
|
3040
|
+
function kr() {
|
|
2992
3041
|
if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
|
|
2993
3042
|
let e;
|
|
2994
3043
|
try {
|
|
@@ -3013,14 +3062,14 @@ function wr() {
|
|
|
3013
3062
|
integration: "INTEGRATION_KIND_IFRAME"
|
|
3014
3063
|
};
|
|
3015
3064
|
}
|
|
3016
|
-
function
|
|
3065
|
+
function Ar() {
|
|
3017
3066
|
if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
|
|
3018
3067
|
let e = navigator.userAgentData, t = e?.platform ?? "";
|
|
3019
3068
|
if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
|
|
3020
3069
|
let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
|
|
3021
3070
|
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
3071
|
}
|
|
3023
|
-
function
|
|
3072
|
+
function jr() {
|
|
3024
3073
|
let e = typeof navigator < "u" ? navigator.connection : void 0;
|
|
3025
3074
|
if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
|
|
3026
3075
|
let t = {
|
|
@@ -3039,17 +3088,17 @@ function Er() {
|
|
|
3039
3088
|
}
|
|
3040
3089
|
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
3090
|
}
|
|
3042
|
-
function
|
|
3043
|
-
let t =
|
|
3044
|
-
deviceClass:
|
|
3091
|
+
function Mr(e) {
|
|
3092
|
+
let t = kr(), n = {
|
|
3093
|
+
deviceClass: Ar(),
|
|
3045
3094
|
integration: t.integration,
|
|
3046
|
-
...
|
|
3095
|
+
...jr()
|
|
3047
3096
|
};
|
|
3048
3097
|
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
3098
|
let r = e.getBoundingClientRect?.();
|
|
3050
3099
|
return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
|
|
3051
3100
|
}
|
|
3052
|
-
async function
|
|
3101
|
+
async function Nr() {
|
|
3053
3102
|
let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
|
|
3054
3103
|
if (!e?.getHighEntropyValues) return {};
|
|
3055
3104
|
try {
|
|
@@ -3061,7 +3110,7 @@ async function Or() {
|
|
|
3061
3110
|
}
|
|
3062
3111
|
//#endregion
|
|
3063
3112
|
//#region src/core/version.ts
|
|
3064
|
-
var
|
|
3113
|
+
var Pr = "2.28.1", Fr = {
|
|
3065
3114
|
accent: "#E1B600",
|
|
3066
3115
|
accentText: "#1B1C23",
|
|
3067
3116
|
background: "#0e0f13",
|
|
@@ -3072,7 +3121,7 @@ var kr = "2.27.2", Ar = {
|
|
|
3072
3121
|
border: "rgba(255, 255, 255, 0.1)",
|
|
3073
3122
|
radius: "8px",
|
|
3074
3123
|
fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
|
|
3075
|
-
},
|
|
3124
|
+
}, Ir = {
|
|
3076
3125
|
accent: "--havik-accent",
|
|
3077
3126
|
accentText: "--havik-accent-text",
|
|
3078
3127
|
background: "--havik-bg",
|
|
@@ -3084,26 +3133,26 @@ var kr = "2.27.2", Ar = {
|
|
|
3084
3133
|
radius: "--havik-radius",
|
|
3085
3134
|
fontFamily: "--havik-font"
|
|
3086
3135
|
};
|
|
3087
|
-
function
|
|
3136
|
+
function Lr(e, t) {
|
|
3088
3137
|
let n = {
|
|
3089
|
-
...
|
|
3138
|
+
...Fr,
|
|
3090
3139
|
...t
|
|
3091
3140
|
};
|
|
3092
|
-
for (let t of Object.keys(
|
|
3141
|
+
for (let t of Object.keys(Ir)) e.style.setProperty(Ir[t], n[t]);
|
|
3093
3142
|
n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
|
|
3094
3143
|
}
|
|
3095
3144
|
//#endregion
|
|
3096
3145
|
//#region src/ui/styles.ts
|
|
3097
|
-
var
|
|
3098
|
-
function
|
|
3099
|
-
let n = e.querySelector(`style#${
|
|
3100
|
-
if (n && (!t ||
|
|
3146
|
+
var Rr = "havik-player-styles", zr = "\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", Br = /* @__PURE__ */ new WeakMap();
|
|
3147
|
+
function Vr(e = document, t) {
|
|
3148
|
+
let n = e.querySelector(`style#${Rr}`);
|
|
3149
|
+
if (n && (!t || Br.get(n) === t)) return;
|
|
3101
3150
|
let r = e.createElement("style");
|
|
3102
|
-
r.id =
|
|
3151
|
+
r.id = Rr, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = zr, Br.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
|
|
3103
3152
|
}
|
|
3104
3153
|
//#endregion
|
|
3105
3154
|
//#region src/ui/icons.ts
|
|
3106
|
-
var
|
|
3155
|
+
var Hr = {
|
|
3107
3156
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
3108
3157
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
3109
3158
|
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 +3166,11 @@ var Lr = {
|
|
|
3117
3166
|
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
3167
|
};
|
|
3119
3168
|
function Q(e) {
|
|
3120
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
3169
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Hr[e]}</svg>`;
|
|
3121
3170
|
}
|
|
3122
3171
|
//#endregion
|
|
3123
3172
|
//#region src/ui/controls.ts
|
|
3124
|
-
var
|
|
3173
|
+
var Ur = 3e3, Wr = 250, Gr = /* @__PURE__ */ new Set([
|
|
3125
3174
|
"GONE",
|
|
3126
3175
|
"NOT_FOUND",
|
|
3127
3176
|
"GEO_DENIED",
|
|
@@ -3129,15 +3178,19 @@ var Rr = 3e3, zr = 250, Br = /* @__PURE__ */ new Set([
|
|
|
3129
3178
|
"UNAUTHORIZED",
|
|
3130
3179
|
"DRM_DEVICE_REVOKED"
|
|
3131
3180
|
]);
|
|
3132
|
-
function
|
|
3181
|
+
function Kr(e) {
|
|
3133
3182
|
let t = "This match isn't available in your country";
|
|
3134
3183
|
return e ? `${t} (${e})` : t;
|
|
3135
3184
|
}
|
|
3136
|
-
var
|
|
3137
|
-
function
|
|
3138
|
-
return
|
|
3185
|
+
var qr = "This device can't play protected video";
|
|
3186
|
+
function Jr(e) {
|
|
3187
|
+
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)`;
|
|
3188
|
+
}
|
|
3189
|
+
var Yr = "Protected video can't be shown on this display. Use the built-in screen, or an HDCP-capable monitor and cable";
|
|
3190
|
+
function Xr(e) {
|
|
3191
|
+
return new Zr(e);
|
|
3139
3192
|
}
|
|
3140
|
-
var
|
|
3193
|
+
var Zr = class {
|
|
3141
3194
|
root;
|
|
3142
3195
|
video;
|
|
3143
3196
|
player;
|
|
@@ -3186,7 +3239,7 @@ var Wr = class {
|
|
|
3186
3239
|
scrubbing = !1;
|
|
3187
3240
|
offFns = [];
|
|
3188
3241
|
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 ??
|
|
3242
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Ur, 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", Vr(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
3243
|
let t = (e, t, n) => {
|
|
3191
3244
|
let r = this.doc.createElement(e);
|
|
3192
3245
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -3272,7 +3325,7 @@ var Wr = class {
|
|
|
3272
3325
|
let t = this.surfaceWasHidden;
|
|
3273
3326
|
this.tapTimer = setTimeout(() => {
|
|
3274
3327
|
this.tapTimer = void 0, this.toggleBar(t);
|
|
3275
|
-
},
|
|
3328
|
+
}, Wr);
|
|
3276
3329
|
}
|
|
3277
3330
|
toggleBar(e) {
|
|
3278
3331
|
e ? this.poke() : this.hideIfIdle();
|
|
@@ -3299,7 +3352,20 @@ var Wr = class {
|
|
|
3299
3352
|
this.renderStatus(t);
|
|
3300
3353
|
}
|
|
3301
3354
|
statusMessageFor(e) {
|
|
3302
|
-
|
|
3355
|
+
if (e === "ended") return this.isGone() ? this.endedMessage : this.player.endedReason === "interrupted" ? this.interruptedMessage : this.endedMessage;
|
|
3356
|
+
if (e === "offline") return this.offlineMessage;
|
|
3357
|
+
if (e === "waiting") return this.hasPlayed ? "Reconnecting — please stand by" : "Starting soon…";
|
|
3358
|
+
if (e === "error") {
|
|
3359
|
+
if (this.errorMessage !== void 0) return this.errorMessage;
|
|
3360
|
+
if (this.lastError?.code === "GEO_DENIED") return Kr(this.lastError.country);
|
|
3361
|
+
if (this.lastError?.code === "DRM_DEVICE_REVOKED") return qr;
|
|
3362
|
+
if (this.lastError?.code === "DRM_CLIENT") {
|
|
3363
|
+
if (this.lastError.detail === "keySystemNoAccess") return Jr(!!this.player.descriptor?.drm?.fairplay?.licenseUrl);
|
|
3364
|
+
if (this.lastError.detail === "keySystemStatusOutputRestricted") return Yr;
|
|
3365
|
+
}
|
|
3366
|
+
return this.lastError?.message ?? "Playback unavailable";
|
|
3367
|
+
}
|
|
3368
|
+
return null;
|
|
3303
3369
|
}
|
|
3304
3370
|
renderStatus(e) {
|
|
3305
3371
|
let t = this.statusMessageFor(e);
|
|
@@ -3314,7 +3380,7 @@ var Wr = class {
|
|
|
3314
3380
|
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
3381
|
} else {
|
|
3316
3382
|
let r = this.doc.createElement("div");
|
|
3317
|
-
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !
|
|
3383
|
+
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Gr.has(this.lastError.code)) {
|
|
3318
3384
|
let e = this.doc.createElement("button");
|
|
3319
3385
|
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
3386
|
}
|
|
@@ -3355,7 +3421,7 @@ var Wr = class {
|
|
|
3355
3421
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
3356
3422
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
3357
3423
|
}
|
|
3358
|
-
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${
|
|
3424
|
+
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Qr(this.video.currentTime)} / ${Qr(this.video.duration)}`);
|
|
3359
3425
|
}
|
|
3360
3426
|
syncLive() {
|
|
3361
3427
|
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 +3471,17 @@ var Wr = class {
|
|
|
3405
3471
|
renderQualityMenu() {
|
|
3406
3472
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
3407
3473
|
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(
|
|
3474
|
+
for (let n of e) this.menu.append(this.menuItem($r(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
3409
3475
|
}
|
|
3410
3476
|
renderAudioMenu() {
|
|
3411
3477
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
3412
3478
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
3413
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
3479
|
+
for (let t of e) this.menu.append(this.menuItem(ei(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
3414
3480
|
}
|
|
3415
3481
|
renderCcMenu() {
|
|
3416
3482
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
3417
3483
|
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(
|
|
3484
|
+
for (let t of e) this.menu.append(this.menuItem(ti(t), !1, () => this.player.setTextTrack(t.id)));
|
|
3419
3485
|
}
|
|
3420
3486
|
onTracksChanged() {
|
|
3421
3487
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -3520,23 +3586,23 @@ var Wr = class {
|
|
|
3520
3586
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
3521
3587
|
}
|
|
3522
3588
|
};
|
|
3523
|
-
function
|
|
3589
|
+
function Qr(e) {
|
|
3524
3590
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
3525
3591
|
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
3592
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
3527
3593
|
}
|
|
3528
|
-
function
|
|
3594
|
+
function $r(e) {
|
|
3529
3595
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
3530
3596
|
}
|
|
3531
|
-
function
|
|
3597
|
+
function ei(e) {
|
|
3532
3598
|
return e.name || e.lang || `Track ${e.id}`;
|
|
3533
3599
|
}
|
|
3534
|
-
function
|
|
3600
|
+
function ti(e) {
|
|
3535
3601
|
return e.name || e.lang || `Track ${e.id}`;
|
|
3536
3602
|
}
|
|
3537
3603
|
//#endregion
|
|
3538
3604
|
//#region src/managed/index.ts
|
|
3539
|
-
var
|
|
3605
|
+
var ni = 6e3, ri = 45e3, ii = 2e3, ai = 3, oi = 6e4, si = 2, ci = 6e5, li = 5e3, ui = 2e3, di = 48e4, fi = "keySystemLicenseRequestFailed", pi = /* @__PURE__ */ new Set([
|
|
3540
3606
|
"GONE",
|
|
3541
3607
|
"NOT_FOUND",
|
|
3542
3608
|
"INVALID_URN",
|
|
@@ -3544,27 +3610,27 @@ var Yr = 6e3, Xr = 45e3, Zr = 2e3, Qr = 3, $r = 5e3, ei = 2e3, ti = 48e4, ni = "
|
|
|
3544
3610
|
"GEO_DENIED",
|
|
3545
3611
|
"DRM_DEVICE_REVOKED"
|
|
3546
3612
|
]);
|
|
3547
|
-
function
|
|
3548
|
-
return !
|
|
3613
|
+
function mi(e) {
|
|
3614
|
+
return !pi.has(e);
|
|
3549
3615
|
}
|
|
3550
|
-
function
|
|
3616
|
+
function hi(e) {
|
|
3551
3617
|
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
3618
|
if (e.env !== void 0) return lt(e.env);
|
|
3553
3619
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
|
|
3554
3620
|
return e.baseUrl;
|
|
3555
3621
|
}
|
|
3556
|
-
async function
|
|
3622
|
+
async function gi(e) {
|
|
3557
3623
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
3558
|
-
let t =
|
|
3624
|
+
let t = hi(e);
|
|
3559
3625
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
3560
3626
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
3561
|
-
let r = new
|
|
3627
|
+
let r = new _i({
|
|
3562
3628
|
...e,
|
|
3563
3629
|
baseUrl: t
|
|
3564
3630
|
});
|
|
3565
3631
|
return await r.start(), r;
|
|
3566
3632
|
}
|
|
3567
|
-
var
|
|
3633
|
+
var _i = class {
|
|
3568
3634
|
opts;
|
|
3569
3635
|
abort = new AbortController();
|
|
3570
3636
|
listeners = {};
|
|
@@ -3587,6 +3653,10 @@ var si = class {
|
|
|
3587
3653
|
destroyed = !1;
|
|
3588
3654
|
loadGen = 0;
|
|
3589
3655
|
liveStateSub = null;
|
|
3656
|
+
liveStateLast = null;
|
|
3657
|
+
liveStateAliveAt = 0;
|
|
3658
|
+
staleEndReloads = 0;
|
|
3659
|
+
staleEndWindowAt = 0;
|
|
3590
3660
|
endedHandled = !1;
|
|
3591
3661
|
_endedReason = null;
|
|
3592
3662
|
rejoinTimer = null;
|
|
@@ -3664,7 +3734,7 @@ var si = class {
|
|
|
3664
3734
|
setTimeout(() => {
|
|
3665
3735
|
a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
3666
3736
|
phase: i ? "unavailable" : "tooEarly",
|
|
3667
|
-
retryInMs:
|
|
3737
|
+
retryInMs: ri,
|
|
3668
3738
|
attempt: 1,
|
|
3669
3739
|
elapsedMs: 0,
|
|
3670
3740
|
...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
|
|
@@ -3703,13 +3773,13 @@ var si = class {
|
|
|
3703
3773
|
!a && !p() && h();
|
|
3704
3774
|
}, e);
|
|
3705
3775
|
};
|
|
3706
|
-
_(
|
|
3776
|
+
_(ni), this.armingSub = D({
|
|
3707
3777
|
eventsBaseUrl: t,
|
|
3708
3778
|
matchUrn: this.opts.matchUrn,
|
|
3709
3779
|
credential: this.opts.credential,
|
|
3710
|
-
onAlive: () => _(
|
|
3780
|
+
onAlive: () => _(ri),
|
|
3711
3781
|
onState: (e) => {
|
|
3712
|
-
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() *
|
|
3782
|
+
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * ii);
|
|
3713
3783
|
},
|
|
3714
3784
|
onError: () => h()
|
|
3715
3785
|
});
|
|
@@ -3754,19 +3824,19 @@ var si = class {
|
|
|
3754
3824
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
|
|
3755
3825
|
let i = e.analytics?.sid;
|
|
3756
3826
|
if (!i) return;
|
|
3757
|
-
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } =
|
|
3827
|
+
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = Dr(this.opts.baseUrl, a, e.analytics?.endpoint);
|
|
3758
3828
|
if (!o) {
|
|
3759
3829
|
s && setTimeout(() => {
|
|
3760
3830
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
|
|
3761
3831
|
}, 0);
|
|
3762
3832
|
return;
|
|
3763
3833
|
}
|
|
3764
|
-
let c = this.opts.video, l = new
|
|
3834
|
+
let c = this.opts.video, l = new Or({
|
|
3765
3835
|
endpoint: o,
|
|
3766
3836
|
sid: i,
|
|
3767
3837
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
3768
|
-
sdkVersion:
|
|
3769
|
-
environment:
|
|
3838
|
+
sdkVersion: Pr,
|
|
3839
|
+
environment: Mr(c),
|
|
3770
3840
|
idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
|
|
3771
3841
|
onIdle: () => this.onAnalyticsIdle(t),
|
|
3772
3842
|
onBlocked: (e) => setTimeout(() => {
|
|
@@ -3787,7 +3857,7 @@ var si = class {
|
|
|
3787
3857
|
let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
|
|
3788
3858
|
c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
|
|
3789
3859
|
c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
|
|
3790
|
-
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()),
|
|
3860
|
+
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), Nr().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
|
|
3791
3861
|
}
|
|
3792
3862
|
currentPresentation() {
|
|
3793
3863
|
let e = this.opts.video;
|
|
@@ -3811,6 +3881,7 @@ var si = class {
|
|
|
3811
3881
|
adaptiveHoldBack: this.opts.adaptiveHoldBack,
|
|
3812
3882
|
adaptiveHoldBackCeiling: this.opts.adaptiveHoldBackCeiling,
|
|
3813
3883
|
stallCap: this.opts.stallCap,
|
|
3884
|
+
stuckReload: this.opts.stuckReload,
|
|
3814
3885
|
mediaDuringKey: this.opts.mediaDuringKey,
|
|
3815
3886
|
preloadHints: this.opts.preloadHints,
|
|
3816
3887
|
debug: this.opts.debug,
|
|
@@ -3820,9 +3891,9 @@ var si = class {
|
|
|
3820
3891
|
freshLicenseUrl: () => this.refreshLicense()
|
|
3821
3892
|
}, o = this.opts.engine ?? "auto";
|
|
3822
3893
|
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 (
|
|
3894
|
+
if (o === "hls") return new sr(a);
|
|
3895
|
+
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);
|
|
3896
|
+
if (Xt()) return new sr(a);
|
|
3826
3897
|
if (B(this.opts.video)) return new H(a);
|
|
3827
3898
|
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
3828
3899
|
}
|
|
@@ -3856,6 +3927,7 @@ var si = class {
|
|
|
3856
3927
|
this.emit("texttrackchange", e.id);
|
|
3857
3928
|
break;
|
|
3858
3929
|
case "ended":
|
|
3930
|
+
if (e.reason === "stalled" && this.reloadStaleEnd()) break;
|
|
3859
3931
|
this.onStreamEnded();
|
|
3860
3932
|
break;
|
|
3861
3933
|
case "error": {
|
|
@@ -3875,17 +3947,17 @@ var si = class {
|
|
|
3875
3947
|
if (this.opts.liveStateEvents === !1) return;
|
|
3876
3948
|
let t = this.opts.eventsBaseUrl ?? O(this.opts.baseUrl);
|
|
3877
3949
|
if (!t) return;
|
|
3878
|
-
this.closeLiveState();
|
|
3950
|
+
this.closeLiveState(), this.liveStateLast = null, this.liveStateAliveAt = 0;
|
|
3879
3951
|
let i = 0, a = !1;
|
|
3880
3952
|
this.liveStateSub = D({
|
|
3881
3953
|
eventsBaseUrl: t,
|
|
3882
3954
|
matchUrn: this.opts.matchUrn,
|
|
3883
3955
|
credential: this.opts.credential,
|
|
3884
3956
|
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));
|
|
3957
|
+
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
3958
|
},
|
|
3887
3959
|
onAlive: () => {
|
|
3888
|
-
i = 0, a = !1;
|
|
3960
|
+
i = 0, a = !1, !this.destroyed && e === this.loadGen && (this.liveStateAliveAt = Date.now());
|
|
3889
3961
|
},
|
|
3890
3962
|
onError: (o) => {
|
|
3891
3963
|
if (!(this.destroyed || e !== this.loadGen || a) && !this.endedHandled) {
|
|
@@ -3893,7 +3965,7 @@ var si = class {
|
|
|
3893
3965
|
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
3966
|
return;
|
|
3895
3967
|
}
|
|
3896
|
-
i += 1, i >=
|
|
3968
|
+
i += 1, i >= ai && (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
3969
|
}
|
|
3898
3970
|
}
|
|
3899
3971
|
});
|
|
@@ -3901,6 +3973,18 @@ var si = class {
|
|
|
3901
3973
|
closeLiveState() {
|
|
3902
3974
|
this.liveStateSub?.close(), this.liveStateSub = null;
|
|
3903
3975
|
}
|
|
3976
|
+
reloadStaleEnd() {
|
|
3977
|
+
if (this.destroyed || this.endedHandled || this._state === "error" || this._state === "ended") return !1;
|
|
3978
|
+
let e = Date.now();
|
|
3979
|
+
if (this.liveStateLast !== "live" || e - this.liveStateAliveAt > oi || (e - this.staleEndWindowAt > ci && (this.staleEndReloads = 0, this.staleEndWindowAt = e), this.staleEndReloads >= si)) return !1;
|
|
3980
|
+
this.staleEndReloads += 1;
|
|
3981
|
+
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 ${si} this window)`);
|
|
3982
|
+
this.analyticsSession?.noteError(t.code, t.message, !1, 0, Math.round(this.opts.video.currentTime * 1e3), "staleEndReload");
|
|
3983
|
+
let r = this.loadGen;
|
|
3984
|
+
return this.emit("warning", t), Promise.resolve().then(() => {
|
|
3985
|
+
if (!(this.destroyed || r !== this.loadGen) && this._state !== "error" && this._state !== "ended") return this.reload().catch(() => void 0);
|
|
3986
|
+
}), !0;
|
|
3987
|
+
}
|
|
3904
3988
|
watchConnectivity() {
|
|
3905
3989
|
this.connectivity || (this.connectivity = ut(), this.connectivity.onChange((e) => {
|
|
3906
3990
|
if (this.destroyed) return;
|
|
@@ -3910,7 +3994,7 @@ var si = class {
|
|
|
3910
3994
|
}
|
|
3911
3995
|
if (this.emit("online"), this._state !== "error" || !this._lastError) return;
|
|
3912
3996
|
let t = this._lastError.code;
|
|
3913
|
-
|
|
3997
|
+
mi(t) && (t === "NETWORK" || this.failedWhileOffline) && this.retry().catch(() => void 0);
|
|
3914
3998
|
}));
|
|
3915
3999
|
}
|
|
3916
4000
|
watchReturn() {
|
|
@@ -3920,7 +4004,7 @@ var si = class {
|
|
|
3920
4004
|
return;
|
|
3921
4005
|
}
|
|
3922
4006
|
let e = this.hiddenAtMs;
|
|
3923
|
-
this.hiddenAtMs = null, e != null && Date.now() - e >=
|
|
4007
|
+
this.hiddenAtMs = null, e != null && Date.now() - e >= li && this.resyncLiveState();
|
|
3924
4008
|
}, this.onReturnPageShow = (e) => {
|
|
3925
4009
|
e.persisted && this.resyncLiveState();
|
|
3926
4010
|
}, document.addEventListener("visibilitychange", this.onReturnVisible), typeof window < "u" && window.addEventListener("pageshow", this.onReturnPageShow));
|
|
@@ -3952,7 +4036,7 @@ var si = class {
|
|
|
3952
4036
|
scheduleRejoin(e) {
|
|
3953
4037
|
this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
|
|
3954
4038
|
this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
|
|
3955
|
-
}, Math.random() *
|
|
4039
|
+
}, Math.random() * ii));
|
|
3956
4040
|
}
|
|
3957
4041
|
cancelRejoin() {
|
|
3958
4042
|
this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
|
|
@@ -3976,7 +4060,7 @@ var si = class {
|
|
|
3976
4060
|
}
|
|
3977
4061
|
t.controls = !1;
|
|
3978
4062
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
3979
|
-
r && r.insertBefore(n, t), n.appendChild(t),
|
|
4063
|
+
r && r.insertBefore(n, t), n.appendChild(t), Lr(n, this.opts.theme), this.container = n, this.controlBar = Xr({
|
|
3980
4064
|
root: n,
|
|
3981
4065
|
video: t,
|
|
3982
4066
|
player: this,
|
|
@@ -4015,7 +4099,7 @@ var si = class {
|
|
|
4015
4099
|
}
|
|
4016
4100
|
startStats() {
|
|
4017
4101
|
this.stopStats();
|
|
4018
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
4102
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? ui);
|
|
4019
4103
|
this.statsTimer = setInterval(() => {
|
|
4020
4104
|
if (!this.engine) return;
|
|
4021
4105
|
let e = this.engine.getStats();
|
|
@@ -4026,14 +4110,14 @@ var si = class {
|
|
|
4026
4110
|
this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
|
|
4027
4111
|
}
|
|
4028
4112
|
isStaleLicenseDenial(e) {
|
|
4029
|
-
return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !==
|
|
4113
|
+
return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== fi || e.error.httpStatus !== 403 || e.error.code !== "FORBIDDEN" || e.error.serverCode === "license_refused" ? !1 : W(this._descriptor?.drm?.widevine?.licenseUrl);
|
|
4030
4114
|
}
|
|
4031
4115
|
scheduleLicenseRefresh() {
|
|
4032
4116
|
if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
|
|
4033
4117
|
typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
|
|
4034
4118
|
document.visibilityState !== "visible" || this.destroyed || W(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
|
|
4035
4119
|
}, document.addEventListener("visibilitychange", this.onRefocus));
|
|
4036
|
-
let e = this.opts.licenseRefreshMs ??
|
|
4120
|
+
let e = this.opts.licenseRefreshMs ?? di;
|
|
4037
4121
|
e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
4038
4122
|
}
|
|
4039
4123
|
stopRefresh() {
|
|
@@ -4203,7 +4287,7 @@ function $(e) {
|
|
|
4203
4287
|
}
|
|
4204
4288
|
//#endregion
|
|
4205
4289
|
//#region src/embed/host.ts
|
|
4206
|
-
function
|
|
4290
|
+
function vi(e) {
|
|
4207
4291
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
4208
4292
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
4209
4293
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -4262,15 +4346,15 @@ function ci(e) {
|
|
|
4262
4346
|
}
|
|
4263
4347
|
//#endregion
|
|
4264
4348
|
//#region src/embed/page.ts
|
|
4265
|
-
var
|
|
4266
|
-
function
|
|
4349
|
+
var yi = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
4350
|
+
function bi(e) {
|
|
4267
4351
|
if (typeof e == "boolean") return e;
|
|
4268
4352
|
if (typeof e == "object" && e) {
|
|
4269
4353
|
let t = e.endpoint;
|
|
4270
4354
|
return typeof t == "string" ? { endpoint: t } : {};
|
|
4271
4355
|
}
|
|
4272
4356
|
}
|
|
4273
|
-
function
|
|
4357
|
+
function xi() {
|
|
4274
4358
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
4275
4359
|
if (e) return {
|
|
4276
4360
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -4280,7 +4364,7 @@ function di() {
|
|
|
4280
4364
|
autoplay: e.autoplay ?? !0,
|
|
4281
4365
|
muted: e.muted ?? !0,
|
|
4282
4366
|
waitForLive: e.waitForLive ?? !0,
|
|
4283
|
-
analytics:
|
|
4367
|
+
analytics: bi(e.analytics)
|
|
4284
4368
|
};
|
|
4285
4369
|
let t = new URLSearchParams(location.search);
|
|
4286
4370
|
return {
|
|
@@ -4293,9 +4377,9 @@ function di() {
|
|
|
4293
4377
|
waitForLive: !0
|
|
4294
4378
|
};
|
|
4295
4379
|
}
|
|
4296
|
-
async function
|
|
4297
|
-
let e =
|
|
4298
|
-
|
|
4380
|
+
async function Si() {
|
|
4381
|
+
let e = xi();
|
|
4382
|
+
wi();
|
|
4299
4383
|
let t = document.createElement("video");
|
|
4300
4384
|
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
4385
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -4351,12 +4435,12 @@ async function fi() {
|
|
|
4351
4435
|
message: e.message,
|
|
4352
4436
|
...e.country === void 0 ? {} : { country: e.country }
|
|
4353
4437
|
})), e.on("autoplayblocked", () => {
|
|
4354
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
4438
|
+
i({ type: "oddin:autoplayblocked" }), Ci(t, e);
|
|
4355
4439
|
});
|
|
4356
4440
|
}, s = async (r) => {
|
|
4357
4441
|
a?.destroy(), a = null;
|
|
4358
4442
|
try {
|
|
4359
|
-
let n = await
|
|
4443
|
+
let n = await gi({
|
|
4360
4444
|
video: t,
|
|
4361
4445
|
baseUrl: e.baseUrl,
|
|
4362
4446
|
matchUrn: r,
|
|
@@ -4419,7 +4503,7 @@ async function fi() {
|
|
|
4419
4503
|
a?.retry();
|
|
4420
4504
|
break;
|
|
4421
4505
|
case "oddin:load":
|
|
4422
|
-
typeof e.matchUrn == "string" &&
|
|
4506
|
+
typeof e.matchUrn == "string" && yi.test(e.matchUrn) && s(e.matchUrn);
|
|
4423
4507
|
break;
|
|
4424
4508
|
case "oddin:destroy": c();
|
|
4425
4509
|
}
|
|
@@ -4431,18 +4515,18 @@ async function fi() {
|
|
|
4431
4515
|
protocol: 1
|
|
4432
4516
|
});
|
|
4433
4517
|
}
|
|
4434
|
-
function
|
|
4518
|
+
function Ci(e, t) {
|
|
4435
4519
|
if (document.getElementById("havik-tap")) return;
|
|
4436
4520
|
let n = document.createElement("button");
|
|
4437
4521
|
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
4522
|
n.remove(), t.play();
|
|
4439
4523
|
}), document.body.appendChild(n);
|
|
4440
4524
|
}
|
|
4441
|
-
function
|
|
4525
|
+
function wi() {
|
|
4442
4526
|
let e = document.createElement("style");
|
|
4443
4527
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
4444
4528
|
}
|
|
4445
4529
|
//#endregion
|
|
4446
|
-
export { E as LiveStateHttpError,
|
|
4530
|
+
export { E as LiveStateHttpError, Fr as ODDIN_THEME, n as PlaybackError, Lr as applyTheme, lt as baseUrlForEnv, Si as bootEmbed, ke as clearDeviceId, He as clearRememberedBandwidth, gi 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, vi as mountEmbed, fe as pollToLive, y as resolveStream, D as subscribeLiveState, S as videoFullscreenActive, we as watchStatus };
|
|
4447
4531
|
|
|
4448
4532
|
//# sourceMappingURL=index.js.map
|