@oddin-gg/havik-player 2.28.0 → 2.28.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1627,12 +1627,12 @@ function K(e, t) {
1627
1627
  function Xt() {
1628
1628
  return e.isSupported();
1629
1629
  }
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) {
1630
+ var Zt = 3, Qt = 1e6, $t = 20, en = 1e4, tn = 3, nn = 2, rn = 5, an = 3, on = 1e4, sn = 3e4, cn = 12e3, ln = 3e3, un = .02, dn = 6e3, fn = .5, pn = 3, mn = .5, hn = 1.1, gn = .25, _n = 5e3, vn = 4e3, yn = 2, bn = 5, xn = 2, Sn = 2, Cn = 4, wn = 4, Tn = 2e3, En = 3e4, Dn = 1, On = 2, kn = .5, An = .6, jn = 2, Mn = 1.5, Nn = 1e4, Pn = 18e4, Fn = .5, In = 2;
1631
+ function Ln(e) {
1632
1632
  let t = e.config ?? {};
1633
1633
  return t.capLevelToPlayerSize === !0 || t.capLevelOnFPSDrop === !0;
1634
1634
  }
1635
- var q = 8, Ln = 12e4, Rn = 6e4;
1635
+ var q = 8, Rn = 12e4, zn = 6e4;
1636
1636
  function J(e, t, n) {
1637
1637
  if (n <= 0 || t < 0 || t >= e.length) return t;
1638
1638
  let r = (t, n) => e[t].width === e[n].width && e[t].height === e[n].height, i = (t) => {
@@ -1645,11 +1645,11 @@ function J(e, t, n) {
1645
1645
  function Y() {
1646
1646
  return typeof self < "u" && self.devicePixelRatio > 0 ? self.devicePixelRatio : 1;
1647
1647
  }
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) {
1648
+ var Bn = .2, Vn = 30, Hn = 2, Un = 2, Wn = 2, Gn = 9, Kn = .5, qn = 64, Jn = 1e4, Yn = 8, Xn = .6, Zn = .4, Qn = .4, $n = 2, er = 6e4, X = .5, tr = 3.5, nr = 300;
1649
+ function rr(e) {
1650
1650
  return (e?.part ?? e?.frag)?.stats;
1651
1651
  }
1652
- function rr() {
1652
+ function ir() {
1653
1653
  if (typeof navigator > "u") return 0;
1654
1654
  try {
1655
1655
  let e = navigator.connection?.rtt;
@@ -1658,20 +1658,20 @@ function rr() {
1658
1658
  return 0;
1659
1659
  }
1660
1660
  }
1661
- function ir(e) {
1661
+ function ar(e) {
1662
1662
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
1663
1663
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
1664
1664
  return;
1665
1665
  }
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);
1666
+ e.liveSyncDuration ??= Wn;
1667
+ let t = Math.max(12, e.liveSyncDuration + Gn);
1668
+ (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), or(e, e.liveSyncDuration);
1669
1669
  }
1670
- function ar(e, t) {
1670
+ function or(e, t) {
1671
1671
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
1672
1672
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
1673
1673
  }
1674
- var or = class {
1674
+ var sr = class {
1675
1675
  name = "hls";
1676
1676
  hls = null;
1677
1677
  deps;
@@ -1696,6 +1696,7 @@ var or = class {
1696
1696
  ladderHeights;
1697
1697
  ladderTopBitrateKbps = 0;
1698
1698
  mediaRecoveries = 0;
1699
+ holeKicks = 0;
1699
1700
  networkRecoveries = 0;
1700
1701
  licenseRecoveries = 0;
1701
1702
  recoveryResetTimer = null;
@@ -1824,7 +1825,7 @@ var or = class {
1824
1825
  }
1825
1826
  this.loadSuspended = !0;
1826
1827
  }
1827
- }, gn));
1828
+ }, _n));
1828
1829
  }
1829
1830
  resumeLoading() {
1830
1831
  if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
@@ -1856,7 +1857,7 @@ var or = class {
1856
1857
  let t = e.liveSyncPosition;
1857
1858
  if (typeof t != "number" || !Number.isFinite(t)) return;
1858
1859
  let { video: n } = this.deps;
1859
- n.currentTime <= t + Gn || (n.currentTime = t);
1860
+ n.currentTime <= t + Kn || (n.currentTime = t);
1860
1861
  }
1861
1862
  reanchorPartTimeline(e, t) {
1862
1863
  let { frag: n, part: r } = t;
@@ -1868,7 +1869,7 @@ var or = class {
1868
1869
  let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
1869
1870
  if (!s) return;
1870
1871
  let c = a.startPTS - s.start;
1871
- if (!(!Number.isFinite(c) || Math.abs(c) < ln)) {
1872
+ if (!(!Number.isFinite(c) || Math.abs(c) < un)) {
1872
1873
  for (let e of i.fragments) e && e.setStart(e.start + c);
1873
1874
  i.fragmentHint?.setStart(i.fragmentHint.start + c), this.deps.debug === !0 && console.info(`havik-player: LL-HLS timeline re-anchored by ${c >= 0 ? "+" : ""}${c.toFixed(3)}s at sn ${n.sn} (level ${n.level})`);
1874
1875
  }
@@ -1908,7 +1909,7 @@ var or = class {
1908
1909
  return;
1909
1910
  }
1910
1911
  let l = this.hls, u, d = new Promise((e) => {
1911
- u = setTimeout(() => e(void 0), an);
1912
+ u = setTimeout(() => e(void 0), on);
1912
1913
  });
1913
1914
  return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
1914
1915
  if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
@@ -1932,22 +1933,22 @@ var or = class {
1932
1933
  }), t = Gt(e, f.loader);
1933
1934
  t && (this.prefetch = e, p = h, m = g, f.fLoader = t);
1934
1935
  }
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;
1936
+ ar(f), this.catchUpRate = typeof f.maxLiveSyncPlaybackRate == "number" ? f.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (f.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = f.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = f.autoStartLoad !== !1;
1936
1937
  let _ = new e(f);
1937
1938
  if (this.hls = _, this.armHoldBack(_, f), _.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(_, t)), _.on(e.Events.MANIFEST_PARSED, () => {
1938
1939
  this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(_), this.measureLadder(_), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
1939
1940
  }), _.on(e.Events.FRAG_BUFFERED, (e, t) => {
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(() => {
1941
- this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
1942
- }, on)));
1941
+ t?.frag?.type === "main" && (this.kickKind !== "dead" && this.clearKick(), (this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0 || this.starvationKicks > 0 || this.starvationRebuilds > 0 || this.holeKicks > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
1942
+ this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.holeKicks = 0, this.recoveryResetTimer = null;
1943
+ }, sn)));
1943
1944
  }), _.on(e.Events.FRAG_LOADING, (e, t) => {
1944
1945
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
1945
1946
  }), _.on(e.Events.FRAG_LOADED, (e, t) => {
1946
1947
  t?.frag?.type === "main" && (this.mainFragsSinceTick += 1, this.bwFragsLoaded += 1, this.maybeRememberBandwidth(!1));
1947
- let n = t?.frag, r = nr(t), i = r?.loaded;
1948
+ let n = t?.frag, r = rr(t), i = r?.loaded;
1948
1949
  typeof i == "number" && (this.bytesLoaded += i), !this.reportedFirstBytes && typeof i == "number" && i > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
1949
1950
  let a = r?.loading;
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);
1951
+ a && a.end > 0 && a.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(a.end - a.start))), this.requestTimesMs.length > qn && this.requestTimesMs.shift()), this.sampleHoldBack(t), this.sampleHeadroom(t);
1951
1952
  let o = n?.url;
1952
1953
  if (o) {
1953
1954
  let e = ft(o);
@@ -1988,7 +1989,7 @@ var or = class {
1988
1989
  u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
1989
1990
  }), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1990
1991
  this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.adaptHoldBack(), this.reviewSizeCapHeadroom(), this.releaseStallCap(), this.checkFrameDrops();
1991
- }, cn), _.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1992
+ }, ln), _.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1992
1993
  this.renditionSwitches += 1;
1993
1994
  let n = this.lastLevelIndex >= 0 ? _.levels[this.lastLevelIndex] : void 0, r = _.levels[t.level];
1994
1995
  n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, this.armFrameDropGrace(), l({
@@ -2049,8 +2050,8 @@ var or = class {
2049
2050
  let e = this.hls, t = this.sizeCapCover();
2050
2051
  if (!e || !t) return null;
2051
2052
  let { cover: n, deviceRatio: r } = t, i = this.deps.sizeCapHeadroom, a = i == null || Number.isNaN(i);
2052
- if (a && r >= Dn) return n;
2053
- if (a) return this.headroomUngated || this.headroomGranted ? J(e.levels, n, En) : n;
2053
+ if (a && r >= On) return n;
2054
+ if (a) return this.headroomUngated || this.headroomGranted ? J(e.levels, n, Dn) : n;
2054
2055
  let o = i === Infinity ? e.levels.length : Math.max(0, Math.floor(i));
2055
2056
  return J(e.levels, n, o);
2056
2057
  }
@@ -2067,11 +2068,11 @@ var or = class {
2067
2068
  return;
2068
2069
  }
2069
2070
  this.capTimer && clearTimeout(this.capTimer);
2070
- let t = e > this.sizeCapLevel ? wn : Tn;
2071
+ let t = e > this.sizeCapLevel ? Tn : En;
2071
2072
  this.capTimer = setTimeout(() => {
2072
2073
  this.capTimer = null;
2073
2074
  let n = this.computeSizeCapTarget();
2074
- n === e || t === Tn && n != null && n < e ? this.applySizeCap() : this.onMediaResize();
2075
+ n === e || t === En && n != null && n < e ? this.applySizeCap() : this.onMediaResize();
2075
2076
  }, t);
2076
2077
  }
2077
2078
  measureLadder(e) {
@@ -2098,7 +2099,7 @@ var or = class {
2098
2099
  }
2099
2100
  defaultHeadroomApplies() {
2100
2101
  let e = this.deps.sizeCapHeadroom;
2101
- return e != null && !Number.isNaN(e) || this.headroomUngated ? !1 : Y() < Dn;
2102
+ return e != null && !Number.isNaN(e) || this.headroomUngated ? !1 : Y() < On;
2102
2103
  }
2103
2104
  applySizeCapUnlessPending() {
2104
2105
  this.capTimer || this.applySizeCap();
@@ -2107,7 +2108,7 @@ var or = class {
2107
2108
  if (!this.sizeCapManaged || !this.defaultHeadroomApplies() || e.frag?.type !== "main" || typeof e.frag.level != "number" || typeof document < "u" && document.hidden) return;
2108
2109
  let t = e.part ? e.part.duration : this.detectedLowLatency ? 0 : e.frag.duration;
2109
2110
  if (typeof t != "number" || !(t > 0)) return;
2110
- let n = nr(e)?.loading;
2111
+ let n = rr(e)?.loading;
2111
2112
  if (!n || !(n.start > 0) || !(n.end >= n.start)) return;
2112
2113
  let r = this.hls?.levels?.[e.frag.level]?.bitrate;
2113
2114
  if (!(typeof r == "number" && r > 0)) return;
@@ -2120,7 +2121,7 @@ var or = class {
2120
2121
  }
2121
2122
  onPlaybackStall(e) {
2122
2123
  let t = Date.now();
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()));
2124
+ this.deps.video.seeking || !this.playingSince || t - this.playingSince < Nn || (this.lastStallAt = t, this.stepStallCapDown(t, e), this.headroomGranted && (this.headroomGranted = !1, this.applySizeCapUnlessPending()));
2124
2125
  }
2125
2126
  stallCapLevel(e) {
2126
2127
  if (this.stallCapBitrate == null) return -1;
@@ -2131,7 +2132,7 @@ var or = class {
2131
2132
  }
2132
2133
  stepStallCapDown(e, t) {
2133
2134
  let n = this.hls;
2134
- if (!n || !this.stallCapEnabled || In(n) || !n.autoLevelEnabled || typeof t == "number" && t >= Pn || this.isLiveEdgeWait(n, t ?? 0)) return;
2135
+ if (!n || !this.stallCapEnabled || Ln(n) || !n.autoLevelEnabled || typeof t == "number" && t >= Fn || this.isLiveEdgeWait(n, t ?? 0)) return;
2135
2136
  this.stallCapBitrate != null && (this.stallCapSince = e);
2136
2137
  let r = Math.max(n.levels[n.currentLevel]?.bitrate ?? 0, n.levels[n.loadLevel]?.bitrate ?? 0);
2137
2138
  if (!(r > 0)) return;
@@ -2142,7 +2143,7 @@ var or = class {
2142
2143
  let n = e.latestLevelDetails;
2143
2144
  if (!n?.live) return !1;
2144
2145
  let r = n.partTarget || n.targetduration;
2145
- return !(r > 0) || !(n.edge > 0) ? !1 : n.edge - (this.deps.video.currentTime + t) < Fn * r;
2146
+ return !(r > 0) || !(n.edge > 0) ? !1 : n.edge - (this.deps.video.currentTime + t) < In * r;
2146
2147
  }
2147
2148
  releaseStallCap() {
2148
2149
  let e = this.hls, t = Date.now(), n = this.stallCapTickAt;
@@ -2151,7 +2152,7 @@ var or = class {
2151
2152
  n && (this.stallCapSince += t - Math.max(n, this.stallCapSince));
2152
2153
  return;
2153
2154
  }
2154
- if (t - this.stallCapSince < Nn) return;
2155
+ if (t - this.stallCapSince < Pn) return;
2155
2156
  let r = this.stallCapBitrate, i = e.levels.map((e) => e.bitrate).filter((e) => e > r).sort((e, t) => e - t)[0];
2156
2157
  this.stallCapBitrate = i ?? null, this.stallCapSince = t, this.pushCap();
2157
2158
  }
@@ -2164,26 +2165,26 @@ var or = class {
2164
2165
  this.headroomGranted = !1, this.headroomSamples = [];
2165
2166
  return;
2166
2167
  }
2167
- this.headroomSamples = this.headroomSamples.filter((t) => t.t >= e - qn);
2168
+ this.headroomSamples = this.headroomSamples.filter((t) => t.t >= e - Jn);
2168
2169
  let r = this.headroomEarned(n, e);
2169
- r !== this.headroomGranted && (r || (this.headroomRegrantAt = e + Rn), this.headroomGranted = r, this.applySizeCapUnlessPending());
2170
+ r !== this.headroomGranted && (r || (this.headroomRegrantAt = e + zn), this.headroomGranted = r, this.applySizeCapUnlessPending());
2170
2171
  }
2171
2172
  headroomEarned(e, t) {
2172
- if (t - this.lastStallAt < Ln || !this.headroomGranted && t < this.headroomRegrantAt || !this.headroomGranted && this.headroomSamples.length < q) return !1;
2173
+ if (t - this.lastStallAt < Rn || !this.headroomGranted && t < this.headroomRegrantAt || !this.headroomGranted && this.headroomSamples.length < q) return !1;
2173
2174
  let n = e.levels, r = this.sizeCapCoverLevel();
2174
2175
  if (r == null) return this.headroomGranted;
2175
- let i = J(n, r, En);
2176
+ let i = J(n, r, Dn);
2176
2177
  if (i === r) return this.headroomGranted;
2177
- let a = n[i]?.bitrate, o = e.bandwidthEstimate, s = this.headroomGranted ? jn : An;
2178
+ let a = n[i]?.bitrate, o = e.bandwidthEstimate, s = this.headroomGranted ? Mn : jn;
2178
2179
  if (!(a > 0) || !(o >= s * a)) return !1;
2179
2180
  let c = (e) => K([...e].sort((e, t) => e - t), 90);
2180
2181
  if (this.headroomGranted) {
2181
2182
  let e = this.headroomSamples.filter((e) => e.bitrate >= a).map((e) => e.ratio);
2182
- return e.length < q || c(e) <= kn;
2183
+ return e.length < q || c(e) <= An;
2183
2184
  }
2184
2185
  let l = [];
2185
2186
  for (let e of this.headroomSamples) e.bitrate < a && l.push(e.ratio * (a / e.bitrate));
2186
- return l.length >= q && c(l) <= On;
2187
+ return l.length >= q && c(l) <= kn;
2187
2188
  }
2188
2189
  applySizeCap() {
2189
2190
  if (!this.sizeCapManaged) return;
@@ -2258,7 +2259,7 @@ var or = class {
2258
2259
  let t = e.currentLevel >= 0 ? e.levels[e.currentLevel] : void 0;
2259
2260
  t && (n.levelHeight = t.height);
2260
2261
  let r = e.autoLevelCapping, i = r >= 0 ? e.levels[r] : void 0;
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));
2262
+ i && i.height > 0 && (n.maxLevelHeight = i.height, !Ln(e) && r === this.pushedCapLevel && this.pushedCapReason && (n.capReason = this.pushedCapReason)), t?.videoCodec && (n.videoCodec = t.videoCodec), t?.audioCodec && (n.audioCodec = t.audioCodec), t && typeof t.bitrate == "number" && (n.renditionBitrateKbps = Math.round(t.bitrate / 1e3)), typeof t?.details?.live == "boolean" && (n.isLive = t.details.live, typeof e.liveSyncPosition == "number" && (n.atLiveEdge = this.deps.video.currentTime >= e.liveSyncPosition - 1.5));
2262
2263
  }
2263
2264
  return n;
2264
2265
  }
@@ -2286,7 +2287,7 @@ var or = class {
2286
2287
  return;
2287
2288
  }
2288
2289
  let e = Date.now() - this.lastAdvanceMs;
2289
- !this.chaseSuspended && e > un && this.suspendChasing(), e > sn && this.emitEnded("stalled");
2290
+ !this.chaseSuspended && e > dn && this.suspendChasing(), e > cn && this.emitEnded("stalled");
2290
2291
  }
2291
2292
  resetStarvationWindow() {
2292
2293
  this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
@@ -2301,7 +2302,7 @@ var or = class {
2301
2302
  this.resetStarvationWindow();
2302
2303
  return;
2303
2304
  }
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;
2305
+ let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < dn, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > vn, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = R(t), c = o - s, l = c !== this.starvedFrames;
2305
2306
  if (this.starvedFrames = c, !a || l) {
2306
2307
  (t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
2307
2308
  return;
@@ -2310,12 +2311,12 @@ var or = class {
2310
2311
  this.resetStarvationWindow();
2311
2312
  return;
2312
2313
  }
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)) {
2314
+ if (this.kickPending && (this.kickKind === "dead" || i) && (this.kickTicks += 1), this.starvedTicks = i ? this.starvedTicks + 1 : 0, this.deadTicks += 1, this.recentMainFrags.push(this.mainFragsSinceTick), this.mainFragsSinceTick = 0, this.recentMainFrags.length > Cn && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= xn && (this.clearKick(), this.starvationRebuilds < Sn)) {
2314
2315
  this.starvationRebuilds += 1, this.resetStarvationWindow(), this.clearRecoveryReset(), console.warn("havik-player: restarting the load did not resume video (the wedge is in hls.js state that only a rebuild clears) — rebuilding the player"), this.rebuildInstance("starvation rebuild");
2315
2316
  return;
2316
2317
  }
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))) {
2318
+ let u = i && this.starvedTicks >= yn, d = !i && this.deadTicks >= Cn && this.recentMainFrags.reduce((e, t) => e + t, 0) >= wn;
2319
+ if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= bn))) {
2319
2320
  this.starvationKicks += 1, this.kickPending = !0, this.kickTicks = 0, this.kickKind = d ? "dead" : "quiet", this.clearRecoveryReset(), console.warn(d ? "havik-player: video starved while hls.js keeps loading media it never plays (dead pipeline at the live edge) — restarting the load" : "havik-player: video starved while the live playlist advances (wedged hls.js fragment pipeline) — restarting the load");
2320
2321
  try {
2321
2322
  e.stopLoad(), e.startLoad(-1);
@@ -2330,7 +2331,7 @@ var or = class {
2330
2331
  let t = e.latency, n = e.targetLatency;
2331
2332
  if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
2332
2333
  let r = t - n;
2333
- !this.catchUpEngaged && r > dn ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= dn && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
2334
+ !this.catchUpEngaged && r > fn ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= fn && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
2334
2335
  let i = this.catchUpEngaged ? this.catchUpRate : 1;
2335
2336
  e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
2336
2337
  }
@@ -2343,7 +2344,7 @@ var or = class {
2343
2344
  }), n < 0 ? 0 : n;
2344
2345
  }
2345
2346
  armFrameDropGrace() {
2346
- this.fpsGraceTicks > 0 || (this.fpsGraceTicks = Hn, this.fpsBadTicks = 0);
2347
+ this.fpsGraceTicks > 0 || (this.fpsGraceTicks = Un, this.fpsBadTicks = 0);
2347
2348
  }
2348
2349
  resetFrameDropWindow() {
2349
2350
  this.fpsLastFrames = -1, this.fpsLastDropped = -1, this.fpsBadTicks = 0;
@@ -2355,7 +2356,7 @@ var or = class {
2355
2356
  return;
2356
2357
  }
2357
2358
  let { totalFrames: n, dropped: r } = R(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
2358
- if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Bn || o < 0) {
2359
+ if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Vn || o < 0) {
2359
2360
  this.fpsBadTicks = 0;
2360
2361
  return;
2361
2362
  }
@@ -2363,11 +2364,11 @@ var or = class {
2363
2364
  --this.fpsGraceTicks, this.fpsBadTicks = 0;
2364
2365
  return;
2365
2366
  }
2366
- if (o <= zn * a) {
2367
+ if (o <= Bn * a) {
2367
2368
  this.fpsBadTicks = 0;
2368
2369
  return;
2369
2370
  }
2370
- if (this.fpsBadTicks += 1, this.fpsBadTicks < Vn) return;
2371
+ if (this.fpsBadTicks += 1, this.fpsBadTicks < Hn) return;
2371
2372
  this.fpsBadTicks = 0;
2372
2373
  let s = e.levels, c = s[e.currentLevel];
2373
2374
  if (!c) return;
@@ -2384,22 +2385,22 @@ var or = class {
2384
2385
  return;
2385
2386
  }
2386
2387
  let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
2387
- if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(mn, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
2388
+ if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(hn, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
2388
2389
  this.resetChaseWindow();
2389
2390
  return;
2390
2391
  }
2391
- if (this.chaseLatency < 0 || this.chaseLatency - n >= pn) {
2392
+ if (this.chaseLatency < 0 || this.chaseLatency - n >= mn) {
2392
2393
  this.chaseLatency = n, this.chaseTicks = 0;
2393
2394
  return;
2394
2395
  }
2395
- if (this.chaseTicks += 1, this.chaseTicks < fn) return;
2396
+ if (this.chaseTicks += 1, this.chaseTicks < pn) return;
2396
2397
  this.resetChaseWindow();
2397
2398
  let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
2398
2399
  if (!(a > 1)) return;
2399
2400
  let o = e.targetLatency;
2400
2401
  if (typeof o != "number" || !(o > 0)) return;
2401
2402
  let s = Math.min(n, a - 1);
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({
2403
+ s < o + gn || (console.warn(`havik-player: catch-up at ${r}x not gaining on the live edge (latency ${n.toFixed(1)}s); holding at ${s.toFixed(1)}s`), this.liveRetargets += 1, e.targetLatency = s, this.deps.emit({
2403
2404
  type: "livetargetchange",
2404
2405
  change: {
2405
2406
  targetSeconds: s,
@@ -2416,13 +2417,13 @@ var or = class {
2416
2417
  if (!this.holdBackEnabled || this.holdBackPriorChecked || !e || (this.holdBackPriorChecked = !0, this.holdBackApplied > 0 || this.holdBackStepCount > 0)) return;
2417
2418
  let t = e.targetLatency;
2418
2419
  if (this.holdBackBase < 0 && typeof t == "number" && t > 0 && (this.holdBackBase = t), this.holdBackBase < 0) return;
2419
- let n = rr();
2420
- if (!(n >= tr)) return;
2420
+ let n = ir();
2421
+ if (!(n >= nr)) return;
2421
2422
  let r = typeof t == "number" && t > 0 ? t : this.holdBackBase, i = Math.min(this.holdBackCeiling(e), this.holdBackBase + X);
2422
2423
  i > r && (this.holdBackStepCount = 1, this.moveHoldBack(e, r, i, "connection-rtt", `connection rtt ${n} ms`));
2423
2424
  }
2424
2425
  holdBackCeiling(e) {
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;
2426
+ let t = this.deps.adaptiveHoldBackCeiling, n = typeof t == "number" && Number.isFinite(t) ? t : tr, r = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
2426
2427
  return r > 1 ? Math.min(n, r - 1) : n;
2427
2428
  }
2428
2429
  sampleHoldBack(e) {
@@ -2431,7 +2432,7 @@ var or = class {
2431
2432
  if (t !== "main" && t !== "audio") return;
2432
2433
  let n = e.part ? e.part.duration : this.detectedLowLatency ? 0 : e.frag?.duration;
2433
2434
  if (typeof n != "number" || !(n > 0)) return;
2434
- let r = nr(e)?.loading;
2435
+ let r = rr(e)?.loading;
2435
2436
  if (!r || !(r.start > 0) || !(r.end > 0)) return;
2436
2437
  let i = r.first > r.start ? r.first : r.end, a = Math.max(0, i - r.start) / (n * 1e3);
2437
2438
  this.holdBackSamples.push({
@@ -2446,20 +2447,20 @@ var or = class {
2446
2447
  this.holdBackSlowTicks = 0, this.holdBackFastSince = 0, this.holdBackSamples = [];
2447
2448
  return;
2448
2449
  }
2449
- let t = Date.now(), n = t - qn, r = this.holdBackSamples, i = 0;
2450
+ let t = Date.now(), n = t - Jn, r = this.holdBackSamples, i = 0;
2450
2451
  for (; i < r.length && r[i].t < n;) i += 1;
2451
2452
  i > 0 && r.splice(0, i);
2452
2453
  let a = e.targetLatency;
2453
2454
  if (typeof a != "number" || !(a > 0)) return;
2454
2455
  this.holdBackBase < 0 && (this.holdBackBase = a);
2455
2456
  let o = this.holdBackBase, s = this.holdBackCeiling(e);
2456
- if (r.length < Jn) {
2457
+ if (r.length < Yn) {
2457
2458
  this.holdBackSlowTicks = 0;
2458
2459
  return;
2459
2460
  }
2460
2461
  let c = r.map((e) => e.ratio).sort((e, t) => e - t), l = K(c, 95), u = K(c, 50), d = Math.round(l * 1e3);
2461
- if (l >= Yn && u >= Xn) {
2462
- if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks < Qn) return;
2462
+ if (l >= Xn && u >= Zn) {
2463
+ if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks < $n) return;
2463
2464
  this.holdBackSlowTicks = 0;
2464
2465
  let t = Math.ceil((s - o) / X), n = Math.ceil((a - o) / X - 1e-9);
2465
2466
  if (n > this.holdBackStepCount && (this.holdBackStepCount = n), this.holdBackStepCount >= t) return;
@@ -2469,7 +2470,7 @@ var or = class {
2469
2470
  this.moveHoldBack(e, a, r, "slow-fetches", `part fetches slow (first byte p50 ${Math.round(u * 1e3)} / p95 ${d} ms per 1 s of media)`);
2470
2471
  return;
2471
2472
  }
2472
- if (this.holdBackSlowTicks = 0, l >= Zn) {
2473
+ if (this.holdBackSlowTicks = 0, l >= Qn) {
2473
2474
  this.holdBackFastSince = 0;
2474
2475
  return;
2475
2476
  }
@@ -2477,7 +2478,7 @@ var or = class {
2477
2478
  this.holdBackFastSince = t;
2478
2479
  return;
2479
2480
  }
2480
- if (t - this.holdBackFastSince < $n || (this.holdBackFastSince = t, this.holdBackStepCount === 0 || a !== this.holdBackApplied)) return;
2481
+ if (t - this.holdBackFastSince < er || (this.holdBackFastSince = t, this.holdBackStepCount === 0 || a !== this.holdBackApplied)) return;
2481
2482
  --this.holdBackStepCount;
2482
2483
  let f = Math.max(o, o + this.holdBackStepCount * X);
2483
2484
  f >= a || this.moveHoldBack(e, a, f, "fast-fetches", `part fetches fast again (p95 first byte ${d} ms per 1 s of media)`);
@@ -2545,7 +2546,7 @@ var or = class {
2545
2546
  scheduleLicenseRetry(t) {
2546
2547
  if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
2547
2548
  let n = t.response?.code ?? 0;
2548
- if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= rn) return !1;
2549
+ if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= an) return !1;
2549
2550
  this.licenseRecoveries += 1;
2550
2551
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
2551
2552
  return this.licenseRetryTimer = setTimeout(() => {
@@ -2581,7 +2582,7 @@ var or = class {
2581
2582
  this.offlineHold = !0, this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null);
2582
2583
  return;
2583
2584
  }
2584
- if (this.networkRecoveries < nn) {
2585
+ if (this.networkRecoveries < rn) {
2585
2586
  this.networkRecoveries += 1;
2586
2587
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
2587
2588
  this.networkRetryTimer = setTimeout(() => {
@@ -2598,6 +2599,15 @@ var or = class {
2598
2599
  return;
2599
2600
  }
2600
2601
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
2602
+ if (t.details != null && (t.details === e.ErrorDetails.BUFFER_SEEK_OVER_HOLE || t.details === e.ErrorDetails.BUFFER_STALLED_ERROR) && this.sawLive && this.holeKicks < nn && this.mediaRecoveries < tn) {
2603
+ this.holeKicks += 1, this.mediaRecoveries += 1, console.warn("havik-player: playback stuck at a buffer hole hls.js could not nudge across — re-syncing to the live edge");
2604
+ try {
2605
+ n.stopLoad(), n.startLoad(-1);
2606
+ return;
2607
+ } catch (e) {
2608
+ console.warn("havik-player: live re-sync after a buffer hole failed", e);
2609
+ }
2610
+ }
2601
2611
  if (this.mediaRecoveries < tn) {
2602
2612
  this.mediaRecoveries += 1, n.recoverMediaError();
2603
2613
  return;
@@ -2625,15 +2635,15 @@ var or = class {
2625
2635
  ...l ? { serverCode: l } : {}
2626
2636
  });
2627
2637
  }
2628
- }, sr = 15e3, cr = 6e5, lr = 3e5, ur = 100, Z = 1, dr = 1e3, fr = 3e4, pr = 1e3, mr = {
2638
+ }, cr = 15e3, lr = 6e5, ur = 3e5, dr = 100, Z = 1, fr = 1e3, pr = 3e4, mr = 1e3, hr = {
2629
2639
  inline: "PRESENTATION_INLINE",
2630
2640
  fullscreen: "PRESENTATION_FULLSCREEN",
2631
2641
  pip: "PRESENTATION_PIP"
2632
- }, hr = {
2642
+ }, gr = {
2633
2643
  widevine: "KEY_SYSTEM_WIDEVINE",
2634
2644
  fairplay: "KEY_SYSTEM_FAIRPLAY",
2635
2645
  none: "KEY_SYSTEM_NONE"
2636
- }, gr = /* @__PURE__ */ new Set([
2646
+ }, _r = /* @__PURE__ */ new Set([
2637
2647
  "INVALID_URN",
2638
2648
  "NOT_FOUND",
2639
2649
  "GEO_DENIED",
@@ -2644,7 +2654,7 @@ var or = class {
2644
2654
  "FORBIDDEN",
2645
2655
  "RATE_LIMITED",
2646
2656
  "TIMEOUT"
2647
- ]), _r = {
2657
+ ]), vr = {
2648
2658
  idle: "PLAYER_STATE_IDLE",
2649
2659
  waiting: "PLAYER_STATE_WAITING",
2650
2660
  loading: "PLAYER_STATE_LOADING",
@@ -2654,7 +2664,7 @@ var or = class {
2654
2664
  ended: "PLAYER_STATE_ENDED",
2655
2665
  error: "PLAYER_STATE_ERROR"
2656
2666
  };
2657
- function vr(e) {
2667
+ function yr(e) {
2658
2668
  try {
2659
2669
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
2660
2670
  return !n || r.length === 0 || n !== "feed" && !n.startsWith("feed-") ? void 0 : (t.hostname = [n.replace(/^feed/, "beacons"), ...r].join("."), t.pathname = "", t.search = "", t.origin);
@@ -2662,8 +2672,8 @@ function vr(e) {
2662
2672
  return;
2663
2673
  }
2664
2674
  }
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) {
2675
+ var br = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), xr = /* @__PURE__ */ new Set(), Sr = /* @__PURE__ */ new Set(), Cr = /* @__PURE__ */ new Set(), wr = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2676
+ function Tr(e) {
2667
2677
  if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
2668
2678
  let t;
2669
2679
  try {
@@ -2672,19 +2682,19 @@ function wr(e) {
2672
2682
  } catch {
2673
2683
  return;
2674
2684
  }
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();
2685
+ if (xr.has(t) && !Sr.has(t)) {
2686
+ Sr.add(t), _(wr(new URL(t).origin));
2687
+ for (let e of Cr) e.noteCspBlocked();
2678
2688
  }
2679
2689
  }
2680
- function Tr(e, t) {
2690
+ function Er(e, t) {
2681
2691
  return _(t, e), { disabledReason: t };
2682
2692
  }
2683
- function Er(e, t, n) {
2684
- if (n) return t && !yr(t, n) && _(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2693
+ function Dr(e, t, n) {
2694
+ if (n) return t && !br(t, n) && _(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2685
2695
  if (t) return { endpoint: t };
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);
2696
+ if (t !== void 0) return Er("empty-endpoint", "analytics is disabled: no QoE beacons will be sent. analytics.endpoint was supplied but empty. Pass a real beacons origin, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, or omit the option to derive it from baseUrl (or analytics: false to opt out).");
2697
+ let r = yr(e);
2688
2698
  if (r) return { endpoint: r };
2689
2699
  let i;
2690
2700
  try {
@@ -2692,9 +2702,9 @@ function Er(e, t, n) {
2692
2702
  } catch {
2693
2703
  i = e;
2694
2704
  }
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).`);
2705
+ return Er(i, `analytics is disabled: no QoE beacons will be sent. The beacons endpoint cannot be derived from the baseUrl host "${i}" — the convention is feed[-dev].<domain> → beacons[-dev].<domain>. Pass an explicit endpoint, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, to createPlayer (or analytics: false to opt out deliberately).`);
2696
2706
  }
2697
- var Dr = class {
2707
+ var Or = class {
2698
2708
  opts;
2699
2709
  url;
2700
2710
  cspKey;
@@ -2776,8 +2786,8 @@ var Dr = class {
2776
2786
  constructor(e) {
2777
2787
  this.opts = {
2778
2788
  ...e,
2779
- heartbeatMs: e.heartbeatMs ?? sr,
2780
- idleMs: e.idleMs ?? cr
2789
+ heartbeatMs: e.heartbeatMs ?? cr,
2790
+ idleMs: e.idleMs ?? lr
2781
2791
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
2782
2792
  try {
2783
2793
  let e = new URL(this.url);
@@ -2794,11 +2804,11 @@ var Dr = class {
2794
2804
  sdkVersion: this.opts.sdkVersion,
2795
2805
  ...this.opts.environment
2796
2806
  };
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());
2807
+ this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), fr), this.lastTickMs = this.now(), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), document.addEventListener("freeze", this.onFreeze), document.addEventListener("resume", this.onResume), this.cspKey && xr.add(this.cspKey), document.addEventListener("securitypolicyviolation", Tr), Cr.add(this), this.noteCspBlocked(), this.onVisibility());
2798
2808
  }
2799
2809
  checkSuspension(e) {
2800
2810
  if (this.endedFlag || !this.opts.idleMs) return !1;
2801
- let t = Math.max(this.opts.idleMs, lr);
2811
+ let t = Math.max(this.opts.idleMs, ur);
2802
2812
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
2803
2813
  }
2804
2814
  syncIdle(e) {
@@ -2819,14 +2829,14 @@ var Dr = class {
2819
2829
  } else e === "buffering" && (this.isBuffering = !1, this.stallIsSeekInduced = !1);
2820
2830
  this.syncBuffering(), t === "paused" && (this.pauseCount += 1), this.syncIdle(t);
2821
2831
  let a = {
2822
- fromState: _r[e] ?? "PLAYER_STATE_UNSPECIFIED",
2823
- toState: _r[t] ?? "PLAYER_STATE_UNSPECIFIED",
2824
- presentation: mr[this.presentation]
2832
+ fromState: vr[e] ?? "PLAYER_STATE_UNSPECIFIED",
2833
+ toState: vr[t] ?? "PLAYER_STATE_UNSPECIFIED",
2834
+ presentation: hr[this.presentation]
2825
2835
  }, o = this.causeOf(e, t, i);
2826
2836
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
2827
2837
  }
2828
2838
  seekInduced(e) {
2829
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < pr;
2839
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < mr;
2830
2840
  }
2831
2841
  causeOf(e, t, n) {
2832
2842
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -2900,7 +2910,7 @@ var Dr = class {
2900
2910
  let r = n ?? "";
2901
2911
  if (r !== "") return /^fragLoad/i.test(r) ? this.sawFirstBytes ? "ERROR_STAGE_SEGMENT" : "ERROR_STAGE_FIRST_SEGMENT" : /^(manifest|level|audioTrack|subtitleTrack)/i.test(r) ? "ERROR_STAGE_MANIFEST" : /key|licen[cs]e/i.test(r) ? "ERROR_STAGE_DRM" : /parsing|append|buffer|remux|decrypt|media/i.test(r) ? "ERROR_STAGE_DECODE" : "ERROR_STAGE_OTHER";
2902
2912
  if (e === "DRM_CLIENT" || e === "DRM_DEVICE_REVOKED") return "ERROR_STAGE_DRM";
2903
- if (gr.has(e)) return "ERROR_STAGE_RESOLVE";
2913
+ if (_r.has(e)) return "ERROR_STAGE_RESOLVE";
2904
2914
  let i = t ?? "";
2905
2915
  return /frag|segment/i.test(i) ? this.sawFirstBytes ? "ERROR_STAGE_SEGMENT" : "ERROR_STAGE_FIRST_SEGMENT" : /manifest|level|playlist/i.test(i) ? "ERROR_STAGE_MANIFEST" : /key|licen[cs]e/i.test(i) ? "ERROR_STAGE_DRM" : /buffer|decode|media|append/i.test(i) ? "ERROR_STAGE_DECODE" : "ERROR_STAGE_OTHER";
2906
2916
  }
@@ -2932,7 +2942,7 @@ var Dr = class {
2932
2942
  let l = t.droppedFrames ?? 0;
2933
2943
  l > this.lastDropped && (o.droppedFramesDelta = l - this.lastDropped), this.lastDropped = l;
2934
2944
  let u = t.renditionSwitches ?? 0;
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";
2945
+ u > this.lastSwitches && (o.renditionSwitchesDelta = u - this.lastSwitches), this.lastSwitches = u, n > this.lastHbPlayingMs && (o.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (o.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, i > this.lastHbRebufferMs && (o.rebufferMsDelta = Math.round(i - this.lastHbRebufferMs)), this.lastHbRebufferMs = i, this.rebufferCount > this.lastHbRebufferCount && (o.rebufferCountDelta = this.rebufferCount - this.lastHbRebufferCount), this.lastHbRebufferCount = this.rebufferCount, a > this.lastHbActiveMs && (o.activeMsDelta = Math.round(a - this.lastHbActiveMs)), this.lastHbActiveMs = a, typeof t.latencySeconds == "number" && (o.latencyMs = Math.round(t.latencySeconds * 1e3)), typeof t.targetLatencySeconds == "number" && (o.targetLatencyMs = Math.round(t.targetLatencySeconds * 1e3)), typeof t.bandwidthKbps == "number" && (o.bandwidthEstKbps = t.bandwidthKbps), typeof t.levelHeight == "number" && (o.renditionHeight = t.levelHeight), typeof t.renditionBitrateKbps == "number" && (o.renditionBitrateKbps = t.renditionBitrateKbps), t.atLiveEdge === !0 && (o.atLiveEdge = !0), typeof t.bufferedMs == "number" && t.bufferedMs > 0 && (o.bufferedMs = Math.round(t.bufferedMs)), o.playerState = vr[t.state] ?? "PLAYER_STATE_UNSPECIFIED";
2936
2946
  let d = this.mutedTotalMs;
2937
2947
  this.mutedSinceMs !== null && (d += e - this.mutedSinceMs), d > this.lastHbMutedMs && (o.mutedMsDelta = Math.round(d - this.lastHbMutedMs)), this.lastHbMutedMs = d;
2938
2948
  let f = t.upshifts ?? 0;
@@ -2954,13 +2964,13 @@ var Dr = class {
2954
2964
  maybeEmitMediaInfo(e) {
2955
2965
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
2956
2966
  let t = {};
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);
2967
+ e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = gr[e.keySystem]), e.drmSecurityLevel && (t.drmSecurityLevel = e.drmSecurityLevel), e.ladderHeights?.length && (t.ladderHeights = e.ladderHeights), e.ladderTopBitrateKbps && (t.ladderTopBitrateKbps = e.ladderTopBitrateKbps), e.lowLatency && (t.lowLatency = !0);
2958
2968
  let n = JSON.stringify(t);
2959
2969
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
2960
2970
  }
2961
2971
  end(e, t) {
2962
2972
  if (this.endedFlag) return;
2963
- this.endedFlag = !0, Sr.delete(this);
2973
+ this.endedFlag = !0, Cr.delete(this);
2964
2974
  let n = t ?? this.now();
2965
2975
  this.playingSinceMs !== null && (this.playingTotalMs += n - this.playingSinceMs, this.playingSinceMs = null), this.hiddenSinceMs !== null && (this.hiddenTotalMs += n - this.hiddenSinceMs, this.hiddenSinceMs = null), this.bufferingSinceMs !== null && (this.rebufferTotalMs += n - this.bufferingSinceMs, this.bufferingSinceMs = null), this.mutedSinceMs !== null && (this.mutedTotalMs += n - this.mutedSinceMs, this.mutedSinceMs = null), this.waitingSinceMs !== null && (this.waitingTotalMs += n - this.waitingSinceMs, this.waitingSinceMs = null), this.isPlaying = !1, this.syncActive(n), this.closePresentation(n), this.firstFlushTimer &&= (clearTimeout(this.firstFlushTimer), null), this.timer &&= (clearInterval(this.timer), null), this.idleTimer &&= (clearTimeout(this.idleTimer), null), typeof window < "u" && window.removeEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), document.removeEventListener("freeze", this.onFreeze), document.removeEventListener("resume", this.onResume));
2966
2976
  let r = this.safeSample();
@@ -2974,7 +2984,7 @@ var Dr = class {
2974
2984
  let c = r?.positionMs ?? 0;
2975
2985
  c > 0 && (i.exitPositionMs = Math.round(c)), this.activeTotalMs > 0 && (i.activeWatchTimeMs = Math.round(this.activeTotalMs)), this.mutedTotalMs > 0 && (i.mutedTimeMs = Math.round(this.mutedTotalMs));
2976
2986
  let l = e !== "END_REASON_ENDED";
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);
2987
+ l && this.lastStallMs > 0 && n - this.lastStallMs <= pr && (i.abandonAfterStallMs = Math.max(Z, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= pr && (i.abandonAfterErrorMs = Math.max(Z, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
2978
2988
  let u = r?.decodedFrames ?? this.lastDecoded;
2979
2989
  u > 0 && (i.decodedFramesTotal = u), e === "END_REASON_STOPPED" && this.startupTimeMs === 0 && this.lastErrorStage === null && (e = "END_REASON_ABORTED", i.reason = e), this.startupTimeMs === 0 && e !== "END_REASON_ABORTED" && (i.failedStage = this.lastErrorStage ?? (this.manifestLoadMs === 0 ? "ERROR_STAGE_MANIFEST" : this.firstFragLoadMs === 0 ? "ERROR_STAGE_FIRST_SEGMENT" : "ERROR_STAGE_OTHER")), this.pending.push(this.wrap({ sessionEnd: i })), this.flush(e === "END_REASON_PAGEHIDE");
2980
2990
  }
@@ -2994,13 +3004,13 @@ var Dr = class {
2994
3004
  };
2995
3005
  }
2996
3006
  noteCspBlocked() {
2997
- this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(Cr(new URL(this.url).origin)));
3007
+ this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(wr(new URL(this.url).origin)));
2998
3008
  }
2999
3009
  cspBlocked() {
3000
- return !!this.cspKey && xr.has(this.cspKey);
3010
+ return !!this.cspKey && Sr.has(this.cspKey);
3001
3011
  }
3002
3012
  enqueue(e) {
3003
- if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > ur;) {
3013
+ if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > dr;) {
3004
3014
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
3005
3015
  this.pending.splice(e >= 0 ? e : 0, 1);
3006
3016
  }
@@ -3027,7 +3037,7 @@ var Dr = class {
3027
3037
  };
3028
3038
  //#endregion
3029
3039
  //#region src/core/environment.ts
3030
- function Or() {
3040
+ function kr() {
3031
3041
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
3032
3042
  let e;
3033
3043
  try {
@@ -3052,14 +3062,14 @@ function Or() {
3052
3062
  integration: "INTEGRATION_KIND_IFRAME"
3053
3063
  };
3054
3064
  }
3055
- function kr() {
3065
+ function Ar() {
3056
3066
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
3057
3067
  let e = navigator.userAgentData, t = e?.platform ?? "";
3058
3068
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
3059
3069
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
3060
3070
  return e?.mobile ?? (typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1 && n > 0 && n < 900) ? n >= 600 ? "DEVICE_CLASS_TABLET" : "DEVICE_CLASS_PHONE" : e || n >= 900 || /mac|win|linux|chrome os/i.test(t) ? "DEVICE_CLASS_DESKTOP" : "DEVICE_CLASS_OTHER";
3061
3071
  }
3062
- function Ar() {
3072
+ function jr() {
3063
3073
  let e = typeof navigator < "u" ? navigator.connection : void 0;
3064
3074
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
3065
3075
  let t = {
@@ -3078,17 +3088,17 @@ function Ar() {
3078
3088
  }
3079
3089
  return typeof e.downlink == "number" && e.downlink > 0 && (i.downlinkKbps = Math.round(e.downlink * 1e3)), typeof e.rtt == "number" && e.rtt > 0 && (i.rttMs = Math.round(e.rtt)), e.saveData && (i.saveData = !0), i;
3080
3090
  }
3081
- function jr(e) {
3082
- let t = Or(), n = {
3083
- deviceClass: kr(),
3091
+ function Mr(e) {
3092
+ let t = kr(), n = {
3093
+ deviceClass: Ar(),
3084
3094
  integration: t.integration,
3085
- ...Ar()
3095
+ ...jr()
3086
3096
  };
3087
3097
  t.host && (n.host = t.host), typeof screen < "u" && screen.width > 0 && (n.screenWidth = screen.width, n.screenHeight = screen.height), typeof window < "u" && window.devicePixelRatio > 0 && (n.devicePixelRatio = Math.round(window.devicePixelRatio * 100) / 100);
3088
3098
  let r = e.getBoundingClientRect?.();
3089
3099
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
3090
3100
  }
3091
- async function Mr() {
3101
+ async function Nr() {
3092
3102
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
3093
3103
  if (!e?.getHighEntropyValues) return {};
3094
3104
  try {
@@ -3100,7 +3110,7 @@ async function Mr() {
3100
3110
  }
3101
3111
  //#endregion
3102
3112
  //#region src/core/version.ts
3103
- var Nr = "2.28.0", Pr = {
3113
+ var Pr = "2.28.1", Fr = {
3104
3114
  accent: "#E1B600",
3105
3115
  accentText: "#1B1C23",
3106
3116
  background: "#0e0f13",
@@ -3111,7 +3121,7 @@ var Nr = "2.28.0", Pr = {
3111
3121
  border: "rgba(255, 255, 255, 0.1)",
3112
3122
  radius: "8px",
3113
3123
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
3114
- }, Fr = {
3124
+ }, Ir = {
3115
3125
  accent: "--havik-accent",
3116
3126
  accentText: "--havik-accent-text",
3117
3127
  background: "--havik-bg",
@@ -3123,26 +3133,26 @@ var Nr = "2.28.0", Pr = {
3123
3133
  radius: "--havik-radius",
3124
3134
  fontFamily: "--havik-font"
3125
3135
  };
3126
- function Ir(e, t) {
3136
+ function Lr(e, t) {
3127
3137
  let n = {
3128
- ...Pr,
3138
+ ...Fr,
3129
3139
  ...t
3130
3140
  };
3131
- for (let t of Object.keys(Fr)) e.style.setProperty(Fr[t], n[t]);
3141
+ for (let t of Object.keys(Ir)) e.style.setProperty(Ir[t], n[t]);
3132
3142
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
3133
3143
  }
3134
3144
  //#endregion
3135
3145
  //#region src/ui/styles.ts
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;
3146
+ var Rr = "havik-player-styles", zr = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer;\n touch-action:manipulation}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n/* Absolutely centred, NOT a flex sibling of .havik-center: the hidden center\n button (.havik-gone) still occupies its 74px in the row, which pushed an\n in-flow spinner 37px right of centre. */\n.havik-spinner{position:absolute;inset:0;margin:auto;width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n", Br = /* @__PURE__ */ new WeakMap();
3147
+ function Vr(e = document, t) {
3148
+ let n = e.querySelector(`style#${Rr}`);
3149
+ if (n && (!t || Br.get(n) === t)) return;
3140
3150
  let r = e.createElement("style");
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);
3151
+ r.id = Rr, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = zr, Br.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
3142
3152
  }
3143
3153
  //#endregion
3144
3154
  //#region src/ui/icons.ts
3145
- var Vr = {
3155
+ var Hr = {
3146
3156
  play: "<path d=\"M8 5v14l11-7z\"/>",
3147
3157
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
3148
3158
  volumeHigh: "<path d=\"M3 10v4h4l5 5V5L7 10H3zm13.5 2a4.5 4.5 0 0 0-2.5-4v8a4.5 4.5 0 0 0 2.5-4zm-2.5-9v2.06A7 7 0 0 1 14 19v2a9 9 0 0 0 0-18z\"/>",
@@ -3156,11 +3166,11 @@ var Vr = {
3156
3166
  retry: "<path d=\"M17.65 6.35A8 8 0 1 0 19.73 13h-2.08A6 6 0 1 1 12 6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z\"/>"
3157
3167
  };
3158
3168
  function Q(e) {
3159
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Vr[e]}</svg>`;
3169
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Hr[e]}</svg>`;
3160
3170
  }
3161
3171
  //#endregion
3162
3172
  //#region src/ui/controls.ts
3163
- var Hr = 3e3, Ur = 250, Wr = /* @__PURE__ */ new Set([
3173
+ var Ur = 3e3, Wr = 250, Gr = /* @__PURE__ */ new Set([
3164
3174
  "GONE",
3165
3175
  "NOT_FOUND",
3166
3176
  "GEO_DENIED",
@@ -3168,19 +3178,19 @@ var Hr = 3e3, Ur = 250, Wr = /* @__PURE__ */ new Set([
3168
3178
  "UNAUTHORIZED",
3169
3179
  "DRM_DEVICE_REVOKED"
3170
3180
  ]);
3171
- function Gr(e) {
3181
+ function Kr(e) {
3172
3182
  let t = "This match isn't available in your country";
3173
3183
  return e ? `${t} (${e})` : t;
3174
3184
  }
3175
- var Kr = "This device can't play protected video";
3176
- function qr(e) {
3185
+ var qr = "This device can't play protected video";
3186
+ function Jr(e) {
3177
3187
  return `This browser can't play protected video. Allow protected content in its site settings, or use ${e ? "Chrome, Edge or Safari" : "Chrome or Edge"} (Firefox asks when you retry)`;
3178
3188
  }
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);
3189
+ var Yr = "Protected video can't be shown on this display. Use the built-in screen, or an HDCP-capable monitor and cable";
3190
+ function Xr(e) {
3191
+ return new Zr(e);
3182
3192
  }
3183
- var Xr = class {
3193
+ var Zr = class {
3184
3194
  root;
3185
3195
  video;
3186
3196
  player;
@@ -3229,7 +3239,7 @@ var Xr = class {
3229
3239
  scrubbing = !1;
3230
3240
  offFns = [];
3231
3241
  constructor(e) {
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");
3242
+ this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Ur, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.streamEnded = e.streamEnded ?? (() => !1), this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, this.offlineMessage = e.offlineMessage ?? "No internet connection — waiting to reconnect", Vr(this.doc, e.cspNonce), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
3233
3243
  let t = (e, t, n) => {
3234
3244
  let r = this.doc.createElement(e);
3235
3245
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -3315,7 +3325,7 @@ var Xr = class {
3315
3325
  let t = this.surfaceWasHidden;
3316
3326
  this.tapTimer = setTimeout(() => {
3317
3327
  this.tapTimer = void 0, this.toggleBar(t);
3318
- }, Ur);
3328
+ }, Wr);
3319
3329
  }
3320
3330
  toggleBar(e) {
3321
3331
  e ? this.poke() : this.hideIfIdle();
@@ -3347,11 +3357,11 @@ var Xr = class {
3347
3357
  if (e === "waiting") return this.hasPlayed ? "Reconnecting — please stand by" : "Starting soon…";
3348
3358
  if (e === "error") {
3349
3359
  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;
3360
+ if (this.lastError?.code === "GEO_DENIED") return Kr(this.lastError.country);
3361
+ if (this.lastError?.code === "DRM_DEVICE_REVOKED") return qr;
3352
3362
  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;
3363
+ if (this.lastError.detail === "keySystemNoAccess") return Jr(!!this.player.descriptor?.drm?.fairplay?.licenseUrl);
3364
+ if (this.lastError.detail === "keySystemStatusOutputRestricted") return Yr;
3355
3365
  }
3356
3366
  return this.lastError?.message ?? "Playback unavailable";
3357
3367
  }
@@ -3370,7 +3380,7 @@ var Xr = class {
3370
3380
  e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = Q("play"), e.addEventListener("click", () => void this.player.play()), n.append(e);
3371
3381
  } else {
3372
3382
  let r = this.doc.createElement("div");
3373
- if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Wr.has(this.lastError.code)) {
3383
+ if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Gr.has(this.lastError.code)) {
3374
3384
  let e = this.doc.createElement("button");
3375
3385
  e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${Q("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), n.append(e);
3376
3386
  }
@@ -3411,7 +3421,7 @@ var Xr = class {
3411
3421
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
3412
3422
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
3413
3423
  }
3414
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Zr(this.video.currentTime)} / ${Zr(this.video.duration)}`);
3424
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Qr(this.video.currentTime)} / ${Qr(this.video.duration)}`);
3415
3425
  }
3416
3426
  syncLive() {
3417
3427
  let e = this.player.getStats(), t = e.isLive !== !1, n = this.isGone(), r = this.player.state === "ended" || n, i = !t && !this.streamEnded() && !n;
@@ -3461,17 +3471,17 @@ var Xr = class {
3461
3471
  renderQualityMenu() {
3462
3472
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
3463
3473
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
3464
- for (let n of e) this.menu.append(this.menuItem(Qr(n), t === n.index, () => this.player.setQuality(n.index)));
3474
+ for (let n of e) this.menu.append(this.menuItem($r(n), t === n.index, () => this.player.setQuality(n.index)));
3465
3475
  }
3466
3476
  renderAudioMenu() {
3467
3477
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
3468
3478
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
3469
- for (let t of e) this.menu.append(this.menuItem($r(t), t.default, () => this.player.setAudioTrack(t.id)));
3479
+ for (let t of e) this.menu.append(this.menuItem(ei(t), t.default, () => this.player.setAudioTrack(t.id)));
3470
3480
  }
3471
3481
  renderCcMenu() {
3472
3482
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
3473
3483
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
3474
- for (let t of e) this.menu.append(this.menuItem(ei(t), !1, () => this.player.setTextTrack(t.id)));
3484
+ for (let t of e) this.menu.append(this.menuItem(ti(t), !1, () => this.player.setTextTrack(t.id)));
3475
3485
  }
3476
3486
  onTracksChanged() {
3477
3487
  this.openMenu && this.renderMenu(this.openMenu);
@@ -3576,23 +3586,23 @@ var Xr = class {
3576
3586
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
3577
3587
  }
3578
3588
  };
3579
- function Zr(e) {
3589
+ function Qr(e) {
3580
3590
  (!Number.isFinite(e) || e < 0) && (e = 0);
3581
3591
  let t = Math.floor(e % 60), n = Math.floor(e / 60 % 60), r = Math.floor(e / 3600), i = r > 0 ? String(n).padStart(2, "0") : String(n), a = String(t).padStart(2, "0");
3582
3592
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
3583
3593
  }
3584
- function Qr(e) {
3594
+ function $r(e) {
3585
3595
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
3586
3596
  }
3587
- function $r(e) {
3597
+ function ei(e) {
3588
3598
  return e.name || e.lang || `Track ${e.id}`;
3589
3599
  }
3590
- function ei(e) {
3600
+ function ti(e) {
3591
3601
  return e.name || e.lang || `Track ${e.id}`;
3592
3602
  }
3593
3603
  //#endregion
3594
3604
  //#region src/managed/index.ts
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([
3605
+ var ni = 6e3, ri = 45e3, ii = 2e3, ai = 3, oi = 6e4, si = 2, ci = 6e5, li = 5e3, ui = 2e3, di = 48e4, fi = "keySystemLicenseRequestFailed", pi = /* @__PURE__ */ new Set([
3596
3606
  "GONE",
3597
3607
  "NOT_FOUND",
3598
3608
  "INVALID_URN",
@@ -3600,27 +3610,27 @@ var ti = 6e3, ni = 45e3, ri = 2e3, ii = 3, ai = 6e4, oi = 2, si = 6e5, ci = 5e3,
3600
3610
  "GEO_DENIED",
3601
3611
  "DRM_DEVICE_REVOKED"
3602
3612
  ]);
3603
- function pi(e) {
3604
- return !fi.has(e);
3605
- }
3606
3613
  function mi(e) {
3614
+ return !pi.has(e);
3615
+ }
3616
+ function hi(e) {
3607
3617
  if (e.env !== void 0 && e.baseUrl !== void 0) throw new n("INTERNAL", 0, `createPlayer: pass env OR baseUrl, not both (got env=${JSON.stringify(e.env)} and baseUrl=${JSON.stringify(e.baseUrl)})`);
3608
3618
  if (e.env !== void 0) return lt(e.env);
3609
3619
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
3610
3620
  return e.baseUrl;
3611
3621
  }
3612
- async function hi(e) {
3622
+ async function gi(e) {
3613
3623
  if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
3614
- let t = mi(e);
3624
+ let t = hi(e);
3615
3625
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
3616
3626
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
3617
- let r = new gi({
3627
+ let r = new _i({
3618
3628
  ...e,
3619
3629
  baseUrl: t
3620
3630
  });
3621
3631
  return await r.start(), r;
3622
3632
  }
3623
- var gi = class {
3633
+ var _i = class {
3624
3634
  opts;
3625
3635
  abort = new AbortController();
3626
3636
  listeners = {};
@@ -3724,7 +3734,7 @@ var gi = class {
3724
3734
  setTimeout(() => {
3725
3735
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
3726
3736
  phase: i ? "unavailable" : "tooEarly",
3727
- retryInMs: ni,
3737
+ retryInMs: ri,
3728
3738
  attempt: 1,
3729
3739
  elapsedMs: 0,
3730
3740
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -3763,13 +3773,13 @@ var gi = class {
3763
3773
  !a && !p() && h();
3764
3774
  }, e);
3765
3775
  };
3766
- _(ti), this.armingSub = D({
3776
+ _(ni), this.armingSub = D({
3767
3777
  eventsBaseUrl: t,
3768
3778
  matchUrn: this.opts.matchUrn,
3769
3779
  credential: this.opts.credential,
3770
- onAlive: () => _(ni),
3780
+ onAlive: () => _(ri),
3771
3781
  onState: (e) => {
3772
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * ri);
3782
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * ii);
3773
3783
  },
3774
3784
  onError: () => h()
3775
3785
  });
@@ -3814,19 +3824,19 @@ var gi = class {
3814
3824
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
3815
3825
  let i = e.analytics?.sid;
3816
3826
  if (!i) return;
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);
3827
+ let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = Dr(this.opts.baseUrl, a, e.analytics?.endpoint);
3818
3828
  if (!o) {
3819
3829
  s && setTimeout(() => {
3820
3830
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
3821
3831
  }, 0);
3822
3832
  return;
3823
3833
  }
3824
- let c = this.opts.video, l = new Dr({
3834
+ let c = this.opts.video, l = new Or({
3825
3835
  endpoint: o,
3826
3836
  sid: i,
3827
3837
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
3828
- sdkVersion: Nr,
3829
- environment: jr(c),
3838
+ sdkVersion: Pr,
3839
+ environment: Mr(c),
3830
3840
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
3831
3841
  onIdle: () => this.onAnalyticsIdle(t),
3832
3842
  onBlocked: (e) => setTimeout(() => {
@@ -3847,7 +3857,7 @@ var gi = class {
3847
3857
  let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
3848
3858
  c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
3849
3859
  c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
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");
3860
+ }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), Nr().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3851
3861
  }
3852
3862
  currentPresentation() {
3853
3863
  let e = this.opts.video;
@@ -3881,9 +3891,9 @@ var gi = class {
3881
3891
  freshLicenseUrl: () => this.refreshLicense()
3882
3892
  }, o = this.opts.engine ?? "auto";
3883
3893
  if (o === "native") return new H(a);
3884
- if (o === "hls") return new or(a);
3894
+ if (o === "hls") return new sr(a);
3885
3895
  if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && B(this.opts.video) && V() || !e.drmEnabled && Pt() && B(this.opts.video)) return new H(a);
3886
- if (Xt()) return new or(a);
3896
+ if (Xt()) return new sr(a);
3887
3897
  if (B(this.opts.video)) return new H(a);
3888
3898
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
3889
3899
  }
@@ -3955,7 +3965,7 @@ var gi = class {
3955
3965
  a = !0, this.emit("warning", new n(r(o.status), o.status, `live-state events answered HTTP ${o.status} for ${this.opts.matchUrn}: the match is ` + (o.terminal ? "gone, so the subscription stopped" : "not in the catalog (ended and dropped, or not listed yet), so it retries every 5 min") + " — end-of-stream detection falls back to the HLS staleness watchdog."));
3956
3966
  return;
3957
3967
  }
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.`)));
3968
+ i += 1, i >= ai && (a = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${i} attempts — end-of-stream detection degraded to the HLS staleness watchdog. Check the events host, the api-key's allowed origins, and CSP connect-src.`)));
3959
3969
  }
3960
3970
  }
3961
3971
  });
@@ -3966,9 +3976,9 @@ var gi = class {
3966
3976
  reloadStaleEnd() {
3967
3977
  if (this.destroyed || this.endedHandled || this._state === "error" || this._state === "ended") return !1;
3968
3978
  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;
3979
+ if (this.liveStateLast !== "live" || e - this.liveStateAliveAt > oi || (e - this.staleEndWindowAt > ci && (this.staleEndReloads = 0, this.staleEndWindowAt = e), this.staleEndReloads >= si)) return !1;
3970
3980
  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)`);
3981
+ let t = new n("UNAVAILABLE", 0, `live playlist stopped advancing for 12 s while the match is live (live-state push heard ${Math.round((e - this.liveStateAliveAt) / 1e3)} s ago): reloading instead of ending (${this.staleEndReloads} of ${si} this window)`);
3972
3982
  this.analyticsSession?.noteError(t.code, t.message, !1, 0, Math.round(this.opts.video.currentTime * 1e3), "staleEndReload");
3973
3983
  let r = this.loadGen;
3974
3984
  return this.emit("warning", t), Promise.resolve().then(() => {
@@ -3984,7 +3994,7 @@ var gi = class {
3984
3994
  }
3985
3995
  if (this.emit("online"), this._state !== "error" || !this._lastError) return;
3986
3996
  let t = this._lastError.code;
3987
- pi(t) && (t === "NETWORK" || this.failedWhileOffline) && this.retry().catch(() => void 0);
3997
+ mi(t) && (t === "NETWORK" || this.failedWhileOffline) && this.retry().catch(() => void 0);
3988
3998
  }));
3989
3999
  }
3990
4000
  watchReturn() {
@@ -3994,7 +4004,7 @@ var gi = class {
3994
4004
  return;
3995
4005
  }
3996
4006
  let e = this.hiddenAtMs;
3997
- this.hiddenAtMs = null, e != null && Date.now() - e >= ci && this.resyncLiveState();
4007
+ this.hiddenAtMs = null, e != null && Date.now() - e >= li && this.resyncLiveState();
3998
4008
  }, this.onReturnPageShow = (e) => {
3999
4009
  e.persisted && this.resyncLiveState();
4000
4010
  }, document.addEventListener("visibilitychange", this.onReturnVisible), typeof window < "u" && window.addEventListener("pageshow", this.onReturnPageShow));
@@ -4026,7 +4036,7 @@ var gi = class {
4026
4036
  scheduleRejoin(e) {
4027
4037
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
4028
4038
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
4029
- }, Math.random() * ri));
4039
+ }, Math.random() * ii));
4030
4040
  }
4031
4041
  cancelRejoin() {
4032
4042
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -4050,7 +4060,7 @@ var gi = class {
4050
4060
  }
4051
4061
  t.controls = !1;
4052
4062
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
4053
- r && r.insertBefore(n, t), n.appendChild(t), Ir(n, this.opts.theme), this.container = n, this.controlBar = Yr({
4063
+ r && r.insertBefore(n, t), n.appendChild(t), Lr(n, this.opts.theme), this.container = n, this.controlBar = Xr({
4054
4064
  root: n,
4055
4065
  video: t,
4056
4066
  player: this,
@@ -4089,7 +4099,7 @@ var gi = class {
4089
4099
  }
4090
4100
  startStats() {
4091
4101
  this.stopStats();
4092
- let e = Math.max(500, this.opts.statsIntervalMs ?? li);
4102
+ let e = Math.max(500, this.opts.statsIntervalMs ?? ui);
4093
4103
  this.statsTimer = setInterval(() => {
4094
4104
  if (!this.engine) return;
4095
4105
  let e = this.engine.getStats();
@@ -4100,14 +4110,14 @@ var gi = class {
4100
4110
  this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
4101
4111
  }
4102
4112
  isStaleLicenseDenial(e) {
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);
4113
+ return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== fi || e.error.httpStatus !== 403 || e.error.code !== "FORBIDDEN" || e.error.serverCode === "license_refused" ? !1 : W(this._descriptor?.drm?.widevine?.licenseUrl);
4104
4114
  }
4105
4115
  scheduleLicenseRefresh() {
4106
4116
  if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
4107
4117
  typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
4108
4118
  document.visibilityState !== "visible" || this.destroyed || W(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
4109
4119
  }, document.addEventListener("visibilitychange", this.onRefocus));
4110
- let e = this.opts.licenseRefreshMs ?? ui;
4120
+ let e = this.opts.licenseRefreshMs ?? di;
4111
4121
  e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
4112
4122
  }
4113
4123
  stopRefresh() {
@@ -4277,7 +4287,7 @@ function $(e) {
4277
4287
  }
4278
4288
  //#endregion
4279
4289
  //#region src/embed/host.ts
4280
- function _i(e) {
4290
+ function vi(e) {
4281
4291
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
4282
4292
  if (!e.src) throw Error("mountEmbed: opts.src is required");
4283
4293
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -4336,15 +4346,15 @@ function _i(e) {
4336
4346
  }
4337
4347
  //#endregion
4338
4348
  //#region src/embed/page.ts
4339
- var vi = /^[A-Za-z0-9:_.-]{1,128}$/;
4340
- function yi(e) {
4349
+ var yi = /^[A-Za-z0-9:_.-]{1,128}$/;
4350
+ function bi(e) {
4341
4351
  if (typeof e == "boolean") return e;
4342
4352
  if (typeof e == "object" && e) {
4343
4353
  let t = e.endpoint;
4344
4354
  return typeof t == "string" ? { endpoint: t } : {};
4345
4355
  }
4346
4356
  }
4347
- function bi() {
4357
+ function xi() {
4348
4358
  let e = window.HAVIK_EMBED_CONFIG;
4349
4359
  if (e) return {
4350
4360
  baseUrl: e.baseUrl ?? "",
@@ -4354,7 +4364,7 @@ function bi() {
4354
4364
  autoplay: e.autoplay ?? !0,
4355
4365
  muted: e.muted ?? !0,
4356
4366
  waitForLive: e.waitForLive ?? !0,
4357
- analytics: yi(e.analytics)
4367
+ analytics: bi(e.analytics)
4358
4368
  };
4359
4369
  let t = new URLSearchParams(location.search);
4360
4370
  return {
@@ -4367,9 +4377,9 @@ function bi() {
4367
4377
  waitForLive: !0
4368
4378
  };
4369
4379
  }
4370
- async function xi() {
4371
- let e = bi();
4372
- Ci();
4380
+ async function Si() {
4381
+ let e = xi();
4382
+ wi();
4373
4383
  let t = document.createElement("video");
4374
4384
  t.setAttribute("playsinline", ""), t.muted = e.muted ?? !0, t.style.cssText = "width:100%;height:100%;object-fit:contain;background:#000;aspect-ratio:auto", document.body.appendChild(t);
4375
4385
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -4425,12 +4435,12 @@ async function xi() {
4425
4435
  message: e.message,
4426
4436
  ...e.country === void 0 ? {} : { country: e.country }
4427
4437
  })), e.on("autoplayblocked", () => {
4428
- i({ type: "oddin:autoplayblocked" }), Si(t, e);
4438
+ i({ type: "oddin:autoplayblocked" }), Ci(t, e);
4429
4439
  });
4430
4440
  }, s = async (r) => {
4431
4441
  a?.destroy(), a = null;
4432
4442
  try {
4433
- let n = await hi({
4443
+ let n = await gi({
4434
4444
  video: t,
4435
4445
  baseUrl: e.baseUrl,
4436
4446
  matchUrn: r,
@@ -4493,7 +4503,7 @@ async function xi() {
4493
4503
  a?.retry();
4494
4504
  break;
4495
4505
  case "oddin:load":
4496
- typeof e.matchUrn == "string" && vi.test(e.matchUrn) && s(e.matchUrn);
4506
+ typeof e.matchUrn == "string" && yi.test(e.matchUrn) && s(e.matchUrn);
4497
4507
  break;
4498
4508
  case "oddin:destroy": c();
4499
4509
  }
@@ -4505,18 +4515,18 @@ async function xi() {
4505
4515
  protocol: 1
4506
4516
  });
4507
4517
  }
4508
- function Si(e, t) {
4518
+ function Ci(e, t) {
4509
4519
  if (document.getElementById("havik-tap")) return;
4510
4520
  let n = document.createElement("button");
4511
4521
  n.id = "havik-tap", n.textContent = "▶ Tap to play", n.style.cssText = "position:fixed;inset:0;width:100%;height:100%;border:0;background:rgba(0,0,0,.55);color:#fff;font:600 18px system-ui,sans-serif;cursor:pointer;z-index:9", n.addEventListener("click", () => {
4512
4522
  n.remove(), t.play();
4513
4523
  }), document.body.appendChild(n);
4514
4524
  }
4515
- function Ci() {
4525
+ function wi() {
4516
4526
  let e = document.createElement("style");
4517
4527
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
4518
4528
  }
4519
4529
  //#endregion
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 };
4530
+ export { E as LiveStateHttpError, Fr as ODDIN_THEME, n as PlaybackError, Lr as applyTheme, lt as baseUrlForEnv, Si as bootEmbed, ke as clearDeviceId, He as clearRememberedBandwidth, gi as createPlayer, O as deriveEventsBaseUrl, at as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, ve as fetchCatalog, be as fetchTournament, Se as flattenMatches, C as fullscreenSupported, Oe as getDeviceId, st as isLowLatencyManifest, $ as isOddinMessage, je as licenseRequestHeaders, vi as mountEmbed, fe as pollToLive, y as resolveStream, D as subscribeLiveState, S as videoFullscreenActive, we as watchStatus };
4521
4531
 
4522
4532
  //# sourceMappingURL=index.js.map