@oddin-gg/havik-player 2.16.12 → 2.16.13

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
@@ -2519,7 +2519,7 @@ async function Sn() {
2519
2519
  }
2520
2520
  //#endregion
2521
2521
  //#region src/core/version.ts
2522
- var Cn = "2.16.12", wn = {
2522
+ var Cn = "2.16.13", wn = {
2523
2523
  accent: "#E1B600",
2524
2524
  accentText: "#1B1C23",
2525
2525
  background: "#0e0f13",
@@ -2622,6 +2622,7 @@ var In = class {
2622
2622
  lastError = null;
2623
2623
  logoUrl;
2624
2624
  statusOverlays;
2625
+ streamEnded;
2625
2626
  endedMessage;
2626
2627
  interruptedMessage;
2627
2628
  errorMessage;
@@ -2634,7 +2635,7 @@ var In = class {
2634
2635
  scrubbing = !1;
2635
2636
  offFns = [];
2636
2637
  constructor(e) {
2637
- this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Mn, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, An(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");
2638
+ this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Mn, 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, An(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");
2638
2639
  let t = (e, t, n) => {
2639
2640
  let r = this.doc.createElement(e);
2640
2641
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -2799,8 +2800,8 @@ var In = class {
2799
2800
  !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Ln(this.video.currentTime)} / ${Ln(this.video.duration)}`);
2800
2801
  }
2801
2802
  syncLive() {
2802
- let e = this.player.getStats(), t = e.isLive !== !1;
2803
- this.live.style.display = t ? "" : "none", this.time.style.display = t ? "none" : "", this.seek.style.display = t ? "none" : "", this.live.classList.toggle("is-live", e.atLiveEdge !== !1 && t);
2803
+ let e = this.player.getStats(), t = e.isLive !== !1, n = this.player.state === "ended", r = !t && !this.streamEnded();
2804
+ this.live.style.display = t && !n ? "" : "none", this.time.style.display = r ? "" : "none", this.seek.style.display = r ? "" : "none", this.live.classList.toggle("is-live", e.atLiveEdge !== !1 && t);
2804
2805
  }
2805
2806
  onSeekDown(e) {
2806
2807
  let t = this.seekableRange();
@@ -3000,6 +3001,7 @@ var Xn = class {
3000
3001
  container = null;
3001
3002
  detachMedia;
3002
3003
  detachPip;
3004
+ detachEndedPlayGuard;
3003
3005
  statsTimer;
3004
3006
  refreshTimer;
3005
3007
  refreshInFlight;
@@ -3035,7 +3037,7 @@ var Xn = class {
3035
3037
  return this._endedReason;
3036
3038
  }
3037
3039
  async start() {
3038
- this.opts.muted && (this.opts.video.muted = !0), this.opts.poster && (this.opts.video.poster = this.opts.poster), this.mountControls(), this.attachPipListeners(), this.setState("loading");
3040
+ 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");
3039
3041
  let e = ++this.loadGen, t = this.resolveOptions();
3040
3042
  try {
3041
3043
  let n = await v(t);
@@ -3307,12 +3309,18 @@ var Xn = class {
3307
3309
  onStreamEnded(e = !1, t) {
3308
3310
  if (!this.destroyed) {
3309
3311
  if ((e || !this.rejoinEnabled()) && (this.cancelRejoin(), this.closeLiveState()), this.endedHandled) {
3310
- t === "match_ended" && this._endedReason !== "match_ended" && (this._endedReason = t, this.emit("ended", t));
3312
+ t === "match_ended" && this._endedReason !== "match_ended" && (this._endedReason = t, this.emit("ended", t), this.leavePipOnEnd());
3311
3313
  return;
3312
3314
  }
3313
- this.endedHandled = !0, this._endedReason = t ?? null, this.stopRefresh(), this.pendingStartLoad = !1, this.engine?.stop(), this.setState("ended");
3315
+ this.endedHandled = !0, this._endedReason = t ?? null, this.stopRefresh(), this.pendingStartLoad = !1, this.engine?.stop(), this.setState("ended"), this.leavePipOnEnd();
3314
3316
  }
3315
3317
  }
3318
+ leavePipOnEnd() {
3319
+ this._endedReason === "interrupted" && this.rejoinEnabled() || this.exitPictureInPicture().catch(() => {});
3320
+ }
3321
+ get streamEnded() {
3322
+ return this._state === "ended" && this.endedHandled;
3323
+ }
3316
3324
  rejoinEnabled() {
3317
3325
  return this.opts.rejoinOnLive !== !1 && this.opts.liveStateEvents !== !1;
3318
3326
  }
@@ -3350,6 +3358,7 @@ var Xn = class {
3350
3358
  logoUrl: this.opts.theme?.logoUrl,
3351
3359
  statusOverlays: this.opts.statusOverlays,
3352
3360
  endedMessage: this.opts.endedMessage,
3361
+ streamEnded: () => this.streamEnded,
3353
3362
  interruptedMessage: this.opts.interruptedMessage,
3354
3363
  errorMessage: this.opts.errorMessage,
3355
3364
  cspNonce: this.opts.cspNonce
@@ -3372,6 +3381,12 @@ var Xn = class {
3372
3381
  e.removeEventListener("enterpictureinpicture", n), e.removeEventListener("leavepictureinpicture", r), i?.removeEventListener("fullscreenchange", t), i?.removeEventListener("webkitfullscreenchange", t);
3373
3382
  };
3374
3383
  }
3384
+ attachEndedPlayGuard() {
3385
+ let e = this.opts.video, t = () => {
3386
+ this.streamEnded && e.pause();
3387
+ };
3388
+ e.addEventListener("play", t), this.detachEndedPlayGuard = () => e.removeEventListener("play", t);
3389
+ }
3375
3390
  startStats() {
3376
3391
  this.stopStats();
3377
3392
  let e = Math.max(500, this.opts.statsIntervalMs ?? Gn);
@@ -3430,6 +3445,7 @@ var Xn = class {
3430
3445
  this.idleClosed = !1, await this.reload();
3431
3446
  return;
3432
3447
  }
3448
+ if (this.streamEnded) return;
3433
3449
  let t = this.pendingStartLoad && this._state !== "ended" && this._state !== "error";
3434
3450
  this.opts.autoplay === !1 && this.analyticsSession?.notePlayIntent(), t && (this.pendingStartLoad = !1, this.setState("loading"), this.engine?.startLoad());
3435
3451
  try {
@@ -3515,7 +3531,7 @@ var Xn = class {
3515
3531
  return n.add(t), () => n.delete(t);
3516
3532
  }
3517
3533
  destroy() {
3518
- this.destroyed || (this.destroyed = !0, this.loadGen += 1, this.abort.abort(), this.stopStats(), this.stopRefresh(), this.unmountControls(), this.cancelRejoin(), this.closeArming(), this.closeLiveState(), this.detachMedia?.(), this.detachPip?.(), this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.engine?.destroy(), this.engine = null, this.setState("idle"), this.clearListeners());
3534
+ this.destroyed || (this.destroyed = !0, this.loadGen += 1, this.abort.abort(), this.stopStats(), this.stopRefresh(), this.unmountControls(), this.cancelRejoin(), this.closeArming(), this.closeLiveState(), this.detachMedia?.(), this.detachPip?.(), this.detachEndedPlayGuard?.(), this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.engine?.destroy(), this.engine = null, this.setState("idle"), this.clearListeners());
3519
3535
  }
3520
3536
  clearListeners() {
3521
3537
  for (let e of Object.keys(this.listeners)) this.listeners[e]?.clear();