@oddin-gg/havik-player 2.26.0 → 2.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1574,7 +1574,12 @@ function K(e, t) {
1574
1574
  function Wt() {
1575
1575
  return e.isSupported();
1576
1576
  }
1577
- var Gt = 3, Kt = 1e6, qt = 20, Jt = 1e4, Yt = 3, Xt = 5, Zt = 3, Qt = 1e4, $t = 3e4, en = 12e3, tn = 3e3, nn = .02, rn = 6e3, an = .5, on = 3, sn = .5, cn = 1.1, ln = .25, un = 5e3, dn = 4e3, fn = 2, pn = 5, mn = 2, hn = 2, gn = 4, _n = 4, vn = 2e3, yn = 3e4, bn = 1, xn = 2, Sn = .5, Cn = .6, wn = 2, Tn = 1.5, En = 1e4, q = 8, Dn = 12e4, On = 6e4;
1577
+ var Gt = 3, Kt = 1e6, qt = 20, Jt = 1e4, Yt = 3, Xt = 5, Zt = 3, Qt = 1e4, $t = 3e4, en = 12e3, tn = 3e3, nn = .02, rn = 6e3, an = .5, on = 3, sn = .5, cn = 1.1, ln = .25, un = 5e3, dn = 4e3, fn = 2, pn = 5, mn = 2, hn = 2, gn = 4, _n = 4, vn = 2e3, yn = 3e4, bn = 1, xn = 2, Sn = .5, Cn = .6, wn = 2, Tn = 1.5, En = 1e4, Dn = 18e4, On = .5, kn = 2;
1578
+ function An(e) {
1579
+ let t = e.config ?? {};
1580
+ return t.capLevelToPlayerSize === !0 || t.capLevelOnFPSDrop === !0;
1581
+ }
1582
+ var q = 8, jn = 12e4, Mn = 6e4;
1578
1583
  function J(e, t, n) {
1579
1584
  if (n <= 0 || t < 0 || t >= e.length) return t;
1580
1585
  let r = (t, n) => e[t].width === e[n].width && e[t].height === e[n].height, i = (t) => {
@@ -1587,11 +1592,11 @@ function J(e, t, n) {
1587
1592
  function Y() {
1588
1593
  return typeof self < "u" && self.devicePixelRatio > 0 ? self.devicePixelRatio : 1;
1589
1594
  }
1590
- var kn = .2, An = 30, jn = 2, Mn = 2, Nn = 2, Pn = 9, Fn = .5, In = 64, Ln = 1e4, Rn = 8, zn = .6, Bn = .4, Vn = .4, Hn = 2, Un = 6e4, X = .5, Wn = 3.5, Gn = 300;
1591
- function Kn(e) {
1595
+ var Nn = .2, Pn = 30, Fn = 2, In = 2, Ln = 2, Rn = 9, zn = .5, Bn = 64, Vn = 1e4, Hn = 8, Un = .6, Wn = .4, Gn = .4, Kn = 2, qn = 6e4, X = .5, Jn = 3.5, Yn = 300;
1596
+ function Xn(e) {
1592
1597
  return (e?.part ?? e?.frag)?.stats;
1593
1598
  }
1594
- function qn() {
1599
+ function Zn() {
1595
1600
  if (typeof navigator > "u") return 0;
1596
1601
  try {
1597
1602
  let e = navigator.connection?.rtt;
@@ -1600,20 +1605,20 @@ function qn() {
1600
1605
  return 0;
1601
1606
  }
1602
1607
  }
1603
- function Jn(e) {
1608
+ function Qn(e) {
1604
1609
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
1605
1610
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
1606
1611
  return;
1607
1612
  }
1608
- e.liveSyncDuration ??= Nn;
1609
- let t = Math.max(12, e.liveSyncDuration + Pn);
1610
- (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Yn(e, e.liveSyncDuration);
1613
+ e.liveSyncDuration ??= Ln;
1614
+ let t = Math.max(12, e.liveSyncDuration + Rn);
1615
+ (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), $n(e, e.liveSyncDuration);
1611
1616
  }
1612
- function Yn(e, t) {
1617
+ function $n(e, t) {
1613
1618
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
1614
1619
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
1615
1620
  }
1616
- var Xn = class {
1621
+ var er = class {
1617
1622
  name = "hls";
1618
1623
  hls = null;
1619
1624
  deps;
@@ -1702,6 +1707,11 @@ var Xn = class {
1702
1707
  pushedCapLevel = -1;
1703
1708
  pushedCapReason = null;
1704
1709
  fpsCapBitrate = null;
1710
+ stallCapBitrate = null;
1711
+ stallCapSince = 0;
1712
+ stallCapTickAt = 0;
1713
+ stallDownCaps = 0;
1714
+ stallCapEnabled;
1705
1715
  fpsCapFailedHeight = null;
1706
1716
  fpsCapManaged = !0;
1707
1717
  fpsLastFrames = -1;
@@ -1716,7 +1726,7 @@ var Xn = class {
1716
1726
  frameCounter;
1717
1727
  detachFrames = null;
1718
1728
  constructor(e) {
1719
- this.deps = e, this.holdBackEnabled = e.adaptiveHoldBack !== !1, this.frameCounter = new ht(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1729
+ this.deps = e, this.holdBackEnabled = e.adaptiveHoldBack !== !1, this.stallCapEnabled = e.stallCap !== !1, this.frameCounter = new ht(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1720
1730
  }
1721
1731
  async load() {
1722
1732
  this.detachFrames ??= this.frameCounter.attach();
@@ -1793,7 +1803,7 @@ var Xn = class {
1793
1803
  let t = e.liveSyncPosition;
1794
1804
  if (typeof t != "number" || !Number.isFinite(t)) return;
1795
1805
  let { video: n } = this.deps;
1796
- n.currentTime <= t + Fn || (n.currentTime = t);
1806
+ n.currentTime <= t + zn || (n.currentTime = t);
1797
1807
  }
1798
1808
  reanchorPartTimeline(e, t) {
1799
1809
  let { frag: n, part: r } = t;
@@ -1869,7 +1879,7 @@ var Xn = class {
1869
1879
  }), t = zt(e, f.loader);
1870
1880
  t && (this.prefetch = e, p = h, m = g, f.fLoader = t);
1871
1881
  }
1872
- Jn(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;
1882
+ Qn(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;
1873
1883
  let _ = new e(f);
1874
1884
  if (this.hls = _, this.armHoldBack(_, f), _.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(_, t)), _.on(e.Events.MANIFEST_PARSED, () => {
1875
1885
  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" });
@@ -1881,10 +1891,10 @@ var Xn = class {
1881
1891
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
1882
1892
  }), _.on(e.Events.FRAG_LOADED, (e, t) => {
1883
1893
  t?.frag?.type === "main" && (this.mainFragsSinceTick += 1, this.bwFragsLoaded += 1, this.maybeRememberBandwidth(!1));
1884
- let n = t?.frag, r = Kn(t), i = r?.loaded;
1894
+ let n = t?.frag, r = Xn(t), i = r?.loaded;
1885
1895
  typeof i == "number" && (this.bytesLoaded += i), !this.reportedFirstBytes && typeof i == "number" && i > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
1886
1896
  let a = r?.loading;
1887
- 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 > In && this.requestTimesMs.shift()), this.sampleHoldBack(t), this.sampleHeadroom(t);
1897
+ 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 > Bn && this.requestTimesMs.shift()), this.sampleHoldBack(t), this.sampleHeadroom(t);
1888
1898
  let o = n?.url;
1889
1899
  if (o) {
1890
1900
  let e = ft(o);
@@ -1924,7 +1934,7 @@ var Xn = class {
1924
1934
  _.on(e.Events.KEY_LOADED, () => {
1925
1935
  u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
1926
1936
  }), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1927
- this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.adaptHoldBack(), this.reviewSizeCapHeadroom(), this.checkFrameDrops();
1937
+ this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.adaptHoldBack(), this.reviewSizeCapHeadroom(), this.releaseStallCap(), this.checkFrameDrops();
1928
1938
  }, tn), _.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1929
1939
  this.renditionSwitches += 1;
1930
1940
  let n = this.lastLevelIndex >= 0 ? _.levels[this.lastLevelIndex] : void 0, r = _.levels[t.level];
@@ -2044,7 +2054,7 @@ var Xn = class {
2044
2054
  if (!this.sizeCapManaged || !this.defaultHeadroomApplies() || e.frag?.type !== "main" || typeof e.frag.level != "number" || typeof document < "u" && document.hidden) return;
2045
2055
  let t = e.part ? e.part.duration : this.detectedLowLatency ? 0 : e.frag.duration;
2046
2056
  if (typeof t != "number" || !(t > 0)) return;
2047
- let n = Kn(e)?.loading;
2057
+ let n = Xn(e)?.loading;
2048
2058
  if (!n || !(n.start > 0) || !(n.end >= n.start)) return;
2049
2059
  let r = this.hls?.levels?.[e.frag.level]?.bitrate;
2050
2060
  if (!(typeof r == "number" && r > 0)) return;
@@ -2055,9 +2065,42 @@ var Xn = class {
2055
2065
  bitrate: r
2056
2066
  }), this.headroomSamples.length > 256 && this.headroomSamples.shift();
2057
2067
  }
2058
- onPlaybackStall() {
2059
- let e = Date.now();
2060
- this.deps.video.seeking || !this.playingSince || e - this.playingSince < En || (this.lastStallAt = e, this.headroomGranted && (this.headroomGranted = !1, this.applySizeCapUnlessPending()));
2068
+ onPlaybackStall(e) {
2069
+ let t = Date.now();
2070
+ this.deps.video.seeking || !this.playingSince || t - this.playingSince < En || (this.lastStallAt = t, this.stepStallCapDown(t, e), this.headroomGranted && (this.headroomGranted = !1, this.applySizeCapUnlessPending()));
2071
+ }
2072
+ stallCapLevel(e) {
2073
+ if (this.stallCapBitrate == null) return -1;
2074
+ let t = -1;
2075
+ return e.levels.forEach((e, n) => {
2076
+ e.bitrate <= this.stallCapBitrate && (t = n);
2077
+ }), t < 0 ? 0 : t;
2078
+ }
2079
+ stepStallCapDown(e, t) {
2080
+ let n = this.hls;
2081
+ if (!n || !this.stallCapEnabled || An(n) || !n.autoLevelEnabled || typeof t == "number" && t >= On || this.isLiveEdgeWait(n, t ?? 0)) return;
2082
+ this.stallCapBitrate != null && (this.stallCapSince = e);
2083
+ let r = Math.max(n.levels[n.currentLevel]?.bitrate ?? 0, n.levels[n.loadLevel]?.bitrate ?? 0);
2084
+ if (!(r > 0)) return;
2085
+ let i = n.levels.map((e) => e.bitrate).filter((e) => e > 0 && e < r).sort((e, t) => t - e)[0];
2086
+ i != null && (this.stallCapBitrate != null && i >= this.stallCapBitrate || (this.stallCapBitrate = i, this.stallCapSince = e, this.stallDownCaps += 1, this.pushCap()));
2087
+ }
2088
+ isLiveEdgeWait(e, t) {
2089
+ let n = e.latestLevelDetails;
2090
+ if (!n?.live) return !1;
2091
+ let r = n.partTarget || n.targetduration;
2092
+ return !(r > 0) || !(n.edge > 0) ? !1 : n.edge - (this.deps.video.currentTime + t) < kn * r;
2093
+ }
2094
+ releaseStallCap() {
2095
+ let e = this.hls, t = Date.now(), n = this.stallCapTickAt;
2096
+ if (this.stallCapTickAt = t, !e || this.stallCapBitrate == null) return;
2097
+ if (this.deps.video.paused || this.loadSuspended || this.offlineHold) {
2098
+ n && (this.stallCapSince += t - Math.max(n, this.stallCapSince));
2099
+ return;
2100
+ }
2101
+ if (t - this.stallCapSince < Dn) return;
2102
+ let r = this.stallCapBitrate, i = e.levels.map((e) => e.bitrate).filter((e) => e > r).sort((e, t) => e - t)[0];
2103
+ this.stallCapBitrate = i ?? null, this.stallCapSince = t, this.pushCap();
2061
2104
  }
2062
2105
  reviewSizeCapHeadroom() {
2063
2106
  let e = Date.now(), { video: t } = this.deps;
@@ -2068,12 +2111,12 @@ var Xn = class {
2068
2111
  this.headroomGranted = !1, this.headroomSamples = [];
2069
2112
  return;
2070
2113
  }
2071
- this.headroomSamples = this.headroomSamples.filter((t) => t.t >= e - Ln);
2114
+ this.headroomSamples = this.headroomSamples.filter((t) => t.t >= e - Vn);
2072
2115
  let r = this.headroomEarned(n, e);
2073
- r !== this.headroomGranted && (r || (this.headroomRegrantAt = e + On), this.headroomGranted = r, this.applySizeCapUnlessPending());
2116
+ r !== this.headroomGranted && (r || (this.headroomRegrantAt = e + Mn), this.headroomGranted = r, this.applySizeCapUnlessPending());
2074
2117
  }
2075
2118
  headroomEarned(e, t) {
2076
- if (t - this.lastStallAt < Dn || !this.headroomGranted && t < this.headroomRegrantAt || !this.headroomGranted && this.headroomSamples.length < q) return !1;
2119
+ if (t - this.lastStallAt < jn || !this.headroomGranted && t < this.headroomRegrantAt || !this.headroomGranted && this.headroomSamples.length < q) return !1;
2077
2120
  let n = e.levels, r = this.sizeCapCoverLevel();
2078
2121
  if (r == null) return this.headroomGranted;
2079
2122
  let i = J(n, r, bn);
@@ -2101,7 +2144,8 @@ var Xn = class {
2101
2144
  let t = [
2102
2145
  ["size", this.sizeCapLevel ?? -1],
2103
2146
  ["bitrate", this.bitrateCapLevel],
2104
- ["fps", this.fpsCapLevel(e)]
2147
+ ["fps", this.fpsCapLevel(e)],
2148
+ ["stall", this.stallCapLevel(e)]
2105
2149
  ], n = -1, r = null;
2106
2150
  for (let [e, i] of t) i >= 0 && (n < 0 || i < n) && (n = i, r = e);
2107
2151
  e.autoLevelCapping = n, this.pushedCapLevel = n, this.pushedCapReason = r;
@@ -2146,6 +2190,7 @@ var Xn = class {
2146
2190
  liveRetargets: this.liveRetargets,
2147
2191
  holdBackSteps: this.holdBackSteps,
2148
2192
  fpsDownCaps: this.fpsDownCaps,
2193
+ stallDownCaps: this.stallDownCaps,
2149
2194
  licenseTimeMs: this.licenseTimeMs,
2150
2195
  upshifts: this.upshifts,
2151
2196
  downshifts: this.downshifts,
@@ -2160,12 +2205,7 @@ var Xn = class {
2160
2205
  let t = e.currentLevel >= 0 ? e.levels[e.currentLevel] : void 0;
2161
2206
  t && (n.levelHeight = t.height);
2162
2207
  let r = e.autoLevelCapping, i = r >= 0 ? e.levels[r] : void 0;
2163
- if (i && i.height > 0) {
2164
- n.maxLevelHeight = i.height;
2165
- let t = e.config ?? {};
2166
- t.capLevelToPlayerSize !== !0 && t.capLevelOnFPSDrop !== !0 && r === this.pushedCapLevel && this.pushedCapReason && (n.capReason = this.pushedCapReason);
2167
- }
2168
- 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));
2208
+ i && i.height > 0 && (n.maxLevelHeight = i.height, !An(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));
2169
2209
  }
2170
2210
  return n;
2171
2211
  }
@@ -2250,7 +2290,7 @@ var Xn = class {
2250
2290
  }), n < 0 ? 0 : n;
2251
2291
  }
2252
2292
  armFrameDropGrace() {
2253
- this.fpsGraceTicks > 0 || (this.fpsGraceTicks = Mn, this.fpsBadTicks = 0);
2293
+ this.fpsGraceTicks > 0 || (this.fpsGraceTicks = In, this.fpsBadTicks = 0);
2254
2294
  }
2255
2295
  resetFrameDropWindow() {
2256
2296
  this.fpsLastFrames = -1, this.fpsLastDropped = -1, this.fpsBadTicks = 0;
@@ -2262,7 +2302,7 @@ var Xn = class {
2262
2302
  return;
2263
2303
  }
2264
2304
  let { totalFrames: n, dropped: r } = R(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
2265
- if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < An || o < 0) {
2305
+ if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Pn || o < 0) {
2266
2306
  this.fpsBadTicks = 0;
2267
2307
  return;
2268
2308
  }
@@ -2270,11 +2310,11 @@ var Xn = class {
2270
2310
  --this.fpsGraceTicks, this.fpsBadTicks = 0;
2271
2311
  return;
2272
2312
  }
2273
- if (o <= kn * a) {
2313
+ if (o <= Nn * a) {
2274
2314
  this.fpsBadTicks = 0;
2275
2315
  return;
2276
2316
  }
2277
- if (this.fpsBadTicks += 1, this.fpsBadTicks < jn) return;
2317
+ if (this.fpsBadTicks += 1, this.fpsBadTicks < Fn) return;
2278
2318
  this.fpsBadTicks = 0;
2279
2319
  let s = e.levels, c = s[e.currentLevel];
2280
2320
  if (!c) return;
@@ -2323,13 +2363,13 @@ var Xn = class {
2323
2363
  if (!this.holdBackEnabled || this.holdBackPriorChecked || !e || (this.holdBackPriorChecked = !0, this.holdBackApplied > 0 || this.holdBackStepCount > 0)) return;
2324
2364
  let t = e.targetLatency;
2325
2365
  if (this.holdBackBase < 0 && typeof t == "number" && t > 0 && (this.holdBackBase = t), this.holdBackBase < 0) return;
2326
- let n = qn();
2327
- if (!(n >= Gn)) return;
2366
+ let n = Zn();
2367
+ if (!(n >= Yn)) return;
2328
2368
  let r = typeof t == "number" && t > 0 ? t : this.holdBackBase, i = Math.min(this.holdBackCeiling(e), this.holdBackBase + X);
2329
2369
  i > r && (this.holdBackStepCount = 1, this.moveHoldBack(e, r, i, "connection-rtt", `connection rtt ${n} ms`));
2330
2370
  }
2331
2371
  holdBackCeiling(e) {
2332
- let t = this.deps.adaptiveHoldBackCeiling, n = typeof t == "number" && Number.isFinite(t) ? t : Wn, r = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
2372
+ let t = this.deps.adaptiveHoldBackCeiling, n = typeof t == "number" && Number.isFinite(t) ? t : Jn, r = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
2333
2373
  return r > 1 ? Math.min(n, r - 1) : n;
2334
2374
  }
2335
2375
  sampleHoldBack(e) {
@@ -2338,7 +2378,7 @@ var Xn = class {
2338
2378
  if (t !== "main" && t !== "audio") return;
2339
2379
  let n = e.part ? e.part.duration : this.detectedLowLatency ? 0 : e.frag?.duration;
2340
2380
  if (typeof n != "number" || !(n > 0)) return;
2341
- let r = Kn(e)?.loading;
2381
+ let r = Xn(e)?.loading;
2342
2382
  if (!r || !(r.start > 0) || !(r.end > 0)) return;
2343
2383
  let i = r.first > r.start ? r.first : r.end, a = Math.max(0, i - r.start) / (n * 1e3);
2344
2384
  this.holdBackSamples.push({
@@ -2353,20 +2393,20 @@ var Xn = class {
2353
2393
  this.holdBackSlowTicks = 0, this.holdBackFastSince = 0, this.holdBackSamples = [];
2354
2394
  return;
2355
2395
  }
2356
- let t = Date.now(), n = t - Ln, r = this.holdBackSamples, i = 0;
2396
+ let t = Date.now(), n = t - Vn, r = this.holdBackSamples, i = 0;
2357
2397
  for (; i < r.length && r[i].t < n;) i += 1;
2358
2398
  i > 0 && r.splice(0, i);
2359
2399
  let a = e.targetLatency;
2360
2400
  if (typeof a != "number" || !(a > 0)) return;
2361
2401
  this.holdBackBase < 0 && (this.holdBackBase = a);
2362
2402
  let o = this.holdBackBase, s = this.holdBackCeiling(e);
2363
- if (r.length < Rn) {
2403
+ if (r.length < Hn) {
2364
2404
  this.holdBackSlowTicks = 0;
2365
2405
  return;
2366
2406
  }
2367
2407
  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);
2368
- if (l >= zn && u >= Bn) {
2369
- if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks < Hn) return;
2408
+ if (l >= Un && u >= Wn) {
2409
+ if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks < Kn) return;
2370
2410
  this.holdBackSlowTicks = 0;
2371
2411
  let t = Math.ceil((s - o) / X), n = Math.ceil((a - o) / X - 1e-9);
2372
2412
  if (n > this.holdBackStepCount && (this.holdBackStepCount = n), this.holdBackStepCount >= t) return;
@@ -2376,7 +2416,7 @@ var Xn = class {
2376
2416
  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)`);
2377
2417
  return;
2378
2418
  }
2379
- if (this.holdBackSlowTicks = 0, l >= Vn) {
2419
+ if (this.holdBackSlowTicks = 0, l >= Gn) {
2380
2420
  this.holdBackFastSince = 0;
2381
2421
  return;
2382
2422
  }
@@ -2384,7 +2424,7 @@ var Xn = class {
2384
2424
  this.holdBackFastSince = t;
2385
2425
  return;
2386
2426
  }
2387
- if (t - this.holdBackFastSince < Un || (this.holdBackFastSince = t, this.holdBackStepCount === 0 || a !== this.holdBackApplied)) return;
2427
+ if (t - this.holdBackFastSince < qn || (this.holdBackFastSince = t, this.holdBackStepCount === 0 || a !== this.holdBackApplied)) return;
2388
2428
  --this.holdBackStepCount;
2389
2429
  let f = Math.max(o, o + this.holdBackStepCount * X);
2390
2430
  f >= a || this.moveHoldBack(e, a, f, "fast-fetches", `part fetches fast again (p95 first byte ${d} ms per 1 s of media)`);
@@ -2470,7 +2510,7 @@ var Xn = class {
2470
2510
  }
2471
2511
  }
2472
2512
  onError(t) {
2473
- if (t.details === e.ErrorDetails.BUFFER_STALLED_ERROR && this.onPlaybackStall(), t.type === e.ErrorTypes.NETWORK_ERROR && String(t.details ?? "").startsWith("frag") && (this.requestErrors += 1), !t.fatal) return;
2513
+ if (t.details === e.ErrorDetails.BUFFER_STALLED_ERROR && this.onPlaybackStall(t.buffer), t.type === e.ErrorTypes.NETWORK_ERROR && String(t.details ?? "").startsWith("frag") && (this.requestErrors += 1), !t.fatal) return;
2474
2514
  let n = this.hls;
2475
2515
  if (n) {
2476
2516
  if (this.clearRecoveryReset(), t.type === e.ErrorTypes.KEY_SYSTEM_ERROR) {
@@ -2529,15 +2569,15 @@ var Xn = class {
2529
2569
  let o = t.response?.code ?? 0, s = t.details ?? t.type, c = t.reason ?? t.error?.message ?? "", l = r === "DRM" && o === 403 && t.details === e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED ? i(Mt(t.networkDetails)) : void 0;
2530
2570
  return new n(r === "DRM" ? a(o, l) : r === "NETWORK" && o === 0 ? "NETWORK" : o === 401 ? "UNAUTHORIZED" : o === 403 ? "FORBIDDEN" : "INTERNAL", o, `${r} error: ${s}${c ? ` (${c})` : ""}`, l ? { serverCode: l } : void 0);
2531
2571
  }
2532
- }, Zn = 15e3, Qn = 6e5, $n = 3e5, er = 100, Z = 1, tr = 1e3, nr = 3e4, rr = 1e3, ir = {
2572
+ }, tr = 15e3, nr = 6e5, rr = 3e5, ir = 100, Z = 1, ar = 1e3, or = 3e4, sr = 1e3, cr = {
2533
2573
  inline: "PRESENTATION_INLINE",
2534
2574
  fullscreen: "PRESENTATION_FULLSCREEN",
2535
2575
  pip: "PRESENTATION_PIP"
2536
- }, ar = {
2576
+ }, lr = {
2537
2577
  widevine: "KEY_SYSTEM_WIDEVINE",
2538
2578
  fairplay: "KEY_SYSTEM_FAIRPLAY",
2539
2579
  none: "KEY_SYSTEM_NONE"
2540
- }, or = /* @__PURE__ */ new Set([
2580
+ }, ur = /* @__PURE__ */ new Set([
2541
2581
  "INVALID_URN",
2542
2582
  "NOT_FOUND",
2543
2583
  "GEO_DENIED",
@@ -2548,7 +2588,7 @@ var Xn = class {
2548
2588
  "FORBIDDEN",
2549
2589
  "RATE_LIMITED",
2550
2590
  "TIMEOUT"
2551
- ]), sr = {
2591
+ ]), dr = {
2552
2592
  idle: "PLAYER_STATE_IDLE",
2553
2593
  waiting: "PLAYER_STATE_WAITING",
2554
2594
  loading: "PLAYER_STATE_LOADING",
@@ -2558,7 +2598,7 @@ var Xn = class {
2558
2598
  ended: "PLAYER_STATE_ENDED",
2559
2599
  error: "PLAYER_STATE_ERROR"
2560
2600
  };
2561
- function cr(e) {
2601
+ function fr(e) {
2562
2602
  try {
2563
2603
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
2564
2604
  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);
@@ -2566,8 +2606,8 @@ function cr(e) {
2566
2606
  return;
2567
2607
  }
2568
2608
  }
2569
- var lr = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), ur = /* @__PURE__ */ new Set(), dr = /* @__PURE__ */ new Set(), fr = /* @__PURE__ */ new Set(), pr = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2570
- function mr(e) {
2609
+ var pr = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), mr = /* @__PURE__ */ new Set(), hr = /* @__PURE__ */ new Set(), gr = /* @__PURE__ */ new Set(), _r = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2610
+ function vr(e) {
2571
2611
  if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
2572
2612
  let t;
2573
2613
  try {
@@ -2576,19 +2616,19 @@ function mr(e) {
2576
2616
  } catch {
2577
2617
  return;
2578
2618
  }
2579
- if (ur.has(t) && !dr.has(t)) {
2580
- dr.add(t), _(pr(new URL(t).origin));
2581
- for (let e of fr) e.noteCspBlocked();
2619
+ if (mr.has(t) && !hr.has(t)) {
2620
+ hr.add(t), _(_r(new URL(t).origin));
2621
+ for (let e of gr) e.noteCspBlocked();
2582
2622
  }
2583
2623
  }
2584
- function hr(e, t) {
2624
+ function yr(e, t) {
2585
2625
  return _(t, e), { disabledReason: t };
2586
2626
  }
2587
- function gr(e, t, n) {
2588
- if (n) return t && !lr(t, n) && _(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2627
+ function br(e, t, n) {
2628
+ if (n) return t && !pr(t, n) && _(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2589
2629
  if (t) return { endpoint: t };
2590
- if (t !== void 0) return hr("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).");
2591
- let r = cr(e);
2630
+ if (t !== void 0) return yr("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).");
2631
+ let r = fr(e);
2592
2632
  if (r) return { endpoint: r };
2593
2633
  let i;
2594
2634
  try {
@@ -2596,9 +2636,9 @@ function gr(e, t, n) {
2596
2636
  } catch {
2597
2637
  i = e;
2598
2638
  }
2599
- return hr(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).`);
2639
+ return yr(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).`);
2600
2640
  }
2601
- var _r = class {
2641
+ var xr = class {
2602
2642
  opts;
2603
2643
  url;
2604
2644
  cspKey;
@@ -2680,8 +2720,8 @@ var _r = class {
2680
2720
  constructor(e) {
2681
2721
  this.opts = {
2682
2722
  ...e,
2683
- heartbeatMs: e.heartbeatMs ?? Zn,
2684
- idleMs: e.idleMs ?? Qn
2723
+ heartbeatMs: e.heartbeatMs ?? tr,
2724
+ idleMs: e.idleMs ?? nr
2685
2725
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
2686
2726
  try {
2687
2727
  let e = new URL(this.url);
@@ -2698,11 +2738,11 @@ var _r = class {
2698
2738
  sdkVersion: this.opts.sdkVersion,
2699
2739
  ...this.opts.environment
2700
2740
  };
2701
- this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), tr), 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 && ur.add(this.cspKey), document.addEventListener("securitypolicyviolation", mr), fr.add(this), this.noteCspBlocked(), this.onVisibility());
2741
+ this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), ar), 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 && mr.add(this.cspKey), document.addEventListener("securitypolicyviolation", vr), gr.add(this), this.noteCspBlocked(), this.onVisibility());
2702
2742
  }
2703
2743
  checkSuspension(e) {
2704
2744
  if (this.endedFlag || !this.opts.idleMs) return !1;
2705
- let t = Math.max(this.opts.idleMs, $n);
2745
+ let t = Math.max(this.opts.idleMs, rr);
2706
2746
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
2707
2747
  }
2708
2748
  syncIdle(e) {
@@ -2723,14 +2763,14 @@ var _r = class {
2723
2763
  } else e === "buffering" && (this.isBuffering = !1, this.stallIsSeekInduced = !1);
2724
2764
  this.syncBuffering(), t === "paused" && (this.pauseCount += 1), this.syncIdle(t);
2725
2765
  let a = {
2726
- fromState: sr[e] ?? "PLAYER_STATE_UNSPECIFIED",
2727
- toState: sr[t] ?? "PLAYER_STATE_UNSPECIFIED",
2728
- presentation: ir[this.presentation]
2766
+ fromState: dr[e] ?? "PLAYER_STATE_UNSPECIFIED",
2767
+ toState: dr[t] ?? "PLAYER_STATE_UNSPECIFIED",
2768
+ presentation: cr[this.presentation]
2729
2769
  }, o = this.causeOf(e, t, i);
2730
2770
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
2731
2771
  }
2732
2772
  seekInduced(e) {
2733
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < rr;
2773
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < sr;
2734
2774
  }
2735
2775
  causeOf(e, t, n) {
2736
2776
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -2804,7 +2844,7 @@ var _r = class {
2804
2844
  let r = n ?? "";
2805
2845
  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";
2806
2846
  if (e === "DRM_CLIENT" || e === "DRM_DEVICE_REVOKED") return "ERROR_STAGE_DRM";
2807
- if (or.has(e)) return "ERROR_STAGE_RESOLVE";
2847
+ if (ur.has(e)) return "ERROR_STAGE_RESOLVE";
2808
2848
  let i = t ?? "";
2809
2849
  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";
2810
2850
  }
@@ -2836,7 +2876,7 @@ var _r = class {
2836
2876
  let l = t.droppedFrames ?? 0;
2837
2877
  l > this.lastDropped && (o.droppedFramesDelta = l - this.lastDropped), this.lastDropped = l;
2838
2878
  let u = t.renditionSwitches ?? 0;
2839
- 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 = sr[t.state] ?? "PLAYER_STATE_UNSPECIFIED";
2879
+ 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 = dr[t.state] ?? "PLAYER_STATE_UNSPECIFIED";
2840
2880
  let d = this.mutedTotalMs;
2841
2881
  this.mutedSinceMs !== null && (d += e - this.mutedSinceMs), d > this.lastHbMutedMs && (o.mutedMsDelta = Math.round(d - this.lastHbMutedMs)), this.lastHbMutedMs = d;
2842
2882
  let f = t.upshifts ?? 0;
@@ -2858,13 +2898,13 @@ var _r = class {
2858
2898
  maybeEmitMediaInfo(e) {
2859
2899
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
2860
2900
  let t = {};
2861
- e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = ar[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);
2901
+ e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = lr[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);
2862
2902
  let n = JSON.stringify(t);
2863
2903
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
2864
2904
  }
2865
2905
  end(e, t) {
2866
2906
  if (this.endedFlag) return;
2867
- this.endedFlag = !0, fr.delete(this);
2907
+ this.endedFlag = !0, gr.delete(this);
2868
2908
  let n = t ?? this.now();
2869
2909
  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));
2870
2910
  let r = this.safeSample();
@@ -2878,7 +2918,7 @@ var _r = class {
2878
2918
  let c = r?.positionMs ?? 0;
2879
2919
  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));
2880
2920
  let l = e !== "END_REASON_ENDED";
2881
- l && this.lastStallMs > 0 && n - this.lastStallMs <= nr && (i.abandonAfterStallMs = Math.max(Z, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= nr && (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);
2921
+ l && this.lastStallMs > 0 && n - this.lastStallMs <= or && (i.abandonAfterStallMs = Math.max(Z, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= or && (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);
2882
2922
  let u = r?.decodedFrames ?? this.lastDecoded;
2883
2923
  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");
2884
2924
  }
@@ -2898,13 +2938,13 @@ var _r = class {
2898
2938
  };
2899
2939
  }
2900
2940
  noteCspBlocked() {
2901
- this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(pr(new URL(this.url).origin)));
2941
+ this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(_r(new URL(this.url).origin)));
2902
2942
  }
2903
2943
  cspBlocked() {
2904
- return !!this.cspKey && dr.has(this.cspKey);
2944
+ return !!this.cspKey && hr.has(this.cspKey);
2905
2945
  }
2906
2946
  enqueue(e) {
2907
- if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > er;) {
2947
+ if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > ir;) {
2908
2948
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
2909
2949
  this.pending.splice(e >= 0 ? e : 0, 1);
2910
2950
  }
@@ -2931,7 +2971,7 @@ var _r = class {
2931
2971
  };
2932
2972
  //#endregion
2933
2973
  //#region src/core/environment.ts
2934
- function vr() {
2974
+ function Sr() {
2935
2975
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
2936
2976
  let e;
2937
2977
  try {
@@ -2956,14 +2996,14 @@ function vr() {
2956
2996
  integration: "INTEGRATION_KIND_IFRAME"
2957
2997
  };
2958
2998
  }
2959
- function yr() {
2999
+ function Cr() {
2960
3000
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
2961
3001
  let e = navigator.userAgentData, t = e?.platform ?? "";
2962
3002
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
2963
3003
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
2964
3004
  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";
2965
3005
  }
2966
- function br() {
3006
+ function wr() {
2967
3007
  let e = typeof navigator < "u" ? navigator.connection : void 0;
2968
3008
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
2969
3009
  let t = {
@@ -2982,17 +3022,17 @@ function br() {
2982
3022
  }
2983
3023
  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;
2984
3024
  }
2985
- function xr(e) {
2986
- let t = vr(), n = {
2987
- deviceClass: yr(),
3025
+ function Tr(e) {
3026
+ let t = Sr(), n = {
3027
+ deviceClass: Cr(),
2988
3028
  integration: t.integration,
2989
- ...br()
3029
+ ...wr()
2990
3030
  };
2991
3031
  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);
2992
3032
  let r = e.getBoundingClientRect?.();
2993
3033
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
2994
3034
  }
2995
- async function Sr() {
3035
+ async function Er() {
2996
3036
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
2997
3037
  if (!e?.getHighEntropyValues) return {};
2998
3038
  try {
@@ -3004,7 +3044,7 @@ async function Sr() {
3004
3044
  }
3005
3045
  //#endregion
3006
3046
  //#region src/core/version.ts
3007
- var Cr = "2.26.0", wr = {
3047
+ var Dr = "2.27.0", Or = {
3008
3048
  accent: "#E1B600",
3009
3049
  accentText: "#1B1C23",
3010
3050
  background: "#0e0f13",
@@ -3015,7 +3055,7 @@ var Cr = "2.26.0", wr = {
3015
3055
  border: "rgba(255, 255, 255, 0.1)",
3016
3056
  radius: "8px",
3017
3057
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
3018
- }, Tr = {
3058
+ }, kr = {
3019
3059
  accent: "--havik-accent",
3020
3060
  accentText: "--havik-accent-text",
3021
3061
  background: "--havik-bg",
@@ -3027,26 +3067,26 @@ var Cr = "2.26.0", wr = {
3027
3067
  radius: "--havik-radius",
3028
3068
  fontFamily: "--havik-font"
3029
3069
  };
3030
- function Er(e, t) {
3070
+ function Ar(e, t) {
3031
3071
  let n = {
3032
- ...wr,
3072
+ ...Or,
3033
3073
  ...t
3034
3074
  };
3035
- for (let t of Object.keys(Tr)) e.style.setProperty(Tr[t], n[t]);
3075
+ for (let t of Object.keys(kr)) e.style.setProperty(kr[t], n[t]);
3036
3076
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
3037
3077
  }
3038
3078
  //#endregion
3039
3079
  //#region src/ui/styles.ts
3040
- var Dr = "havik-player-styles", Or = "\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", kr = /* @__PURE__ */ new WeakMap();
3041
- function Ar(e = document, t) {
3042
- let n = e.querySelector(`style#${Dr}`);
3043
- if (n && (!t || kr.get(n) === t)) return;
3080
+ var jr = "havik-player-styles", Mr = "\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", Nr = /* @__PURE__ */ new WeakMap();
3081
+ function Pr(e = document, t) {
3082
+ let n = e.querySelector(`style#${jr}`);
3083
+ if (n && (!t || Nr.get(n) === t)) return;
3044
3084
  let r = e.createElement("style");
3045
- r.id = Dr, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = Or, kr.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
3085
+ r.id = jr, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = Mr, Nr.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
3046
3086
  }
3047
3087
  //#endregion
3048
3088
  //#region src/ui/icons.ts
3049
- var jr = {
3089
+ var Fr = {
3050
3090
  play: "<path d=\"M8 5v14l11-7z\"/>",
3051
3091
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
3052
3092
  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\"/>",
@@ -3060,11 +3100,11 @@ var jr = {
3060
3100
  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\"/>"
3061
3101
  };
3062
3102
  function Q(e) {
3063
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${jr[e]}</svg>`;
3103
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Fr[e]}</svg>`;
3064
3104
  }
3065
3105
  //#endregion
3066
3106
  //#region src/ui/controls.ts
3067
- var Mr = 3e3, Nr = 250, Pr = /* @__PURE__ */ new Set([
3107
+ var Ir = 3e3, Lr = 250, Rr = /* @__PURE__ */ new Set([
3068
3108
  "GONE",
3069
3109
  "NOT_FOUND",
3070
3110
  "GEO_DENIED",
@@ -3072,15 +3112,15 @@ var Mr = 3e3, Nr = 250, Pr = /* @__PURE__ */ new Set([
3072
3112
  "UNAUTHORIZED",
3073
3113
  "DRM_DEVICE_REVOKED"
3074
3114
  ]);
3075
- function Fr(e) {
3115
+ function zr(e) {
3076
3116
  let t = "This match isn't available in your country";
3077
3117
  return e ? `${t} (${e})` : t;
3078
3118
  }
3079
- var Ir = "This device can't play protected video";
3080
- function Lr(e) {
3081
- return new Rr(e);
3119
+ var Br = "This device can't play protected video";
3120
+ function Vr(e) {
3121
+ return new Hr(e);
3082
3122
  }
3083
- var Rr = class {
3123
+ var Hr = class {
3084
3124
  root;
3085
3125
  video;
3086
3126
  player;
@@ -3129,7 +3169,7 @@ var Rr = class {
3129
3169
  scrubbing = !1;
3130
3170
  offFns = [];
3131
3171
  constructor(e) {
3132
- this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Mr, 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", Ar(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");
3172
+ this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Ir, 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", Pr(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");
3133
3173
  let t = (e, t, n) => {
3134
3174
  let r = this.doc.createElement(e);
3135
3175
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -3215,7 +3255,7 @@ var Rr = class {
3215
3255
  let t = this.surfaceWasHidden;
3216
3256
  this.tapTimer = setTimeout(() => {
3217
3257
  this.tapTimer = void 0, this.toggleBar(t);
3218
- }, Nr);
3258
+ }, Lr);
3219
3259
  }
3220
3260
  toggleBar(e) {
3221
3261
  e ? this.poke() : this.hideIfIdle();
@@ -3230,16 +3270,19 @@ var Rr = class {
3230
3270
  let t = e === "loading" || e === "buffering";
3231
3271
  this.spinner.style.display = t && !this.statusBox ? "" : "none", (t || this.statusBox) && this.center.classList.add("havik-gone"), this.syncLive();
3232
3272
  }
3273
+ isGone() {
3274
+ return this.player.state === "error" && this.lastError?.code === "GONE";
3275
+ }
3233
3276
  syncStatus(e) {
3234
3277
  let t = null;
3235
3278
  if (this.statusOverlays) {
3236
- let n = this.player.offline && e !== "ended" && e !== "idle", r = !this.hasPlayed && (e === "paused" || e === "waiting");
3237
- e === "ended" ? t = "ended" : n && !r ? t = "offline" : e === "error" ? t = "error" : e === "waiting" ? t = "waiting" : !this.hasPlayed && (e === "idle" || e === "paused") && (t = "preplay");
3279
+ let n = e === "ended" || this.isGone(), r = this.player.offline && !n && e !== "idle", i = !this.hasPlayed && (e === "paused" || e === "waiting");
3280
+ n ? t = "ended" : r && !i ? t = "offline" : e === "error" ? t = "error" : e === "waiting" ? t = "waiting" : !this.hasPlayed && (e === "idle" || e === "paused") && (t = "preplay");
3238
3281
  }
3239
3282
  this.renderStatus(t);
3240
3283
  }
3241
3284
  statusMessageFor(e) {
3242
- return e === "ended" ? this.player.endedReason === "interrupted" ? this.interruptedMessage : this.endedMessage : e === "offline" ? this.offlineMessage : e === "waiting" ? this.hasPlayed ? "Reconnecting — please stand by" : "Starting soon…" : e === "error" ? this.errorMessage === void 0 ? this.lastError?.code === "GEO_DENIED" ? Fr(this.lastError.country) : this.lastError?.code === "DRM_DEVICE_REVOKED" ? Ir : this.lastError?.message ?? "Playback unavailable" : this.errorMessage : null;
3285
+ return e === "ended" ? this.isGone() ? this.endedMessage : this.player.endedReason === "interrupted" ? this.interruptedMessage : this.endedMessage : e === "offline" ? this.offlineMessage : e === "waiting" ? this.hasPlayed ? "Reconnecting — please stand by" : "Starting soon…" : e === "error" ? this.errorMessage === void 0 ? this.lastError?.code === "GEO_DENIED" ? zr(this.lastError.country) : this.lastError?.code === "DRM_DEVICE_REVOKED" ? Br : this.lastError?.message ?? "Playback unavailable" : this.errorMessage : null;
3243
3286
  }
3244
3287
  renderStatus(e) {
3245
3288
  let t = this.statusMessageFor(e);
@@ -3254,7 +3297,7 @@ var Rr = class {
3254
3297
  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);
3255
3298
  } else {
3256
3299
  let r = this.doc.createElement("div");
3257
- if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Pr.has(this.lastError.code)) {
3300
+ if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Rr.has(this.lastError.code)) {
3258
3301
  let e = this.doc.createElement("button");
3259
3302
  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);
3260
3303
  }
@@ -3295,11 +3338,11 @@ var Rr = class {
3295
3338
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
3296
3339
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
3297
3340
  }
3298
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${zr(this.video.currentTime)} / ${zr(this.video.duration)}`);
3341
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Ur(this.video.currentTime)} / ${Ur(this.video.duration)}`);
3299
3342
  }
3300
3343
  syncLive() {
3301
- let e = this.player.getStats(), t = e.isLive !== !1, n = this.player.state === "ended", r = !t && !this.streamEnded();
3302
- this.live.style.display = t && !n ? "" : "none", this.time.style.display = r ? "" : "none", this.seek.style.display = r ? "" : "none", this.live.classList.toggle("is-live", e.atLiveEdge !== !1 && t);
3344
+ let e = this.player.getStats(), t = e.isLive !== !1, n = this.isGone(), r = this.player.state === "ended" || n, i = !t && !this.streamEnded() && !n;
3345
+ this.live.style.display = t && !r ? "" : "none", this.time.style.display = i ? "" : "none", this.seek.style.display = i ? "" : "none", this.live.classList.toggle("is-live", e.atLiveEdge !== !1 && t);
3303
3346
  }
3304
3347
  onSeekDown(e) {
3305
3348
  let t = this.seekableRange();
@@ -3345,17 +3388,17 @@ var Rr = class {
3345
3388
  renderQualityMenu() {
3346
3389
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
3347
3390
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
3348
- for (let n of e) this.menu.append(this.menuItem(Br(n), t === n.index, () => this.player.setQuality(n.index)));
3391
+ for (let n of e) this.menu.append(this.menuItem(Wr(n), t === n.index, () => this.player.setQuality(n.index)));
3349
3392
  }
3350
3393
  renderAudioMenu() {
3351
3394
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
3352
3395
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
3353
- for (let t of e) this.menu.append(this.menuItem(Vr(t), t.default, () => this.player.setAudioTrack(t.id)));
3396
+ for (let t of e) this.menu.append(this.menuItem(Gr(t), t.default, () => this.player.setAudioTrack(t.id)));
3354
3397
  }
3355
3398
  renderCcMenu() {
3356
3399
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
3357
3400
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
3358
- for (let t of e) this.menu.append(this.menuItem(Hr(t), !1, () => this.player.setTextTrack(t.id)));
3401
+ for (let t of e) this.menu.append(this.menuItem(Kr(t), !1, () => this.player.setTextTrack(t.id)));
3359
3402
  }
3360
3403
  onTracksChanged() {
3361
3404
  this.openMenu && this.renderMenu(this.openMenu);
@@ -3460,23 +3503,23 @@ var Rr = class {
3460
3503
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
3461
3504
  }
3462
3505
  };
3463
- function zr(e) {
3506
+ function Ur(e) {
3464
3507
  (!Number.isFinite(e) || e < 0) && (e = 0);
3465
3508
  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");
3466
3509
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
3467
3510
  }
3468
- function Br(e) {
3511
+ function Wr(e) {
3469
3512
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
3470
3513
  }
3471
- function Vr(e) {
3514
+ function Gr(e) {
3472
3515
  return e.name || e.lang || `Track ${e.id}`;
3473
3516
  }
3474
- function Hr(e) {
3517
+ function Kr(e) {
3475
3518
  return e.name || e.lang || `Track ${e.id}`;
3476
3519
  }
3477
3520
  //#endregion
3478
3521
  //#region src/managed/index.ts
3479
- var Ur = 6e3, Wr = 45e3, Gr = 2e3, Kr = 3, qr = 5e3, Jr = 2e3, Yr = 48e4, Xr = "keySystemLicenseRequestFailed", Zr = /* @__PURE__ */ new Set([
3522
+ var qr = 6e3, Jr = 45e3, Yr = 2e3, Xr = 3, Zr = 5e3, Qr = 2e3, $r = 48e4, ei = "keySystemLicenseRequestFailed", ti = /* @__PURE__ */ new Set([
3480
3523
  "GONE",
3481
3524
  "NOT_FOUND",
3482
3525
  "INVALID_URN",
@@ -3484,27 +3527,27 @@ var Ur = 6e3, Wr = 45e3, Gr = 2e3, Kr = 3, qr = 5e3, Jr = 2e3, Yr = 48e4, Xr = "
3484
3527
  "GEO_DENIED",
3485
3528
  "DRM_DEVICE_REVOKED"
3486
3529
  ]);
3487
- function Qr(e) {
3488
- return !Zr.has(e);
3530
+ function ni(e) {
3531
+ return !ti.has(e);
3489
3532
  }
3490
- function $r(e) {
3533
+ function ri(e) {
3491
3534
  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)})`);
3492
3535
  if (e.env !== void 0) return lt(e.env);
3493
3536
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
3494
3537
  return e.baseUrl;
3495
3538
  }
3496
- async function ei(e) {
3539
+ async function ii(e) {
3497
3540
  if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
3498
- let t = $r(e);
3541
+ let t = ri(e);
3499
3542
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
3500
3543
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
3501
- let r = new ti({
3544
+ let r = new ai({
3502
3545
  ...e,
3503
3546
  baseUrl: t
3504
3547
  });
3505
3548
  return await r.start(), r;
3506
3549
  }
3507
- var ti = class {
3550
+ var ai = class {
3508
3551
  opts;
3509
3552
  abort = new AbortController();
3510
3553
  listeners = {};
@@ -3604,7 +3647,7 @@ var ti = class {
3604
3647
  setTimeout(() => {
3605
3648
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
3606
3649
  phase: i ? "unavailable" : "tooEarly",
3607
- retryInMs: Wr,
3650
+ retryInMs: Jr,
3608
3651
  attempt: 1,
3609
3652
  elapsedMs: 0,
3610
3653
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -3643,13 +3686,13 @@ var ti = class {
3643
3686
  !a && !p() && h();
3644
3687
  }, e);
3645
3688
  };
3646
- _(Ur), this.armingSub = D({
3689
+ _(qr), this.armingSub = D({
3647
3690
  eventsBaseUrl: t,
3648
3691
  matchUrn: this.opts.matchUrn,
3649
3692
  credential: this.opts.credential,
3650
- onAlive: () => _(Wr),
3693
+ onAlive: () => _(Jr),
3651
3694
  onState: (e) => {
3652
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Gr);
3695
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Yr);
3653
3696
  },
3654
3697
  onError: () => h()
3655
3698
  });
@@ -3694,19 +3737,19 @@ var ti = class {
3694
3737
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
3695
3738
  let i = e.analytics?.sid;
3696
3739
  if (!i) return;
3697
- let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = gr(this.opts.baseUrl, a, e.analytics?.endpoint);
3740
+ let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = br(this.opts.baseUrl, a, e.analytics?.endpoint);
3698
3741
  if (!o) {
3699
3742
  s && setTimeout(() => {
3700
3743
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
3701
3744
  }, 0);
3702
3745
  return;
3703
3746
  }
3704
- let c = this.opts.video, l = new _r({
3747
+ let c = this.opts.video, l = new xr({
3705
3748
  endpoint: o,
3706
3749
  sid: i,
3707
3750
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
3708
- sdkVersion: Cr,
3709
- environment: xr(c),
3751
+ sdkVersion: Dr,
3752
+ environment: Tr(c),
3710
3753
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
3711
3754
  onIdle: () => this.onAnalyticsIdle(t),
3712
3755
  onBlocked: (e) => setTimeout(() => {
@@ -3727,7 +3770,7 @@ var ti = class {
3727
3770
  let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
3728
3771
  c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
3729
3772
  c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
3730
- }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), Sr().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3773
+ }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), Er().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3731
3774
  }
3732
3775
  currentPresentation() {
3733
3776
  let e = this.opts.video;
@@ -3750,6 +3793,7 @@ var ti = class {
3750
3793
  sizeCapHeadroom: this.opts.sizeCapHeadroom,
3751
3794
  adaptiveHoldBack: this.opts.adaptiveHoldBack,
3752
3795
  adaptiveHoldBackCeiling: this.opts.adaptiveHoldBackCeiling,
3796
+ stallCap: this.opts.stallCap,
3753
3797
  mediaDuringKey: this.opts.mediaDuringKey,
3754
3798
  preloadHints: this.opts.preloadHints,
3755
3799
  debug: this.opts.debug,
@@ -3759,9 +3803,9 @@ var ti = class {
3759
3803
  freshLicenseUrl: () => this.refreshLicense()
3760
3804
  }, o = this.opts.engine ?? "auto";
3761
3805
  if (o === "native") return new H(a);
3762
- if (o === "hls") return new Xn(a);
3806
+ if (o === "hls") return new er(a);
3763
3807
  if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && B(this.opts.video) && V() || !e.drmEnabled && Ot() && B(this.opts.video)) return new H(a);
3764
- if (Wt()) return new Xn(a);
3808
+ if (Wt()) return new er(a);
3765
3809
  if (B(this.opts.video)) return new H(a);
3766
3810
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
3767
3811
  }
@@ -3832,7 +3876,7 @@ var ti = class {
3832
3876
  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."));
3833
3877
  return;
3834
3878
  }
3835
- i += 1, i >= Kr && (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.`)));
3879
+ i += 1, i >= Xr && (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.`)));
3836
3880
  }
3837
3881
  }
3838
3882
  });
@@ -3849,7 +3893,7 @@ var ti = class {
3849
3893
  }
3850
3894
  if (this.emit("online"), this._state !== "error" || !this._lastError) return;
3851
3895
  let t = this._lastError.code;
3852
- Qr(t) && (t === "NETWORK" || this.failedWhileOffline) && this.retry().catch(() => void 0);
3896
+ ni(t) && (t === "NETWORK" || this.failedWhileOffline) && this.retry().catch(() => void 0);
3853
3897
  }));
3854
3898
  }
3855
3899
  watchReturn() {
@@ -3859,7 +3903,7 @@ var ti = class {
3859
3903
  return;
3860
3904
  }
3861
3905
  let e = this.hiddenAtMs;
3862
- this.hiddenAtMs = null, e != null && Date.now() - e >= qr && this.resyncLiveState();
3906
+ this.hiddenAtMs = null, e != null && Date.now() - e >= Zr && this.resyncLiveState();
3863
3907
  }, this.onReturnPageShow = (e) => {
3864
3908
  e.persisted && this.resyncLiveState();
3865
3909
  }, document.addEventListener("visibilitychange", this.onReturnVisible), typeof window < "u" && window.addEventListener("pageshow", this.onReturnPageShow));
@@ -3891,7 +3935,7 @@ var ti = class {
3891
3935
  scheduleRejoin(e) {
3892
3936
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
3893
3937
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
3894
- }, Math.random() * Gr));
3938
+ }, Math.random() * Yr));
3895
3939
  }
3896
3940
  cancelRejoin() {
3897
3941
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -3915,7 +3959,7 @@ var ti = class {
3915
3959
  }
3916
3960
  t.controls = !1;
3917
3961
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
3918
- r && r.insertBefore(n, t), n.appendChild(t), Er(n, this.opts.theme), this.container = n, this.controlBar = Lr({
3962
+ r && r.insertBefore(n, t), n.appendChild(t), Ar(n, this.opts.theme), this.container = n, this.controlBar = Vr({
3919
3963
  root: n,
3920
3964
  video: t,
3921
3965
  player: this,
@@ -3954,7 +3998,7 @@ var ti = class {
3954
3998
  }
3955
3999
  startStats() {
3956
4000
  this.stopStats();
3957
- let e = Math.max(500, this.opts.statsIntervalMs ?? Jr);
4001
+ let e = Math.max(500, this.opts.statsIntervalMs ?? Qr);
3958
4002
  this.statsTimer = setInterval(() => {
3959
4003
  if (!this.engine) return;
3960
4004
  let e = this.engine.getStats();
@@ -3965,14 +4009,14 @@ var ti = class {
3965
4009
  this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
3966
4010
  }
3967
4011
  isStaleLicenseDenial(e) {
3968
- return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== Xr || e.error.httpStatus !== 403 || e.error.code !== "FORBIDDEN" || e.error.serverCode === "license_refused" ? !1 : W(this._descriptor?.drm?.widevine?.licenseUrl);
4012
+ return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== ei || e.error.httpStatus !== 403 || e.error.code !== "FORBIDDEN" || e.error.serverCode === "license_refused" ? !1 : W(this._descriptor?.drm?.widevine?.licenseUrl);
3969
4013
  }
3970
4014
  scheduleLicenseRefresh() {
3971
4015
  if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
3972
4016
  typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
3973
4017
  document.visibilityState !== "visible" || this.destroyed || W(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
3974
4018
  }, document.addEventListener("visibilitychange", this.onRefocus));
3975
- let e = this.opts.licenseRefreshMs ?? Yr;
4019
+ let e = this.opts.licenseRefreshMs ?? $r;
3976
4020
  e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
3977
4021
  }
3978
4022
  stopRefresh() {
@@ -4142,7 +4186,7 @@ function $(e) {
4142
4186
  }
4143
4187
  //#endregion
4144
4188
  //#region src/embed/host.ts
4145
- function ni(e) {
4189
+ function oi(e) {
4146
4190
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
4147
4191
  if (!e.src) throw Error("mountEmbed: opts.src is required");
4148
4192
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -4201,15 +4245,15 @@ function ni(e) {
4201
4245
  }
4202
4246
  //#endregion
4203
4247
  //#region src/embed/page.ts
4204
- var ri = /^[A-Za-z0-9:_.-]{1,128}$/;
4205
- function ii(e) {
4248
+ var si = /^[A-Za-z0-9:_.-]{1,128}$/;
4249
+ function ci(e) {
4206
4250
  if (typeof e == "boolean") return e;
4207
4251
  if (typeof e == "object" && e) {
4208
4252
  let t = e.endpoint;
4209
4253
  return typeof t == "string" ? { endpoint: t } : {};
4210
4254
  }
4211
4255
  }
4212
- function ai() {
4256
+ function li() {
4213
4257
  let e = window.HAVIK_EMBED_CONFIG;
4214
4258
  if (e) return {
4215
4259
  baseUrl: e.baseUrl ?? "",
@@ -4219,7 +4263,7 @@ function ai() {
4219
4263
  autoplay: e.autoplay ?? !0,
4220
4264
  muted: e.muted ?? !0,
4221
4265
  waitForLive: e.waitForLive ?? !0,
4222
- analytics: ii(e.analytics)
4266
+ analytics: ci(e.analytics)
4223
4267
  };
4224
4268
  let t = new URLSearchParams(location.search);
4225
4269
  return {
@@ -4232,9 +4276,9 @@ function ai() {
4232
4276
  waitForLive: !0
4233
4277
  };
4234
4278
  }
4235
- async function oi() {
4236
- let e = ai();
4237
- ci();
4279
+ async function ui() {
4280
+ let e = li();
4281
+ fi();
4238
4282
  let t = document.createElement("video");
4239
4283
  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);
4240
4284
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -4290,12 +4334,12 @@ async function oi() {
4290
4334
  message: e.message,
4291
4335
  ...e.country === void 0 ? {} : { country: e.country }
4292
4336
  })), e.on("autoplayblocked", () => {
4293
- i({ type: "oddin:autoplayblocked" }), si(t, e);
4337
+ i({ type: "oddin:autoplayblocked" }), di(t, e);
4294
4338
  });
4295
4339
  }, s = async (r) => {
4296
4340
  a?.destroy(), a = null;
4297
4341
  try {
4298
- let n = await ei({
4342
+ let n = await ii({
4299
4343
  video: t,
4300
4344
  baseUrl: e.baseUrl,
4301
4345
  matchUrn: r,
@@ -4358,7 +4402,7 @@ async function oi() {
4358
4402
  a?.retry();
4359
4403
  break;
4360
4404
  case "oddin:load":
4361
- typeof e.matchUrn == "string" && ri.test(e.matchUrn) && s(e.matchUrn);
4405
+ typeof e.matchUrn == "string" && si.test(e.matchUrn) && s(e.matchUrn);
4362
4406
  break;
4363
4407
  case "oddin:destroy": c();
4364
4408
  }
@@ -4370,18 +4414,18 @@ async function oi() {
4370
4414
  protocol: 1
4371
4415
  });
4372
4416
  }
4373
- function si(e, t) {
4417
+ function di(e, t) {
4374
4418
  if (document.getElementById("havik-tap")) return;
4375
4419
  let n = document.createElement("button");
4376
4420
  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", () => {
4377
4421
  n.remove(), t.play();
4378
4422
  }), document.body.appendChild(n);
4379
4423
  }
4380
- function ci() {
4424
+ function fi() {
4381
4425
  let e = document.createElement("style");
4382
4426
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
4383
4427
  }
4384
4428
  //#endregion
4385
- export { E as LiveStateHttpError, wr as ODDIN_THEME, n as PlaybackError, Er as applyTheme, lt as baseUrlForEnv, oi as bootEmbed, ke as clearDeviceId, He as clearRememberedBandwidth, ei 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, ni as mountEmbed, fe as pollToLive, y as resolveStream, D as subscribeLiveState, S as videoFullscreenActive, we as watchStatus };
4429
+ export { E as LiveStateHttpError, Or as ODDIN_THEME, n as PlaybackError, Ar as applyTheme, lt as baseUrlForEnv, ui as bootEmbed, ke as clearDeviceId, He as clearRememberedBandwidth, ii 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, oi as mountEmbed, fe as pollToLive, y as resolveStream, D as subscribeLiveState, S as videoFullscreenActive, we as watchStatus };
4386
4430
 
4387
4431
  //# sourceMappingURL=index.js.map