@oddin-gg/havik-player 2.27.2 → 2.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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 kt(e) {
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 At() {
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 = Mt(t.manifestUrl, t.analytics?.sid), e.load();
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 = kt(a.initData), (async () => {
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.checkEndStale();
1265
- let t = jt(e, e.currentTime);
1266
- t != null && ((this.lastBufferedEnd == null || Math.abs(t - this.lastBufferedEnd) >= wt) && (this.bufferedAdvancedAt = U()), this.lastBufferedEnd = t);
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 = jt(e, e.currentTime) ?? this.lastBufferedEnd;
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 jt(e, t) {
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 Mt(e, t) {
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 Nt = 4096;
1360
- function Pt(e) {
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 > Nt)) try {
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 Ft = 15e3, It = 5e3, Lt = 6, Rt = 4e3, zt = 2;
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 Bt = class {
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 >= Lt || (this.perTrack.set(t, i + 1), this.start(r, this.withCmcd(e, t, n), !1, Ft), this.stats.started += 1);
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 >= zt;) {
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, Rt), this.stats.hintStarted += 1;
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 Vt(t, n) {
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 = Ht();
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 || It, u = setTimeout(s, l);
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 Ht() {
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 Ut(e) {
1589
+ function qt(e) {
1554
1590
  return e === "audio" ? "audio" : "main";
1555
1591
  }
1556
- function Wt(e, t) {
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 Gt(e) {
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 Kt() {
1627
+ function Xt() {
1592
1628
  return e.isSupported();
1593
1629
  }
1594
- var qt = 3, Jt = 1e6, Yt = 20, Xt = 1e4, Zt = 3, Qt = 5, $t = 3, en = 1e4, tn = 3e4, nn = 12e3, rn = 3e3, an = .02, on = 6e3, sn = .5, cn = 3, ln = .5, un = 1.1, dn = .25, fn = 5e3, pn = 4e3, mn = 2, hn = 5, gn = 2, _n = 2, vn = 4, yn = 4, bn = 2e3, xn = 3e4, Sn = 1, Cn = 2, wn = .5, Tn = .6, En = 2, Dn = 1.5, On = 1e4, kn = 18e4, An = .5, jn = 2;
1595
- function Mn(e) {
1630
+ var Zt = 3, Qt = 1e6, $t = 20, en = 1e4, tn = 3, nn = 5, rn = 3, an = 1e4, on = 3e4, sn = 12e3, cn = 3e3, ln = .02, un = 6e3, dn = .5, fn = 3, pn = .5, mn = 1.1, hn = .25, gn = 5e3, _n = 4e3, vn = 2, yn = 5, bn = 2, xn = 2, Sn = 4, Cn = 4, wn = 2e3, Tn = 3e4, En = 1, Dn = 2, On = .5, kn = .6, An = 2, jn = 1.5, Mn = 1e4, Nn = 18e4, Pn = .5, Fn = 2;
1631
+ function In(e) {
1596
1632
  let t = e.config ?? {};
1597
1633
  return t.capLevelToPlayerSize === !0 || t.capLevelOnFPSDrop === !0;
1598
1634
  }
1599
- var q = 8, Nn = 12e4, Pn = 6e4;
1635
+ var q = 8, Ln = 12e4, Rn = 6e4;
1600
1636
  function J(e, t, n) {
1601
1637
  if (n <= 0 || t < 0 || t >= e.length) return t;
1602
1638
  let r = (t, n) => e[t].width === e[n].width && e[t].height === e[n].height, i = (t) => {
@@ -1609,11 +1645,11 @@ function J(e, t, n) {
1609
1645
  function Y() {
1610
1646
  return typeof self < "u" && self.devicePixelRatio > 0 ? self.devicePixelRatio : 1;
1611
1647
  }
1612
- var Fn = .2, In = 30, Ln = 2, Rn = 2, zn = 2, Bn = 9, Vn = .5, Hn = 64, Un = 1e4, Wn = 8, Gn = .6, Kn = .4, qn = .4, Jn = 2, Yn = 6e4, X = .5, Xn = 3.5, Zn = 300;
1613
- function Qn(e) {
1648
+ var zn = .2, Bn = 30, Vn = 2, Hn = 2, Un = 2, Wn = 9, Gn = .5, Kn = 64, qn = 1e4, Jn = 8, Yn = .6, Xn = .4, Zn = .4, Qn = 2, $n = 6e4, X = .5, er = 3.5, tr = 300;
1649
+ function nr(e) {
1614
1650
  return (e?.part ?? e?.frag)?.stats;
1615
1651
  }
1616
- function $n() {
1652
+ function rr() {
1617
1653
  if (typeof navigator > "u") return 0;
1618
1654
  try {
1619
1655
  let e = navigator.connection?.rtt;
@@ -1622,20 +1658,20 @@ function $n() {
1622
1658
  return 0;
1623
1659
  }
1624
1660
  }
1625
- function er(e) {
1661
+ function ir(e) {
1626
1662
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
1627
1663
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
1628
1664
  return;
1629
1665
  }
1630
- e.liveSyncDuration ??= zn;
1631
- let t = Math.max(12, e.liveSyncDuration + Bn);
1632
- (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), tr(e, e.liveSyncDuration);
1666
+ e.liveSyncDuration ??= Un;
1667
+ let t = Math.max(12, e.liveSyncDuration + Wn);
1668
+ (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), ar(e, e.liveSyncDuration);
1633
1669
  }
1634
- function tr(e, t) {
1670
+ function ar(e, t) {
1635
1671
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
1636
1672
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
1637
1673
  }
1638
- var nr = class {
1674
+ var or = class {
1639
1675
  name = "hls";
1640
1676
  hls = null;
1641
1677
  deps;
@@ -1788,7 +1824,7 @@ var nr = class {
1788
1824
  }
1789
1825
  this.loadSuspended = !0;
1790
1826
  }
1791
- }, fn));
1827
+ }, gn));
1792
1828
  }
1793
1829
  resumeLoading() {
1794
1830
  if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
@@ -1820,7 +1856,7 @@ var nr = class {
1820
1856
  let t = e.liveSyncPosition;
1821
1857
  if (typeof t != "number" || !Number.isFinite(t)) return;
1822
1858
  let { video: n } = this.deps;
1823
- n.currentTime <= t + Vn || (n.currentTime = t);
1859
+ n.currentTime <= t + Gn || (n.currentTime = t);
1824
1860
  }
1825
1861
  reanchorPartTimeline(e, t) {
1826
1862
  let { frag: n, part: r } = t;
@@ -1832,7 +1868,7 @@ var nr = class {
1832
1868
  let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
1833
1869
  if (!s) return;
1834
1870
  let c = a.startPTS - s.start;
1835
- if (!(!Number.isFinite(c) || Math.abs(c) < an)) {
1871
+ if (!(!Number.isFinite(c) || Math.abs(c) < ln)) {
1836
1872
  for (let e of i.fragments) e && e.setStart(e.start + c);
1837
1873
  i.fragmentHint?.setStart(i.fragmentHint.start + c), this.deps.debug === !0 && console.info(`havik-player: LL-HLS timeline re-anchored by ${c >= 0 ? "+" : ""}${c.toFixed(3)}s at sn ${n.sn} (level ${n.level})`);
1838
1874
  }
@@ -1872,7 +1908,7 @@ var nr = class {
1872
1908
  return;
1873
1909
  }
1874
1910
  let l = this.hls, u, d = new Promise((e) => {
1875
- u = setTimeout(() => e(void 0), en);
1911
+ u = setTimeout(() => e(void 0), an);
1876
1912
  });
1877
1913
  return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
1878
1914
  if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
@@ -1890,28 +1926,28 @@ var nr = class {
1890
1926
  this.prefetch?.destroy(), this.prefetch = null;
1891
1927
  let p = !1, m = !1, h = u && this.deps.mediaDuringKey !== !1, g = this.deps.preloadHints !== !1;
1892
1928
  if ((h || g) && !f.fLoader) {
1893
- let e = new Bt({
1929
+ let e = new Wt({
1894
1930
  sessionId: n.analytics?.sid,
1895
1931
  contentId: n.matchUrn
1896
- }), t = Vt(e, f.loader);
1932
+ }), t = Gt(e, f.loader);
1897
1933
  t && (this.prefetch = e, p = h, m = g, f.fLoader = t);
1898
1934
  }
1899
- er(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;
1935
+ ir(f), this.catchUpRate = typeof f.maxLiveSyncPlaybackRate == "number" ? f.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (f.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = f.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = f.autoStartLoad !== !1;
1900
1936
  let _ = new e(f);
1901
1937
  if (this.hls = _, this.armHoldBack(_, f), _.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(_, t)), _.on(e.Events.MANIFEST_PARSED, () => {
1902
1938
  this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(_), this.measureLadder(_), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
1903
1939
  }), _.on(e.Events.FRAG_BUFFERED, (e, t) => {
1904
1940
  t?.frag?.type === "main" && (this.kickKind !== "dead" && this.clearKick(), (this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0 || this.starvationKicks > 0 || this.starvationRebuilds > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
1905
1941
  this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
1906
- }, tn)));
1942
+ }, on)));
1907
1943
  }), _.on(e.Events.FRAG_LOADING, (e, t) => {
1908
1944
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
1909
1945
  }), _.on(e.Events.FRAG_LOADED, (e, t) => {
1910
1946
  t?.frag?.type === "main" && (this.mainFragsSinceTick += 1, this.bwFragsLoaded += 1, this.maybeRememberBandwidth(!1));
1911
- let n = t?.frag, r = Qn(t), i = r?.loaded;
1947
+ let n = t?.frag, r = nr(t), i = r?.loaded;
1912
1948
  typeof i == "number" && (this.bytesLoaded += i), !this.reportedFirstBytes && typeof i == "number" && i > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
1913
1949
  let a = r?.loading;
1914
- a && a.end > 0 && a.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(a.end - a.start))), this.requestTimesMs.length > Hn && this.requestTimesMs.shift()), this.sampleHoldBack(t), this.sampleHeadroom(t);
1950
+ a && a.end > 0 && a.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(a.end - a.start))), this.requestTimesMs.length > Kn && this.requestTimesMs.shift()), this.sampleHoldBack(t), this.sampleHeadroom(t);
1915
1951
  let o = n?.url;
1916
1952
  if (o) {
1917
1953
  let e = ft(o);
@@ -1931,8 +1967,8 @@ var nr = class {
1931
1967
  let i = e;
1932
1968
  if (!i?.live || !i.partList?.length || typeof i.edge != "number") return;
1933
1969
  let a = n.buffered, o = a.length ? a.end(a.length - 1) : 0;
1934
- if (i.edge - o > qt * (i.partTarget || .5)) return;
1935
- let s = Gt(e);
1970
+ if (i.edge - o > Zt * (i.partTarget || .5)) return;
1971
+ let s = Yt(e);
1936
1972
  s && t.prefetchHint(s, r);
1937
1973
  };
1938
1974
  _.on(e.Events.LEVEL_LOADED, (e, t) => {
@@ -1944,15 +1980,15 @@ var nr = class {
1944
1980
  if (this.prefetch && p) {
1945
1981
  let t = this.prefetch;
1946
1982
  _.on(e.Events.KEY_LOADING, (e, n) => {
1947
- let r = n?.frag, i = Ut(r?.type);
1948
- if (r && t.isActive(i)) for (let e of Wt(_, r)) t.prefetch(e.url, i, e.kind);
1949
- }), _.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(Ut(n?.frag?.type)));
1983
+ let r = n?.frag, i = qt(r?.type);
1984
+ if (r && t.isActive(i)) for (let e of Jt(_, r)) t.prefetch(e.url, i, e.kind);
1985
+ }), _.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(qt(n?.frag?.type)));
1950
1986
  }
1951
1987
  _.on(e.Events.KEY_LOADED, () => {
1952
1988
  u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
1953
1989
  }), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1954
1990
  this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.adaptHoldBack(), this.reviewSizeCapHeadroom(), this.releaseStallCap(), this.checkFrameDrops();
1955
- }, rn), _.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1991
+ }, cn), _.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1956
1992
  this.renditionSwitches += 1;
1957
1993
  let n = this.lastLevelIndex >= 0 ? _.levels[this.lastLevelIndex] : void 0, r = _.levels[t.level];
1958
1994
  n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, this.armFrameDropGrace(), l({
@@ -2013,8 +2049,8 @@ var nr = class {
2013
2049
  let e = this.hls, t = this.sizeCapCover();
2014
2050
  if (!e || !t) return null;
2015
2051
  let { cover: n, deviceRatio: r } = t, i = this.deps.sizeCapHeadroom, a = i == null || Number.isNaN(i);
2016
- if (a && r >= Cn) return n;
2017
- if (a) return this.headroomUngated || this.headroomGranted ? J(e.levels, n, Sn) : n;
2052
+ if (a && r >= Dn) return n;
2053
+ if (a) return this.headroomUngated || this.headroomGranted ? J(e.levels, n, En) : n;
2018
2054
  let o = i === Infinity ? e.levels.length : Math.max(0, Math.floor(i));
2019
2055
  return J(e.levels, n, o);
2020
2056
  }
@@ -2031,11 +2067,11 @@ var nr = class {
2031
2067
  return;
2032
2068
  }
2033
2069
  this.capTimer && clearTimeout(this.capTimer);
2034
- let t = e > this.sizeCapLevel ? bn : xn;
2070
+ let t = e > this.sizeCapLevel ? wn : Tn;
2035
2071
  this.capTimer = setTimeout(() => {
2036
2072
  this.capTimer = null;
2037
2073
  let n = this.computeSizeCapTarget();
2038
- n === e || t === xn && n != null && n < e ? this.applySizeCap() : this.onMediaResize();
2074
+ n === e || t === Tn && n != null && n < e ? this.applySizeCap() : this.onMediaResize();
2039
2075
  }, t);
2040
2076
  }
2041
2077
  measureLadder(e) {
@@ -2062,7 +2098,7 @@ var nr = class {
2062
2098
  }
2063
2099
  defaultHeadroomApplies() {
2064
2100
  let e = this.deps.sizeCapHeadroom;
2065
- return e != null && !Number.isNaN(e) || this.headroomUngated ? !1 : Y() < Cn;
2101
+ return e != null && !Number.isNaN(e) || this.headroomUngated ? !1 : Y() < Dn;
2066
2102
  }
2067
2103
  applySizeCapUnlessPending() {
2068
2104
  this.capTimer || this.applySizeCap();
@@ -2071,7 +2107,7 @@ var nr = class {
2071
2107
  if (!this.sizeCapManaged || !this.defaultHeadroomApplies() || e.frag?.type !== "main" || typeof e.frag.level != "number" || typeof document < "u" && document.hidden) return;
2072
2108
  let t = e.part ? e.part.duration : this.detectedLowLatency ? 0 : e.frag.duration;
2073
2109
  if (typeof t != "number" || !(t > 0)) return;
2074
- let n = Qn(e)?.loading;
2110
+ let n = nr(e)?.loading;
2075
2111
  if (!n || !(n.start > 0) || !(n.end >= n.start)) return;
2076
2112
  let r = this.hls?.levels?.[e.frag.level]?.bitrate;
2077
2113
  if (!(typeof r == "number" && r > 0)) return;
@@ -2084,7 +2120,7 @@ var nr = class {
2084
2120
  }
2085
2121
  onPlaybackStall(e) {
2086
2122
  let t = Date.now();
2087
- this.deps.video.seeking || !this.playingSince || t - this.playingSince < On || (this.lastStallAt = t, this.stepStallCapDown(t, e), this.headroomGranted && (this.headroomGranted = !1, this.applySizeCapUnlessPending()));
2123
+ this.deps.video.seeking || !this.playingSince || t - this.playingSince < Mn || (this.lastStallAt = t, this.stepStallCapDown(t, e), this.headroomGranted && (this.headroomGranted = !1, this.applySizeCapUnlessPending()));
2088
2124
  }
2089
2125
  stallCapLevel(e) {
2090
2126
  if (this.stallCapBitrate == null) return -1;
@@ -2095,7 +2131,7 @@ var nr = class {
2095
2131
  }
2096
2132
  stepStallCapDown(e, t) {
2097
2133
  let n = this.hls;
2098
- if (!n || !this.stallCapEnabled || Mn(n) || !n.autoLevelEnabled || typeof t == "number" && t >= An || this.isLiveEdgeWait(n, t ?? 0)) return;
2134
+ if (!n || !this.stallCapEnabled || In(n) || !n.autoLevelEnabled || typeof t == "number" && t >= Pn || this.isLiveEdgeWait(n, t ?? 0)) return;
2099
2135
  this.stallCapBitrate != null && (this.stallCapSince = e);
2100
2136
  let r = Math.max(n.levels[n.currentLevel]?.bitrate ?? 0, n.levels[n.loadLevel]?.bitrate ?? 0);
2101
2137
  if (!(r > 0)) return;
@@ -2106,7 +2142,7 @@ var nr = class {
2106
2142
  let n = e.latestLevelDetails;
2107
2143
  if (!n?.live) return !1;
2108
2144
  let r = n.partTarget || n.targetduration;
2109
- return !(r > 0) || !(n.edge > 0) ? !1 : n.edge - (this.deps.video.currentTime + t) < jn * r;
2145
+ return !(r > 0) || !(n.edge > 0) ? !1 : n.edge - (this.deps.video.currentTime + t) < Fn * r;
2110
2146
  }
2111
2147
  releaseStallCap() {
2112
2148
  let e = this.hls, t = Date.now(), n = this.stallCapTickAt;
@@ -2115,7 +2151,7 @@ var nr = class {
2115
2151
  n && (this.stallCapSince += t - Math.max(n, this.stallCapSince));
2116
2152
  return;
2117
2153
  }
2118
- if (t - this.stallCapSince < kn) return;
2154
+ if (t - this.stallCapSince < Nn) return;
2119
2155
  let r = this.stallCapBitrate, i = e.levels.map((e) => e.bitrate).filter((e) => e > r).sort((e, t) => e - t)[0];
2120
2156
  this.stallCapBitrate = i ?? null, this.stallCapSince = t, this.pushCap();
2121
2157
  }
@@ -2128,26 +2164,26 @@ var nr = class {
2128
2164
  this.headroomGranted = !1, this.headroomSamples = [];
2129
2165
  return;
2130
2166
  }
2131
- this.headroomSamples = this.headroomSamples.filter((t) => t.t >= e - Un);
2167
+ this.headroomSamples = this.headroomSamples.filter((t) => t.t >= e - qn);
2132
2168
  let r = this.headroomEarned(n, e);
2133
- r !== this.headroomGranted && (r || (this.headroomRegrantAt = e + Pn), this.headroomGranted = r, this.applySizeCapUnlessPending());
2169
+ r !== this.headroomGranted && (r || (this.headroomRegrantAt = e + Rn), this.headroomGranted = r, this.applySizeCapUnlessPending());
2134
2170
  }
2135
2171
  headroomEarned(e, t) {
2136
- if (t - this.lastStallAt < Nn || !this.headroomGranted && t < this.headroomRegrantAt || !this.headroomGranted && this.headroomSamples.length < q) return !1;
2172
+ if (t - this.lastStallAt < Ln || !this.headroomGranted && t < this.headroomRegrantAt || !this.headroomGranted && this.headroomSamples.length < q) return !1;
2137
2173
  let n = e.levels, r = this.sizeCapCoverLevel();
2138
2174
  if (r == null) return this.headroomGranted;
2139
- let i = J(n, r, Sn);
2175
+ let i = J(n, r, En);
2140
2176
  if (i === r) return this.headroomGranted;
2141
- let a = n[i]?.bitrate, o = e.bandwidthEstimate, s = this.headroomGranted ? Dn : En;
2177
+ let a = n[i]?.bitrate, o = e.bandwidthEstimate, s = this.headroomGranted ? jn : An;
2142
2178
  if (!(a > 0) || !(o >= s * a)) return !1;
2143
2179
  let c = (e) => K([...e].sort((e, t) => e - t), 90);
2144
2180
  if (this.headroomGranted) {
2145
2181
  let e = this.headroomSamples.filter((e) => e.bitrate >= a).map((e) => e.ratio);
2146
- return e.length < q || c(e) <= Tn;
2182
+ return e.length < q || c(e) <= kn;
2147
2183
  }
2148
2184
  let l = [];
2149
2185
  for (let e of this.headroomSamples) e.bitrate < a && l.push(e.ratio * (a / e.bitrate));
2150
- return l.length >= q && c(l) <= wn;
2186
+ return l.length >= q && c(l) <= On;
2151
2187
  }
2152
2188
  applySizeCap() {
2153
2189
  if (!this.sizeCapManaged) return;
@@ -2222,7 +2258,7 @@ var nr = class {
2222
2258
  let t = e.currentLevel >= 0 ? e.levels[e.currentLevel] : void 0;
2223
2259
  t && (n.levelHeight = t.height);
2224
2260
  let r = e.autoLevelCapping, i = r >= 0 ? e.levels[r] : void 0;
2225
- i && i.height > 0 && (n.maxLevelHeight = i.height, !Mn(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));
2261
+ i && i.height > 0 && (n.maxLevelHeight = i.height, !In(e) && r === this.pushedCapLevel && this.pushedCapReason && (n.capReason = this.pushedCapReason)), t?.videoCodec && (n.videoCodec = t.videoCodec), t?.audioCodec && (n.audioCodec = t.audioCodec), t && typeof t.bitrate == "number" && (n.renditionBitrateKbps = Math.round(t.bitrate / 1e3)), typeof t?.details?.live == "boolean" && (n.isLive = t.details.live, typeof e.liveSyncPosition == "number" && (n.atLiveEdge = this.deps.video.currentTime >= e.liveSyncPosition - 1.5));
2226
2262
  }
2227
2263
  return n;
2228
2264
  }
@@ -2250,7 +2286,7 @@ var nr = class {
2250
2286
  return;
2251
2287
  }
2252
2288
  let e = Date.now() - this.lastAdvanceMs;
2253
- !this.chaseSuspended && e > on && this.suspendChasing(), e > nn && this.emitEnded("stalled");
2289
+ !this.chaseSuspended && e > un && this.suspendChasing(), e > sn && this.emitEnded("stalled");
2254
2290
  }
2255
2291
  resetStarvationWindow() {
2256
2292
  this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
@@ -2265,7 +2301,7 @@ var nr = class {
2265
2301
  this.resetStarvationWindow();
2266
2302
  return;
2267
2303
  }
2268
- let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < on, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > pn, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = R(t), c = o - s, l = c !== this.starvedFrames;
2304
+ let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < un, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > _n, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = R(t), c = o - s, l = c !== this.starvedFrames;
2269
2305
  if (this.starvedFrames = c, !a || l) {
2270
2306
  (t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
2271
2307
  return;
@@ -2274,12 +2310,12 @@ var nr = class {
2274
2310
  this.resetStarvationWindow();
2275
2311
  return;
2276
2312
  }
2277
- if (this.kickPending && (this.kickKind === "dead" || i) && (this.kickTicks += 1), this.starvedTicks = i ? this.starvedTicks + 1 : 0, this.deadTicks += 1, this.recentMainFrags.push(this.mainFragsSinceTick), this.mainFragsSinceTick = 0, this.recentMainFrags.length > vn && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= gn && (this.clearKick(), this.starvationRebuilds < _n)) {
2313
+ if (this.kickPending && (this.kickKind === "dead" || i) && (this.kickTicks += 1), this.starvedTicks = i ? this.starvedTicks + 1 : 0, this.deadTicks += 1, this.recentMainFrags.push(this.mainFragsSinceTick), this.mainFragsSinceTick = 0, this.recentMainFrags.length > Sn && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= bn && (this.clearKick(), this.starvationRebuilds < xn)) {
2278
2314
  this.starvationRebuilds += 1, this.resetStarvationWindow(), this.clearRecoveryReset(), console.warn("havik-player: restarting the load did not resume video (the wedge is in hls.js state that only a rebuild clears) — rebuilding the player"), this.rebuildInstance("starvation rebuild");
2279
2315
  return;
2280
2316
  }
2281
- let u = i && this.starvedTicks >= mn, d = !i && this.deadTicks >= vn && this.recentMainFrags.reduce((e, t) => e + t, 0) >= yn;
2282
- if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= hn))) {
2317
+ let u = i && this.starvedTicks >= vn, d = !i && this.deadTicks >= Sn && this.recentMainFrags.reduce((e, t) => e + t, 0) >= Cn;
2318
+ if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= yn))) {
2283
2319
  this.starvationKicks += 1, this.kickPending = !0, this.kickTicks = 0, this.kickKind = d ? "dead" : "quiet", this.clearRecoveryReset(), console.warn(d ? "havik-player: video starved while hls.js keeps loading media it never plays (dead pipeline at the live edge) — restarting the load" : "havik-player: video starved while the live playlist advances (wedged hls.js fragment pipeline) — restarting the load");
2284
2320
  try {
2285
2321
  e.stopLoad(), e.startLoad(-1);
@@ -2294,7 +2330,7 @@ var nr = class {
2294
2330
  let t = e.latency, n = e.targetLatency;
2295
2331
  if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
2296
2332
  let r = t - n;
2297
- !this.catchUpEngaged && r > sn ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= sn && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
2333
+ !this.catchUpEngaged && r > dn ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= dn && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
2298
2334
  let i = this.catchUpEngaged ? this.catchUpRate : 1;
2299
2335
  e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
2300
2336
  }
@@ -2307,7 +2343,7 @@ var nr = class {
2307
2343
  }), n < 0 ? 0 : n;
2308
2344
  }
2309
2345
  armFrameDropGrace() {
2310
- this.fpsGraceTicks > 0 || (this.fpsGraceTicks = Rn, this.fpsBadTicks = 0);
2346
+ this.fpsGraceTicks > 0 || (this.fpsGraceTicks = Hn, this.fpsBadTicks = 0);
2311
2347
  }
2312
2348
  resetFrameDropWindow() {
2313
2349
  this.fpsLastFrames = -1, this.fpsLastDropped = -1, this.fpsBadTicks = 0;
@@ -2319,7 +2355,7 @@ var nr = class {
2319
2355
  return;
2320
2356
  }
2321
2357
  let { totalFrames: n, dropped: r } = R(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
2322
- if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < In || o < 0) {
2358
+ if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Bn || o < 0) {
2323
2359
  this.fpsBadTicks = 0;
2324
2360
  return;
2325
2361
  }
@@ -2327,11 +2363,11 @@ var nr = class {
2327
2363
  --this.fpsGraceTicks, this.fpsBadTicks = 0;
2328
2364
  return;
2329
2365
  }
2330
- if (o <= Fn * a) {
2366
+ if (o <= zn * a) {
2331
2367
  this.fpsBadTicks = 0;
2332
2368
  return;
2333
2369
  }
2334
- if (this.fpsBadTicks += 1, this.fpsBadTicks < Ln) return;
2370
+ if (this.fpsBadTicks += 1, this.fpsBadTicks < Vn) return;
2335
2371
  this.fpsBadTicks = 0;
2336
2372
  let s = e.levels, c = s[e.currentLevel];
2337
2373
  if (!c) return;
@@ -2348,22 +2384,22 @@ var nr = class {
2348
2384
  return;
2349
2385
  }
2350
2386
  let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
2351
- if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(un, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
2387
+ if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(mn, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
2352
2388
  this.resetChaseWindow();
2353
2389
  return;
2354
2390
  }
2355
- if (this.chaseLatency < 0 || this.chaseLatency - n >= ln) {
2391
+ if (this.chaseLatency < 0 || this.chaseLatency - n >= pn) {
2356
2392
  this.chaseLatency = n, this.chaseTicks = 0;
2357
2393
  return;
2358
2394
  }
2359
- if (this.chaseTicks += 1, this.chaseTicks < cn) return;
2395
+ if (this.chaseTicks += 1, this.chaseTicks < fn) return;
2360
2396
  this.resetChaseWindow();
2361
2397
  let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
2362
2398
  if (!(a > 1)) return;
2363
2399
  let o = e.targetLatency;
2364
2400
  if (typeof o != "number" || !(o > 0)) return;
2365
2401
  let s = Math.min(n, a - 1);
2366
- s < o + dn || (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({
2402
+ s < o + hn || (console.warn(`havik-player: catch-up at ${r}x not gaining on the live edge (latency ${n.toFixed(1)}s); holding at ${s.toFixed(1)}s`), this.liveRetargets += 1, e.targetLatency = s, this.deps.emit({
2367
2403
  type: "livetargetchange",
2368
2404
  change: {
2369
2405
  targetSeconds: s,
@@ -2380,13 +2416,13 @@ var nr = class {
2380
2416
  if (!this.holdBackEnabled || this.holdBackPriorChecked || !e || (this.holdBackPriorChecked = !0, this.holdBackApplied > 0 || this.holdBackStepCount > 0)) return;
2381
2417
  let t = e.targetLatency;
2382
2418
  if (this.holdBackBase < 0 && typeof t == "number" && t > 0 && (this.holdBackBase = t), this.holdBackBase < 0) return;
2383
- let n = $n();
2384
- if (!(n >= Zn)) return;
2419
+ let n = rr();
2420
+ if (!(n >= tr)) return;
2385
2421
  let r = typeof t == "number" && t > 0 ? t : this.holdBackBase, i = Math.min(this.holdBackCeiling(e), this.holdBackBase + X);
2386
2422
  i > r && (this.holdBackStepCount = 1, this.moveHoldBack(e, r, i, "connection-rtt", `connection rtt ${n} ms`));
2387
2423
  }
2388
2424
  holdBackCeiling(e) {
2389
- let t = this.deps.adaptiveHoldBackCeiling, n = typeof t == "number" && Number.isFinite(t) ? t : Xn, r = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
2425
+ let t = this.deps.adaptiveHoldBackCeiling, n = typeof t == "number" && Number.isFinite(t) ? t : er, r = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
2390
2426
  return r > 1 ? Math.min(n, r - 1) : n;
2391
2427
  }
2392
2428
  sampleHoldBack(e) {
@@ -2395,7 +2431,7 @@ var nr = class {
2395
2431
  if (t !== "main" && t !== "audio") return;
2396
2432
  let n = e.part ? e.part.duration : this.detectedLowLatency ? 0 : e.frag?.duration;
2397
2433
  if (typeof n != "number" || !(n > 0)) return;
2398
- let r = Qn(e)?.loading;
2434
+ let r = nr(e)?.loading;
2399
2435
  if (!r || !(r.start > 0) || !(r.end > 0)) return;
2400
2436
  let i = r.first > r.start ? r.first : r.end, a = Math.max(0, i - r.start) / (n * 1e3);
2401
2437
  this.holdBackSamples.push({
@@ -2410,20 +2446,20 @@ var nr = class {
2410
2446
  this.holdBackSlowTicks = 0, this.holdBackFastSince = 0, this.holdBackSamples = [];
2411
2447
  return;
2412
2448
  }
2413
- let t = Date.now(), n = t - Un, r = this.holdBackSamples, i = 0;
2449
+ let t = Date.now(), n = t - qn, r = this.holdBackSamples, i = 0;
2414
2450
  for (; i < r.length && r[i].t < n;) i += 1;
2415
2451
  i > 0 && r.splice(0, i);
2416
2452
  let a = e.targetLatency;
2417
2453
  if (typeof a != "number" || !(a > 0)) return;
2418
2454
  this.holdBackBase < 0 && (this.holdBackBase = a);
2419
2455
  let o = this.holdBackBase, s = this.holdBackCeiling(e);
2420
- if (r.length < Wn) {
2456
+ if (r.length < Jn) {
2421
2457
  this.holdBackSlowTicks = 0;
2422
2458
  return;
2423
2459
  }
2424
2460
  let c = r.map((e) => e.ratio).sort((e, t) => e - t), l = K(c, 95), u = K(c, 50), d = Math.round(l * 1e3);
2425
- if (l >= Gn && u >= Kn) {
2426
- if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks < Jn) return;
2461
+ if (l >= Yn && u >= Xn) {
2462
+ if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks < Qn) return;
2427
2463
  this.holdBackSlowTicks = 0;
2428
2464
  let t = Math.ceil((s - o) / X), n = Math.ceil((a - o) / X - 1e-9);
2429
2465
  if (n > this.holdBackStepCount && (this.holdBackStepCount = n), this.holdBackStepCount >= t) return;
@@ -2433,7 +2469,7 @@ var nr = class {
2433
2469
  this.moveHoldBack(e, a, r, "slow-fetches", `part fetches slow (first byte p50 ${Math.round(u * 1e3)} / p95 ${d} ms per 1 s of media)`);
2434
2470
  return;
2435
2471
  }
2436
- if (this.holdBackSlowTicks = 0, l >= qn) {
2472
+ if (this.holdBackSlowTicks = 0, l >= Zn) {
2437
2473
  this.holdBackFastSince = 0;
2438
2474
  return;
2439
2475
  }
@@ -2441,7 +2477,7 @@ var nr = class {
2441
2477
  this.holdBackFastSince = t;
2442
2478
  return;
2443
2479
  }
2444
- if (t - this.holdBackFastSince < Yn || (this.holdBackFastSince = t, this.holdBackStepCount === 0 || a !== this.holdBackApplied)) return;
2480
+ if (t - this.holdBackFastSince < $n || (this.holdBackFastSince = t, this.holdBackStepCount === 0 || a !== this.holdBackApplied)) return;
2445
2481
  --this.holdBackStepCount;
2446
2482
  let f = Math.max(o, o + this.holdBackStepCount * X);
2447
2483
  f >= a || this.moveHoldBack(e, a, f, "fast-fetches", `part fetches fast again (p95 first byte ${d} ms per 1 s of media)`);
@@ -2484,12 +2520,12 @@ var nr = class {
2484
2520
  } catch {}
2485
2521
  }
2486
2522
  startEstimate() {
2487
- return this.deps.rememberBandwidth === !1 ? Jt : Be() ?? Jt;
2523
+ return this.deps.rememberBandwidth === !1 ? Qt : Be() ?? Qt;
2488
2524
  }
2489
2525
  maybeRememberBandwidth(e) {
2490
- if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < Yt) return;
2526
+ if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < $t) return;
2491
2527
  let t = Date.now();
2492
- if (!e && t - this.bwSavedAt < Xt) return;
2528
+ if (!e && t - this.bwSavedAt < en) return;
2493
2529
  let n = this.hls?.bandwidthEstimate;
2494
2530
  typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Ve(n));
2495
2531
  }
@@ -2509,7 +2545,7 @@ var nr = class {
2509
2545
  scheduleLicenseRetry(t) {
2510
2546
  if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
2511
2547
  let n = t.response?.code ?? 0;
2512
- if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= $t) return !1;
2548
+ if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= rn) return !1;
2513
2549
  this.licenseRecoveries += 1;
2514
2550
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
2515
2551
  return this.licenseRetryTimer = setTimeout(() => {
@@ -2545,7 +2581,7 @@ var nr = class {
2545
2581
  this.offlineHold = !0, this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null);
2546
2582
  return;
2547
2583
  }
2548
- if (this.networkRecoveries < Qt) {
2584
+ if (this.networkRecoveries < nn) {
2549
2585
  this.networkRecoveries += 1;
2550
2586
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
2551
2587
  this.networkRetryTimer = setTimeout(() => {
@@ -2562,7 +2598,7 @@ var nr = class {
2562
2598
  return;
2563
2599
  }
2564
2600
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
2565
- if (this.mediaRecoveries < Zt) {
2601
+ if (this.mediaRecoveries < tn) {
2566
2602
  this.mediaRecoveries += 1, n.recoverMediaError();
2567
2603
  return;
2568
2604
  }
@@ -2583,18 +2619,21 @@ var nr = class {
2583
2619
  }
2584
2620
  }
2585
2621
  toError(t, r = "PLAYBACK") {
2586
- let o = t.response?.code ?? 0, s = t.details ?? t.type, c = t.reason ?? t.error?.message ?? "", l = r === "DRM" && o === 403 && t.details === e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED ? i(Pt(t.networkDetails)) : void 0;
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})` : ""}`, l ? { serverCode: l } : void 0);
2622
+ let o = t.response?.code ?? 0, s = t.details ?? t.type, c = t.reason ?? t.error?.message ?? "", l = r === "DRM" && o === 403 && t.details === e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED ? i(Rt(t.networkDetails)) : void 0;
2623
+ return new n(r === "DRM" ? a(o, l) : r === "NETWORK" && o === 0 ? "NETWORK" : o === 401 ? "UNAUTHORIZED" : o === 403 ? "FORBIDDEN" : "INTERNAL", o, `${r} error: ${s}${c ? ` (${c})` : ""}`, {
2624
+ detail: s,
2625
+ ...l ? { serverCode: l } : {}
2626
+ });
2588
2627
  }
2589
- }, rr = 15e3, ir = 6e5, ar = 3e5, or = 100, Z = 1, sr = 1e3, cr = 3e4, lr = 1e3, ur = {
2628
+ }, sr = 15e3, cr = 6e5, lr = 3e5, ur = 100, Z = 1, dr = 1e3, fr = 3e4, pr = 1e3, mr = {
2590
2629
  inline: "PRESENTATION_INLINE",
2591
2630
  fullscreen: "PRESENTATION_FULLSCREEN",
2592
2631
  pip: "PRESENTATION_PIP"
2593
- }, dr = {
2632
+ }, hr = {
2594
2633
  widevine: "KEY_SYSTEM_WIDEVINE",
2595
2634
  fairplay: "KEY_SYSTEM_FAIRPLAY",
2596
2635
  none: "KEY_SYSTEM_NONE"
2597
- }, fr = /* @__PURE__ */ new Set([
2636
+ }, gr = /* @__PURE__ */ new Set([
2598
2637
  "INVALID_URN",
2599
2638
  "NOT_FOUND",
2600
2639
  "GEO_DENIED",
@@ -2605,7 +2644,7 @@ var nr = class {
2605
2644
  "FORBIDDEN",
2606
2645
  "RATE_LIMITED",
2607
2646
  "TIMEOUT"
2608
- ]), pr = {
2647
+ ]), _r = {
2609
2648
  idle: "PLAYER_STATE_IDLE",
2610
2649
  waiting: "PLAYER_STATE_WAITING",
2611
2650
  loading: "PLAYER_STATE_LOADING",
@@ -2615,7 +2654,7 @@ var nr = class {
2615
2654
  ended: "PLAYER_STATE_ENDED",
2616
2655
  error: "PLAYER_STATE_ERROR"
2617
2656
  };
2618
- function mr(e) {
2657
+ function vr(e) {
2619
2658
  try {
2620
2659
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
2621
2660
  return !n || r.length === 0 || n !== "feed" && !n.startsWith("feed-") ? void 0 : (t.hostname = [n.replace(/^feed/, "beacons"), ...r].join("."), t.pathname = "", t.search = "", t.origin);
@@ -2623,8 +2662,8 @@ function mr(e) {
2623
2662
  return;
2624
2663
  }
2625
2664
  }
2626
- var hr = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), gr = /* @__PURE__ */ new Set(), _r = /* @__PURE__ */ new Set(), vr = /* @__PURE__ */ new Set(), yr = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2627
- function br(e) {
2665
+ var yr = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), br = /* @__PURE__ */ new Set(), xr = /* @__PURE__ */ new Set(), Sr = /* @__PURE__ */ new Set(), Cr = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2666
+ function wr(e) {
2628
2667
  if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
2629
2668
  let t;
2630
2669
  try {
@@ -2633,19 +2672,19 @@ function br(e) {
2633
2672
  } catch {
2634
2673
  return;
2635
2674
  }
2636
- if (gr.has(t) && !_r.has(t)) {
2637
- _r.add(t), _(yr(new URL(t).origin));
2638
- for (let e of vr) e.noteCspBlocked();
2675
+ if (br.has(t) && !xr.has(t)) {
2676
+ xr.add(t), _(Cr(new URL(t).origin));
2677
+ for (let e of Sr) e.noteCspBlocked();
2639
2678
  }
2640
2679
  }
2641
- function xr(e, t) {
2680
+ function Tr(e, t) {
2642
2681
  return _(t, e), { disabledReason: t };
2643
2682
  }
2644
- function Sr(e, t, n) {
2645
- if (n) return t && !hr(t, n) && _(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2683
+ function Er(e, t, n) {
2684
+ if (n) return t && !yr(t, n) && _(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2646
2685
  if (t) return { endpoint: t };
2647
- if (t !== void 0) return xr("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).");
2648
- let r = mr(e);
2686
+ if (t !== void 0) return Tr("empty-endpoint", "analytics is disabled: no QoE beacons will be sent. analytics.endpoint was supplied but empty. Pass a real beacons origin, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, or omit the option to derive it from baseUrl (or analytics: false to opt out).");
2687
+ let r = vr(e);
2649
2688
  if (r) return { endpoint: r };
2650
2689
  let i;
2651
2690
  try {
@@ -2653,9 +2692,9 @@ function Sr(e, t, n) {
2653
2692
  } catch {
2654
2693
  i = e;
2655
2694
  }
2656
- return xr(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).`);
2695
+ return Tr(i, `analytics is disabled: no QoE beacons will be sent. The beacons endpoint cannot be derived from the baseUrl host "${i}" — the convention is feed[-dev].<domain> → beacons[-dev].<domain>. Pass an explicit endpoint, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, to createPlayer (or analytics: false to opt out deliberately).`);
2657
2696
  }
2658
- var Cr = class {
2697
+ var Dr = class {
2659
2698
  opts;
2660
2699
  url;
2661
2700
  cspKey;
@@ -2737,8 +2776,8 @@ var Cr = class {
2737
2776
  constructor(e) {
2738
2777
  this.opts = {
2739
2778
  ...e,
2740
- heartbeatMs: e.heartbeatMs ?? rr,
2741
- idleMs: e.idleMs ?? ir
2779
+ heartbeatMs: e.heartbeatMs ?? sr,
2780
+ idleMs: e.idleMs ?? cr
2742
2781
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
2743
2782
  try {
2744
2783
  let e = new URL(this.url);
@@ -2755,11 +2794,11 @@ var Cr = class {
2755
2794
  sdkVersion: this.opts.sdkVersion,
2756
2795
  ...this.opts.environment
2757
2796
  };
2758
- this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), sr), 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 && gr.add(this.cspKey), document.addEventListener("securitypolicyviolation", br), vr.add(this), this.noteCspBlocked(), this.onVisibility());
2797
+ this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), dr), this.lastTickMs = this.now(), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), document.addEventListener("freeze", this.onFreeze), document.addEventListener("resume", this.onResume), this.cspKey && br.add(this.cspKey), document.addEventListener("securitypolicyviolation", wr), Sr.add(this), this.noteCspBlocked(), this.onVisibility());
2759
2798
  }
2760
2799
  checkSuspension(e) {
2761
2800
  if (this.endedFlag || !this.opts.idleMs) return !1;
2762
- let t = Math.max(this.opts.idleMs, ar);
2801
+ let t = Math.max(this.opts.idleMs, lr);
2763
2802
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
2764
2803
  }
2765
2804
  syncIdle(e) {
@@ -2780,14 +2819,14 @@ var Cr = class {
2780
2819
  } else e === "buffering" && (this.isBuffering = !1, this.stallIsSeekInduced = !1);
2781
2820
  this.syncBuffering(), t === "paused" && (this.pauseCount += 1), this.syncIdle(t);
2782
2821
  let a = {
2783
- fromState: pr[e] ?? "PLAYER_STATE_UNSPECIFIED",
2784
- toState: pr[t] ?? "PLAYER_STATE_UNSPECIFIED",
2785
- presentation: ur[this.presentation]
2822
+ fromState: _r[e] ?? "PLAYER_STATE_UNSPECIFIED",
2823
+ toState: _r[t] ?? "PLAYER_STATE_UNSPECIFIED",
2824
+ presentation: mr[this.presentation]
2786
2825
  }, o = this.causeOf(e, t, i);
2787
2826
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
2788
2827
  }
2789
2828
  seekInduced(e) {
2790
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < lr;
2829
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < pr;
2791
2830
  }
2792
2831
  causeOf(e, t, n) {
2793
2832
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -2861,7 +2900,7 @@ var Cr = class {
2861
2900
  let r = n ?? "";
2862
2901
  if (r !== "") return /^fragLoad/i.test(r) ? this.sawFirstBytes ? "ERROR_STAGE_SEGMENT" : "ERROR_STAGE_FIRST_SEGMENT" : /^(manifest|level|audioTrack|subtitleTrack)/i.test(r) ? "ERROR_STAGE_MANIFEST" : /key|licen[cs]e/i.test(r) ? "ERROR_STAGE_DRM" : /parsing|append|buffer|remux|decrypt|media/i.test(r) ? "ERROR_STAGE_DECODE" : "ERROR_STAGE_OTHER";
2863
2902
  if (e === "DRM_CLIENT" || e === "DRM_DEVICE_REVOKED") return "ERROR_STAGE_DRM";
2864
- if (fr.has(e)) return "ERROR_STAGE_RESOLVE";
2903
+ if (gr.has(e)) return "ERROR_STAGE_RESOLVE";
2865
2904
  let i = t ?? "";
2866
2905
  return /frag|segment/i.test(i) ? this.sawFirstBytes ? "ERROR_STAGE_SEGMENT" : "ERROR_STAGE_FIRST_SEGMENT" : /manifest|level|playlist/i.test(i) ? "ERROR_STAGE_MANIFEST" : /key|licen[cs]e/i.test(i) ? "ERROR_STAGE_DRM" : /buffer|decode|media|append/i.test(i) ? "ERROR_STAGE_DECODE" : "ERROR_STAGE_OTHER";
2867
2906
  }
@@ -2893,7 +2932,7 @@ var Cr = class {
2893
2932
  let l = t.droppedFrames ?? 0;
2894
2933
  l > this.lastDropped && (o.droppedFramesDelta = l - this.lastDropped), this.lastDropped = l;
2895
2934
  let u = t.renditionSwitches ?? 0;
2896
- u > this.lastSwitches && (o.renditionSwitchesDelta = u - this.lastSwitches), this.lastSwitches = u, n > this.lastHbPlayingMs && (o.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (o.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, i > this.lastHbRebufferMs && (o.rebufferMsDelta = Math.round(i - this.lastHbRebufferMs)), this.lastHbRebufferMs = i, this.rebufferCount > this.lastHbRebufferCount && (o.rebufferCountDelta = this.rebufferCount - this.lastHbRebufferCount), this.lastHbRebufferCount = this.rebufferCount, a > this.lastHbActiveMs && (o.activeMsDelta = Math.round(a - this.lastHbActiveMs)), this.lastHbActiveMs = a, typeof t.latencySeconds == "number" && (o.latencyMs = Math.round(t.latencySeconds * 1e3)), typeof t.targetLatencySeconds == "number" && (o.targetLatencyMs = Math.round(t.targetLatencySeconds * 1e3)), typeof t.bandwidthKbps == "number" && (o.bandwidthEstKbps = t.bandwidthKbps), typeof t.levelHeight == "number" && (o.renditionHeight = t.levelHeight), typeof t.renditionBitrateKbps == "number" && (o.renditionBitrateKbps = t.renditionBitrateKbps), t.atLiveEdge === !0 && (o.atLiveEdge = !0), typeof t.bufferedMs == "number" && t.bufferedMs > 0 && (o.bufferedMs = Math.round(t.bufferedMs)), o.playerState = pr[t.state] ?? "PLAYER_STATE_UNSPECIFIED";
2935
+ u > this.lastSwitches && (o.renditionSwitchesDelta = u - this.lastSwitches), this.lastSwitches = u, n > this.lastHbPlayingMs && (o.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (o.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, i > this.lastHbRebufferMs && (o.rebufferMsDelta = Math.round(i - this.lastHbRebufferMs)), this.lastHbRebufferMs = i, this.rebufferCount > this.lastHbRebufferCount && (o.rebufferCountDelta = this.rebufferCount - this.lastHbRebufferCount), this.lastHbRebufferCount = this.rebufferCount, a > this.lastHbActiveMs && (o.activeMsDelta = Math.round(a - this.lastHbActiveMs)), this.lastHbActiveMs = a, typeof t.latencySeconds == "number" && (o.latencyMs = Math.round(t.latencySeconds * 1e3)), typeof t.targetLatencySeconds == "number" && (o.targetLatencyMs = Math.round(t.targetLatencySeconds * 1e3)), typeof t.bandwidthKbps == "number" && (o.bandwidthEstKbps = t.bandwidthKbps), typeof t.levelHeight == "number" && (o.renditionHeight = t.levelHeight), typeof t.renditionBitrateKbps == "number" && (o.renditionBitrateKbps = t.renditionBitrateKbps), t.atLiveEdge === !0 && (o.atLiveEdge = !0), typeof t.bufferedMs == "number" && t.bufferedMs > 0 && (o.bufferedMs = Math.round(t.bufferedMs)), o.playerState = _r[t.state] ?? "PLAYER_STATE_UNSPECIFIED";
2897
2936
  let d = this.mutedTotalMs;
2898
2937
  this.mutedSinceMs !== null && (d += e - this.mutedSinceMs), d > this.lastHbMutedMs && (o.mutedMsDelta = Math.round(d - this.lastHbMutedMs)), this.lastHbMutedMs = d;
2899
2938
  let f = t.upshifts ?? 0;
@@ -2915,13 +2954,13 @@ var Cr = class {
2915
2954
  maybeEmitMediaInfo(e) {
2916
2955
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
2917
2956
  let t = {};
2918
- e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = dr[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);
2957
+ e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = hr[e.keySystem]), e.drmSecurityLevel && (t.drmSecurityLevel = e.drmSecurityLevel), e.ladderHeights?.length && (t.ladderHeights = e.ladderHeights), e.ladderTopBitrateKbps && (t.ladderTopBitrateKbps = e.ladderTopBitrateKbps), e.lowLatency && (t.lowLatency = !0);
2919
2958
  let n = JSON.stringify(t);
2920
2959
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
2921
2960
  }
2922
2961
  end(e, t) {
2923
2962
  if (this.endedFlag) return;
2924
- this.endedFlag = !0, vr.delete(this);
2963
+ this.endedFlag = !0, Sr.delete(this);
2925
2964
  let n = t ?? this.now();
2926
2965
  this.playingSinceMs !== null && (this.playingTotalMs += n - this.playingSinceMs, this.playingSinceMs = null), this.hiddenSinceMs !== null && (this.hiddenTotalMs += n - this.hiddenSinceMs, this.hiddenSinceMs = null), this.bufferingSinceMs !== null && (this.rebufferTotalMs += n - this.bufferingSinceMs, this.bufferingSinceMs = null), this.mutedSinceMs !== null && (this.mutedTotalMs += n - this.mutedSinceMs, this.mutedSinceMs = null), this.waitingSinceMs !== null && (this.waitingTotalMs += n - this.waitingSinceMs, this.waitingSinceMs = null), this.isPlaying = !1, this.syncActive(n), this.closePresentation(n), this.firstFlushTimer &&= (clearTimeout(this.firstFlushTimer), null), this.timer &&= (clearInterval(this.timer), null), this.idleTimer &&= (clearTimeout(this.idleTimer), null), typeof window < "u" && window.removeEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), document.removeEventListener("freeze", this.onFreeze), document.removeEventListener("resume", this.onResume));
2927
2966
  let r = this.safeSample();
@@ -2935,7 +2974,7 @@ var Cr = class {
2935
2974
  let c = r?.positionMs ?? 0;
2936
2975
  c > 0 && (i.exitPositionMs = Math.round(c)), this.activeTotalMs > 0 && (i.activeWatchTimeMs = Math.round(this.activeTotalMs)), this.mutedTotalMs > 0 && (i.mutedTimeMs = Math.round(this.mutedTotalMs));
2937
2976
  let l = e !== "END_REASON_ENDED";
2938
- l && this.lastStallMs > 0 && n - this.lastStallMs <= cr && (i.abandonAfterStallMs = Math.max(Z, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= cr && (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);
2977
+ l && this.lastStallMs > 0 && n - this.lastStallMs <= fr && (i.abandonAfterStallMs = Math.max(Z, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= fr && (i.abandonAfterErrorMs = Math.max(Z, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
2939
2978
  let u = r?.decodedFrames ?? this.lastDecoded;
2940
2979
  u > 0 && (i.decodedFramesTotal = u), e === "END_REASON_STOPPED" && this.startupTimeMs === 0 && this.lastErrorStage === null && (e = "END_REASON_ABORTED", i.reason = e), this.startupTimeMs === 0 && e !== "END_REASON_ABORTED" && (i.failedStage = this.lastErrorStage ?? (this.manifestLoadMs === 0 ? "ERROR_STAGE_MANIFEST" : this.firstFragLoadMs === 0 ? "ERROR_STAGE_FIRST_SEGMENT" : "ERROR_STAGE_OTHER")), this.pending.push(this.wrap({ sessionEnd: i })), this.flush(e === "END_REASON_PAGEHIDE");
2941
2980
  }
@@ -2955,13 +2994,13 @@ var Cr = class {
2955
2994
  };
2956
2995
  }
2957
2996
  noteCspBlocked() {
2958
- this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(yr(new URL(this.url).origin)));
2997
+ this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(Cr(new URL(this.url).origin)));
2959
2998
  }
2960
2999
  cspBlocked() {
2961
- return !!this.cspKey && _r.has(this.cspKey);
3000
+ return !!this.cspKey && xr.has(this.cspKey);
2962
3001
  }
2963
3002
  enqueue(e) {
2964
- if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > or;) {
3003
+ if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > ur;) {
2965
3004
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
2966
3005
  this.pending.splice(e >= 0 ? e : 0, 1);
2967
3006
  }
@@ -2988,7 +3027,7 @@ var Cr = class {
2988
3027
  };
2989
3028
  //#endregion
2990
3029
  //#region src/core/environment.ts
2991
- function wr() {
3030
+ function Or() {
2992
3031
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
2993
3032
  let e;
2994
3033
  try {
@@ -3013,14 +3052,14 @@ function wr() {
3013
3052
  integration: "INTEGRATION_KIND_IFRAME"
3014
3053
  };
3015
3054
  }
3016
- function Tr() {
3055
+ function kr() {
3017
3056
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
3018
3057
  let e = navigator.userAgentData, t = e?.platform ?? "";
3019
3058
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
3020
3059
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
3021
3060
  return e?.mobile ?? (typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1 && n > 0 && n < 900) ? n >= 600 ? "DEVICE_CLASS_TABLET" : "DEVICE_CLASS_PHONE" : e || n >= 900 || /mac|win|linux|chrome os/i.test(t) ? "DEVICE_CLASS_DESKTOP" : "DEVICE_CLASS_OTHER";
3022
3061
  }
3023
- function Er() {
3062
+ function Ar() {
3024
3063
  let e = typeof navigator < "u" ? navigator.connection : void 0;
3025
3064
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
3026
3065
  let t = {
@@ -3039,17 +3078,17 @@ function Er() {
3039
3078
  }
3040
3079
  return typeof e.downlink == "number" && e.downlink > 0 && (i.downlinkKbps = Math.round(e.downlink * 1e3)), typeof e.rtt == "number" && e.rtt > 0 && (i.rttMs = Math.round(e.rtt)), e.saveData && (i.saveData = !0), i;
3041
3080
  }
3042
- function Dr(e) {
3043
- let t = wr(), n = {
3044
- deviceClass: Tr(),
3081
+ function jr(e) {
3082
+ let t = Or(), n = {
3083
+ deviceClass: kr(),
3045
3084
  integration: t.integration,
3046
- ...Er()
3085
+ ...Ar()
3047
3086
  };
3048
3087
  t.host && (n.host = t.host), typeof screen < "u" && screen.width > 0 && (n.screenWidth = screen.width, n.screenHeight = screen.height), typeof window < "u" && window.devicePixelRatio > 0 && (n.devicePixelRatio = Math.round(window.devicePixelRatio * 100) / 100);
3049
3088
  let r = e.getBoundingClientRect?.();
3050
3089
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
3051
3090
  }
3052
- async function Or() {
3091
+ async function Mr() {
3053
3092
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
3054
3093
  if (!e?.getHighEntropyValues) return {};
3055
3094
  try {
@@ -3061,7 +3100,7 @@ async function Or() {
3061
3100
  }
3062
3101
  //#endregion
3063
3102
  //#region src/core/version.ts
3064
- var kr = "2.27.2", Ar = {
3103
+ var Nr = "2.28.0", Pr = {
3065
3104
  accent: "#E1B600",
3066
3105
  accentText: "#1B1C23",
3067
3106
  background: "#0e0f13",
@@ -3072,7 +3111,7 @@ var kr = "2.27.2", Ar = {
3072
3111
  border: "rgba(255, 255, 255, 0.1)",
3073
3112
  radius: "8px",
3074
3113
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
3075
- }, jr = {
3114
+ }, Fr = {
3076
3115
  accent: "--havik-accent",
3077
3116
  accentText: "--havik-accent-text",
3078
3117
  background: "--havik-bg",
@@ -3084,26 +3123,26 @@ var kr = "2.27.2", Ar = {
3084
3123
  radius: "--havik-radius",
3085
3124
  fontFamily: "--havik-font"
3086
3125
  };
3087
- function Mr(e, t) {
3126
+ function Ir(e, t) {
3088
3127
  let n = {
3089
- ...Ar,
3128
+ ...Pr,
3090
3129
  ...t
3091
3130
  };
3092
- for (let t of Object.keys(jr)) e.style.setProperty(jr[t], n[t]);
3131
+ for (let t of Object.keys(Fr)) e.style.setProperty(Fr[t], n[t]);
3093
3132
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
3094
3133
  }
3095
3134
  //#endregion
3096
3135
  //#region src/ui/styles.ts
3097
- var Nr = "havik-player-styles", Pr = "\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", Fr = /* @__PURE__ */ new WeakMap();
3098
- function Ir(e = document, t) {
3099
- let n = e.querySelector(`style#${Nr}`);
3100
- if (n && (!t || Fr.get(n) === t)) return;
3136
+ var Lr = "havik-player-styles", Rr = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer;\n touch-action:manipulation}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n/* Absolutely centred, NOT a flex sibling of .havik-center: the hidden center\n button (.havik-gone) still occupies its 74px in the row, which pushed an\n in-flow spinner 37px right of centre. */\n.havik-spinner{position:absolute;inset:0;margin:auto;width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n", zr = /* @__PURE__ */ new WeakMap();
3137
+ function Br(e = document, t) {
3138
+ let n = e.querySelector(`style#${Lr}`);
3139
+ if (n && (!t || zr.get(n) === t)) return;
3101
3140
  let r = e.createElement("style");
3102
- r.id = Nr, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = Pr, Fr.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
3141
+ r.id = Lr, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = Rr, zr.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
3103
3142
  }
3104
3143
  //#endregion
3105
3144
  //#region src/ui/icons.ts
3106
- var Lr = {
3145
+ var Vr = {
3107
3146
  play: "<path d=\"M8 5v14l11-7z\"/>",
3108
3147
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
3109
3148
  volumeHigh: "<path d=\"M3 10v4h4l5 5V5L7 10H3zm13.5 2a4.5 4.5 0 0 0-2.5-4v8a4.5 4.5 0 0 0 2.5-4zm-2.5-9v2.06A7 7 0 0 1 14 19v2a9 9 0 0 0 0-18z\"/>",
@@ -3117,11 +3156,11 @@ var Lr = {
3117
3156
  retry: "<path d=\"M17.65 6.35A8 8 0 1 0 19.73 13h-2.08A6 6 0 1 1 12 6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z\"/>"
3118
3157
  };
3119
3158
  function Q(e) {
3120
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Lr[e]}</svg>`;
3159
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Vr[e]}</svg>`;
3121
3160
  }
3122
3161
  //#endregion
3123
3162
  //#region src/ui/controls.ts
3124
- var Rr = 3e3, zr = 250, Br = /* @__PURE__ */ new Set([
3163
+ var Hr = 3e3, Ur = 250, Wr = /* @__PURE__ */ new Set([
3125
3164
  "GONE",
3126
3165
  "NOT_FOUND",
3127
3166
  "GEO_DENIED",
@@ -3129,15 +3168,19 @@ var Rr = 3e3, zr = 250, Br = /* @__PURE__ */ new Set([
3129
3168
  "UNAUTHORIZED",
3130
3169
  "DRM_DEVICE_REVOKED"
3131
3170
  ]);
3132
- function Vr(e) {
3171
+ function Gr(e) {
3133
3172
  let t = "This match isn't available in your country";
3134
3173
  return e ? `${t} (${e})` : t;
3135
3174
  }
3136
- var Hr = "This device can't play protected video";
3137
- function Ur(e) {
3138
- return new Wr(e);
3175
+ var Kr = "This device can't play protected video";
3176
+ function qr(e) {
3177
+ return `This browser can't play protected video. Allow protected content in its site settings, or use ${e ? "Chrome, Edge or Safari" : "Chrome or Edge"} (Firefox asks when you retry)`;
3139
3178
  }
3140
- var Wr = class {
3179
+ var Jr = "Protected video can't be shown on this display. Use the built-in screen, or an HDCP-capable monitor and cable";
3180
+ function Yr(e) {
3181
+ return new Xr(e);
3182
+ }
3183
+ var Xr = class {
3141
3184
  root;
3142
3185
  video;
3143
3186
  player;
@@ -3186,7 +3229,7 @@ var Wr = class {
3186
3229
  scrubbing = !1;
3187
3230
  offFns = [];
3188
3231
  constructor(e) {
3189
- this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Rr, 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", Ir(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");
3232
+ this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Hr, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.streamEnded = e.streamEnded ?? (() => !1), this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, this.offlineMessage = e.offlineMessage ?? "No internet connection — waiting to reconnect", Br(this.doc, e.cspNonce), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
3190
3233
  let t = (e, t, n) => {
3191
3234
  let r = this.doc.createElement(e);
3192
3235
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -3272,7 +3315,7 @@ var Wr = class {
3272
3315
  let t = this.surfaceWasHidden;
3273
3316
  this.tapTimer = setTimeout(() => {
3274
3317
  this.tapTimer = void 0, this.toggleBar(t);
3275
- }, zr);
3318
+ }, Ur);
3276
3319
  }
3277
3320
  toggleBar(e) {
3278
3321
  e ? this.poke() : this.hideIfIdle();
@@ -3299,7 +3342,20 @@ var Wr = class {
3299
3342
  this.renderStatus(t);
3300
3343
  }
3301
3344
  statusMessageFor(e) {
3302
- return e === "ended" ? this.isGone() ? this.endedMessage : this.player.endedReason === "interrupted" ? this.interruptedMessage : this.endedMessage : e === "offline" ? this.offlineMessage : e === "waiting" ? this.hasPlayed ? "Reconnecting — please stand by" : "Starting soon…" : e === "error" ? this.errorMessage === void 0 ? this.lastError?.code === "GEO_DENIED" ? Vr(this.lastError.country) : this.lastError?.code === "DRM_DEVICE_REVOKED" ? Hr : this.lastError?.message ?? "Playback unavailable" : this.errorMessage : null;
3345
+ if (e === "ended") return this.isGone() ? this.endedMessage : this.player.endedReason === "interrupted" ? this.interruptedMessage : this.endedMessage;
3346
+ if (e === "offline") return this.offlineMessage;
3347
+ if (e === "waiting") return this.hasPlayed ? "Reconnecting — please stand by" : "Starting soon…";
3348
+ if (e === "error") {
3349
+ if (this.errorMessage !== void 0) return this.errorMessage;
3350
+ if (this.lastError?.code === "GEO_DENIED") return Gr(this.lastError.country);
3351
+ if (this.lastError?.code === "DRM_DEVICE_REVOKED") return Kr;
3352
+ if (this.lastError?.code === "DRM_CLIENT") {
3353
+ if (this.lastError.detail === "keySystemNoAccess") return qr(!!this.player.descriptor?.drm?.fairplay?.licenseUrl);
3354
+ if (this.lastError.detail === "keySystemStatusOutputRestricted") return Jr;
3355
+ }
3356
+ return this.lastError?.message ?? "Playback unavailable";
3357
+ }
3358
+ return null;
3303
3359
  }
3304
3360
  renderStatus(e) {
3305
3361
  let t = this.statusMessageFor(e);
@@ -3314,7 +3370,7 @@ var Wr = class {
3314
3370
  e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = Q("play"), e.addEventListener("click", () => void this.player.play()), n.append(e);
3315
3371
  } else {
3316
3372
  let r = this.doc.createElement("div");
3317
- if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Br.has(this.lastError.code)) {
3373
+ if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Wr.has(this.lastError.code)) {
3318
3374
  let e = this.doc.createElement("button");
3319
3375
  e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${Q("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), n.append(e);
3320
3376
  }
@@ -3355,7 +3411,7 @@ var Wr = class {
3355
3411
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
3356
3412
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
3357
3413
  }
3358
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Gr(this.video.currentTime)} / ${Gr(this.video.duration)}`);
3414
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Zr(this.video.currentTime)} / ${Zr(this.video.duration)}`);
3359
3415
  }
3360
3416
  syncLive() {
3361
3417
  let e = this.player.getStats(), t = e.isLive !== !1, n = this.isGone(), r = this.player.state === "ended" || n, i = !t && !this.streamEnded() && !n;
@@ -3405,17 +3461,17 @@ var Wr = class {
3405
3461
  renderQualityMenu() {
3406
3462
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
3407
3463
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
3408
- for (let n of e) this.menu.append(this.menuItem(Kr(n), t === n.index, () => this.player.setQuality(n.index)));
3464
+ for (let n of e) this.menu.append(this.menuItem(Qr(n), t === n.index, () => this.player.setQuality(n.index)));
3409
3465
  }
3410
3466
  renderAudioMenu() {
3411
3467
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
3412
3468
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
3413
- for (let t of e) this.menu.append(this.menuItem(qr(t), t.default, () => this.player.setAudioTrack(t.id)));
3469
+ for (let t of e) this.menu.append(this.menuItem($r(t), t.default, () => this.player.setAudioTrack(t.id)));
3414
3470
  }
3415
3471
  renderCcMenu() {
3416
3472
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
3417
3473
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
3418
- for (let t of e) this.menu.append(this.menuItem(Jr(t), !1, () => this.player.setTextTrack(t.id)));
3474
+ for (let t of e) this.menu.append(this.menuItem(ei(t), !1, () => this.player.setTextTrack(t.id)));
3419
3475
  }
3420
3476
  onTracksChanged() {
3421
3477
  this.openMenu && this.renderMenu(this.openMenu);
@@ -3520,23 +3576,23 @@ var Wr = class {
3520
3576
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
3521
3577
  }
3522
3578
  };
3523
- function Gr(e) {
3579
+ function Zr(e) {
3524
3580
  (!Number.isFinite(e) || e < 0) && (e = 0);
3525
3581
  let t = Math.floor(e % 60), n = Math.floor(e / 60 % 60), r = Math.floor(e / 3600), i = r > 0 ? String(n).padStart(2, "0") : String(n), a = String(t).padStart(2, "0");
3526
3582
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
3527
3583
  }
3528
- function Kr(e) {
3584
+ function Qr(e) {
3529
3585
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
3530
3586
  }
3531
- function qr(e) {
3587
+ function $r(e) {
3532
3588
  return e.name || e.lang || `Track ${e.id}`;
3533
3589
  }
3534
- function Jr(e) {
3590
+ function ei(e) {
3535
3591
  return e.name || e.lang || `Track ${e.id}`;
3536
3592
  }
3537
3593
  //#endregion
3538
3594
  //#region src/managed/index.ts
3539
- var Yr = 6e3, Xr = 45e3, Zr = 2e3, Qr = 3, $r = 5e3, ei = 2e3, ti = 48e4, ni = "keySystemLicenseRequestFailed", ri = /* @__PURE__ */ new Set([
3595
+ var ti = 6e3, ni = 45e3, ri = 2e3, ii = 3, ai = 6e4, oi = 2, si = 6e5, ci = 5e3, li = 2e3, ui = 48e4, di = "keySystemLicenseRequestFailed", fi = /* @__PURE__ */ new Set([
3540
3596
  "GONE",
3541
3597
  "NOT_FOUND",
3542
3598
  "INVALID_URN",
@@ -3544,27 +3600,27 @@ var Yr = 6e3, Xr = 45e3, Zr = 2e3, Qr = 3, $r = 5e3, ei = 2e3, ti = 48e4, ni = "
3544
3600
  "GEO_DENIED",
3545
3601
  "DRM_DEVICE_REVOKED"
3546
3602
  ]);
3547
- function ii(e) {
3548
- return !ri.has(e);
3603
+ function pi(e) {
3604
+ return !fi.has(e);
3549
3605
  }
3550
- function ai(e) {
3606
+ function mi(e) {
3551
3607
  if (e.env !== void 0 && e.baseUrl !== void 0) throw new n("INTERNAL", 0, `createPlayer: pass env OR baseUrl, not both (got env=${JSON.stringify(e.env)} and baseUrl=${JSON.stringify(e.baseUrl)})`);
3552
3608
  if (e.env !== void 0) return lt(e.env);
3553
3609
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
3554
3610
  return e.baseUrl;
3555
3611
  }
3556
- async function oi(e) {
3612
+ async function hi(e) {
3557
3613
  if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
3558
- let t = ai(e);
3614
+ let t = mi(e);
3559
3615
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
3560
3616
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
3561
- let r = new si({
3617
+ let r = new gi({
3562
3618
  ...e,
3563
3619
  baseUrl: t
3564
3620
  });
3565
3621
  return await r.start(), r;
3566
3622
  }
3567
- var si = class {
3623
+ var gi = class {
3568
3624
  opts;
3569
3625
  abort = new AbortController();
3570
3626
  listeners = {};
@@ -3587,6 +3643,10 @@ var si = class {
3587
3643
  destroyed = !1;
3588
3644
  loadGen = 0;
3589
3645
  liveStateSub = null;
3646
+ liveStateLast = null;
3647
+ liveStateAliveAt = 0;
3648
+ staleEndReloads = 0;
3649
+ staleEndWindowAt = 0;
3590
3650
  endedHandled = !1;
3591
3651
  _endedReason = null;
3592
3652
  rejoinTimer = null;
@@ -3664,7 +3724,7 @@ var si = class {
3664
3724
  setTimeout(() => {
3665
3725
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
3666
3726
  phase: i ? "unavailable" : "tooEarly",
3667
- retryInMs: Xr,
3727
+ retryInMs: ni,
3668
3728
  attempt: 1,
3669
3729
  elapsedMs: 0,
3670
3730
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -3703,13 +3763,13 @@ var si = class {
3703
3763
  !a && !p() && h();
3704
3764
  }, e);
3705
3765
  };
3706
- _(Yr), this.armingSub = D({
3766
+ _(ti), this.armingSub = D({
3707
3767
  eventsBaseUrl: t,
3708
3768
  matchUrn: this.opts.matchUrn,
3709
3769
  credential: this.opts.credential,
3710
- onAlive: () => _(Xr),
3770
+ onAlive: () => _(ni),
3711
3771
  onState: (e) => {
3712
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Zr);
3772
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * ri);
3713
3773
  },
3714
3774
  onError: () => h()
3715
3775
  });
@@ -3754,19 +3814,19 @@ var si = class {
3754
3814
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
3755
3815
  let i = e.analytics?.sid;
3756
3816
  if (!i) return;
3757
- let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = Sr(this.opts.baseUrl, a, e.analytics?.endpoint);
3817
+ let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = Er(this.opts.baseUrl, a, e.analytics?.endpoint);
3758
3818
  if (!o) {
3759
3819
  s && setTimeout(() => {
3760
3820
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
3761
3821
  }, 0);
3762
3822
  return;
3763
3823
  }
3764
- let c = this.opts.video, l = new Cr({
3824
+ let c = this.opts.video, l = new Dr({
3765
3825
  endpoint: o,
3766
3826
  sid: i,
3767
3827
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
3768
- sdkVersion: kr,
3769
- environment: Dr(c),
3828
+ sdkVersion: Nr,
3829
+ environment: jr(c),
3770
3830
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
3771
3831
  onIdle: () => this.onAnalyticsIdle(t),
3772
3832
  onBlocked: (e) => setTimeout(() => {
@@ -3787,7 +3847,7 @@ var si = class {
3787
3847
  let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
3788
3848
  c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
3789
3849
  c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
3790
- }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), Or().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3850
+ }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), Mr().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3791
3851
  }
3792
3852
  currentPresentation() {
3793
3853
  let e = this.opts.video;
@@ -3811,6 +3871,7 @@ var si = class {
3811
3871
  adaptiveHoldBack: this.opts.adaptiveHoldBack,
3812
3872
  adaptiveHoldBackCeiling: this.opts.adaptiveHoldBackCeiling,
3813
3873
  stallCap: this.opts.stallCap,
3874
+ stuckReload: this.opts.stuckReload,
3814
3875
  mediaDuringKey: this.opts.mediaDuringKey,
3815
3876
  preloadHints: this.opts.preloadHints,
3816
3877
  debug: this.opts.debug,
@@ -3820,9 +3881,9 @@ var si = class {
3820
3881
  freshLicenseUrl: () => this.refreshLicense()
3821
3882
  }, o = this.opts.engine ?? "auto";
3822
3883
  if (o === "native") return new H(a);
3823
- if (o === "hls") return new nr(a);
3824
- if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && B(this.opts.video) && V() || !e.drmEnabled && At() && B(this.opts.video)) return new H(a);
3825
- if (Kt()) return new nr(a);
3884
+ if (o === "hls") return new or(a);
3885
+ if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && B(this.opts.video) && V() || !e.drmEnabled && Pt() && B(this.opts.video)) return new H(a);
3886
+ if (Xt()) return new or(a);
3826
3887
  if (B(this.opts.video)) return new H(a);
3827
3888
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
3828
3889
  }
@@ -3856,6 +3917,7 @@ var si = class {
3856
3917
  this.emit("texttrackchange", e.id);
3857
3918
  break;
3858
3919
  case "ended":
3920
+ if (e.reason === "stalled" && this.reloadStaleEnd()) break;
3859
3921
  this.onStreamEnded();
3860
3922
  break;
3861
3923
  case "error": {
@@ -3875,17 +3937,17 @@ var si = class {
3875
3937
  if (this.opts.liveStateEvents === !1) return;
3876
3938
  let t = this.opts.eventsBaseUrl ?? O(this.opts.baseUrl);
3877
3939
  if (!t) return;
3878
- this.closeLiveState();
3940
+ this.closeLiveState(), this.liveStateLast = null, this.liveStateAliveAt = 0;
3879
3941
  let i = 0, a = !1;
3880
3942
  this.liveStateSub = D({
3881
3943
  eventsBaseUrl: t,
3882
3944
  matchUrn: this.opts.matchUrn,
3883
3945
  credential: this.opts.credential,
3884
3946
  onState: (t) => {
3885
- this.destroyed || e !== this.loadGen || (t.state === "gone" ? this.onStreamEnded(!0, t.reason ?? "match_ended") : t.state === "ended" ? this.onStreamEnded(!1, t.reason) : t.state === "live" && this.endedHandled && this.scheduleRejoin(e));
3947
+ this.destroyed || e !== this.loadGen || (this.liveStateLast = t.state, this.liveStateAliveAt = Date.now(), t.state === "gone" ? this.onStreamEnded(!0, t.reason ?? "match_ended") : t.state === "ended" ? this.onStreamEnded(!1, t.reason) : t.state === "live" && this.endedHandled && this.scheduleRejoin(e));
3886
3948
  },
3887
3949
  onAlive: () => {
3888
- i = 0, a = !1;
3950
+ i = 0, a = !1, !this.destroyed && e === this.loadGen && (this.liveStateAliveAt = Date.now());
3889
3951
  },
3890
3952
  onError: (o) => {
3891
3953
  if (!(this.destroyed || e !== this.loadGen || a) && !this.endedHandled) {
@@ -3893,7 +3955,7 @@ var si = class {
3893
3955
  a = !0, this.emit("warning", new n(r(o.status), o.status, `live-state events answered HTTP ${o.status} for ${this.opts.matchUrn}: the match is ` + (o.terminal ? "gone, so the subscription stopped" : "not in the catalog (ended and dropped, or not listed yet), so it retries every 5 min") + " — end-of-stream detection falls back to the HLS staleness watchdog."));
3894
3956
  return;
3895
3957
  }
3896
- i += 1, i >= Qr && (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.`)));
3958
+ i += 1, i >= ii && (a = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${i} attempts — end-of-stream detection degraded to the HLS staleness watchdog. Check the events host, the api-key's allowed origins, and CSP connect-src.`)));
3897
3959
  }
3898
3960
  }
3899
3961
  });
@@ -3901,6 +3963,18 @@ var si = class {
3901
3963
  closeLiveState() {
3902
3964
  this.liveStateSub?.close(), this.liveStateSub = null;
3903
3965
  }
3966
+ reloadStaleEnd() {
3967
+ if (this.destroyed || this.endedHandled || this._state === "error" || this._state === "ended") return !1;
3968
+ let e = Date.now();
3969
+ if (this.liveStateLast !== "live" || e - this.liveStateAliveAt > ai || (e - this.staleEndWindowAt > si && (this.staleEndReloads = 0, this.staleEndWindowAt = e), this.staleEndReloads >= oi)) return !1;
3970
+ this.staleEndReloads += 1;
3971
+ let t = new n("UNAVAILABLE", 0, `live playlist stopped advancing for 12 s while the match is live (live-state push heard ${Math.round((e - this.liveStateAliveAt) / 1e3)} s ago): reloading instead of ending (${this.staleEndReloads} of ${oi} this window)`);
3972
+ this.analyticsSession?.noteError(t.code, t.message, !1, 0, Math.round(this.opts.video.currentTime * 1e3), "staleEndReload");
3973
+ let r = this.loadGen;
3974
+ return this.emit("warning", t), Promise.resolve().then(() => {
3975
+ if (!(this.destroyed || r !== this.loadGen) && this._state !== "error" && this._state !== "ended") return this.reload().catch(() => void 0);
3976
+ }), !0;
3977
+ }
3904
3978
  watchConnectivity() {
3905
3979
  this.connectivity || (this.connectivity = ut(), this.connectivity.onChange((e) => {
3906
3980
  if (this.destroyed) return;
@@ -3910,7 +3984,7 @@ var si = class {
3910
3984
  }
3911
3985
  if (this.emit("online"), this._state !== "error" || !this._lastError) return;
3912
3986
  let t = this._lastError.code;
3913
- ii(t) && (t === "NETWORK" || this.failedWhileOffline) && this.retry().catch(() => void 0);
3987
+ pi(t) && (t === "NETWORK" || this.failedWhileOffline) && this.retry().catch(() => void 0);
3914
3988
  }));
3915
3989
  }
3916
3990
  watchReturn() {
@@ -3920,7 +3994,7 @@ var si = class {
3920
3994
  return;
3921
3995
  }
3922
3996
  let e = this.hiddenAtMs;
3923
- this.hiddenAtMs = null, e != null && Date.now() - e >= $r && this.resyncLiveState();
3997
+ this.hiddenAtMs = null, e != null && Date.now() - e >= ci && this.resyncLiveState();
3924
3998
  }, this.onReturnPageShow = (e) => {
3925
3999
  e.persisted && this.resyncLiveState();
3926
4000
  }, document.addEventListener("visibilitychange", this.onReturnVisible), typeof window < "u" && window.addEventListener("pageshow", this.onReturnPageShow));
@@ -3952,7 +4026,7 @@ var si = class {
3952
4026
  scheduleRejoin(e) {
3953
4027
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
3954
4028
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
3955
- }, Math.random() * Zr));
4029
+ }, Math.random() * ri));
3956
4030
  }
3957
4031
  cancelRejoin() {
3958
4032
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -3976,7 +4050,7 @@ var si = class {
3976
4050
  }
3977
4051
  t.controls = !1;
3978
4052
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
3979
- r && r.insertBefore(n, t), n.appendChild(t), Mr(n, this.opts.theme), this.container = n, this.controlBar = Ur({
4053
+ r && r.insertBefore(n, t), n.appendChild(t), Ir(n, this.opts.theme), this.container = n, this.controlBar = Yr({
3980
4054
  root: n,
3981
4055
  video: t,
3982
4056
  player: this,
@@ -4015,7 +4089,7 @@ var si = class {
4015
4089
  }
4016
4090
  startStats() {
4017
4091
  this.stopStats();
4018
- let e = Math.max(500, this.opts.statsIntervalMs ?? ei);
4092
+ let e = Math.max(500, this.opts.statsIntervalMs ?? li);
4019
4093
  this.statsTimer = setInterval(() => {
4020
4094
  if (!this.engine) return;
4021
4095
  let e = this.engine.getStats();
@@ -4026,14 +4100,14 @@ var si = class {
4026
4100
  this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
4027
4101
  }
4028
4102
  isStaleLicenseDenial(e) {
4029
- return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== ni || e.error.httpStatus !== 403 || e.error.code !== "FORBIDDEN" || e.error.serverCode === "license_refused" ? !1 : W(this._descriptor?.drm?.widevine?.licenseUrl);
4103
+ return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== di || e.error.httpStatus !== 403 || e.error.code !== "FORBIDDEN" || e.error.serverCode === "license_refused" ? !1 : W(this._descriptor?.drm?.widevine?.licenseUrl);
4030
4104
  }
4031
4105
  scheduleLicenseRefresh() {
4032
4106
  if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
4033
4107
  typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
4034
4108
  document.visibilityState !== "visible" || this.destroyed || W(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
4035
4109
  }, document.addEventListener("visibilitychange", this.onRefocus));
4036
- let e = this.opts.licenseRefreshMs ?? ti;
4110
+ let e = this.opts.licenseRefreshMs ?? ui;
4037
4111
  e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
4038
4112
  }
4039
4113
  stopRefresh() {
@@ -4203,7 +4277,7 @@ function $(e) {
4203
4277
  }
4204
4278
  //#endregion
4205
4279
  //#region src/embed/host.ts
4206
- function ci(e) {
4280
+ function _i(e) {
4207
4281
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
4208
4282
  if (!e.src) throw Error("mountEmbed: opts.src is required");
4209
4283
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -4262,15 +4336,15 @@ function ci(e) {
4262
4336
  }
4263
4337
  //#endregion
4264
4338
  //#region src/embed/page.ts
4265
- var li = /^[A-Za-z0-9:_.-]{1,128}$/;
4266
- function ui(e) {
4339
+ var vi = /^[A-Za-z0-9:_.-]{1,128}$/;
4340
+ function yi(e) {
4267
4341
  if (typeof e == "boolean") return e;
4268
4342
  if (typeof e == "object" && e) {
4269
4343
  let t = e.endpoint;
4270
4344
  return typeof t == "string" ? { endpoint: t } : {};
4271
4345
  }
4272
4346
  }
4273
- function di() {
4347
+ function bi() {
4274
4348
  let e = window.HAVIK_EMBED_CONFIG;
4275
4349
  if (e) return {
4276
4350
  baseUrl: e.baseUrl ?? "",
@@ -4280,7 +4354,7 @@ function di() {
4280
4354
  autoplay: e.autoplay ?? !0,
4281
4355
  muted: e.muted ?? !0,
4282
4356
  waitForLive: e.waitForLive ?? !0,
4283
- analytics: ui(e.analytics)
4357
+ analytics: yi(e.analytics)
4284
4358
  };
4285
4359
  let t = new URLSearchParams(location.search);
4286
4360
  return {
@@ -4293,9 +4367,9 @@ function di() {
4293
4367
  waitForLive: !0
4294
4368
  };
4295
4369
  }
4296
- async function fi() {
4297
- let e = di();
4298
- mi();
4370
+ async function xi() {
4371
+ let e = bi();
4372
+ Ci();
4299
4373
  let t = document.createElement("video");
4300
4374
  t.setAttribute("playsinline", ""), t.muted = e.muted ?? !0, t.style.cssText = "width:100%;height:100%;object-fit:contain;background:#000;aspect-ratio:auto", document.body.appendChild(t);
4301
4375
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -4351,12 +4425,12 @@ async function fi() {
4351
4425
  message: e.message,
4352
4426
  ...e.country === void 0 ? {} : { country: e.country }
4353
4427
  })), e.on("autoplayblocked", () => {
4354
- i({ type: "oddin:autoplayblocked" }), pi(t, e);
4428
+ i({ type: "oddin:autoplayblocked" }), Si(t, e);
4355
4429
  });
4356
4430
  }, s = async (r) => {
4357
4431
  a?.destroy(), a = null;
4358
4432
  try {
4359
- let n = await oi({
4433
+ let n = await hi({
4360
4434
  video: t,
4361
4435
  baseUrl: e.baseUrl,
4362
4436
  matchUrn: r,
@@ -4419,7 +4493,7 @@ async function fi() {
4419
4493
  a?.retry();
4420
4494
  break;
4421
4495
  case "oddin:load":
4422
- typeof e.matchUrn == "string" && li.test(e.matchUrn) && s(e.matchUrn);
4496
+ typeof e.matchUrn == "string" && vi.test(e.matchUrn) && s(e.matchUrn);
4423
4497
  break;
4424
4498
  case "oddin:destroy": c();
4425
4499
  }
@@ -4431,18 +4505,18 @@ async function fi() {
4431
4505
  protocol: 1
4432
4506
  });
4433
4507
  }
4434
- function pi(e, t) {
4508
+ function Si(e, t) {
4435
4509
  if (document.getElementById("havik-tap")) return;
4436
4510
  let n = document.createElement("button");
4437
4511
  n.id = "havik-tap", n.textContent = "▶ Tap to play", n.style.cssText = "position:fixed;inset:0;width:100%;height:100%;border:0;background:rgba(0,0,0,.55);color:#fff;font:600 18px system-ui,sans-serif;cursor:pointer;z-index:9", n.addEventListener("click", () => {
4438
4512
  n.remove(), t.play();
4439
4513
  }), document.body.appendChild(n);
4440
4514
  }
4441
- function mi() {
4515
+ function Ci() {
4442
4516
  let e = document.createElement("style");
4443
4517
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
4444
4518
  }
4445
4519
  //#endregion
4446
- export { E as LiveStateHttpError, Ar as ODDIN_THEME, n as PlaybackError, Mr as applyTheme, lt as baseUrlForEnv, fi as bootEmbed, ke as clearDeviceId, He as clearRememberedBandwidth, oi 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, ci as mountEmbed, fe as pollToLive, y as resolveStream, D as subscribeLiveState, S as videoFullscreenActive, we as watchStatus };
4520
+ export { E as LiveStateHttpError, Pr as ODDIN_THEME, n as PlaybackError, Ir as applyTheme, lt as baseUrlForEnv, xi as bootEmbed, ke as clearDeviceId, He as clearRememberedBandwidth, hi as createPlayer, O as deriveEventsBaseUrl, at as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, ve as fetchCatalog, be as fetchTournament, Se as flattenMatches, C as fullscreenSupported, Oe as getDeviceId, st as isLowLatencyManifest, $ as isOddinMessage, je as licenseRequestHeaders, _i as mountEmbed, fe as pollToLive, y as resolveStream, D as subscribeLiveState, S as videoFullscreenActive, we as watchStatus };
4447
4521
 
4448
4522
  //# sourceMappingURL=index.js.map