movi-player 0.3.4 → 0.3.5

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/element.cjs CHANGED
@@ -51298,10 +51298,10 @@ class CanvasRenderer {
51298
51298
  Logger$1.error(TAG$d, "Error redrawing frame after resize", A2);
51299
51299
  }
51300
51300
  if (this.subtitleOverlay) {
51301
- const b2 = A, j2 = v, s3 = CanvasRenderer.computeSubtitleBottomPadding(j2);
51302
- this.subtitleOverlay.style.position = "absolute", this.subtitleOverlay.style.top = "0", this.subtitleOverlay.style.left = "0", this.subtitleOverlay.style.right = "auto", this.subtitleOverlay.style.bottom = "auto", this.subtitleOverlay.style.width = `${b2}px`, this.subtitleOverlay.style.height = `${j2}px`, this.subtitleOverlay.style.margin = "0", this.subtitleOverlay.style.padding = "0";
51303
- const E2 = this.subtitleControlsPadding > 0 ? this.subtitleControlsPadding : s3;
51304
- this.subtitleOverlay.style.paddingBottom = `${E2}px`, this.subtitleOverlay.style.display = "flex", this.subtitleOverlay.style.flexDirection = "column", this.subtitleOverlay.style.justifyContent = "flex-end", this.subtitleOverlay.style.alignItems = "center", this.subtitleOverlay.style.transform = "none", this.subtitleOverlay.style.boxSizing = "border-box", this.activeSubtitleCue && _ && this.scheduleSubtitleRerender();
51301
+ const b2 = ((this.rotation ?? 0) % 360 + 360) % 360, j2 = 90 === b2 || 270 === b2, s3 = j2 ? v : A, E2 = j2 ? A : v, F2 = CanvasRenderer.computeSubtitleBottomPadding(E2);
51302
+ this.subtitleOverlay.style.position = "absolute", this.subtitleOverlay.style.right = "auto", this.subtitleOverlay.style.bottom = "auto", this.subtitleOverlay.style.width = `${s3}px`, this.subtitleOverlay.style.height = `${E2}px`, this.subtitleOverlay.style.left = (A - s3) / 2 + "px", this.subtitleOverlay.style.top = (v - E2) / 2 + "px", this.subtitleOverlay.style.margin = "0", this.subtitleOverlay.style.padding = "0";
51303
+ const k2 = this.subtitleControlsPadding > 0 ? this.subtitleControlsPadding : F2;
51304
+ this.subtitleOverlay.style.paddingBottom = `${k2}px`, this.subtitleOverlay.style.display = "flex", this.subtitleOverlay.style.flexDirection = "column", this.subtitleOverlay.style.justifyContent = "flex-end", this.subtitleOverlay.style.alignItems = "center", this.subtitleOverlay.style.transformOrigin = "center center", this.subtitleOverlay.style.transform = b2 ? `rotate(${b2}deg)` : "none", this.subtitleOverlay.style.boxSizing = "border-box", this.activeSubtitleCue && _ && this.scheduleSubtitleRerender();
51305
51305
  }
51306
51306
  }
51307
51307
  }
@@ -51605,15 +51605,17 @@ class CanvasRenderer {
51605
51605
  const A2 = k - N - D;
51606
51606
  P = A2 < 0 ? Math.max(0, k - N - 10) : A2, P = Math.max(0, Math.min(P, k - N));
51607
51607
  }
51608
- R = Math.max(0, Math.min(R, F - w)), this.subtitleOverlay.style.position = "absolute", this.subtitleOverlay.style.top = "0", this.subtitleOverlay.style.left = "0", this.subtitleOverlay.style.right = "auto", this.subtitleOverlay.style.bottom = "auto", this.subtitleOverlay.style.width = `${F}px`, this.subtitleOverlay.style.height = `${k}px`, this.subtitleOverlay.style.pointerEvents = "none", this.subtitleOverlay.style.transform = "none", this.subtitleOverlay.style.display = "flex", this.subtitleOverlay.style.flexDirection = "column", this.subtitleOverlay.style.justifyContent = "flex-end", this.subtitleOverlay.style.alignItems = "center", this.subtitleOverlay.style.overflow = "hidden", this.subtitleOverlay.style.padding = "0";
51609
- const H = CanvasRenderer.computeSubtitleBottomPadding(k), M = this.subtitleControlsPadding > 0 ? this.subtitleControlsPadding : H;
51610
- this.subtitleOverlay.style.paddingBottom = `${M}px`, this.subtitleOverlay.style.textAlign = "center", this.subtitleOverlay.style.boxSizing = "border-box", this.subtitleOverlay.style.margin = "0";
51611
- let G = this.subtitleOverlay.querySelector("img.movi-subtitle-image");
51612
- if (Logger$1.debug(TAG$d, `Rendering image subtitle in overlay: ${G ? "img exists" : "creating img"}, x=${R.toFixed(0)}, y=${P.toFixed(0)}, width=${(A.image.width * T).toFixed(0)}, height=${(A.image.height * B).toFixed(0)}`), G || (G = document.createElement("img"), G.className = "movi-subtitle-image", G.style.display = "block", G.style.position = "relative", G.style.margin = "0", G.style.padding = "0", G.style.border = "none", G.style.outline = "none", this.subtitleOverlay.innerHTML = "", this.subtitleOverlay.appendChild(G)), A.position?.x) {
51608
+ R = Math.max(0, Math.min(R, F - w));
51609
+ const H = ((this.rotation ?? 0) % 360 + 360) % 360, M = 90 === H || 270 === H, G = M ? k : F, O = M ? F : k;
51610
+ this.subtitleOverlay.style.position = "absolute", this.subtitleOverlay.style.right = "auto", this.subtitleOverlay.style.bottom = "auto", this.subtitleOverlay.style.width = `${G}px`, this.subtitleOverlay.style.height = `${O}px`, this.subtitleOverlay.style.left = (F - G) / 2 + "px", this.subtitleOverlay.style.top = (k - O) / 2 + "px", this.subtitleOverlay.style.pointerEvents = "none", this.subtitleOverlay.style.transformOrigin = "center center", this.subtitleOverlay.style.transform = H ? `rotate(${H}deg)` : "none", this.subtitleOverlay.style.display = "flex", this.subtitleOverlay.style.flexDirection = "column", this.subtitleOverlay.style.justifyContent = "flex-end", this.subtitleOverlay.style.alignItems = "center", this.subtitleOverlay.style.overflow = "hidden", this.subtitleOverlay.style.padding = "0";
51611
+ const J = CanvasRenderer.computeSubtitleBottomPadding(O), U = this.subtitleControlsPadding > 0 ? this.subtitleControlsPadding : J;
51612
+ this.subtitleOverlay.style.paddingBottom = `${U}px`, this.subtitleOverlay.style.textAlign = "center", this.subtitleOverlay.style.boxSizing = "border-box", this.subtitleOverlay.style.margin = "0";
51613
+ let K = this.subtitleOverlay.querySelector("img.movi-subtitle-image");
51614
+ if (Logger$1.debug(TAG$d, `Rendering image subtitle in overlay: ${K ? "img exists" : "creating img"}, x=${R.toFixed(0)}, y=${P.toFixed(0)}, width=${(A.image.width * T).toFixed(0)}, height=${(A.image.height * B).toFixed(0)}`), K || (K = document.createElement("img"), K.className = "movi-subtitle-image", K.style.display = "block", K.style.position = "relative", K.style.margin = "0", K.style.padding = "0", K.style.border = "none", K.style.outline = "none", this.subtitleOverlay.innerHTML = "", this.subtitleOverlay.appendChild(K)), A.position?.x) {
51613
51615
  const A2 = R - (F - w) / 2;
51614
- G.style.marginLeft = `${A2}px`, G.style.marginRight = "0";
51615
- } else G.style.marginLeft = "auto", G.style.marginRight = "auto";
51616
- G.src = j, G.style.width = `${w}px`, G.style.height = `${N}px`, G.style.maxWidth = `${F}px`, G.style.maxHeight = `${k}px`, G.style.objectFit = "contain", G.style.display = "block", G.style.visibility = "visible", G.style.opacity = "1", Logger$1.debug(TAG$d, `Image subtitle rendered: src set, dimensions=${(A.image.width * T).toFixed(0)}x${(A.image.height * B).toFixed(0)}, position=(${R.toFixed(0)}, ${P.toFixed(0)})`);
51616
+ K.style.marginLeft = `${A2}px`, K.style.marginRight = "0";
51617
+ } else K.style.marginLeft = "auto", K.style.marginRight = "auto";
51618
+ K.src = j, K.style.width = `${w}px`, K.style.height = `${N}px`, K.style.maxWidth = `${G}px`, K.style.maxHeight = `${O}px`, K.style.objectFit = "contain", K.style.display = "block", K.style.visibility = "visible", K.style.opacity = "1", Logger$1.debug(TAG$d, `Image subtitle rendered: src set, dimensions=${(A.image.width * T).toFixed(0)}x${(A.image.height * B).toFixed(0)}, position=(${R.toFixed(0)}, ${P.toFixed(0)})`);
51617
51619
  } catch (A2) {
51618
51620
  Logger$1.error(TAG$d, "Failed to render image subtitle in overlay", A2);
51619
51621
  }
@@ -51650,49 +51652,49 @@ class CanvasRenderer {
51650
51652
  if (j.image) return this.subtitleOverlay ? void this.renderImageSubtitleInOverlay(j) : void 0;
51651
51653
  if (this.subtitleOverlay) {
51652
51654
  if (!j.text) return this.subtitleOverlay.textContent = "", void (this.subtitleOverlay.style.display = "none");
51653
- const A2 = this.canvas instanceof HTMLCanvasElement ? this.canvas : null, s2 = A2?.getBoundingClientRect(), E = s2?.width || v, F = s2?.height || b, k = CanvasRenderer.computeSubtitleBottomPadding(F);
51654
- this.subtitleOverlay.style.position = "absolute", this.subtitleOverlay.style.top = "0", this.subtitleOverlay.style.left = "0", this.subtitleOverlay.style.right = "auto", this.subtitleOverlay.style.bottom = "auto", this.subtitleOverlay.style.width = `${E}px`, this.subtitleOverlay.style.height = `${F}px`, this.subtitleOverlay.style.margin = "0", this.subtitleOverlay.style.padding = "0";
51655
- const x = this.subtitleControlsPadding > 0 ? this.subtitleControlsPadding : k;
51656
- this.subtitleOverlay.style.paddingBottom = `${x}px`, this.subtitleOverlay.style.transform = "none", this.subtitleOverlay.style.boxSizing = "border-box", this.subtitleOverlay.style.display = "flex", this.subtitleOverlay.style.flexDirection = "column", this.subtitleOverlay.style.justifyContent = "flex-end", this.subtitleOverlay.style.alignItems = "center", this.subtitleOverlay.style.textAlign = "left", this.subtitleOverlay.style.pointerEvents = "none";
51657
- const _ = `${j.start.toFixed(3)}|${j.text}`;
51658
- if (_ === this._lastRenderedSubtitleKey) return;
51659
- this._lastRenderedSubtitleKey = _;
51660
- const T = "⟨⟨GHOST⟩⟩", B = j.text.indexOf(T), S = B >= 0 ? j.text.slice(0, B) : j.text, I = B >= 0 ? j.text.slice(B + T.length) : j.text, $ = (() => {
51655
+ const A2 = this.canvas instanceof HTMLCanvasElement ? this.canvas : null, s2 = A2?.getBoundingClientRect(), E = s2?.width || v, F = s2?.height || b, k = ((this.rotation ?? 0) % 360 + 360) % 360, x = 90 === k || 270 === k, _ = x ? F : E, T = x ? E : F, B = CanvasRenderer.computeSubtitleBottomPadding(T);
51656
+ this.subtitleOverlay.style.position = "absolute", this.subtitleOverlay.style.right = "auto", this.subtitleOverlay.style.bottom = "auto", this.subtitleOverlay.style.width = `${_}px`, this.subtitleOverlay.style.height = `${T}px`, this.subtitleOverlay.style.left = (E - _) / 2 + "px", this.subtitleOverlay.style.top = (F - T) / 2 + "px", this.subtitleOverlay.style.margin = "0", this.subtitleOverlay.style.padding = "0";
51657
+ const S = this.subtitleControlsPadding > 0 ? this.subtitleControlsPadding : B;
51658
+ this.subtitleOverlay.style.paddingBottom = `${S}px`, this.subtitleOverlay.style.transformOrigin = "center center", this.subtitleOverlay.style.transform = k ? `rotate(${k}deg)` : "none", this.subtitleOverlay.style.boxSizing = "border-box", this.subtitleOverlay.style.display = "flex", this.subtitleOverlay.style.flexDirection = "column", this.subtitleOverlay.style.justifyContent = "flex-end", this.subtitleOverlay.style.alignItems = "center", this.subtitleOverlay.style.textAlign = "left", this.subtitleOverlay.style.pointerEvents = "none";
51659
+ const I = `${j.start.toFixed(3)}|${j.text}`;
51660
+ if (I === this._lastRenderedSubtitleKey) return;
51661
+ this._lastRenderedSubtitleKey = I;
51662
+ const $ = "⟨⟨GHOST⟩⟩", q = j.text.indexOf($), w = q >= 0 ? j.text.slice(0, q) : j.text, N = q >= 0 ? j.text.slice(q + $.length) : j.text, C = (() => {
51661
51663
  const A3 = this._subtitleFontCache;
51662
51664
  if (A3 && A3.viewport === window.innerWidth) return A3.font;
51663
51665
  const v2 = document.createElement("div");
51664
51666
  v2.className = "movi-subtitle-line", v2.style.position = "absolute", v2.style.left = "-99999px", v2.style.top = "-99999px", v2.style.visibility = "hidden", v2.textContent = "M", this.subtitleOverlay.parentNode?.appendChild(v2);
51665
51667
  const b2 = window.getComputedStyle(v2), j2 = `${b2.fontStyle} ${b2.fontWeight} ${b2.fontSize} ${b2.fontFamily}`;
51666
51668
  return v2.remove(), this._subtitleFontCache = { viewport: window.innerWidth, font: j2 }, j2;
51667
- })(), q = (A3) => {
51668
- const v2 = A3.indexOf(T);
51669
+ })(), L = (A3) => {
51670
+ const v2 = A3.indexOf($);
51669
51671
  return v2 >= 0 ? A3.slice(0, v2) : A3;
51670
51672
  };
51671
- let w = I;
51672
- const N = this.subtitleCues.indexOf(this.activeSubtitleCue);
51673
- if (N >= 0) {
51674
- let A3 = S;
51675
- for (let v2 = N + 1; v2 < this.subtitleCues.length; v2++) {
51673
+ let D = N;
51674
+ const R = this.subtitleCues.indexOf(this.activeSubtitleCue);
51675
+ if (R >= 0) {
51676
+ let A3 = w;
51677
+ for (let v2 = R + 1; v2 < this.subtitleCues.length; v2++) {
51676
51678
  const b2 = this.subtitleCues[v2];
51677
51679
  if (!b2?.text) break;
51678
- const j2 = q(b2.text);
51679
- if (j2.length > A3.length && j2.startsWith(A3)) A3 = j2, w = b2.text.length > j2.length ? b2.text : j2;
51680
+ const j2 = L(b2.text);
51681
+ if (j2.length > A3.length && j2.startsWith(A3)) A3 = j2, D = b2.text.length > j2.length ? b2.text : j2;
51680
51682
  else if (!j2.startsWith(A3)) break;
51681
51683
  }
51682
51684
  }
51683
- const C = q(w).replace(/<[^>]*>/g, ""), L = (this._subtitleMeasureCanvas ||= document.createElement("canvas")).getContext("2d");
51684
- let D = 0;
51685
- if (L) {
51686
- L.font = $;
51687
- for (const A3 of C.split("\n")) {
51688
- const v2 = Math.ceil(L.measureText(A3).width);
51689
- v2 > D && (D = v2);
51685
+ const P = L(D).replace(/<[^>]*>/g, ""), H = (this._subtitleMeasureCanvas ||= document.createElement("canvas")).getContext("2d");
51686
+ let M = 0;
51687
+ if (H) {
51688
+ H.font = C;
51689
+ for (const A3 of P.split("\n")) {
51690
+ const v2 = Math.ceil(H.measureText(A3).width);
51691
+ v2 > M && (M = v2);
51690
51692
  }
51691
51693
  }
51692
- const R = S.split("\n"), P = this._lastRenderedSubtitlePlain, H = P && S.startsWith(P) && S.length > P.length ? P.split(/\s+/).filter(Boolean).length : 0;
51693
- this._lastRenderedSubtitlePlain = S;
51694
- let M = 0;
51695
- const G = R.map((A3) => {
51694
+ const G = w.split("\n"), O = this._lastRenderedSubtitlePlain, J = O && w.startsWith(O) && w.length > O.length ? O.split(/\s+/).filter(Boolean).length : 0;
51695
+ this._lastRenderedSubtitlePlain = w;
51696
+ let U = 0;
51697
+ const K = G.map((A3) => {
51696
51698
  const v2 = [];
51697
51699
  let b2 = A3.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#0?39;/g, "'").replace(/&#x27;/g, "'").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&");
51698
51700
  b2 = b2.replace(/<(\/?)i>/gi, (A4) => {
@@ -51727,24 +51729,24 @@ class CanvasRenderer {
51727
51729
  }
51728
51730
  const _2 = [], T2 = [];
51729
51731
  for (const A4 of k2) {
51730
- const v3 = (A5) => A5 < H ? _2 : T2;
51732
+ const v3 = (A5) => A5 < J ? _2 : T2;
51731
51733
  if ("ws" === A4.kind) {
51732
- const b4 = v3(M);
51733
- if (b4 === _2 && 0 === _2.length && 0 === M) continue;
51734
+ const b4 = v3(U);
51735
+ if (b4 === _2 && 0 === _2.length && 0 === U) continue;
51734
51736
  b4.push(A4.text);
51735
51737
  continue;
51736
51738
  }
51737
- const b3 = v3(M);
51739
+ const b3 = v3(U);
51738
51740
  if (b3 === T2 && 0 === T2.length && _2.length > 0) {
51739
51741
  const A5 = _2[_2.length - 1];
51740
51742
  /\s$/.test(A5) || _2.push(" ");
51741
51743
  }
51742
- b3.push(A4.text), M += 1;
51744
+ b3.push(A4.text), U += 1;
51743
51745
  }
51744
51746
  const B2 = _2.join("").replace(/\s+$/, " "), S2 = T2.join(""), I2 = ['<div class="movi-subtitle-line">'];
51745
51747
  return B2 && I2.push(`<span class="movi-subtitle-static">${B2}</span>`), S2 && I2.push(`<span class="movi-subtitle-new">${S2}</span>`), I2.push("</div>"), I2.join("");
51746
- }).join(""), O = parseFloat(this.subtitleOverlay.style.width) || 0, J = O > 0 && D > 0 && D <= 0.92 * O, U = J ? Math.max(0, Math.floor((O - D) / 2)) : 0, K = J ? U > 0 ? ` style="padding-left:${U}px"` : "" : ' style="text-align:center"';
51747
- return void (this.subtitleOverlay.innerHTML = `<div class="movi-subtitle-anchor"${K}><div class="movi-subtitle-block">${G}</div></div>`);
51748
+ }).join(""), V = parseFloat(this.subtitleOverlay.style.width) || 0, z = V > 0 && M > 0 && M <= 0.92 * V, X = z ? Math.max(0, Math.floor((V - M) / 2)) : 0, Y = z ? X > 0 ? ` style="padding-left:${X}px"` : "" : ' style="text-align:center"';
51749
+ return void (this.subtitleOverlay.innerHTML = `<div class="movi-subtitle-anchor"${Y}><div class="movi-subtitle-block">${K}</div></div>`);
51748
51750
  }
51749
51751
  }
51750
51752
  setPlaybackRate(A) {
@@ -108895,7 +108897,7 @@ class MoviPlayer extends EventEmitter$1 {
108895
108897
  return this.trackManager.getAudioTracks().length > 0 || this.hasNativeAudio() || null !== this.streamWrapper;
108896
108898
  }
108897
108899
  usesNativeAudio() {
108898
- return null !== this.streamWrapper || this.isNativeAudioActive();
108900
+ return null !== this.streamWrapper || null !== this.nativeAudioEl;
108899
108901
  }
108900
108902
  isLiveStream() {
108901
108903
  return this.streamWrapper?.isLive?.() ?? false;
@@ -109464,6 +109466,7 @@ class MoviElement extends HTMLElement {
109464
109466
  _posterCoverUrl = "";
109465
109467
  _posterCoverLoading = false;
109466
109468
  _coverArtBgEl = null;
109469
+ _coverArtBgUrl = "";
109467
109470
  _coverArtResolved = false;
109468
109471
  _lastStripDispatched = null;
109469
109472
  controlsTimeout = null;
@@ -110418,7 +110421,7 @@ class MoviElement extends HTMLElement {
110418
110421
  if (A.preventDefault(), this.player && !this._pipWindow) {
110419
110422
  const A2 = this.player.rotateVideo();
110420
110423
  this.showOSD('<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/></svg>', `${A2}°`);
110421
- const v2 = this.shadowRoot?.querySelector(".movi-rotate-status");
110424
+ const v2 = this.contextMenuRoot().querySelector(".movi-rotate-status");
110422
110425
  v2 && (v2.textContent = `${A2}°`), this.syncThumbnailRotation(A2);
110423
110426
  }
110424
110427
  break;
@@ -110583,18 +110586,20 @@ class MoviElement extends HTMLElement {
110583
110586
  } else {
110584
110587
  v.classList.remove("movi-context-menu-mobile");
110585
110588
  const j3 = A.querySelector(".movi-context-menu-backdrop");
110586
- if (j3 && (j3.style.display = "none"), this.classList.contains("movi-audio-strip")) {
110587
- v.style.position = "fixed", v.style.maxHeight = `${Math.max(180, window.innerHeight - 40)}px`, v.style.display = "block", v.style.visibility = "hidden";
110589
+ j3 && (j3.style.display = "none");
110590
+ const s4 = this.classList.contains("movi-audio-strip"), E3 = this.isFullscreenActive();
110591
+ if (s4 || E3) {
110592
+ E3 && this.classList.add("movi-menu-overflow"), v.style.position = "fixed", v.style.maxHeight = `${Math.max(180, window.innerHeight - 40)}px`, v.style.display = "block", v.style.visibility = "hidden";
110588
110593
  const A2 = v.offsetWidth, j4 = v.offsetHeight;
110589
110594
  v.style.visibility = "visible";
110590
- let s5 = b2.clientX, E4 = b2.clientY;
110591
- return s5 + A2 > window.innerWidth && (s5 = window.innerWidth - A2 - 10), s5 < 10 && (s5 = 10), E4 + j4 > window.innerHeight && (E4 = window.innerHeight - j4 - 10), E4 < 10 && (E4 = 10), v.style.left = `${s5}px`, v.style.top = `${E4}px`, this.clampMenuToViewport(v), requestAnimationFrame(() => v.classList.add("visible")), void (this._contextMenuVisible = true);
110595
+ let s5 = b2.clientX, F4 = b2.clientY;
110596
+ return s5 + A2 > window.innerWidth && (s5 = window.innerWidth - A2 - 10), s5 < 10 && (s5 = 10), F4 + j4 > window.innerHeight && (F4 = window.innerHeight - j4 - 10), F4 < 10 && (F4 = 10), v.style.left = `${s5}px`, v.style.top = `${F4}px`, this.clampMenuToViewport(v), requestAnimationFrame(() => v.classList.add("visible")), void (this._contextMenuVisible = true);
110592
110597
  }
110593
110598
  this.portalContextMenu(v), v.style.position = "fixed";
110594
- let s4 = b2.clientX, E3 = b2.clientY;
110599
+ let F3 = b2.clientX, k2 = b2.clientY;
110595
110600
  v.style.maxHeight = `${Math.max(180, window.innerHeight - 40)}px`, v.style.display = "block", v.style.visibility = "hidden";
110596
- const F3 = v.offsetWidth, k2 = v.offsetHeight;
110597
- v.style.visibility = "visible", s4 + F3 > window.innerWidth - 10 && (s4 -= F3), E3 + k2 > window.innerHeight - 10 && (E3 -= k2), v.style.left = `${s4}px`, v.style.top = `${E3}px`, this.clampMenuToViewport(v);
110601
+ const x2 = v.offsetWidth, _2 = v.offsetHeight;
110602
+ v.style.visibility = "visible", F3 + x2 > window.innerWidth - 10 && (F3 -= x2), k2 + _2 > window.innerHeight - 10 && (k2 -= _2), v.style.left = `${F3}px`, v.style.top = `${k2}px`, this.clampMenuToViewport(v);
110598
110603
  }
110599
110604
  return requestAnimationFrame(() => {
110600
110605
  v.classList.add("visible");
@@ -110729,8 +110734,8 @@ class MoviElement extends HTMLElement {
110729
110734
  } else if ("hdr-toggle" === E2) this.hdr = !this.hdr, this.showOSD(OSD_hdr, this.hdr ? "HDR On" : "HDR Off"), j();
110730
110735
  else if ("rotate-video" === E2) {
110731
110736
  if (this.player && !this._pipWindow) {
110732
- const v2 = this.player.rotateVideo(), b3 = A.querySelector(".movi-rotate-status");
110733
- b3 && (b3.textContent = `${v2}°`), this.syncThumbnailRotation(v2), this.showOSD('<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>', `Rotate ${v2}°`);
110737
+ const A2 = this.player.rotateVideo(), v2 = this.contextMenuRoot().querySelector(".movi-rotate-status");
110738
+ v2 && (v2.textContent = `${A2}°`), this.syncThumbnailRotation(A2), this.showOSD('<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>', `Rotate ${A2}°`);
110734
110739
  }
110735
110740
  j();
110736
110741
  } else if ("loop-toggle" === E2) this.loop = !this.loop, this.showOSD(OSD_loop, this.loop ? "Loop On" : "Loop Off"), j();
@@ -116072,7 +116077,7 @@ class MoviElement extends HTMLElement {
116072
116077
  border: 1px solid rgba(255, 255, 255, 0.12);
116073
116078
  border-radius: 16px;
116074
116079
  padding: 8px 4px;
116075
- min-width: 160px;
116080
+ min-width: 230px;
116076
116081
  visibility: hidden;
116077
116082
  opacity: 0;
116078
116083
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
@@ -116102,7 +116107,7 @@ class MoviElement extends HTMLElement {
116102
116107
  border: 1px solid rgba(255, 255, 255, 0.12);
116103
116108
  border-radius: 16px;
116104
116109
  padding: 8px 4px;
116105
- min-width: 160px;
116110
+ min-width: 230px;
116106
116111
  visibility: hidden;
116107
116112
  opacity: 0;
116108
116113
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
@@ -117782,6 +117787,16 @@ class MoviElement extends HTMLElement {
117782
117787
  this._posterCoverUrl === v && (this._posterCoverLoading = false, this._posterCoverUrl = "", this.updateCoverArtOverlay());
117783
117788
  }, b.src = v;
117784
117789
  }
117790
+ makeCoverArtBgUrl(A) {
117791
+ try {
117792
+ const v = 96, b = A.width / A.height, j = Math.max(1, b >= 1 ? v : Math.round(v * b)), s2 = Math.max(1, b >= 1 ? Math.round(v / b) : v), E = document.createElement("canvas");
117793
+ E.width = j, E.height = s2;
117794
+ const F = E.getContext("2d");
117795
+ return F ? (F.drawImage(A, 0, 0, j, s2), E.toDataURL("image/jpeg", 0.7)) : "";
117796
+ } catch {
117797
+ return "";
117798
+ }
117799
+ }
117785
117800
  updateCoverArtOverlay() {
117786
117801
  const A = this.coverArtOverlay, v = this.coverArtCanvas;
117787
117802
  if (!A || !v) return;
@@ -117796,7 +117811,7 @@ class MoviElement extends HTMLElement {
117796
117811
  const H = v.getContext("2d");
117797
117812
  if (!H) return;
117798
117813
  if (H.save(), H.scale(D, D), this._coverArtBgEl) {
117799
- const A2 = this.coverArtBitmap ? "" : this._posterCoverUrl;
117814
+ const A2 = this.coverArtBitmap ? this._coverArtBgUrl : this._posterCoverUrl;
117800
117815
  this._coverArtBgEl.style.backgroundImage = A2 ? `url("${A2.replace(/"/g, '\\"')}")` : "none";
117801
117816
  }
117802
117817
  H.clearRect(0, 0, C, L);
@@ -117994,12 +118009,12 @@ class MoviElement extends HTMLElement {
117994
118009
  };
117995
118010
  this.player.on("error", _), this.eventHandlers.set("error", () => this.player?.off("error", _));
117996
118011
  const T = (A2) => {
117997
- this.coverArtBitmap = A2, this._coverArtResolved = true, this.updateCoverArtOverlay(), A2 && (this.setMediaSessionArtworkFromBitmap(A2), this.dispatchEvent(new CustomEvent("coverart", { detail: { bitmap: A2, width: A2.width, height: A2.height }, bubbles: true, composed: true })));
118012
+ this.coverArtBitmap = A2, this._coverArtBgUrl = A2 ? this.makeCoverArtBgUrl(A2) : "", this._coverArtResolved = true, this.updateCoverArtOverlay(), A2 && (this.setMediaSessionArtworkFromBitmap(A2), this.dispatchEvent(new CustomEvent("coverart", { detail: { bitmap: A2, width: A2.width, height: A2.height }, bubbles: true, composed: true })));
117998
118013
  };
117999
118014
  this.player.on("coverart", T), this.eventHandlers.set("coverart", () => this.player?.off("coverart", T));
118000
118015
  }
118001
118016
  async load() {
118002
- if (this._titleAutoLoaded = false, this._lastDuration = 0, this.coverArtBitmap = null, this._coverArtResolved = false, this._posterCoverBitmap) try {
118017
+ if (this._titleAutoLoaded = false, this._lastDuration = 0, this.coverArtBitmap = null, this._coverArtBgUrl = "", this._coverArtResolved = false, this._posterCoverBitmap) try {
118003
118018
  this._posterCoverBitmap.close();
118004
118019
  } catch {
118005
118020
  }
@@ -118527,22 +118542,24 @@ class MoviElement extends HTMLElement {
118527
118542
  set loop(A) {
118528
118543
  this._loop = !!A, this._loop ? this.setAttribute("loop", "") : this.removeAttribute("loop"), this.updateLoopUI();
118529
118544
  }
118545
+ contextMenuRoot() {
118546
+ return this._menuPortalRoot?.querySelector(".movi-context-menu") ? this._menuPortalRoot : this.shadowRoot;
118547
+ }
118530
118548
  updateLoopUI() {
118531
118549
  const A = this.shadowRoot;
118532
118550
  if (!A) return;
118533
- const v = A.querySelector(".movi-loop-btn"), b = A.querySelector('.movi-context-menu-item[data-action="loop-toggle"]'), j = A.querySelector(".movi-loop-status"), s2 = A.querySelector(".movi-context-menu-loop-outline"), E = A.querySelector(".movi-context-menu-loop-filled");
118534
- this._loop ? (v?.classList.add("active"), b?.classList.add("movi-context-menu-active"), j && (j.textContent = "On"), s2 && (s2.style.display = "none"), E && (E.style.display = "block")) : (v?.classList.remove("active"), b?.classList.remove("movi-context-menu-active"), j && (j.textContent = "Off"), s2 && (s2.style.display = "block"), E && (E.style.display = "none"));
118551
+ const v = this.contextMenuRoot(), b = A.querySelector(".movi-loop-btn"), j = v.querySelector('.movi-context-menu-item[data-action="loop-toggle"]'), s2 = v.querySelector(".movi-loop-status"), E = v.querySelector(".movi-context-menu-loop-outline"), F = v.querySelector(".movi-context-menu-loop-filled");
118552
+ this._loop ? (b?.classList.add("active"), j?.classList.add("movi-context-menu-active"), s2 && (s2.textContent = "On"), E && (E.style.display = "none"), F && (F.style.display = "block")) : (b?.classList.remove("active"), j?.classList.remove("movi-context-menu-active"), s2 && (s2.textContent = "Off"), E && (E.style.display = "block"), F && (F.style.display = "none"));
118535
118553
  }
118536
118554
  updateAmbientUI() {
118537
- const A = this.shadowRoot;
118538
- if (!A) return;
118539
- const v = A.querySelector('.movi-context-menu-item[data-action="ambient-toggle"]'), b = A.querySelector(".movi-ambient-status"), j = A.querySelector(".movi-context-menu-ambient-outline"), s2 = A.querySelector(".movi-context-menu-ambient-filled");
118555
+ if (!this.shadowRoot) return;
118556
+ const A = this.contextMenuRoot(), v = A.querySelector('.movi-context-menu-item[data-action="ambient-toggle"]'), b = A.querySelector(".movi-ambient-status"), j = A.querySelector(".movi-context-menu-ambient-outline"), s2 = A.querySelector(".movi-context-menu-ambient-filled");
118540
118557
  this._ambientMode ? (v?.classList.add("movi-context-menu-active"), b && (b.textContent = "On"), j && (j.style.display = "none"), s2 && (s2.style.display = "block")) : (v?.classList.remove("movi-context-menu-active"), b && (b.textContent = "Off"), j && (j.style.display = "block"), s2 && (s2.style.display = "none"));
118541
118558
  }
118542
118559
  updateStableAudioUI(A = this.shadowRoot) {
118543
118560
  if (!A) return;
118544
- const v = this.player?.getStableAudio() ?? true, b = A.querySelector(".movi-stable-audio-btn"), j = A.querySelector('.movi-context-menu-item[data-action="stable-audio-toggle"]'), s2 = A.querySelector(".movi-stable-audio-status"), E = A.querySelector(".movi-context-menu-stable-outline"), F = A.querySelector(".movi-context-menu-stable-filled");
118545
- v ? (b?.classList.add("active"), j?.classList.add("movi-context-menu-active"), s2 && (s2.textContent = "On"), E && (E.style.display = "none"), F && (F.style.display = "block")) : (b?.classList.remove("active"), j?.classList.remove("movi-context-menu-active"), s2 && (s2.textContent = "Off"), E && (E.style.display = "block"), F && (F.style.display = "none"));
118561
+ const v = this.player?.getStableAudio() ?? true, b = this.contextMenuRoot(), j = A.querySelector(".movi-stable-audio-btn"), s2 = b.querySelector('.movi-context-menu-item[data-action="stable-audio-toggle"]'), E = b.querySelector(".movi-stable-audio-status"), F = b.querySelector(".movi-context-menu-stable-outline"), k = b.querySelector(".movi-context-menu-stable-filled");
118562
+ v ? (j?.classList.add("active"), s2?.classList.add("movi-context-menu-active"), E && (E.textContent = "On"), F && (F.style.display = "none"), k && (k.style.display = "block")) : (j?.classList.remove("active"), s2?.classList.remove("movi-context-menu-active"), E && (E.textContent = "Off"), F && (F.style.display = "block"), k && (k.style.display = "none"));
118546
118563
  }
118547
118564
  toggleNerdStats(A = this.shadowRoot) {
118548
118565
  if (!A) return;
@@ -119110,8 +119127,8 @@ class MoviElement extends HTMLElement {
119110
119127
  return !!this.player?.isHDRSupported?.();
119111
119128
  }
119112
119129
  updateHDRUI() {
119113
- const A = this.shadowRoot?.querySelector(".movi-hdr-btn"), v = this.shadowRoot?.querySelector(".movi-hdr-status"), b = this.shadowRoot?.querySelector('.movi-context-menu-item[data-action="hdr-toggle"]');
119114
- this._hdr ? (A?.classList.add("movi-hdr-active"), b?.classList.add("movi-context-menu-active"), v && (v.textContent = "On")) : (A?.classList.remove("movi-hdr-active"), b?.classList.remove("movi-context-menu-active"), v && (v.textContent = "Off"));
119130
+ const A = this.contextMenuRoot(), v = this.shadowRoot?.querySelector(".movi-hdr-btn"), b = A.querySelector(".movi-hdr-status"), j = A.querySelector('.movi-context-menu-item[data-action="hdr-toggle"]');
119131
+ this._hdr ? (v?.classList.add("movi-hdr-active"), j?.classList.add("movi-context-menu-active"), b && (b.textContent = "On")) : (v?.classList.remove("movi-hdr-active"), j?.classList.remove("movi-context-menu-active"), b && (b.textContent = "Off"));
119115
119132
  }
119116
119133
  async takeSnapshot() {
119117
119134
  if (this.player) try {