@oddin-gg/havik-player 2.17.0 → 2.19.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
@@ -174,7 +174,7 @@ function ue(e, t) {
174
174
  t?.addEventListener("abort", a, { once: !0 });
175
175
  });
176
176
  }
177
- async function v(e, t, r) {
177
+ async function de(e, t, r) {
178
178
  let i = ae(t), a = Date.now(), s = i.timeoutMs == null ? Infinity : a + i.timeoutMs, c = 0, l;
179
179
  for (;;) {
180
180
  if (r?.aborted) throw new n("ABORTED", 0, "wait-for-live aborted");
@@ -200,21 +200,21 @@ async function v(e, t, r) {
200
200
  }
201
201
  //#endregion
202
202
  //#region src/core/resolve.ts
203
- async function y(e) {
203
+ async function v(e) {
204
204
  if (!e.matchUrn || typeof e.matchUrn != "string") throw new n("INVALID_URN", 0, "resolveStream: a non-empty matchUrn is required");
205
205
  let t = await p(d(e.baseUrl, `/v1/playback/${encodeURIComponent(e.matchUrn)}`), {
206
206
  credential: e.credential,
207
207
  signal: e.signal,
208
208
  apiHeaders: e.apiHeaders
209
209
  });
210
- if (!t.ok) throw await de(t);
211
- return me(await t.json(), e.matchUrn);
210
+ if (!t.ok) throw await fe(t);
211
+ return he(await t.json(), e.matchUrn);
212
212
  }
213
- function b(e) {
214
- let t = () => y(e);
215
- return e.waitForLive ? v(t, e.waitForLive, e.signal) : t();
213
+ function y(e) {
214
+ let t = () => v(e);
215
+ return e.waitForLive ? de(t, e.waitForLive, e.signal) : t();
216
216
  }
217
- async function de(e) {
217
+ async function fe(e) {
218
218
  let t = f(e.headers.get("retry-after")), i = e.headers.get("x-request-id") ?? e.headers.get("x-amzn-requestid") ?? void 0, a = e.statusText || `HTTP ${e.status}`, o, s;
219
219
  try {
220
220
  let t = await e.json();
@@ -230,7 +230,7 @@ async function de(e) {
230
230
  liveStartsAtMs: s
231
231
  });
232
232
  }
233
- var fe = /* @__PURE__ */ new Set([
233
+ var pe = /* @__PURE__ */ new Set([
234
234
  "matchUrn",
235
235
  "protocol",
236
236
  "drmEnabled",
@@ -241,7 +241,7 @@ var fe = /* @__PURE__ */ new Set([
241
241
  "expiresAt",
242
242
  "analytics"
243
243
  ]);
244
- function x(e, t) {
244
+ function b(e, t) {
245
245
  let r;
246
246
  try {
247
247
  r = new URL(t);
@@ -251,7 +251,7 @@ function x(e, t) {
251
251
  if (r.protocol !== "https:" && r.protocol !== "http:") throw new n("INTERNAL", 0, `playback ${e} has a disallowed scheme: ${r.protocol}`);
252
252
  return t;
253
253
  }
254
- function pe(e) {
254
+ function me(e) {
255
255
  if (e !== void 0) {
256
256
  if (typeof e == "string" && !e.endsWith("/")) try {
257
257
  let t = new URL(e);
@@ -260,57 +260,64 @@ function pe(e) {
260
260
  g(`server analytics.endpoint ${JSON.stringify(e)} ignored: not a bare https origin.`);
261
261
  }
262
262
  }
263
- function me(e, t) {
263
+ function he(e, t) {
264
264
  if (!e.manifestUrl) throw new n("INTERNAL", 0, "playback response is missing manifestUrl");
265
265
  let r = e.drmEnabled ?? !!e.drm, i = {
266
266
  matchUrn: e.matchUrn ?? t,
267
267
  protocol: "hls",
268
268
  drmEnabled: r,
269
- manifestUrl: x("manifestUrl", e.manifestUrl),
269
+ manifestUrl: b("manifestUrl", e.manifestUrl),
270
270
  serverTime: e.serverTime ?? ""
271
271
  };
272
272
  if (e.liveStartsAt && (i.liveStartsAt = e.liveStartsAt), typeof e.analytics?.sid == "string" && e.analytics.sid) {
273
273
  i.analytics = { sid: e.analytics.sid };
274
- let t = pe(e.analytics.endpoint);
274
+ let t = me(e.analytics.endpoint);
275
275
  t && (i.analytics.endpoint = t);
276
276
  }
277
277
  if (r && e.drm) {
278
278
  let t = {};
279
- e.drm.widevine?.licenseUrl && (t.widevine = { licenseUrl: x("widevine licenseUrl", e.drm.widevine.licenseUrl) }), e.drm.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && (t.fairplay = {
280
- licenseUrl: x("fairplay licenseUrl", e.drm.fairplay.licenseUrl),
281
- certificateUrl: x("fairplay certificateUrl", e.drm.fairplay.certificateUrl)
279
+ e.drm.widevine?.licenseUrl && (t.widevine = { licenseUrl: b("widevine licenseUrl", e.drm.widevine.licenseUrl) }), e.drm.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && (t.fairplay = {
280
+ licenseUrl: b("fairplay licenseUrl", e.drm.fairplay.licenseUrl),
281
+ certificateUrl: b("fairplay certificateUrl", e.drm.fairplay.certificateUrl)
282
282
  }), (t.widevine || t.fairplay) && (i.drm = t);
283
283
  }
284
284
  let a = {};
285
- for (let [t, n] of Object.entries(e)) fe.has(t) || (a[t] = n);
285
+ for (let [t, n] of Object.entries(e)) pe.has(t) || (a[t] = n);
286
286
  return Object.keys(a).length > 0 && (i.extensions = a), i;
287
287
  }
288
288
  //#endregion
289
289
  //#region src/core/fullscreen.ts
290
- function he(e) {
290
+ function x(e) {
291
291
  return e.ownerDocument ?? document;
292
292
  }
293
293
  function ge(e) {
294
294
  return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
295
295
  }
296
296
  function S(e, t) {
297
- let n = ge(he(e));
297
+ let n = ge(x(e));
298
298
  return n != null && (n === e || t != null && n === t) || e.webkitDisplayingFullscreen === !0;
299
299
  }
300
- async function C(e, t) {
300
+ function C(e, t) {
301
+ let n = t ?? e, r = x(e);
302
+ if (typeof n.requestFullscreen == "function") return r.fullscreenEnabled !== !1;
303
+ if (typeof n.webkitRequestFullscreen == "function") return r.webkitFullscreenEnabled !== !1;
304
+ let i = e;
305
+ return i.webkitSupportsFullscreen === !0 && typeof i.webkitEnterFullscreen == "function" || e.readyState < 1;
306
+ }
307
+ async function w(e, t) {
301
308
  let n = t ?? e;
302
309
  if (typeof n.requestFullscreen == "function") return await n.requestFullscreen(), !0;
303
310
  if (typeof n.webkitRequestFullscreen == "function") return n.webkitRequestFullscreen(), !0;
304
311
  let r = e;
305
312
  return r.webkitSupportsFullscreen && typeof r.webkitEnterFullscreen == "function" ? (r.webkitEnterFullscreen(), !0) : !1;
306
313
  }
307
- async function w(e, t) {
314
+ async function T(e, t) {
308
315
  let n = e;
309
316
  if (n.webkitDisplayingFullscreen) {
310
317
  n.webkitExitFullscreen?.();
311
318
  return;
312
319
  }
313
- let r = he(e), i = ge(r);
320
+ let r = x(e), i = ge(r);
314
321
  i != null && (i === e || t != null && i === t) && (typeof r.exitFullscreen == "function" ? await r.exitFullscreen() : r.webkitExitFullscreen?.());
315
322
  }
316
323
  //#endregion
@@ -462,7 +469,7 @@ function Ce(e) {
462
469
  //#endregion
463
470
  //#region src/core/events.ts
464
471
  var we = 45e3;
465
- function T(e) {
472
+ function E(e) {
466
473
  let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = e.idleTimeoutMs ?? we, i = Number.isFinite(r) && r > 0 ? r : 0, a = new AbortController(), o = !1, c = (e) => new Promise((t) => {
467
474
  if (a.signal.aborted) return t();
468
475
  let n = setTimeout(t, e);
@@ -545,7 +552,7 @@ function T(e) {
545
552
  o || (o = !0, a.abort());
546
553
  } };
547
554
  }
548
- function E(e) {
555
+ function D(e) {
549
556
  try {
550
557
  let t = new URL(e);
551
558
  return t.hostname = `events.${t.hostname}`, t.pathname = "", t.search = "", t.origin;
@@ -555,24 +562,24 @@ function E(e) {
555
562
  }
556
563
  //#endregion
557
564
  //#region src/core/drm/deviceId.ts
558
- var D = "havik.player.deviceId", O;
559
- function k() {
560
- if (O) return O;
565
+ var O = "havik.player.deviceId", k;
566
+ function A() {
567
+ if (k) return k;
561
568
  try {
562
- let e = globalThis.localStorage?.getItem(D);
563
- if (e) return O = e, e;
569
+ let e = globalThis.localStorage?.getItem(O);
570
+ if (e) return k = e, e;
564
571
  } catch {}
565
572
  let e = Ee();
566
- O = e;
573
+ k = e;
567
574
  try {
568
- globalThis.localStorage?.setItem(D, e);
575
+ globalThis.localStorage?.setItem(O, e);
569
576
  } catch {}
570
577
  return e;
571
578
  }
572
579
  function Te() {
573
- O = void 0;
580
+ k = void 0;
574
581
  try {
575
- globalThis.localStorage?.removeItem(D);
582
+ globalThis.localStorage?.removeItem(O);
576
583
  } catch {}
577
584
  }
578
585
  function Ee() {
@@ -591,17 +598,65 @@ function De(e, t, n = {}) {
591
598
  let r = {
592
599
  "x-api-key": t.apiKey,
593
600
  "X-Match-Urn": e.matchUrn,
594
- "X-Device-Id": n.deviceId ?? k(),
601
+ "X-Device-Id": n.deviceId ?? A(),
595
602
  "Content-Type": "application/octet-stream"
596
603
  };
597
604
  return n.userId && (r["X-User-Id"] = n.userId), r;
598
605
  }
599
606
  //#endregion
607
+ //#region src/core/bandwidthMemory.ts
608
+ var j = "havik.player.bandwidth", Oe = .8, ke = 2e7, Ae = 3e5;
609
+ function M() {
610
+ return globalThis.navigator?.connection;
611
+ }
612
+ function je() {
613
+ let e = M()?.type;
614
+ return typeof e == "string" && e !== "" && e !== "unknown" ? e : "any";
615
+ }
616
+ function Me() {
617
+ let e = M()?.downlink;
618
+ return typeof e == "number" && Number.isFinite(e) && e > 0 ? e * 1e6 : void 0;
619
+ }
620
+ function Ne() {
621
+ try {
622
+ let e = globalThis.localStorage?.getItem(j);
623
+ if (!e) return {};
624
+ let t = JSON.parse(e);
625
+ return t && typeof t == "object" && !Array.isArray(t) ? t : {};
626
+ } catch {
627
+ return {};
628
+ }
629
+ }
630
+ function Pe(e = Date.now()) {
631
+ let t = Ne()[je()];
632
+ if (!t || typeof t.bps != "number" || typeof t.at != "number" || !Number.isFinite(t.bps) || t.bps <= 0) return;
633
+ let n = e - t.at;
634
+ if (n < 0 || n > 2592e5) return;
635
+ let r = Me(), i = r === void 0 ? t.bps : Math.min(t.bps, r);
636
+ return Math.round(Math.min(ke, Math.max(Ae, i * Oe)));
637
+ }
638
+ function Fe(e, t = Date.now()) {
639
+ if (!Number.isFinite(e) || e <= 0) return;
640
+ let n = Ne();
641
+ n[je()] = {
642
+ bps: Math.round(e),
643
+ at: t
644
+ };
645
+ try {
646
+ globalThis.localStorage?.setItem(j, JSON.stringify(n));
647
+ } catch {}
648
+ }
649
+ function Ie() {
650
+ try {
651
+ globalThis.localStorage?.removeItem(j);
652
+ } catch {}
653
+ }
654
+ //#endregion
600
655
  //#region src/core/drm/cdm.ts
601
- var A = /* @__PURE__ */ new WeakMap();
602
- function Oe(e, t) {
603
- let n = A.get(e);
604
- n || (n = /* @__PURE__ */ new Map(), A.set(e, n));
656
+ var Le = /* @__PURE__ */ new WeakMap();
657
+ function Re(e, t) {
658
+ let n = Le.get(e);
659
+ n || (n = /* @__PURE__ */ new Map(), Le.set(e, n));
605
660
  let r = n.get(t.keySystem);
606
661
  if (r) return r;
607
662
  let i = t.createMediaKeys().catch((e) => {
@@ -609,22 +664,22 @@ function Oe(e, t) {
609
664
  });
610
665
  return n.set(t.keySystem, i), i;
611
666
  }
612
- function j() {
667
+ function N() {
613
668
  return typeof navigator < "u" && typeof navigator.requestMediaKeySystemAccess == "function";
614
669
  }
615
- var M = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
616
- function ke(e) {
670
+ var P = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
671
+ function ze(e) {
617
672
  return e.startsWith("com.widevine");
618
673
  }
619
- function N(e, t) {
620
- if (!ke(e)) return t;
674
+ function F(e, t) {
675
+ if (!ze(e)) return t;
621
676
  let n = (e, t) => {
622
677
  let n = e.videoCapabilities;
623
678
  return !n?.length || !n.some((e) => e.robustness) ? !1 : n.every((e) => {
624
- let n = M.indexOf(e.robustness);
625
- return n === -1 || M.indexOf(t) > n;
679
+ let n = P.indexOf(e.robustness);
680
+ return n === -1 || P.indexOf(t) > n;
626
681
  });
627
- }, r = M.flatMap((e) => t.filter((t) => n(t, e)).map((t) => ({
682
+ }, r = P.flatMap((e) => t.filter((t) => n(t, e)).map((t) => ({
628
683
  ...t,
629
684
  videoCapabilities: t.videoCapabilities?.map((t) => ({
630
685
  ...t,
@@ -633,53 +688,53 @@ function N(e, t) {
633
688
  })));
634
689
  return [...t, ...r];
635
690
  }
636
- function P(e) {
637
- return (t, n) => j() ? navigator.requestMediaKeySystemAccess(t, N(t, n)).then((t) => ({
691
+ function Be(e) {
692
+ return (t, n) => N() ? navigator.requestMediaKeySystemAccess(t, F(t, n)).then((t) => ({
638
693
  keySystem: t.keySystem,
639
694
  getConfiguration: () => t.getConfiguration(),
640
- createMediaKeys: () => Oe(e, t)
695
+ createMediaKeys: () => Re(e, t)
641
696
  })) : Promise.reject(/* @__PURE__ */ Error("navigator.requestMediaKeySystemAccess is unavailable — EME needs a secure context (https, or localhost)"));
642
697
  }
643
- var F = {
698
+ var I = {
644
699
  video: "SW_SECURE_DECODE",
645
700
  audio: "SW_SECURE_CRYPTO",
646
701
  scheme: "cbcs"
647
702
  };
648
- function Ae(e) {
649
- if (!j()) return;
703
+ function Ve(e) {
704
+ if (!N()) return;
650
705
  let t = (e, t) => ({
651
706
  contentType: e,
652
707
  robustness: t,
653
- encryptionScheme: F.scheme
708
+ encryptionScheme: I.scheme
654
709
  });
655
- P(e)("com.widevine.alpha", [{
710
+ Be(e)("com.widevine.alpha", [{
656
711
  initDataTypes: ["cenc"],
657
712
  distinctiveIdentifier: "optional",
658
713
  persistentState: "optional",
659
714
  sessionTypes: ["temporary"],
660
- audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"", F.audio)],
661
- videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"", F.video)]
715
+ audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"", I.audio)],
716
+ videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"", I.video)]
662
717
  }]).then((e) => e.createMediaKeys()).catch(() => {});
663
718
  }
664
- function I(e) {
665
- let t = L(e);
719
+ function L(e) {
720
+ let t = R(e);
666
721
  if (/^avc[13]/.test(t)) return "avc";
667
722
  if (/^(hvc1|hev1)/.test(t)) return "hevc";
668
723
  if (/^(dvh1|dvhe)/.test(t)) return "dv";
669
724
  if (t.startsWith("av01")) return "av1";
670
725
  if (/^vp0?9/.test(t)) return "vp9";
671
726
  }
672
- function L(e) {
727
+ function R(e) {
673
728
  return (e ?? "").trim().toLowerCase();
674
729
  }
675
- var R = {
730
+ var He = {
676
731
  hevc: "hvc1.1.6.L93.90",
677
732
  dv: "dvh1.05.06",
678
733
  av1: "av01.0.05M.08",
679
734
  vp9: "vp09.00.10.08"
680
- }, je = /* @__PURE__ */ new Map(), z = /* @__PURE__ */ new Map();
681
- function Me(e) {
682
- let t = L(e), n = je.get(t);
735
+ }, Ue = /* @__PURE__ */ new Map(), z = /* @__PURE__ */ new Map();
736
+ function We(e) {
737
+ let t = R(e), n = Ue.get(t);
683
738
  if (n) return n;
684
739
  let r = {
685
740
  initDataTypes: ["cenc"],
@@ -688,32 +743,32 @@ function Me(e) {
688
743
  sessionTypes: ["temporary"],
689
744
  videoCapabilities: [{
690
745
  contentType: `video/mp4; codecs="${e.trim()}"`,
691
- robustness: F.video,
692
- encryptionScheme: F.scheme
746
+ robustness: I.video,
747
+ encryptionScheme: I.scheme
693
748
  }]
694
749
  }, i = (async () => {
695
750
  try {
696
- return await navigator.requestMediaKeySystemAccess("com.widevine.alpha", N("com.widevine.alpha", [r])), !0;
751
+ return await navigator.requestMediaKeySystemAccess("com.widevine.alpha", F("com.widevine.alpha", [r])), !0;
697
752
  } catch {
698
753
  return !1;
699
754
  }
700
755
  })().then((e) => (z.set(t, e), e));
701
- return je.set(t, i), i;
756
+ return Ue.set(t, i), i;
702
757
  }
703
- function Ne() {
704
- if (j()) for (let e of Object.values(R)) Me(e);
758
+ function Ge() {
759
+ if (N()) for (let e of Object.values(He)) We(e);
705
760
  }
706
- function Pe(e) {
707
- let t = I(e);
708
- if (t) return t === "avc" ? !0 : z.get(L(e)) ?? z.get(L(R[t]));
761
+ function Ke(e) {
762
+ let t = L(e);
763
+ if (t) return t === "avc" ? !0 : z.get(R(e)) ?? z.get(R(He[t]));
709
764
  }
710
765
  //#endregion
711
766
  //#region src/core/drm/support.ts
712
- var Fe = 5e3, Ie = "video/mp4; codecs=\"avc1.42E01E\"", Le = "audio/mp4; codecs=\"mp4a.40.2\"", Re = {
767
+ var qe = 5e3, Je = "video/mp4; codecs=\"avc1.42E01E\"", Ye = "audio/mp4; codecs=\"mp4a.40.2\"", Xe = {
713
768
  widevine: ["com.widevine.alpha"],
714
769
  fairplay: ["com.apple.fps"]
715
770
  };
716
- function ze(e) {
771
+ function Ze(e) {
717
772
  return e === "fairplay" ? [{
718
773
  initDataTypes: [
719
774
  "sinf",
@@ -721,30 +776,30 @@ function ze(e) {
721
776
  "cenc"
722
777
  ],
723
778
  videoCapabilities: [{
724
- contentType: Ie,
779
+ contentType: Je,
725
780
  robustness: "",
726
781
  encryptionScheme: "cbcs"
727
782
  }],
728
783
  audioCapabilities: [{
729
- contentType: Le,
784
+ contentType: Ye,
730
785
  robustness: "",
731
786
  encryptionScheme: "cbcs"
732
787
  }]
733
- }] : N("com.widevine.alpha", [{
788
+ }] : F("com.widevine.alpha", [{
734
789
  initDataTypes: ["cenc"],
735
790
  videoCapabilities: [{
736
- contentType: Ie,
737
- robustness: F.video,
738
- encryptionScheme: F.scheme
791
+ contentType: Je,
792
+ robustness: I.video,
793
+ encryptionScheme: I.scheme
739
794
  }],
740
795
  audioCapabilities: [{
741
- contentType: Le,
742
- robustness: F.audio,
743
- encryptionScheme: F.scheme
796
+ contentType: Ye,
797
+ robustness: I.audio,
798
+ encryptionScheme: I.scheme
744
799
  }]
745
800
  }]);
746
801
  }
747
- function Be(e, t) {
802
+ function Qe(e, t) {
748
803
  return new Promise((n, r) => {
749
804
  let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
750
805
  e.then((e) => {
@@ -754,8 +809,8 @@ function Be(e, t) {
754
809
  });
755
810
  });
756
811
  }
757
- async function Ve(e = {}) {
758
- let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Fe, r = {};
812
+ async function $e(e = {}) {
813
+ let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? qe, r = {};
759
814
  if (typeof window < "u" && window.isSecureContext === !1) return {
760
815
  verdict: "insecure-context",
761
816
  detail: r
@@ -767,7 +822,7 @@ async function Ve(e = {}) {
767
822
  };
768
823
  let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
769
824
  for (let e of t) {
770
- let t = Re[e];
825
+ let t = Xe[e];
771
826
  if (!t) {
772
827
  r[e] = "unknown system";
773
828
  continue;
@@ -778,7 +833,7 @@ async function Ve(e = {}) {
778
833
  break;
779
834
  }
780
835
  try {
781
- return await Be((await Be(i(n, ze(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
836
+ return await Qe((await Qe(i(n, Ze(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
782
837
  verdict: "supported",
783
838
  system: e,
784
839
  detail: r
@@ -802,37 +857,37 @@ async function Ve(e = {}) {
802
857
  }
803
858
  //#endregion
804
859
  //#region src/core/manifest.ts
805
- var He = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
806
- function Ue(e) {
807
- return He.test(e);
860
+ var et = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
861
+ function tt(e) {
862
+ return et.test(e);
808
863
  }
809
864
  //#endregion
810
865
  //#region src/core/env.ts
811
- var We = {
866
+ var nt = {
812
867
  integration: "https://feed-dev.oddin-video.gg",
813
868
  production: "https://feed.oddin-video.gg"
814
869
  };
815
- function Ge(e) {
816
- let t = Object.prototype.hasOwnProperty.call(We, e) ? We[e] : void 0;
870
+ function rt(e) {
871
+ let t = Object.prototype.hasOwnProperty.call(nt, e) ? nt[e] : void 0;
817
872
  if (!t) throw new n("INTERNAL", 0, `unknown env ${JSON.stringify(e)} — expected 'integration' or 'production'`);
818
873
  return t;
819
874
  }
820
875
  //#endregion
821
876
  //#region src/core/stats.ts
822
- var Ke = { droppedFrames: 0 };
823
- function qe(e) {
877
+ var it = { droppedFrames: 0 };
878
+ function at(e) {
824
879
  try {
825
880
  return new URL(e).host;
826
881
  } catch {
827
882
  return "";
828
883
  }
829
884
  }
830
- var Je = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
831
- function Ye(e) {
885
+ var ot = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
886
+ function st(e) {
832
887
  if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
833
888
  let t = "", n = -1, r = performance.getEntriesByType("resource");
834
- for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || Je.test(i.name)) && i.startTime >= n) {
835
- let e = qe(i.name);
889
+ for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || ot.test(i.name)) && i.startTime >= n) {
890
+ let e = at(i.name);
836
891
  e && (t = e, n = i.startTime);
837
892
  }
838
893
  return t;
@@ -844,7 +899,7 @@ function B(e) {
844
899
  totalFrames: t?.totalVideoFrames ?? 0
845
900
  };
846
901
  }
847
- var Xe = class {
902
+ var ct = class {
848
903
  video;
849
904
  baseFrames = 0;
850
905
  baseDropped = 0;
@@ -867,7 +922,7 @@ var Xe = class {
867
922
  };
868
923
  }
869
924
  };
870
- function Ze(e, t) {
925
+ function lt(e, t) {
871
926
  let n = [
872
927
  ["playing", () => t("playing")],
873
928
  ["waiting", () => t("buffering")],
@@ -884,8 +939,8 @@ function Ze(e, t) {
884
939
  }
885
940
  //#endregion
886
941
  //#region src/core/engine/native.ts
887
- var Qe = 2e3, $e = 3, V = 500, et = 6e3, tt = .25, nt = 250, rt = .05, it = 4, at = 12e3, ot = .25, st = 1e3;
888
- function ct(e) {
942
+ var ut = 2e3, dt = 3, V = 500, ft = 6e3, pt = .25, mt = 250, ht = .05, gt = 4, _t = 12e3, vt = .25, yt = 1e3;
943
+ function bt(e) {
889
944
  try {
890
945
  let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
891
946
  return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
@@ -901,7 +956,7 @@ function U() {
901
956
  let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
902
957
  return e || t;
903
958
  }
904
- function lt() {
959
+ function xt() {
905
960
  if (typeof navigator > "u" || !U()) return !1;
906
961
  let e = navigator.userAgent ?? "";
907
962
  return /iPhone|iPad|iPod/.test(e) ? !0 : /Macintosh/.test(e) && typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1;
@@ -936,7 +991,7 @@ var W = class {
936
991
  frameCounter;
937
992
  detachFrames = null;
938
993
  constructor(e) {
939
- this.deps = e, this.frameCounter = new Xe(e.video), this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
994
+ this.deps = e, this.frameCounter = new ct(e.video), this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
940
995
  }
941
996
  async load() {
942
997
  this.detachFrames ??= this.frameCounter.attach();
@@ -957,7 +1012,7 @@ var W = class {
957
1012
  type: "error",
958
1013
  error: new n("INTERNAL", 0, "native HLS playback error"),
959
1014
  fatal: !0
960
- }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = dt(t.manifestUrl, t.analytics?.sid), e.load();
1015
+ }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Ct(t.manifestUrl, t.analytics?.sid), e.load();
961
1016
  }
962
1017
  startLoad() {
963
1018
  this.loadStarted || (this.loadStarted = !0, this.restorePreload());
@@ -979,7 +1034,7 @@ var W = class {
979
1034
  });
980
1035
  this.onEncrypted = (n) => {
981
1036
  let i = n;
982
- i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = ct(i.initData), (async () => {
1037
+ i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = bt(i.initData), (async () => {
983
1038
  try {
984
1039
  let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
985
1040
  initDataTypes: [i.initDataType],
@@ -1078,10 +1133,10 @@ var W = class {
1078
1133
  droppedFrames: t.dropped,
1079
1134
  decodedFrames: t.totalFrames
1080
1135
  };
1081
- if (this.cdnHost ||= Ye(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity) {
1136
+ if (this.cdnHost ||= st(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity) {
1082
1137
  n.isLive = !0;
1083
1138
  let t = this.liveEdgeEstimate(), r = t == null ? NaN : t - e.currentTime;
1084
- Number.isFinite(r) && (n.atLiveEdge = r <= it, !e.paused && r >= 0 && (n.latencySeconds = r));
1139
+ Number.isFinite(r) && (n.atLiveEdge = r <= gt, !e.paused && r >= 0 && (n.latencySeconds = r));
1085
1140
  } else Number.isFinite(e.duration) && e.duration > 0 && (n.isLive = !1);
1086
1141
  return n;
1087
1142
  }
@@ -1099,7 +1154,7 @@ var W = class {
1099
1154
  return;
1100
1155
  }
1101
1156
  let t = this.hiddenSince;
1102
- this.hiddenSince = null, t != null && e - t >= Qe && this.armRefocus();
1157
+ this.hiddenSince = null, t != null && e - t >= ut && this.armRefocus();
1103
1158
  }, this.onPageShow = (e) => {
1104
1159
  e.persisted && this.armRefocus();
1105
1160
  }, document.addEventListener("visibilitychange", this.onVisibility), typeof window < "u" && window.addEventListener("pageshow", this.onPageShow));
@@ -1109,7 +1164,7 @@ var W = class {
1109
1164
  let e = this.liveEnd(), t = G, n = t(), r = 0, i = () => {
1110
1165
  if (this.refocusTimer = null, Number.isFinite(this.deps.video.duration)) return;
1111
1166
  r += V;
1112
- let a = this.liveEnd(), o = a != null && (e == null || a >= e + tt), s = Math.max(r, t() - n) >= et;
1167
+ let a = this.liveEnd(), o = a != null && (e == null || a >= e + pt), s = Math.max(r, t() - n) >= ft;
1113
1168
  if (o || s && a != null) {
1114
1169
  this.snapToLive();
1115
1170
  return;
@@ -1129,9 +1184,9 @@ var W = class {
1129
1184
  }, e.addEventListener("seeking", this.onEdgeReset), e.addEventListener("emptied", this.onEdgeReset), this.edgeTimer = setInterval(() => {
1130
1185
  if (e.duration !== Infinity) return;
1131
1186
  this.checkEndStale();
1132
- let t = ut(e, e.currentTime);
1133
- t != null && ((this.lastBufferedEnd == null || Math.abs(t - this.lastBufferedEnd) >= rt) && (this.bufferedAdvancedAt = G()), this.lastBufferedEnd = t);
1134
- }, nt);
1187
+ let t = St(e, e.currentTime);
1188
+ t != null && ((this.lastBufferedEnd == null || Math.abs(t - this.lastBufferedEnd) >= ht) && (this.bufferedAdvancedAt = G()), this.lastBufferedEnd = t);
1189
+ }, mt);
1135
1190
  }
1136
1191
  checkEndStale() {
1137
1192
  if (this.endedEmitted) return;
@@ -1139,14 +1194,14 @@ var W = class {
1139
1194
  this.lastTickAt = e;
1140
1195
  let n = this.liveEnd();
1141
1196
  if (n == null) return;
1142
- let r = this.lastSeekableEnd == null || Math.abs(n - this.lastSeekableEnd) >= ot;
1197
+ let r = this.lastSeekableEnd == null || Math.abs(n - this.lastSeekableEnd) >= vt;
1143
1198
  this.lastSeekableEnd = n;
1144
1199
  let i = this.deps.video, a = typeof document < "u" && document.visibilityState === "hidden";
1145
- if (r || t > st || a || i.paused) {
1200
+ if (r || t > yt || a || i.paused) {
1146
1201
  this.edgeStampedAt = e;
1147
1202
  return;
1148
1203
  }
1149
- e - (this.edgeStampedAt ?? e) > at && (this.endedEmitted = !0, this.deps.emit({
1204
+ e - (this.edgeStampedAt ?? e) > _t && (this.endedEmitted = !0, this.deps.emit({
1150
1205
  type: "ended",
1151
1206
  reason: "stalled"
1152
1207
  }));
@@ -1160,7 +1215,7 @@ var W = class {
1160
1215
  liveEdgeEstimate() {
1161
1216
  let e = this.deps.video;
1162
1217
  if (e.duration !== Infinity) return null;
1163
- let t = this.liveEnd(), n = ut(e, e.currentTime) ?? this.lastBufferedEnd;
1218
+ let t = this.liveEnd(), n = St(e, e.currentTime) ?? this.lastBufferedEnd;
1164
1219
  if (n != null) {
1165
1220
  let e = this.bufferedAdvancedAt, r = n + (e == null ? 0 : Math.max(0, (G() - e) / 1e3));
1166
1221
  (t == null || r > t) && (t = r);
@@ -1176,7 +1231,7 @@ var W = class {
1176
1231
  snapToLive() {
1177
1232
  let e = this.deps.video, t = this.liveEnd();
1178
1233
  if (t == null) return;
1179
- let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t - $e, r);
1234
+ let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t - dt, r);
1180
1235
  try {
1181
1236
  e.currentTime = i;
1182
1237
  } catch {}
@@ -1197,7 +1252,7 @@ var W = class {
1197
1252
  function G() {
1198
1253
  return typeof performance < "u" ? performance.now() : Date.now();
1199
1254
  }
1200
- function ut(e, t) {
1255
+ function St(e, t) {
1201
1256
  let n = e.buffered;
1202
1257
  if (!n || !Number.isFinite(t)) return null;
1203
1258
  for (let e = 0; e < n.length; e += 1) if (n.start(e) <= t + .1 && n.end(e) > t) {
@@ -1206,7 +1261,7 @@ function ut(e, t) {
1206
1261
  }
1207
1262
  return null;
1208
1263
  }
1209
- function dt(e, t) {
1264
+ function Ct(e, t) {
1210
1265
  return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
1211
1266
  }
1212
1267
  //#endregion
@@ -1223,8 +1278,8 @@ function K(e, t = Date.now()) {
1223
1278
  }
1224
1279
  //#endregion
1225
1280
  //#region src/core/engine/prefetch.ts
1226
- var ft = 15e3, pt = 5e3, mt = 6;
1227
- function ht(e) {
1281
+ var wt = 15e3, Tt = 5e3, Et = 6;
1282
+ function Dt(e) {
1228
1283
  try {
1229
1284
  let t = new URL(e);
1230
1285
  return t.searchParams.delete("CMCD"), t.toString();
@@ -1232,7 +1287,7 @@ function ht(e) {
1232
1287
  return e;
1233
1288
  }
1234
1289
  }
1235
- var gt = class {
1290
+ var Ot = class {
1236
1291
  cmcd;
1237
1292
  entries = /* @__PURE__ */ new Map();
1238
1293
  keyed = /* @__PURE__ */ new Set();
@@ -1255,10 +1310,10 @@ var gt = class {
1255
1310
  }
1256
1311
  prefetch(e, t, n) {
1257
1312
  if (!this.isActive(t)) return;
1258
- let r = ht(e);
1313
+ let r = Dt(e);
1259
1314
  if (this.entries.has(r)) return;
1260
1315
  let i = this.perTrack.get(t) ?? 0;
1261
- if (i >= mt) return;
1316
+ if (i >= Et) return;
1262
1317
  this.perTrack.set(t, i + 1);
1263
1318
  let a = new AbortController(), o = {
1264
1319
  started: performance.now(),
@@ -1272,10 +1327,10 @@ var gt = class {
1272
1327
  signal: a.signal
1273
1328
  }).then(async (e) => (o.first = performance.now(), e.ok ? e.arrayBuffer() : null)).catch(() => null), this.entries.set(r, o), this.stats.started += 1, setTimeout(() => {
1274
1329
  this.entries.get(r) === o && (this.entries.delete(r), a.abort(), this.stats.expired += 1);
1275
- }, ft);
1330
+ }, wt);
1276
1331
  }
1277
1332
  take(e) {
1278
- let t = ht(e), n = this.entries.get(t);
1333
+ let t = Dt(e), n = this.entries.get(t);
1279
1334
  return n && this.entries.delete(t), n;
1280
1335
  }
1281
1336
  destroy() {
@@ -1295,13 +1350,13 @@ var gt = class {
1295
1350
  }
1296
1351
  }
1297
1352
  };
1298
- function _t(t) {
1353
+ function kt(t) {
1299
1354
  let n = e.DefaultConfig?.loader;
1300
1355
  if (typeof n != "function") return;
1301
1356
  class r extends n {
1302
1357
  served = !1;
1303
1358
  cancelled = !1;
1304
- stats = vt();
1359
+ stats = At();
1305
1360
  load(e, n, r) {
1306
1361
  let i = e.rangeEnd ? void 0 : t.take(e.url);
1307
1362
  if (!i) {
@@ -1309,7 +1364,7 @@ function _t(t) {
1309
1364
  return;
1310
1365
  }
1311
1366
  this.served = !0;
1312
- let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || pt, s = setTimeout(() => {
1367
+ let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || Tt, s = setTimeout(() => {
1313
1368
  !this.cancelled && this.served && (i.abort.abort(), t.stats.failed += 1, this.served = !1, super.load(e, n, r));
1314
1369
  }, o);
1315
1370
  i.bytes.then((o) => {
@@ -1336,7 +1391,7 @@ function _t(t) {
1336
1391
  }
1337
1392
  return r;
1338
1393
  }
1339
- function vt() {
1394
+ function At() {
1340
1395
  return {
1341
1396
  aborted: !1,
1342
1397
  loaded: 0,
@@ -1360,10 +1415,10 @@ function vt() {
1360
1415
  }
1361
1416
  };
1362
1417
  }
1363
- function q(e) {
1418
+ function jt(e) {
1364
1419
  return e === "audio" ? "audio" : "main";
1365
1420
  }
1366
- function yt(e, t) {
1421
+ function Mt(e, t) {
1367
1422
  let n = [];
1368
1423
  t.initSegment?.url && !t.initSegment.data && n.push({
1369
1424
  url: t.initSegment.url,
@@ -1382,24 +1437,24 @@ function yt(e, t) {
1382
1437
  }
1383
1438
  //#endregion
1384
1439
  //#region src/core/engine/hls.ts
1385
- function bt() {
1440
+ function Nt() {
1386
1441
  return e.isSupported();
1387
1442
  }
1388
- var xt = 3, St = 5, Ct = 3, wt = 1e4, Tt = 3e4, Et = 12e3, Dt = 3e3, Ot = .02, kt = 6e3, At = .5, jt = 3, Mt = .5, Nt = 1.1, Pt = .25, Ft = 5e3, It = 4e3, Lt = 2, Rt = 5, zt = 2, Bt = 2, Vt = 4, Ht = 4, Ut = 2e3, Wt = 3e4, Gt = .2, Kt = 30, qt = 2, Jt = 2, Yt = 9, Xt = .5, Zt = 64;
1389
- function Qt(e) {
1443
+ var Pt = 1e6, Ft = 20, It = 1e4, Lt = 3, Rt = 5, zt = 3, Bt = 1e4, Vt = 3e4, Ht = 12e3, Ut = 3e3, Wt = .02, Gt = 6e3, Kt = .5, qt = 3, Jt = .5, Yt = 1.1, Xt = .25, Zt = 5e3, Qt = 4e3, $t = 2, en = 5, tn = 2, nn = 2, rn = 4, an = 4, on = 2e3, sn = 3e4, cn = .2, ln = 30, un = 2, dn = 2, fn = 9, pn = .5, mn = 64;
1444
+ function hn(e) {
1390
1445
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
1391
1446
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
1392
1447
  return;
1393
1448
  }
1394
- e.liveSyncDuration ??= Jt;
1395
- let t = Math.max(12, e.liveSyncDuration + Yt);
1396
- (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), $t(e, e.liveSyncDuration);
1449
+ e.liveSyncDuration ??= dn;
1450
+ let t = Math.max(12, e.liveSyncDuration + fn);
1451
+ (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), gn(e, e.liveSyncDuration);
1397
1452
  }
1398
- function $t(e, t) {
1453
+ function gn(e, t) {
1399
1454
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
1400
1455
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
1401
1456
  }
1402
- var en = class {
1457
+ var _n = class {
1403
1458
  name = "hls";
1404
1459
  hls = null;
1405
1460
  deps;
@@ -1451,6 +1506,8 @@ var en = class {
1451
1506
  starvedFrames = 0;
1452
1507
  deadTicks = 0;
1453
1508
  mainFragsSinceTick = 0;
1509
+ bwFragsLoaded = 0;
1510
+ bwSavedAt = 0;
1454
1511
  recentMainFrags = [];
1455
1512
  chaseSuspended = !1;
1456
1513
  savedLiveMaxLatency;
@@ -1481,7 +1538,7 @@ var en = class {
1481
1538
  frameCounter;
1482
1539
  detachFrames = null;
1483
1540
  constructor(e) {
1484
- this.deps = e, this.frameCounter = new Xe(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1541
+ this.deps = e, this.frameCounter = new ct(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1485
1542
  }
1486
1543
  async load() {
1487
1544
  this.detachFrames ??= this.frameCounter.attach();
@@ -1494,7 +1551,7 @@ var en = class {
1494
1551
  });
1495
1552
  return;
1496
1553
  }
1497
- e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ae(r), Ne()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1554
+ e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ve(r), Ge()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1498
1555
  let e = this.hls;
1499
1556
  if (document.visibilityState !== "visible" || !e) return;
1500
1557
  let t = e.liveSyncPosition;
@@ -1517,7 +1574,7 @@ var en = class {
1517
1574
  }
1518
1575
  this.loadSuspended = !0;
1519
1576
  }
1520
- }, Ft));
1577
+ }, Zt));
1521
1578
  }
1522
1579
  resumeLoading() {
1523
1580
  if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
@@ -1549,7 +1606,7 @@ var en = class {
1549
1606
  let t = e.liveSyncPosition;
1550
1607
  if (typeof t != "number" || !Number.isFinite(t)) return;
1551
1608
  let { video: n } = this.deps;
1552
- n.currentTime <= t + Xt || (n.currentTime = t);
1609
+ n.currentTime <= t + pn || (n.currentTime = t);
1553
1610
  }
1554
1611
  reanchorPartTimeline(e, t) {
1555
1612
  let { frag: n, part: r } = t;
@@ -1561,7 +1618,7 @@ var en = class {
1561
1618
  let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
1562
1619
  if (!s) return;
1563
1620
  let c = a.startPTS - s.start;
1564
- if (!(!Number.isFinite(c) || Math.abs(c) < Ot)) {
1621
+ if (!(!Number.isFinite(c) || Math.abs(c) < Wt)) {
1565
1622
  for (let e of i.fragments) e && e.setStart(e.start + c);
1566
1623
  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})`);
1567
1624
  }
@@ -1577,19 +1634,19 @@ var en = class {
1577
1634
  liveDurationInfinity: !0,
1578
1635
  maxBufferHole: .5,
1579
1636
  maxLiveSyncPlaybackRate: d ? 1 : 1.1,
1580
- abrEwmaDefaultEstimate: 1e6,
1637
+ abrEwmaDefaultEstimate: this.startEstimate(),
1581
1638
  capLevelToPlayerSize: !1,
1582
1639
  ...this.loadStarted ? {} : { autoStartLoad: !1 },
1583
1640
  ...u ? {
1584
1641
  emeEnabled: !0,
1585
1642
  drmSystems: { ...this.licenseUrl ? { "com.widevine.alpha": { licenseUrl: this.licenseUrl } } : {} },
1586
1643
  drmSystemOptions: {
1587
- videoRobustness: F.video,
1588
- audioRobustness: F.audio,
1589
- videoEncryptionScheme: F.scheme,
1590
- audioEncryptionScheme: F.scheme
1644
+ videoRobustness: I.video,
1645
+ audioRobustness: I.audio,
1646
+ videoEncryptionScheme: I.scheme,
1647
+ audioEncryptionScheme: I.scheme
1591
1648
  },
1592
- ...j() ? { requestMediaKeySystemAccessFunc: P(t) } : {},
1649
+ ...N() ? { requestMediaKeySystemAccessFunc: Be(t) } : {},
1593
1650
  licenseXhrSetup: (e, t) => {
1594
1651
  let o = performance.now(), s = () => {
1595
1652
  e.open("POST", this.licenseUrl ?? t, !0), e.setRequestHeader("x-api-key", r.apiKey), e.setRequestHeader("X-Match-Urn", n.matchUrn), e.setRequestHeader("X-Device-Id", i), a && e.setRequestHeader("X-User-Id", a), this.licenseRequested = !0, e.addEventListener("loadend", () => {
@@ -1601,7 +1658,7 @@ var en = class {
1601
1658
  return;
1602
1659
  }
1603
1660
  let l = this.hls, u, d = new Promise((e) => {
1604
- u = setTimeout(() => e(void 0), wt);
1661
+ u = setTimeout(() => e(void 0), Bt);
1605
1662
  });
1606
1663
  return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
1607
1664
  if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
@@ -1617,31 +1674,31 @@ var en = class {
1617
1674
  ...c
1618
1675
  };
1619
1676
  if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !f.fLoader) {
1620
- let e = new gt({
1677
+ let e = new Ot({
1621
1678
  sessionId: n.analytics?.sid,
1622
1679
  contentId: n.matchUrn
1623
- }), t = _t(e);
1680
+ }), t = kt(e);
1624
1681
  t && (this.prefetch = e, f.fLoader = t);
1625
1682
  }
1626
- Qt(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;
1683
+ hn(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;
1627
1684
  let p = new e(f);
1628
1685
  if (this.hls = p, p.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(p, t)), p.on(e.Events.MANIFEST_PARSED, () => {
1629
1686
  this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(p), this.measureLadder(p), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
1630
1687
  }), p.on(e.Events.FRAG_BUFFERED, (e, t) => {
1631
1688
  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(() => {
1632
1689
  this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
1633
- }, Tt)));
1690
+ }, Vt)));
1634
1691
  }), p.on(e.Events.FRAG_LOADING, (e, t) => {
1635
1692
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
1636
1693
  }), p.on(e.Events.FRAG_LOADED, (e, t) => {
1637
- t?.frag?.type === "main" && (this.mainFragsSinceTick += 1);
1694
+ t?.frag?.type === "main" && (this.mainFragsSinceTick += 1, this.bwFragsLoaded += 1, this.maybeRememberBandwidth(!1));
1638
1695
  let n = t?.frag?.stats, r = n?.loaded;
1639
1696
  typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
1640
1697
  let i = n?.loading;
1641
- i && i.end > 0 && i.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(i.end - i.start))), this.requestTimesMs.length > Zt && this.requestTimesMs.shift());
1698
+ i && i.end > 0 && i.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(i.end - i.start))), this.requestTimesMs.length > mn && this.requestTimesMs.shift());
1642
1699
  let a = t?.frag?.url;
1643
1700
  if (a) {
1644
- let e = qe(a);
1701
+ let e = at(a);
1645
1702
  e && (this.cdnHost = e);
1646
1703
  }
1647
1704
  }), p.on(e.Events.LEVEL_LOADED, (e, t) => {
@@ -1655,15 +1712,15 @@ var en = class {
1655
1712
  }), p.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
1656
1713
  let t = this.prefetch;
1657
1714
  p.on(e.Events.KEY_LOADING, (e, n) => {
1658
- let r = n?.frag, i = q(r?.type);
1659
- if (r && t.isActive(i)) for (let e of yt(p, r)) t.prefetch(e.url, i, e.kind);
1660
- }), p.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(q(n?.frag?.type)));
1715
+ let r = n?.frag, i = jt(r?.type);
1716
+ if (r && t.isActive(i)) for (let e of Mt(p, r)) t.prefetch(e.url, i, e.kind);
1717
+ }), p.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(jt(n?.frag?.type)));
1661
1718
  }
1662
1719
  p.on(e.Events.KEY_LOADED, () => {
1663
1720
  u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
1664
1721
  }), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1665
1722
  this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.checkFrameDrops();
1666
- }, Dt), p.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1723
+ }, Ut), p.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1667
1724
  this.renditionSwitches += 1;
1668
1725
  let n = this.lastLevelIndex >= 0 ? p.levels[this.lastLevelIndex] : void 0, r = p.levels[t.level];
1669
1726
  n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
@@ -1727,7 +1784,7 @@ var en = class {
1727
1784
  return;
1728
1785
  }
1729
1786
  this.capTimer && clearTimeout(this.capTimer);
1730
- let t = e > this.sizeCapLevel ? Ut : Wt;
1787
+ let t = e > this.sizeCapLevel ? on : sn;
1731
1788
  this.capTimer = setTimeout(() => {
1732
1789
  this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
1733
1790
  }, t);
@@ -1737,9 +1794,9 @@ var en = class {
1737
1794
  this.ladderHeights = t.length ? [...new Set(t)].sort((e, t) => e - t) : void 0, this.ladderTopBitrateKbps = e.levels.length ? Math.round(Math.max(...e.levels.map((e) => e.bitrate)) / 1e3) : 0;
1738
1795
  }
1739
1796
  dropLevelsWidevineCannotPlay(e) {
1740
- this.removeLevelsWhere(e, (e) => Pe(e) !== !0);
1741
- let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && I(e) !== "avc" && !!I(e)));
1742
- for (let n of t) Me(n).then((t) => {
1797
+ this.removeLevelsWhere(e, (e) => Ke(e) !== !0);
1798
+ let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && L(e) !== "avc" && !!L(e)));
1799
+ for (let n of t) We(n).then((t) => {
1743
1800
  t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
1744
1801
  });
1745
1802
  }
@@ -1747,10 +1804,10 @@ var en = class {
1747
1804
  let n = e.levels ?? [], r = [], i = /* @__PURE__ */ new Set();
1748
1805
  if (n.forEach((e, n) => {
1749
1806
  let a = e.videoCodec;
1750
- a && I(a) && t(a) && (r.push(n), i.add(a));
1807
+ a && L(a) && t(a) && (r.push(n), i.add(a));
1751
1808
  }), !r.length) return !1;
1752
1809
  let a = [...i].join(", ");
1753
- if (!n.some((e, t) => r.includes(t) ? !1 : !I(e.videoCodec) || Pe(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
1810
+ if (!n.some((e, t) => r.includes(t) ? !1 : !L(e.videoCodec) || Ke(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
1754
1811
  for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
1755
1812
  return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
1756
1813
  }
@@ -1856,7 +1913,7 @@ var en = class {
1856
1913
  return;
1857
1914
  }
1858
1915
  let e = Date.now() - this.lastAdvanceMs;
1859
- !this.chaseSuspended && e > kt && this.suspendChasing(), e > Et && this.emitEnded("stalled");
1916
+ !this.chaseSuspended && e > Gt && this.suspendChasing(), e > Ht && this.emitEnded("stalled");
1860
1917
  }
1861
1918
  resetStarvationWindow() {
1862
1919
  this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
@@ -1871,7 +1928,7 @@ var en = class {
1871
1928
  this.resetStarvationWindow();
1872
1929
  return;
1873
1930
  }
1874
- let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < kt, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > It, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = B(t), c = o - s, l = c !== this.starvedFrames;
1931
+ let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < Gt, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > Qt, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = B(t), c = o - s, l = c !== this.starvedFrames;
1875
1932
  if (this.starvedFrames = c, !a || l) {
1876
1933
  (t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
1877
1934
  return;
@@ -1880,12 +1937,12 @@ var en = class {
1880
1937
  this.resetStarvationWindow();
1881
1938
  return;
1882
1939
  }
1883
- 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 > Vt && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= zt && (this.clearKick(), this.starvationRebuilds < Bt)) {
1940
+ 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 > rn && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= tn && (this.clearKick(), this.starvationRebuilds < nn)) {
1884
1941
  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");
1885
1942
  return;
1886
1943
  }
1887
- let u = i && this.starvedTicks >= Lt, d = !i && this.deadTicks >= Vt && this.recentMainFrags.reduce((e, t) => e + t, 0) >= Ht;
1888
- if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= Rt))) {
1944
+ let u = i && this.starvedTicks >= $t, d = !i && this.deadTicks >= rn && this.recentMainFrags.reduce((e, t) => e + t, 0) >= an;
1945
+ if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= en))) {
1889
1946
  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");
1890
1947
  try {
1891
1948
  e.stopLoad(), e.startLoad(-1);
@@ -1900,7 +1957,7 @@ var en = class {
1900
1957
  let t = e.latency, n = e.targetLatency;
1901
1958
  if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
1902
1959
  let r = t - n;
1903
- !this.catchUpEngaged && r > At ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= At && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
1960
+ !this.catchUpEngaged && r > Kt ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= Kt && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
1904
1961
  let i = this.catchUpEngaged ? this.catchUpRate : 1;
1905
1962
  e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
1906
1963
  }
@@ -1922,15 +1979,15 @@ var en = class {
1922
1979
  return;
1923
1980
  }
1924
1981
  let { totalFrames: n, dropped: r } = B(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
1925
- if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Kt || o < 0) {
1982
+ if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < ln || o < 0) {
1926
1983
  this.fpsBadTicks = 0;
1927
1984
  return;
1928
1985
  }
1929
- if (o <= Gt * a) {
1986
+ if (o <= cn * a) {
1930
1987
  this.fpsBadTicks = 0;
1931
1988
  return;
1932
1989
  }
1933
- if (this.fpsBadTicks += 1, this.fpsBadTicks < qt) return;
1990
+ if (this.fpsBadTicks += 1, this.fpsBadTicks < un) return;
1934
1991
  this.fpsBadTicks = 0;
1935
1992
  let s = e.levels, c = s[e.currentLevel];
1936
1993
  if (!c) return;
@@ -1947,20 +2004,20 @@ var en = class {
1947
2004
  return;
1948
2005
  }
1949
2006
  let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
1950
- if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(Nt, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
2007
+ if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(Yt, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
1951
2008
  this.resetChaseWindow();
1952
2009
  return;
1953
2010
  }
1954
- if (this.chaseLatency < 0 || this.chaseLatency - n >= Mt) {
2011
+ if (this.chaseLatency < 0 || this.chaseLatency - n >= Jt) {
1955
2012
  this.chaseLatency = n, this.chaseTicks = 0;
1956
2013
  return;
1957
2014
  }
1958
- if (this.chaseTicks += 1, this.chaseTicks < jt) return;
2015
+ if (this.chaseTicks += 1, this.chaseTicks < qt) return;
1959
2016
  this.resetChaseWindow();
1960
2017
  let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
1961
2018
  if (!(a > 1)) return;
1962
2019
  let o = typeof e.targetLatency == "number" ? e.targetLatency : 0, s = Math.min(n, a - 1);
1963
- s < o + Pt || (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);
2020
+ s < o + Xt || (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);
1964
2021
  }
1965
2022
  suspendChasing() {
1966
2023
  let e = this.hls;
@@ -1989,8 +2046,18 @@ var en = class {
1989
2046
  this.deps.video.pause();
1990
2047
  } catch {}
1991
2048
  }
2049
+ startEstimate() {
2050
+ return this.deps.rememberBandwidth === !1 ? Pt : Pe() ?? Pt;
2051
+ }
2052
+ maybeRememberBandwidth(e) {
2053
+ if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < Ft) return;
2054
+ let t = Date.now();
2055
+ if (!e && t - this.bwSavedAt < It) return;
2056
+ let n = this.hls?.bandwidthEstimate;
2057
+ typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Fe(n));
2058
+ }
1992
2059
  destroy() {
1993
- if (this.detachFrames?.(), this.detachFrames = null, this.prefetch?.destroy(), this.prefetch = null, this.clearRecoveryReset(), this.capTimer &&= (clearTimeout(this.capTimer), null), this.capObserver &&= (this.capObserver.disconnect(), null), this.unwatchDprChanges(), this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.onSeeking &&= (this.deps.video.removeEventListener("seeking", this.onSeeking), null), this.onTimeUpdate &&= (this.deps.video.removeEventListener("timeupdate", this.onTimeUpdate), null), this.onPause &&= (this.deps.video.removeEventListener("pause", this.onPause), null), this.onPlay &&= (this.deps.video.removeEventListener("play", this.onPlay), null), this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), this.licenseRetryTimer &&= (clearTimeout(this.licenseRetryTimer), null), this.hls) {
2060
+ if (this.maybeRememberBandwidth(!0), this.detachFrames?.(), this.detachFrames = null, this.prefetch?.destroy(), this.prefetch = null, this.clearRecoveryReset(), this.capTimer &&= (clearTimeout(this.capTimer), null), this.capObserver &&= (this.capObserver.disconnect(), null), this.unwatchDprChanges(), this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.onSeeking &&= (this.deps.video.removeEventListener("seeking", this.onSeeking), null), this.onTimeUpdate &&= (this.deps.video.removeEventListener("timeupdate", this.onTimeUpdate), null), this.onPause &&= (this.deps.video.removeEventListener("pause", this.onPause), null), this.onPlay &&= (this.deps.video.removeEventListener("play", this.onPlay), null), this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), this.licenseRetryTimer &&= (clearTimeout(this.licenseRetryTimer), null), this.hls) {
1994
2061
  try {
1995
2062
  this.hls.destroy();
1996
2063
  } catch (e) {
@@ -2005,7 +2072,7 @@ var en = class {
2005
2072
  scheduleLicenseRetry(t) {
2006
2073
  if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
2007
2074
  let n = t.response?.code ?? 0;
2008
- if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Ct) return !1;
2075
+ if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= zt) return !1;
2009
2076
  this.licenseRecoveries += 1;
2010
2077
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
2011
2078
  return this.licenseRetryTimer = setTimeout(() => {
@@ -2037,7 +2104,7 @@ var en = class {
2037
2104
  return;
2038
2105
  }
2039
2106
  if (t.type === e.ErrorTypes.NETWORK_ERROR) {
2040
- if (this.networkRecoveries < St) {
2107
+ if (this.networkRecoveries < Rt) {
2041
2108
  this.networkRecoveries += 1;
2042
2109
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
2043
2110
  this.networkRetryTimer = setTimeout(() => {
@@ -2054,7 +2121,7 @@ var en = class {
2054
2121
  return;
2055
2122
  }
2056
2123
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
2057
- if (this.mediaRecoveries < xt) {
2124
+ if (this.mediaRecoveries < Lt) {
2058
2125
  this.mediaRecoveries += 1, n.recoverMediaError();
2059
2126
  return;
2060
2127
  }
@@ -2078,19 +2145,19 @@ var en = class {
2078
2145
  let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
2079
2146
  return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
2080
2147
  }
2081
- }, tn = 15e3, nn = 6e5, rn = 3e5, an = 100, J = 1, on = 1e3, sn = 3e4, cn = 1e3, ln = {
2148
+ }, vn = 15e3, yn = 6e5, bn = 3e5, xn = 100, q = 1, Sn = 1e3, Cn = 3e4, wn = 1e3, Tn = {
2082
2149
  inline: "PRESENTATION_INLINE",
2083
2150
  fullscreen: "PRESENTATION_FULLSCREEN",
2084
2151
  pip: "PRESENTATION_PIP"
2085
- }, un = {
2152
+ }, En = {
2086
2153
  widevine: "KEY_SYSTEM_WIDEVINE",
2087
2154
  fairplay: "KEY_SYSTEM_FAIRPLAY",
2088
2155
  none: "KEY_SYSTEM_NONE"
2089
2156
  };
2090
- function dn(e, t) {
2157
+ function Dn(e, t) {
2091
2158
  return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
2092
2159
  }
2093
- var fn = /* @__PURE__ */ new Set([
2160
+ var On = /* @__PURE__ */ new Set([
2094
2161
  "INVALID_URN",
2095
2162
  "NOT_FOUND",
2096
2163
  "GONE",
@@ -2100,7 +2167,7 @@ var fn = /* @__PURE__ */ new Set([
2100
2167
  "FORBIDDEN",
2101
2168
  "RATE_LIMITED",
2102
2169
  "TIMEOUT"
2103
- ]), Y = {
2170
+ ]), J = {
2104
2171
  idle: "PLAYER_STATE_IDLE",
2105
2172
  waiting: "PLAYER_STATE_WAITING",
2106
2173
  loading: "PLAYER_STATE_LOADING",
@@ -2110,7 +2177,7 @@ var fn = /* @__PURE__ */ new Set([
2110
2177
  ended: "PLAYER_STATE_ENDED",
2111
2178
  error: "PLAYER_STATE_ERROR"
2112
2179
  };
2113
- function pn(e) {
2180
+ function kn(e) {
2114
2181
  try {
2115
2182
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
2116
2183
  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);
@@ -2118,8 +2185,8 @@ function pn(e) {
2118
2185
  return;
2119
2186
  }
2120
2187
  }
2121
- var mn = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), hn = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), Z = /* @__PURE__ */ new Set(), gn = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2122
- function _n(e) {
2188
+ var An = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), jn = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), Mn = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2189
+ function Nn(e) {
2123
2190
  if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
2124
2191
  let t;
2125
2192
  try {
@@ -2128,19 +2195,19 @@ function _n(e) {
2128
2195
  } catch {
2129
2196
  return;
2130
2197
  }
2131
- if (hn.has(t) && !X.has(t)) {
2132
- X.add(t), g(gn(new URL(t).origin));
2133
- for (let e of Z) e.noteCspBlocked();
2198
+ if (jn.has(t) && !Y.has(t)) {
2199
+ Y.add(t), g(Mn(new URL(t).origin));
2200
+ for (let e of X) e.noteCspBlocked();
2134
2201
  }
2135
2202
  }
2136
- function vn(e, t) {
2203
+ function Pn(e, t) {
2137
2204
  return g(t, e), { disabledReason: t };
2138
2205
  }
2139
- function yn(e, t, n) {
2140
- if (n) return t && !mn(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2206
+ function Fn(e, t, n) {
2207
+ if (n) return t && !An(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2141
2208
  if (t) return { endpoint: t };
2142
- if (t !== void 0) return vn("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).");
2143
- let r = pn(e);
2209
+ if (t !== void 0) return Pn("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).");
2210
+ let r = kn(e);
2144
2211
  if (r) return { endpoint: r };
2145
2212
  let i;
2146
2213
  try {
@@ -2148,9 +2215,9 @@ function yn(e, t, n) {
2148
2215
  } catch {
2149
2216
  i = e;
2150
2217
  }
2151
- return vn(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).`);
2218
+ return Pn(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).`);
2152
2219
  }
2153
- var bn = class {
2220
+ var In = class {
2154
2221
  opts;
2155
2222
  url;
2156
2223
  cspKey;
@@ -2232,8 +2299,8 @@ var bn = class {
2232
2299
  constructor(e) {
2233
2300
  this.opts = {
2234
2301
  ...e,
2235
- heartbeatMs: e.heartbeatMs ?? tn,
2236
- idleMs: e.idleMs ?? nn
2302
+ heartbeatMs: e.heartbeatMs ?? vn,
2303
+ idleMs: e.idleMs ?? yn
2237
2304
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
2238
2305
  try {
2239
2306
  let e = new URL(this.url);
@@ -2250,11 +2317,11 @@ var bn = class {
2250
2317
  sdkVersion: this.opts.sdkVersion,
2251
2318
  ...this.opts.environment
2252
2319
  };
2253
- this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), on), 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 && hn.add(this.cspKey), document.addEventListener("securitypolicyviolation", _n), Z.add(this), this.noteCspBlocked(), this.onVisibility());
2320
+ this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Sn), 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 && jn.add(this.cspKey), document.addEventListener("securitypolicyviolation", Nn), X.add(this), this.noteCspBlocked(), this.onVisibility());
2254
2321
  }
2255
2322
  checkSuspension(e) {
2256
2323
  if (this.endedFlag || !this.opts.idleMs) return !1;
2257
- let t = Math.max(this.opts.idleMs, rn);
2324
+ let t = Math.max(this.opts.idleMs, bn);
2258
2325
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
2259
2326
  }
2260
2327
  syncIdle(e) {
@@ -2268,21 +2335,21 @@ var bn = class {
2268
2335
  noteStateChange(e, t, n, r) {
2269
2336
  if (this.endedFlag || e === t) return;
2270
2337
  let i = this.now();
2271
- if (t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(J, i - this.startupAnchorMs)), this.firstAudioMs === 0 && !this.isMuted && (this.firstAudioMs = Math.max(J, i - this.startupAnchorMs)), this.isMuted && this.mutedSinceMs === null && (this.mutedSinceMs = i)) : this.playingSinceMs !== null && (this.playingTotalMs += i - this.playingSinceMs, this.playingSinceMs = null, this.mutedSinceMs !== null && (this.mutedTotalMs += i - this.mutedSinceMs, this.mutedSinceMs = null)), this.isPlaying = t === "playing", this.syncActive(), t === "waiting" ? this.waitingSinceMs = i : this.waitingSinceMs !== null && (this.waitingTotalMs += i - this.waitingSinceMs, this.waitingSinceMs = null), t === "buffering" && e === "playing") {
2338
+ if (t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(q, i - this.startupAnchorMs)), this.firstAudioMs === 0 && !this.isMuted && (this.firstAudioMs = Math.max(q, i - this.startupAnchorMs)), this.isMuted && this.mutedSinceMs === null && (this.mutedSinceMs = i)) : this.playingSinceMs !== null && (this.playingTotalMs += i - this.playingSinceMs, this.playingSinceMs = null, this.mutedSinceMs !== null && (this.mutedTotalMs += i - this.mutedSinceMs, this.mutedSinceMs = null)), this.isPlaying = t === "playing", this.syncActive(), t === "waiting" ? this.waitingSinceMs = i : this.waitingSinceMs !== null && (this.waitingTotalMs += i - this.waitingSinceMs, this.waitingSinceMs = null), t === "buffering" && e === "playing") {
2272
2339
  this.stallIsSeekInduced = this.seekInduced(i);
2273
2340
  let e = !this.isHidden && !this.stallIsSeekInduced;
2274
- e && (this.rebufferCount += 1), this.isBuffering = !0, this.lastStallMs = i, e && this.timeToFirstStallMs === 0 && (this.timeToFirstStallMs = Math.max(J, Math.round(this.playingTotalMs)));
2341
+ e && (this.rebufferCount += 1), this.isBuffering = !0, this.lastStallMs = i, e && this.timeToFirstStallMs === 0 && (this.timeToFirstStallMs = Math.max(q, Math.round(this.playingTotalMs)));
2275
2342
  } else e === "buffering" && (this.isBuffering = !1, this.stallIsSeekInduced = !1);
2276
2343
  this.syncBuffering(), t === "paused" && (this.pauseCount += 1), this.syncIdle(t);
2277
2344
  let a = {
2278
- fromState: Y[e] ?? "PLAYER_STATE_UNSPECIFIED",
2279
- toState: Y[t] ?? "PLAYER_STATE_UNSPECIFIED",
2280
- presentation: ln[this.presentation]
2345
+ fromState: J[e] ?? "PLAYER_STATE_UNSPECIFIED",
2346
+ toState: J[t] ?? "PLAYER_STATE_UNSPECIFIED",
2347
+ presentation: Tn[this.presentation]
2281
2348
  }, o = this.causeOf(e, t, i);
2282
2349
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
2283
2350
  }
2284
2351
  seekInduced(e) {
2285
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < cn;
2352
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < wn;
2286
2353
  }
2287
2354
  causeOf(e, t, n) {
2288
2355
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -2319,25 +2386,25 @@ var bn = class {
2319
2386
  }
2320
2387
  this.muteChanges += 1;
2321
2388
  let r = this.now();
2322
- n ? this.isPlaying && this.mutedSinceMs === null && (this.mutedSinceMs = r) : (this.mutedSinceMs !== null && (this.mutedTotalMs += r - this.mutedSinceMs, this.mutedSinceMs = null), this.firstAudioMs === 0 && this.isPlaying && (this.firstAudioMs = Math.max(J, r - this.startupAnchorMs))), this.isMuted = n, this.syncActive();
2389
+ n ? this.isPlaying && this.mutedSinceMs === null && (this.mutedSinceMs = r) : (this.mutedSinceMs !== null && (this.mutedTotalMs += r - this.mutedSinceMs, this.mutedSinceMs = null), this.firstAudioMs === 0 && this.isPlaying && (this.firstAudioMs = Math.max(q, r - this.startupAnchorMs))), this.isMuted = n, this.syncActive();
2323
2390
  }
2324
2391
  notePresentation(e) {
2325
2392
  this.endedFlag || e === this.presentation || (this.closePresentation(), this.presentation = e);
2326
2393
  }
2327
2394
  notePlayIntent() {
2328
- this.endedFlag || this.startupTimeMs > 0 || (this.startupAnchorMs = this.now(), this.manifestLoadMs > 0 && (this.manifestLoadMs = J), this.firstPlaylistMs > 0 && (this.firstPlaylistMs = J), this.firstFragLoadMs > 0 && (this.firstFragLoadMs = J), this.drmSetupMs > 0 && (this.drmSetupMs = J));
2395
+ this.endedFlag || this.startupTimeMs > 0 || (this.startupAnchorMs = this.now(), this.manifestLoadMs > 0 && (this.manifestLoadMs = q), this.firstPlaylistMs > 0 && (this.firstPlaylistMs = q), this.firstFragLoadMs > 0 && (this.firstFragLoadMs = q), this.drmSetupMs > 0 && (this.drmSetupMs = q));
2329
2396
  }
2330
2397
  noteReady() {
2331
- this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(J, this.now() - this.startupAnchorMs));
2398
+ this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(q, this.now() - this.startupAnchorMs));
2332
2399
  }
2333
2400
  noteFirstPlaylist() {
2334
- this.firstPlaylistMs === 0 && (this.firstPlaylistMs = Math.max(J, this.now() - this.startupAnchorMs));
2401
+ this.firstPlaylistMs === 0 && (this.firstPlaylistMs = Math.max(q, this.now() - this.startupAnchorMs));
2335
2402
  }
2336
2403
  noteDrmReady() {
2337
- this.drmSetupMs === 0 && (this.drmSetupMs = Math.max(J, this.now() - this.startupAnchorMs));
2404
+ this.drmSetupMs === 0 && (this.drmSetupMs = Math.max(q, this.now() - this.startupAnchorMs));
2338
2405
  }
2339
2406
  noteFirstBytes() {
2340
- this.sawFirstBytes = !0, this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(J, this.now() - this.startupAnchorMs));
2407
+ this.sawFirstBytes = !0, this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(q, this.now() - this.startupAnchorMs));
2341
2408
  }
2342
2409
  noteSeek() {
2343
2410
  this.endedFlag || (this.seekCount += 1, this.lastSeekMs = this.now());
@@ -2356,7 +2423,7 @@ var bn = class {
2356
2423
  let r = n ?? "";
2357
2424
  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";
2358
2425
  if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
2359
- if (fn.has(e)) return "ERROR_STAGE_RESOLVE";
2426
+ if (On.has(e)) return "ERROR_STAGE_RESOLVE";
2360
2427
  let i = t ?? "";
2361
2428
  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";
2362
2429
  }
@@ -2388,7 +2455,7 @@ var bn = class {
2388
2455
  let l = t.droppedFrames ?? 0;
2389
2456
  l > this.lastDropped && (o.droppedFramesDelta = l - this.lastDropped), this.lastDropped = l;
2390
2457
  let u = t.renditionSwitches ?? 0;
2391
- 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 = Y[t.state] ?? "PLAYER_STATE_UNSPECIFIED";
2458
+ 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 = J[t.state] ?? "PLAYER_STATE_UNSPECIFIED";
2392
2459
  let d = this.mutedTotalMs;
2393
2460
  this.mutedSinceMs !== null && (d += e - this.mutedSinceMs), d > this.lastHbMutedMs && (o.mutedMsDelta = Math.round(d - this.lastHbMutedMs)), this.lastHbMutedMs = d;
2394
2461
  let f = t.upshifts ?? 0;
@@ -2403,20 +2470,20 @@ var bn = class {
2403
2470
  if (this.lastRequestCount = g, _ > 0) {
2404
2471
  o.requestCountDelta = _;
2405
2472
  let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
2406
- n.length > 0 && (o.requestTimeP50Ms = dn(n, 50), o.requestTimeP95Ms = dn(n, 95));
2473
+ n.length > 0 && (o.requestTimeP50Ms = Dn(n, 50), o.requestTimeP95Ms = Dn(n, 95));
2407
2474
  }
2408
2475
  typeof t.latencySeconds == "number" && typeof t.targetLatencySeconds == "number" && (o.driftMs = Math.round((t.latencySeconds - t.targetLatencySeconds) * 1e3)), typeof t.playbackRate == "number" && t.playbackRate > 0 && (o.playbackRate = t.playbackRate), t.qualityPinned === !0 && (o.qualityPinned = !0), t.cdnHost && (o.cdnHost = t.cdnHost), this.maybeEmitMediaInfo(t), this.enqueue({ heartbeat: o }), this.flush(), s > 0 && this.noteFirstBytes();
2409
2476
  }
2410
2477
  maybeEmitMediaInfo(e) {
2411
2478
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
2412
2479
  let t = {};
2413
- e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = un[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);
2480
+ e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = En[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);
2414
2481
  let n = JSON.stringify(t);
2415
2482
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
2416
2483
  }
2417
2484
  end(e, t) {
2418
2485
  if (this.endedFlag) return;
2419
- this.endedFlag = !0, Z.delete(this);
2486
+ this.endedFlag = !0, X.delete(this);
2420
2487
  let n = t ?? this.now();
2421
2488
  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));
2422
2489
  let r = this.safeSample();
@@ -2430,7 +2497,7 @@ var bn = class {
2430
2497
  let c = r?.positionMs ?? 0;
2431
2498
  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));
2432
2499
  let l = e !== "END_REASON_ENDED";
2433
- l && this.lastStallMs > 0 && n - this.lastStallMs <= sn && (i.abandonAfterStallMs = Math.max(J, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= sn && (i.abandonAfterErrorMs = Math.max(J, 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);
2500
+ l && this.lastStallMs > 0 && n - this.lastStallMs <= Cn && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Cn && (i.abandonAfterErrorMs = Math.max(q, 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);
2434
2501
  let u = r?.decodedFrames ?? this.lastDecoded;
2435
2502
  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");
2436
2503
  }
@@ -2450,13 +2517,13 @@ var bn = class {
2450
2517
  };
2451
2518
  }
2452
2519
  noteCspBlocked() {
2453
- this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(gn(new URL(this.url).origin)));
2520
+ this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(Mn(new URL(this.url).origin)));
2454
2521
  }
2455
2522
  cspBlocked() {
2456
- return !!this.cspKey && X.has(this.cspKey);
2523
+ return !!this.cspKey && Y.has(this.cspKey);
2457
2524
  }
2458
2525
  enqueue(e) {
2459
- if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > an;) {
2526
+ if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > xn;) {
2460
2527
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
2461
2528
  this.pending.splice(e >= 0 ? e : 0, 1);
2462
2529
  }
@@ -2483,7 +2550,7 @@ var bn = class {
2483
2550
  };
2484
2551
  //#endregion
2485
2552
  //#region src/core/environment.ts
2486
- function xn() {
2553
+ function Ln() {
2487
2554
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
2488
2555
  let e;
2489
2556
  try {
@@ -2508,14 +2575,14 @@ function xn() {
2508
2575
  integration: "INTEGRATION_KIND_IFRAME"
2509
2576
  };
2510
2577
  }
2511
- function Sn() {
2578
+ function Rn() {
2512
2579
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
2513
2580
  let e = navigator.userAgentData, t = e?.platform ?? "";
2514
2581
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
2515
2582
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
2516
2583
  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";
2517
2584
  }
2518
- function Cn() {
2585
+ function zn() {
2519
2586
  let e = typeof navigator < "u" ? navigator.connection : void 0;
2520
2587
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
2521
2588
  let t = {
@@ -2534,17 +2601,17 @@ function Cn() {
2534
2601
  }
2535
2602
  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;
2536
2603
  }
2537
- function wn(e) {
2538
- let t = xn(), n = {
2539
- deviceClass: Sn(),
2604
+ function Bn(e) {
2605
+ let t = Ln(), n = {
2606
+ deviceClass: Rn(),
2540
2607
  integration: t.integration,
2541
- ...Cn()
2608
+ ...zn()
2542
2609
  };
2543
2610
  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);
2544
2611
  let r = e.getBoundingClientRect?.();
2545
2612
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
2546
2613
  }
2547
- async function Tn() {
2614
+ async function Vn() {
2548
2615
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
2549
2616
  if (!e?.getHighEntropyValues) return {};
2550
2617
  try {
@@ -2556,7 +2623,7 @@ async function Tn() {
2556
2623
  }
2557
2624
  //#endregion
2558
2625
  //#region src/core/version.ts
2559
- var En = "2.17.0", Dn = {
2626
+ var Hn = "2.19.0", Un = {
2560
2627
  accent: "#E1B600",
2561
2628
  accentText: "#1B1C23",
2562
2629
  background: "#0e0f13",
@@ -2567,7 +2634,7 @@ var En = "2.17.0", Dn = {
2567
2634
  border: "rgba(255, 255, 255, 0.1)",
2568
2635
  radius: "8px",
2569
2636
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
2570
- }, On = {
2637
+ }, Wn = {
2571
2638
  accent: "--havik-accent",
2572
2639
  accentText: "--havik-accent-text",
2573
2640
  background: "--havik-bg",
@@ -2579,26 +2646,26 @@ var En = "2.17.0", Dn = {
2579
2646
  radius: "--havik-radius",
2580
2647
  fontFamily: "--havik-font"
2581
2648
  };
2582
- function kn(e, t) {
2649
+ function Z(e, t) {
2583
2650
  let n = {
2584
- ...Dn,
2651
+ ...Un,
2585
2652
  ...t
2586
2653
  };
2587
- for (let t of Object.keys(On)) e.style.setProperty(On[t], n[t]);
2654
+ for (let t of Object.keys(Wn)) e.style.setProperty(Wn[t], n[t]);
2588
2655
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
2589
2656
  }
2590
2657
  //#endregion
2591
2658
  //#region src/ui/styles.ts
2592
- var An = "havik-player-styles", jn = "\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", Mn = /* @__PURE__ */ new WeakMap();
2593
- function Nn(e = document, t) {
2594
- let n = e.querySelector(`style#${An}`);
2595
- if (n && (!t || Mn.get(n) === t)) return;
2659
+ var Gn = "havik-player-styles", Kn = "\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", qn = /* @__PURE__ */ new WeakMap();
2660
+ function Jn(e = document, t) {
2661
+ let n = e.querySelector(`style#${Gn}`);
2662
+ if (n && (!t || qn.get(n) === t)) return;
2596
2663
  let r = e.createElement("style");
2597
- r.id = An, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = jn, Mn.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2664
+ r.id = Gn, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = Kn, qn.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2598
2665
  }
2599
2666
  //#endregion
2600
2667
  //#region src/ui/icons.ts
2601
- var Pn = {
2668
+ var Yn = {
2602
2669
  play: "<path d=\"M8 5v14l11-7z\"/>",
2603
2670
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
2604
2671
  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\"/>",
@@ -2612,20 +2679,20 @@ var Pn = {
2612
2679
  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\"/>"
2613
2680
  };
2614
2681
  function Q(e) {
2615
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Pn[e]}</svg>`;
2682
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Yn[e]}</svg>`;
2616
2683
  }
2617
2684
  //#endregion
2618
2685
  //#region src/ui/controls.ts
2619
- var Fn = 3e3, In = 250, Ln = /* @__PURE__ */ new Set([
2686
+ var Xn = 3e3, Zn = 250, Qn = /* @__PURE__ */ new Set([
2620
2687
  "GONE",
2621
2688
  "NOT_FOUND",
2622
2689
  "INVALID_URN",
2623
2690
  "UNAUTHORIZED"
2624
2691
  ]);
2625
- function Rn(e) {
2626
- return new zn(e);
2692
+ function $n(e) {
2693
+ return new er(e);
2627
2694
  }
2628
- var zn = class {
2695
+ var er = class {
2629
2696
  root;
2630
2697
  video;
2631
2698
  player;
@@ -2656,6 +2723,7 @@ var zn = class {
2656
2723
  statusKind = null;
2657
2724
  statusMsg = null;
2658
2725
  hasPlayed = !1;
2726
+ fsSupported = !0;
2659
2727
  lastError = null;
2660
2728
  logoUrl;
2661
2729
  statusOverlays;
@@ -2672,7 +2740,7 @@ var zn = class {
2672
2740
  scrubbing = !1;
2673
2741
  offFns = [];
2674
2742
  constructor(e) {
2675
- this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Fn, 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, Nn(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");
2743
+ this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Xn, 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, Jn(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");
2676
2744
  let t = (e, t, n) => {
2677
2745
  let r = this.doc.createElement(e);
2678
2746
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -2710,7 +2778,7 @@ var zn = class {
2710
2778
  let o = this.doc.createElement("span");
2711
2779
  o.textContent = "LIVE", this.liveGo = t("button", "havik-live__go", { type: "button" }), this.liveGo.textContent = "Go live", this.live.append(o, this.liveGo), this.time = t("div", "havik-time"), this.time.textContent = "0:00", this.time.style.display = "none";
2712
2780
  let s = t("div", "havik-spacer");
2713
- if (this.ccBtn = n("havik-btn", "cc", "Subtitles"), this.audioBtn = n("havik-btn", "settings", "Audio track"), this.qualityBtn = n("havik-btn", "settings", "Quality"), this.pipBtn = n("havik-btn", "pip", "Picture in picture"), this.fsBtn = n("havik-btn", "fullscreen", "Fullscreen"), this.ccBtn.style.display = "none", this.audioBtn.style.display = "none", this.qualityBtn.style.display = "none", this.pipSupported() || (this.pipBtn.style.display = "none"), i.append(this.playBtn, a, this.live, this.time, s, this.ccBtn, this.audioBtn, this.qualityBtn, this.pipBtn, this.fsBtn), this.bar.append(this.seek, i), this.menu = t("div", "havik-menu", { role: "menu" }), this.menu.hidden = !0, this.root.append(this.gradient, this.overlay, this.bar, this.menu), e.logoUrl) {
2781
+ if (this.ccBtn = n("havik-btn", "cc", "Subtitles"), this.audioBtn = n("havik-btn", "settings", "Audio track"), this.qualityBtn = n("havik-btn", "settings", "Quality"), this.pipBtn = n("havik-btn", "pip", "Picture in picture"), this.fsBtn = n("havik-btn", "fullscreen", "Fullscreen"), this.ccBtn.style.display = "none", this.audioBtn.style.display = "none", this.qualityBtn.style.display = "none", this.pipSupported() || (this.pipBtn.style.display = "none"), this.syncFullscreenSupport(), i.append(this.playBtn, a, this.live, this.time, s, this.ccBtn, this.audioBtn, this.qualityBtn, this.pipBtn, this.fsBtn), this.bar.append(this.seek, i), this.menu = t("div", "havik-menu", { role: "menu" }), this.menu.hidden = !0, this.root.append(this.gradient, this.overlay, this.bar, this.menu), e.logoUrl) {
2714
2782
  let n = t("div", "havik-watermark");
2715
2783
  n.style.backgroundImage = `url("${e.logoUrl}")`, this.root.append(n);
2716
2784
  }
@@ -2728,7 +2796,7 @@ var zn = class {
2728
2796
  }), this.on(this.muteBtn, "click", () => this.player.setMuted(!e.muted)), this.on(this.volSlider, "input", () => {
2729
2797
  let t = Number(this.volSlider.value);
2730
2798
  this.setVolumeFill(t), this.player.setVolume(t), t > 0 && e.muted && this.player.setMuted(!1);
2731
- }), this.on(this.liveGo, "click", () => this.player.seekToLive()), this.on(this.pipBtn, "click", () => void this.togglePip()), this.on(this.fsBtn, "click", () => void this.toggleFullscreen()), this.on(this.ccBtn, "click", () => this.toggleMenu("cc")), this.on(this.audioBtn, "click", () => this.toggleMenu("audio")), this.on(this.qualityBtn, "click", () => this.toggleMenu("quality")), this.on(this.seek, "pointerdown", (e) => this.onSeekDown(e)), this.on(this.seek, "keydown", (e) => this.onSeekKey(e)), this.on(e, "play", () => this.syncPlayPause()), this.on(e, "pause", () => this.syncPlayPause()), this.on(e, "volumechange", () => this.syncVolume()), this.on(e, "timeupdate", () => this.syncProgress()), this.on(e, "progress", () => this.syncProgress()), this.on(e, "durationchange", () => this.syncProgress()), this.offFns.push(this.player.on("statechange", () => this.syncState())), this.offFns.push(this.player.on("ended", () => this.syncState())), this.offFns.push(this.player.on("ready", () => this.refreshTracks())), this.offFns.push(this.player.on("qualitychange", () => this.onTracksChanged())), this.offFns.push(this.player.on("audiotrackchange", () => this.onTracksChanged())), this.offFns.push(this.player.on("texttrackchange", () => this.onTracksChanged())), this.offFns.push(this.player.on("pipchange", (e) => this.syncPip(e))), this.offFns.push(this.player.on("stats", () => this.syncLive())), this.offFns.push(this.player.on("error", (e) => {
2799
+ }), this.on(this.liveGo, "click", () => this.player.seekToLive()), this.on(this.pipBtn, "click", () => void this.togglePip()), this.on(this.fsBtn, "click", () => void this.toggleFullscreen()), this.on(this.ccBtn, "click", () => this.toggleMenu("cc")), this.on(this.audioBtn, "click", () => this.toggleMenu("audio")), this.on(this.qualityBtn, "click", () => this.toggleMenu("quality")), this.on(this.seek, "pointerdown", (e) => this.onSeekDown(e)), this.on(this.seek, "keydown", (e) => this.onSeekKey(e)), this.on(e, "play", () => this.syncPlayPause()), this.on(e, "pause", () => this.syncPlayPause()), this.on(e, "volumechange", () => this.syncVolume()), this.on(e, "timeupdate", () => this.syncProgress()), this.on(e, "progress", () => this.syncProgress()), this.on(e, "durationchange", () => this.syncProgress()), this.on(e, "loadedmetadata", () => this.syncFullscreenSupport()), this.offFns.push(this.player.on("statechange", () => this.syncState())), this.offFns.push(this.player.on("ended", () => this.syncState())), this.offFns.push(this.player.on("ready", () => this.refreshTracks())), this.offFns.push(this.player.on("qualitychange", () => this.onTracksChanged())), this.offFns.push(this.player.on("audiotrackchange", () => this.onTracksChanged())), this.offFns.push(this.player.on("texttrackchange", () => this.onTracksChanged())), this.offFns.push(this.player.on("pipchange", (e) => this.syncPip(e))), this.offFns.push(this.player.on("stats", () => this.syncLive())), this.offFns.push(this.player.on("error", (e) => {
2732
2800
  this.lastError = e, this.statusKind = null, this.syncState();
2733
2801
  }));
2734
2802
  let t = (e) => e.pointerType !== "touch";
@@ -2758,7 +2826,7 @@ var zn = class {
2758
2826
  let t = this.surfaceWasHidden;
2759
2827
  this.tapTimer = setTimeout(() => {
2760
2828
  this.tapTimer = void 0, this.toggleBar(t);
2761
- }, In);
2829
+ }, Zn);
2762
2830
  }
2763
2831
  toggleBar(e) {
2764
2832
  e ? this.poke() : this.hideIfIdle();
@@ -2793,7 +2861,7 @@ var zn = class {
2793
2861
  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);
2794
2862
  } else {
2795
2863
  let r = this.doc.createElement("div");
2796
- if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Ln.has(this.lastError.code)) {
2864
+ if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Qn.has(this.lastError.code)) {
2797
2865
  let e = this.doc.createElement("button");
2798
2866
  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);
2799
2867
  }
@@ -2834,7 +2902,7 @@ var zn = class {
2834
2902
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
2835
2903
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
2836
2904
  }
2837
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Bn(this.video.currentTime)} / ${Bn(this.video.duration)}`);
2905
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${tr(this.video.currentTime)} / ${tr(this.video.duration)}`);
2838
2906
  }
2839
2907
  syncLive() {
2840
2908
  let e = this.player.getStats(), t = e.isLive !== !1, n = this.player.state === "ended", r = !t && !this.streamEnded();
@@ -2884,17 +2952,17 @@ var zn = class {
2884
2952
  renderQualityMenu() {
2885
2953
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
2886
2954
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
2887
- for (let n of e) this.menu.append(this.menuItem(Vn(n), t === n.index, () => this.player.setQuality(n.index)));
2955
+ for (let n of e) this.menu.append(this.menuItem(nr(n), t === n.index, () => this.player.setQuality(n.index)));
2888
2956
  }
2889
2957
  renderAudioMenu() {
2890
2958
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
2891
2959
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
2892
- for (let t of e) this.menu.append(this.menuItem(Hn(t), t.default, () => this.player.setAudioTrack(t.id)));
2960
+ for (let t of e) this.menu.append(this.menuItem(rr(t), t.default, () => this.player.setAudioTrack(t.id)));
2893
2961
  }
2894
2962
  renderCcMenu() {
2895
2963
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
2896
2964
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
2897
- for (let t of e) this.menu.append(this.menuItem(Un(t), !1, () => this.player.setTextTrack(t.id)));
2965
+ for (let t of e) this.menu.append(this.menuItem(ir(t), !1, () => this.player.setTextTrack(t.id)));
2898
2966
  }
2899
2967
  onTracksChanged() {
2900
2968
  this.openMenu && this.renderMenu(this.openMenu);
@@ -2914,9 +2982,12 @@ var zn = class {
2914
2982
  }
2915
2983
  async toggleFullscreen() {
2916
2984
  try {
2917
- S(this.video, this.root) ? await w(this.video, this.root) : await C(this.video, this.root);
2985
+ S(this.video, this.root) ? await T(this.video, this.root) : await w(this.video, this.root);
2918
2986
  } catch {}
2919
2987
  }
2988
+ syncFullscreenSupport() {
2989
+ this.fsSupported = C(this.video, this.root), this.fsBtn.style.display = this.fsSupported ? "" : "none";
2990
+ }
2920
2991
  syncFullscreen() {
2921
2992
  let e = S(this.video, this.root);
2922
2993
  this.setIcon(this.fsBtn, e ? "fullscreenExit" : "fullscreen"), this.fsBtn.setAttribute("aria-label", e ? "Exit fullscreen" : "Fullscreen");
@@ -2952,6 +3023,7 @@ var zn = class {
2952
3023
  this.player.setMuted(!this.video.muted);
2953
3024
  break;
2954
3025
  case "f":
3026
+ if (!this.fsSupported) return;
2955
3027
  this.toggleFullscreen();
2956
3028
  break;
2957
3029
  case "c":
@@ -2995,41 +3067,41 @@ var zn = class {
2995
3067
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
2996
3068
  }
2997
3069
  };
2998
- function Bn(e) {
3070
+ function tr(e) {
2999
3071
  (!Number.isFinite(e) || e < 0) && (e = 0);
3000
3072
  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");
3001
3073
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
3002
3074
  }
3003
- function Vn(e) {
3075
+ function nr(e) {
3004
3076
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
3005
3077
  }
3006
- function Hn(e) {
3078
+ function rr(e) {
3007
3079
  return e.name || e.lang || `Track ${e.id}`;
3008
3080
  }
3009
- function Un(e) {
3081
+ function ir(e) {
3010
3082
  return e.name || e.lang || `Track ${e.id}`;
3011
3083
  }
3012
3084
  //#endregion
3013
3085
  //#region src/managed/index.ts
3014
- var Wn = 6e3, Gn = 45e3, Kn = 2e3, qn = 3, Jn = 5e3, Yn = 2e3, Xn = 48e4, Zn = "keySystemLicenseRequestFailed";
3015
- function Qn(e) {
3086
+ var ar = 6e3, or = 45e3, sr = 2e3, cr = 3, lr = 5e3, ur = 2e3, dr = 48e4, fr = "keySystemLicenseRequestFailed";
3087
+ function pr(e) {
3016
3088
  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)})`);
3017
- if (e.env !== void 0) return Ge(e.env);
3089
+ if (e.env !== void 0) return rt(e.env);
3018
3090
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
3019
3091
  return e.baseUrl;
3020
3092
  }
3021
- async function $n(e) {
3093
+ async function mr(e) {
3022
3094
  if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
3023
- let t = Qn(e);
3095
+ let t = pr(e);
3024
3096
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
3025
3097
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
3026
- let r = new er({
3098
+ let r = new hr({
3027
3099
  ...e,
3028
3100
  baseUrl: t
3029
3101
  });
3030
3102
  return await r.start(), r;
3031
3103
  }
3032
- var er = class {
3104
+ var hr = class {
3033
3105
  opts;
3034
3106
  abort = new AbortController();
3035
3107
  listeners = {};
@@ -3080,7 +3152,7 @@ var er = class {
3080
3152
  this.opts.muted && (this.opts.video.muted = !0), this.opts.poster && (this.opts.video.poster = this.opts.poster), this.mountControls(), this.attachPipListeners(), this.attachEndedPlayGuard(), this.setState("loading");
3081
3153
  let e = ++this.loadGen, t = this.resolveOptions();
3082
3154
  try {
3083
- let n = await y(t);
3155
+ let n = await v(t);
3084
3156
  if (await this.onResolved(n, e), e === this.loadGen && this._state === "error" && this._lastError) {
3085
3157
  let e = this._lastError;
3086
3158
  throw this.destroy(), e;
@@ -3103,11 +3175,11 @@ var er = class {
3103
3175
  };
3104
3176
  }
3105
3177
  beginArming(e, t, n = !1) {
3106
- let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? E(this.opts.baseUrl);
3178
+ let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? D(this.opts.baseUrl);
3107
3179
  r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
3108
3180
  }
3109
3181
  beginArmingByPolling(e) {
3110
- b({
3182
+ y({
3111
3183
  ...this.resolveOptions(),
3112
3184
  signal: this.abort.signal,
3113
3185
  waitForLive: this.buildWaitConfig(e)
@@ -3124,7 +3196,7 @@ var er = class {
3124
3196
  setTimeout(() => {
3125
3197
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
3126
3198
  phase: i ? "unavailable" : "tooEarly",
3127
- retryInMs: Gn,
3199
+ retryInMs: or,
3128
3200
  attempt: 1,
3129
3201
  elapsedMs: 0,
3130
3202
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -3141,7 +3213,7 @@ var er = class {
3141
3213
  }
3142
3214
  }
3143
3215
  }, h = () => {
3144
- a || s || p() || (s = !0, b({
3216
+ a || s || p() || (s = !0, y({
3145
3217
  ...this.resolveOptions(),
3146
3218
  signal: c.signal,
3147
3219
  waitForLive: this.buildWaitConfig(e)
@@ -3149,7 +3221,7 @@ var er = class {
3149
3221
  a || p() || c.signal.aborted || (a = !0, this.closeArming(), this.fail(e instanceof n ? e : new n("INTERNAL", 0, String(e))));
3150
3222
  }));
3151
3223
  }, g = () => {
3152
- a || p() || y(this.resolveOptions()).then((e) => m(e)).catch((e) => {
3224
+ a || p() || v(this.resolveOptions()).then((e) => m(e)).catch((e) => {
3153
3225
  if (!(a || p())) {
3154
3226
  if (e instanceof n && o(e.code)) {
3155
3227
  h();
@@ -3163,13 +3235,13 @@ var er = class {
3163
3235
  !a && !p() && h();
3164
3236
  }, e);
3165
3237
  };
3166
- _(Wn), this.armingSub = T({
3238
+ _(ar), this.armingSub = E({
3167
3239
  eventsBaseUrl: t,
3168
3240
  matchUrn: this.opts.matchUrn,
3169
3241
  credential: this.opts.credential,
3170
- onAlive: () => _(Gn),
3242
+ onAlive: () => _(or),
3171
3243
  onState: (e) => {
3172
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Kn);
3244
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * sr);
3173
3245
  },
3174
3246
  onError: () => h()
3175
3247
  });
@@ -3192,7 +3264,7 @@ var er = class {
3192
3264
  let n = await s(this.opts.credential);
3193
3265
  if (this.destroyed || t !== this.loadGen) return;
3194
3266
  this.setState("loading");
3195
- let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = Ze(this.opts.video, (e) => {
3267
+ let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = lt(this.opts.video, (e) => {
3196
3268
  this._state !== "ended" && this._state !== "error" && this.setState(e);
3197
3269
  });
3198
3270
  if (await i.load(), this.destroyed || t !== this.loadGen) {
@@ -3214,26 +3286,26 @@ var er = class {
3214
3286
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
3215
3287
  let i = e.analytics?.sid;
3216
3288
  if (!i) return;
3217
- let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = yn(this.opts.baseUrl, a, e.analytics?.endpoint);
3289
+ let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = Fn(this.opts.baseUrl, a, e.analytics?.endpoint);
3218
3290
  if (!o) {
3219
3291
  s && setTimeout(() => {
3220
3292
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
3221
3293
  }, 0);
3222
3294
  return;
3223
3295
  }
3224
- let c = this.opts.video, l = new bn({
3296
+ let c = this.opts.video, l = new In({
3225
3297
  endpoint: o,
3226
3298
  sid: i,
3227
3299
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
3228
- sdkVersion: En,
3229
- environment: wn(c),
3300
+ sdkVersion: Hn,
3301
+ environment: Bn(c),
3230
3302
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
3231
3303
  onIdle: () => this.onAnalyticsIdle(t),
3232
3304
  onBlocked: (e) => setTimeout(() => {
3233
3305
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
3234
3306
  }, 0),
3235
3307
  sample: () => {
3236
- let e = this.engine?.getStats() ?? Ke, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
3308
+ let e = this.engine?.getStats() ?? it, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
3237
3309
  return {
3238
3310
  ...e,
3239
3311
  bufferedMs: Math.round(t * 1e3),
@@ -3247,7 +3319,7 @@ var er = class {
3247
3319
  let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
3248
3320
  c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
3249
3321
  c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
3250
- }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), Tn().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3322
+ }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), Vn().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3251
3323
  }
3252
3324
  currentPresentation() {
3253
3325
  let e = this.opts.video;
@@ -3262,10 +3334,11 @@ var er = class {
3262
3334
  video: this.opts.video,
3263
3335
  descriptor: e,
3264
3336
  credential: t,
3265
- deviceId: k(),
3337
+ deviceId: A(),
3266
3338
  userId: this.opts.userId,
3267
3339
  lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
3268
3340
  snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
3341
+ rememberBandwidth: this.opts.rememberBandwidth,
3269
3342
  mediaDuringKey: this.opts.mediaDuringKey,
3270
3343
  debug: this.opts.debug,
3271
3344
  deferLoad: r,
@@ -3274,9 +3347,9 @@ var er = class {
3274
3347
  freshLicenseUrl: () => this.refreshLicense()
3275
3348
  }, o = this.opts.engine ?? "auto";
3276
3349
  if (o === "native") return new W(a);
3277
- if (o === "hls") return new en(a);
3278
- if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && H(this.opts.video) && U() || !e.drmEnabled && lt() && H(this.opts.video)) return new W(a);
3279
- if (bt()) return new en(a);
3350
+ if (o === "hls") return new _n(a);
3351
+ if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && H(this.opts.video) && U() || !e.drmEnabled && xt() && H(this.opts.video)) return new W(a);
3352
+ if (Nt()) return new _n(a);
3280
3353
  if (H(this.opts.video)) return new W(a);
3281
3354
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
3282
3355
  }
@@ -3324,11 +3397,11 @@ var er = class {
3324
3397
  }
3325
3398
  startLiveState(e) {
3326
3399
  if (this.opts.liveStateEvents === !1) return;
3327
- let t = this.opts.eventsBaseUrl ?? E(this.opts.baseUrl);
3400
+ let t = this.opts.eventsBaseUrl ?? D(this.opts.baseUrl);
3328
3401
  if (!t) return;
3329
3402
  this.closeLiveState();
3330
3403
  let r = 0, i = !1;
3331
- this.liveStateSub = T({
3404
+ this.liveStateSub = E({
3332
3405
  eventsBaseUrl: t,
3333
3406
  matchUrn: this.opts.matchUrn,
3334
3407
  credential: this.opts.credential,
@@ -3339,7 +3412,7 @@ var er = class {
3339
3412
  r = 0, i = !1;
3340
3413
  },
3341
3414
  onError: () => {
3342
- this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= qn && (i = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${r} 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.`))));
3415
+ this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= cr && (i = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${r} 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.`))));
3343
3416
  }
3344
3417
  });
3345
3418
  }
@@ -3353,7 +3426,7 @@ var er = class {
3353
3426
  return;
3354
3427
  }
3355
3428
  let e = this.hiddenAtMs;
3356
- this.hiddenAtMs = null, e != null && Date.now() - e >= Jn && this.resyncLiveState();
3429
+ this.hiddenAtMs = null, e != null && Date.now() - e >= lr && this.resyncLiveState();
3357
3430
  }, this.onReturnPageShow = (e) => {
3358
3431
  e.persisted && this.resyncLiveState();
3359
3432
  }, document.addEventListener("visibilitychange", this.onReturnVisible), typeof window < "u" && window.addEventListener("pageshow", this.onReturnPageShow));
@@ -3385,7 +3458,7 @@ var er = class {
3385
3458
  scheduleRejoin(e) {
3386
3459
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
3387
3460
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
3388
- }, Math.random() * Kn));
3461
+ }, Math.random() * sr));
3389
3462
  }
3390
3463
  cancelRejoin() {
3391
3464
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -3409,7 +3482,7 @@ var er = class {
3409
3482
  }
3410
3483
  t.controls = !1;
3411
3484
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
3412
- r && r.insertBefore(n, t), n.appendChild(t), kn(n, this.opts.theme), this.container = n, this.controlBar = Rn({
3485
+ r && r.insertBefore(n, t), n.appendChild(t), Z(n, this.opts.theme), this.container = n, this.controlBar = $n({
3413
3486
  root: n,
3414
3487
  video: t,
3415
3488
  player: this,
@@ -3447,7 +3520,7 @@ var er = class {
3447
3520
  }
3448
3521
  startStats() {
3449
3522
  this.stopStats();
3450
- let e = Math.max(500, this.opts.statsIntervalMs ?? Yn);
3523
+ let e = Math.max(500, this.opts.statsIntervalMs ?? ur);
3451
3524
  this.statsTimer = setInterval(() => {
3452
3525
  if (!this.engine) return;
3453
3526
  let e = this.engine.getStats();
@@ -3458,14 +3531,14 @@ var er = class {
3458
3531
  this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
3459
3532
  }
3460
3533
  isStaleLicenseDenial(e) {
3461
- return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== Zn || e.error.httpStatus !== 403 ? !1 : K(this._descriptor?.drm?.widevine?.licenseUrl);
3534
+ return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== fr || e.error.httpStatus !== 403 ? !1 : K(this._descriptor?.drm?.widevine?.licenseUrl);
3462
3535
  }
3463
3536
  scheduleLicenseRefresh() {
3464
3537
  if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
3465
3538
  typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
3466
3539
  document.visibilityState !== "visible" || this.destroyed || K(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
3467
3540
  }, document.addEventListener("visibilitychange", this.onRefocus));
3468
- let e = this.opts.licenseRefreshMs ?? Xn;
3541
+ let e = this.opts.licenseRefreshMs ?? dr;
3469
3542
  e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
3470
3543
  }
3471
3544
  stopRefresh() {
@@ -3477,7 +3550,7 @@ var er = class {
3477
3550
  if (this.refreshInFlight?.engine === e) return this.refreshInFlight.promise;
3478
3551
  let t = (async () => {
3479
3552
  try {
3480
- let t = await y(this.resolveOptions());
3553
+ let t = await v(this.resolveOptions());
3481
3554
  if (this.destroyed || this.engine !== e) return;
3482
3555
  let n = t.drm?.widevine?.licenseUrl, r = t.drm?.fairplay?.licenseUrl;
3483
3556
  return (n || r) && (e.setLicenseUrls({
@@ -3522,7 +3595,7 @@ var er = class {
3522
3595
  this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
3523
3596
  }
3524
3597
  getStats() {
3525
- return this.engine?.getStats() ?? Ke;
3598
+ return this.engine?.getStats() ?? it;
3526
3599
  }
3527
3600
  getQualityLevels() {
3528
3601
  return this.engine?.getQualityLevels() ?? [];
@@ -3561,10 +3634,13 @@ var er = class {
3561
3634
  e.pictureInPictureElement === this.opts.video && typeof e.exitPictureInPicture == "function" && await e.exitPictureInPicture();
3562
3635
  }
3563
3636
  async enterFullscreen() {
3564
- return !this.destroyed && C(this.opts.video, this.container ?? void 0);
3637
+ return !this.destroyed && w(this.opts.video, this.container ?? void 0);
3565
3638
  }
3566
3639
  async exitFullscreen() {
3567
- await w(this.opts.video, this.container ?? void 0);
3640
+ await T(this.opts.video, this.container ?? void 0);
3641
+ }
3642
+ fullscreenSupported() {
3643
+ return !this.destroyed && C(this.opts.video, this.container ?? void 0);
3568
3644
  }
3569
3645
  retry() {
3570
3646
  return this.reload();
@@ -3574,7 +3650,7 @@ var er = class {
3574
3650
  let e = ++this.loadGen;
3575
3651
  this.teardownPlayback();
3576
3652
  try {
3577
- let t = await b({
3653
+ let t = await y({
3578
3654
  ...this.resolveOptions(),
3579
3655
  waitForLive: this.opts.waitForLive ? this.buildWaitConfig(e) : void 0
3580
3656
  });
@@ -3632,7 +3708,7 @@ function $(e) {
3632
3708
  }
3633
3709
  //#endregion
3634
3710
  //#region src/embed/host.ts
3635
- function tr(e) {
3711
+ function gr(e) {
3636
3712
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
3637
3713
  if (!e.src) throw Error("mountEmbed: opts.src is required");
3638
3714
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -3691,15 +3767,15 @@ function tr(e) {
3691
3767
  }
3692
3768
  //#endregion
3693
3769
  //#region src/embed/page.ts
3694
- var nr = /^[A-Za-z0-9:_.-]{1,128}$/;
3695
- function rr(e) {
3770
+ var _r = /^[A-Za-z0-9:_.-]{1,128}$/;
3771
+ function vr(e) {
3696
3772
  if (typeof e == "boolean") return e;
3697
3773
  if (typeof e == "object" && e) {
3698
3774
  let t = e.endpoint;
3699
3775
  return typeof t == "string" ? { endpoint: t } : {};
3700
3776
  }
3701
3777
  }
3702
- function ir() {
3778
+ function yr() {
3703
3779
  let e = window.HAVIK_EMBED_CONFIG;
3704
3780
  if (e) return {
3705
3781
  baseUrl: e.baseUrl ?? "",
@@ -3709,7 +3785,7 @@ function ir() {
3709
3785
  autoplay: e.autoplay ?? !0,
3710
3786
  muted: e.muted ?? !0,
3711
3787
  waitForLive: e.waitForLive ?? !0,
3712
- analytics: rr(e.analytics)
3788
+ analytics: vr(e.analytics)
3713
3789
  };
3714
3790
  let t = new URLSearchParams(location.search);
3715
3791
  return {
@@ -3722,9 +3798,9 @@ function ir() {
3722
3798
  waitForLive: !0
3723
3799
  };
3724
3800
  }
3725
- async function ar() {
3726
- let e = ir();
3727
- sr();
3801
+ async function br() {
3802
+ let e = yr();
3803
+ Sr();
3728
3804
  let t = document.createElement("video");
3729
3805
  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);
3730
3806
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -3779,12 +3855,12 @@ async function ar() {
3779
3855
  code: e.code,
3780
3856
  message: e.message
3781
3857
  })), e.on("autoplayblocked", () => {
3782
- i({ type: "oddin:autoplayblocked" }), or(t, e);
3858
+ i({ type: "oddin:autoplayblocked" }), xr(t, e);
3783
3859
  });
3784
3860
  }, s = async (r) => {
3785
3861
  a?.destroy(), a = null;
3786
3862
  try {
3787
- let n = await $n({
3863
+ let n = await mr({
3788
3864
  video: t,
3789
3865
  baseUrl: e.baseUrl,
3790
3866
  matchUrn: r,
@@ -3846,7 +3922,7 @@ async function ar() {
3846
3922
  a?.retry();
3847
3923
  break;
3848
3924
  case "oddin:load":
3849
- typeof e.matchUrn == "string" && nr.test(e.matchUrn) && s(e.matchUrn);
3925
+ typeof e.matchUrn == "string" && _r.test(e.matchUrn) && s(e.matchUrn);
3850
3926
  break;
3851
3927
  case "oddin:destroy": c();
3852
3928
  }
@@ -3858,18 +3934,18 @@ async function ar() {
3858
3934
  protocol: 1
3859
3935
  });
3860
3936
  }
3861
- function or(e, t) {
3937
+ function xr(e, t) {
3862
3938
  if (document.getElementById("havik-tap")) return;
3863
3939
  let n = document.createElement("button");
3864
3940
  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", () => {
3865
3941
  n.remove(), t.play();
3866
3942
  }), document.body.appendChild(n);
3867
3943
  }
3868
- function sr() {
3944
+ function Sr() {
3869
3945
  let e = document.createElement("style");
3870
3946
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
3871
3947
  }
3872
3948
  //#endregion
3873
- export { Dn as ODDIN_THEME, n as PlaybackError, kn as applyTheme, Ge as baseUrlForEnv, ar as bootEmbed, Te as clearDeviceId, $n as createPlayer, E as deriveEventsBaseUrl, Ve as detectDrmSupport, C as enterVideoFullscreen, w as exitVideoFullscreen, _e as fetchCatalog, ye as fetchTournament, xe as flattenMatches, k as getDeviceId, Ue as isLowLatencyManifest, $ as isOddinMessage, De as licenseRequestHeaders, tr as mountEmbed, v as pollToLive, b as resolveStream, T as subscribeLiveState, S as videoFullscreenActive, Ce as watchStatus };
3949
+ export { Un as ODDIN_THEME, n as PlaybackError, Z as applyTheme, rt as baseUrlForEnv, br as bootEmbed, Te as clearDeviceId, Ie as clearRememberedBandwidth, mr as createPlayer, D as deriveEventsBaseUrl, $e as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, _e as fetchCatalog, ye as fetchTournament, xe as flattenMatches, C as fullscreenSupported, A as getDeviceId, tt as isLowLatencyManifest, $ as isOddinMessage, De as licenseRequestHeaders, gr as mountEmbed, de as pollToLive, y as resolveStream, E as subscribeLiveState, S as videoFullscreenActive, Ce as watchStatus };
3874
3950
 
3875
3951
  //# sourceMappingURL=index.js.map