فهرست منبع

fix(#106): volume features now work with both normal and expanded slider elements

Sv443 7 ماه پیش
والد
کامیت
c36ade8292
4فایلهای تغییر یافته به همراه116 افزوده شده و 62 حذف شده
  1. 2 1
      assets/style/volSliderSize.css
  2. 25 13
      dist/BetterYTM.css
  3. 25 13
      src/features/volume.css
  4. 64 35
      src/features/volume.ts

+ 2 - 1
assets/style/volSliderSize.css

@@ -1,3 +1,4 @@
-#bytm-vol-slider-cont tp-yt-paper-slider#volume-slider {
+.bytm-vol-slider-cont tp-yt-paper-slider#volume-slider,
+.bytm-vol-slider-cont tp-yt-paper-slider#expand-volume-slider {
   width: var(--bytm-global-vol-slider-size, 68px) !important;
 }

+ 25 - 13
dist/BetterYTM.css

@@ -2226,55 +2226,67 @@ ytmusic-responsive-list-item-renderer.bytm-has-queue-btns:focus-within
 
 /* #region volume slider */
 
-#bytm-vol-slider-cont {
+.bytm-vol-slider-cont {
   position: relative;
 }
 
-#bytm-vol-slider-label {
-  opacity: 0.000001;
+.bytm-vol-slider-label {
+  --bytm-slider-label-bg-col: var(
+    --bytm-themed-bg,
+    var(--ytmusic-player-bar-background)
+  );
   position: absolute;
+  top: 50%;
+  left: 0;
+  transform: translate(calc(-50% - 11px), -50%);
   display: flex;
   flex-direction: row;
   align-items: center;
   gap: 5px;
+  background-color: var(--bytm-slider-label-bg-col);
+  background: linear-gradient(
+    90deg,
+    rgba(0, 0, 0, 0) 0%,
+    var(--bytm-slider-label-bg-col) 25%
+  );
   font-size: 1.4rem;
-  top: 50%;
-  left: 0;
-  transform: translate(calc(-50% - 10px), -50%);
   text-align: right;
+  padding: 15px;
+  padding-right: 5px;
+  opacity: 0.000001;
   transition: opacity 0.2s ease;
 }
 
-#bytm-vol-slider-label.has-icon {
+.bytm-vol-slider-label.has-icon {
   transform: translate(calc(-50% - 25px), -50%);
 }
 
-#bytm-vol-slider-label svg {
+.bytm-vol-slider-label svg {
   padding: 4px;
 }
 
-#bytm-vol-slider-label svg path {
+.bytm-vol-slider-label svg path {
   fill: #909090;
 }
 
-#bytm-vol-slider-label.bytm-visible {
+.bytm-vol-slider-label.bytm-visible {
   opacity: 1;
 }
 
 :root
   body.bytm-dom-ytm
   ytmusic-app-layout[player-ui-state="FULLSCREEN"]
-  #bytm-vol-slider-label {
+  .bytm-vol-slider-label {
   color: #fff;
 }
 
-#bytm-vol-slider-shared {
+.bytm-vol-slider-shared {
   display: flex;
   flex-direction: row;
   align-items: center;
 }
 
-#bytm-vol-slider-shared svg {
+.bytm-vol-slider-shared svg {
   width: 20px;
   height: 20px;
 }

+ 25 - 13
src/features/volume.css

@@ -1,54 +1,66 @@
 /* #region volume slider */
 
-#bytm-vol-slider-cont {
+.bytm-vol-slider-cont {
   position: relative;
 }
 
-#bytm-vol-slider-label {
-  opacity: 0.000001;
+.bytm-vol-slider-label {
+  --bytm-slider-label-bg-col: var(
+    --bytm-themed-bg,
+    var(--ytmusic-player-bar-background)
+  );
   position: absolute;
+  top: 50%;
+  left: 0;
+  transform: translate(calc(-50% - 11px), -50%);
   display: flex;
   flex-direction: row;
   align-items: center;
   gap: 5px;
+  background-color: var(--bytm-slider-label-bg-col);
+  background: linear-gradient(
+    90deg,
+    rgba(0, 0, 0, 0) 0%,
+    var(--bytm-slider-label-bg-col) 25%
+  );
   font-size: 1.4rem;
-  top: 50%;
-  left: 0;
-  transform: translate(calc(-50% - 10px), -50%);
   text-align: right;
+  padding: 15px;
+  padding-right: 5px;
+  opacity: 0.000001;
   transition: opacity 0.2s ease;
 }
 
-#bytm-vol-slider-label.has-icon {
+.bytm-vol-slider-label.has-icon {
   transform: translate(calc(-50% - 25px), -50%);
 }
 
-#bytm-vol-slider-label svg {
+.bytm-vol-slider-label svg {
   padding: 4px;
 }
 
-#bytm-vol-slider-label svg path {
+.bytm-vol-slider-label svg path {
   fill: #909090;
 }
 
-#bytm-vol-slider-label.bytm-visible {
+.bytm-vol-slider-label.bytm-visible {
   opacity: 1;
 }
 
 :root
   body.bytm-dom-ytm
   ytmusic-app-layout[player-ui-state="FULLSCREEN"]
-  #bytm-vol-slider-label {
+  .bytm-vol-slider-label {
   color: #fff;
 }
 
-#bytm-vol-slider-shared {
+.bytm-vol-slider-shared {
   display: flex;
   flex-direction: row;
   align-items: center;
 }
 
-#bytm-vol-slider-shared svg {
+.bytm-vol-slider-shared svg {
   width: 20px;
   height: 20px;
 }

+ 64 - 35
src/features/volume.ts

@@ -1,4 +1,4 @@
-import { addParent, type Stringifiable } from "@sv443-network/userutils";
+import { addParent, debounce, type Stringifiable } from "@sv443-network/userutils";
 import { getFeature } from "../config.js";
 import { addStyleFromResource, error, log, resourceAsString, setGlobalCssVar, setInnerHtml, t, waitVideoElementReady } from "../utils/index.js";
 import { siteEvents } from "../siteEvents.js";
@@ -10,34 +10,61 @@ import { addSelectorListener } from "../observers.js";
 
 /** Initializes all volume-related features */
 export async function initVolumeFeatures() {
-  // not technically an input element but behaves pretty much the same
-  addSelectorListener<HTMLInputElement>("playerBarRightControls", "tp-yt-paper-slider#volume-slider", {
-    listener: async (sliderElem) => {
-      const volSliderCont = document.createElement("div");
-      volSliderCont.id = "bytm-vol-slider-cont";
+  let listenerOnce = false;
 
-      if(getFeature("volumeSliderScrollStep") !== featInfo.volumeSliderScrollStep.default)
-        initScrollStep(volSliderCont, sliderElem);
+  // sliderElem is not technically an input element but behaves pretty much the same
+  const listener = async (type: "normal" | "expand", sliderElem: HTMLInputElement) => {
+    const volSliderCont = document.createElement("div");
+    volSliderCont.classList.add("bytm-vol-slider-cont");
 
-      addParent(sliderElem, volSliderCont);
+    if(getFeature("volumeSliderScrollStep") !== featInfo.volumeSliderScrollStep.default)
+      initScrollStep(volSliderCont, sliderElem);
 
-      if(typeof getFeature("volumeSliderSize") === "number")
-        setVolSliderSize();
+    addParent(sliderElem, volSliderCont);
 
-      if(getFeature("volumeSliderLabel"))
-        await addVolumeSliderLabel(sliderElem, volSliderCont);
+    if(getFeature("volumeSliderLabel"))
+      await addVolumeSliderLabel(type, sliderElem, volSliderCont);
 
-      setVolSliderStep(sliderElem);
+    setVolSliderStep(sliderElem);
 
-      if(getFeature("volumeSharedBetweenTabs")) {
-        sliderElem.addEventListener("change", () => sharedVolumeChanged(Number(sliderElem.value)));
-        checkSharedVolume();
-      }
+    if(getFeature("volumeSharedBetweenTabs"))
+      sliderElem.addEventListener("change", () => sharedVolumeChanged(Number(sliderElem.value)));
+
+    if(listenerOnce)
+      return;
+    listenerOnce = true;
+
+    // the following are only run once:
+
+    if(getFeature("setInitialTabVolume"))
+      setInitialTabVolume(sliderElem);
+
+    if(typeof getFeature("volumeSliderSize") === "number")
+      setVolSliderSize();
+
+    if(getFeature("volumeSharedBetweenTabs"))
+      checkSharedVolume();
+  };
 
-      if(getFeature("setInitialTabVolume"))
-        setInitialTabVolume(sliderElem);
-    },
+  addSelectorListener<HTMLInputElement>("playerBarRightControls", "tp-yt-paper-slider#volume-slider", {
+    listener: (el) => listener("normal", el),
   });
+
+  let sizeSmOnce = false;
+  const onResize = () => {
+    if(sizeSmOnce || window.innerWidth >= 1150)
+      return;
+    sizeSmOnce = true;
+
+    addSelectorListener<HTMLInputElement>("playerBarRightControls", "ytmusic-player-expanding-menu tp-yt-paper-slider#expand-volume-slider", {
+      listener: (el) => listener("expand", el),
+      debounceEdge: "falling",
+    });
+  };
+
+  window.addEventListener("resize", debounce(onResize, 150, "falling"));
+  waitVideoElementReady().then(onResize);
+  onResize();
 }
 
 //#region scroll step
@@ -68,16 +95,16 @@ function initScrollStep(volSliderCont: HTMLDivElement, sliderElem: HTMLInputElem
 //#region volume slider label
 
 /** Adds a percentage label to the volume slider and tooltip */
-async function addVolumeSliderLabel(sliderElem: HTMLInputElement, sliderContainer: HTMLDivElement) {
+async function addVolumeSliderLabel(type: "normal" | "expand", sliderElem: HTMLInputElement, sliderContainer: HTMLDivElement) {
   const labelContElem = document.createElement("div");
-  labelContElem.id = "bytm-vol-slider-label";
+  labelContElem.classList.add("bytm-vol-slider-label");
 
   const volShared = getFeature("volumeSharedBetweenTabs");
   if(volShared) {
     const linkIconHtml = await resourceAsString("icon-link");
     if(linkIconHtml) {
       const linkIconElem = document.createElement("div");
-      linkIconElem.id = "bytm-vol-slider-shared";
+      linkIconElem.classList.add("bytm-vol-slider-shared");
       setInnerHtml(linkIconElem, linkIconHtml);
       linkIconElem.role = "alert";
       linkIconElem.ariaLive = "polite";
@@ -115,19 +142,21 @@ async function addVolumeSliderLabel(sliderElem: HTMLInputElement, sliderContaine
     sliderElem.setAttribute("title", labelFull);
     sliderElem.setAttribute("aria-valuetext", labelFull);
 
-    const labelElem2 = document.querySelector<HTMLDivElement>("#bytm-vol-slider-label div.label");
-    if(labelElem2)
-      labelElem2.textContent = getLabel(sliderElem.value);
+    const labelElem2 = document.querySelectorAll<HTMLDivElement>(".bytm-vol-slider-label div.label");
+    for(const el of labelElem2)
+      el.textContent = getLabel(sliderElem.value);
   };
 
-  sliderElem.addEventListener("change", () => updateLabel());
-  siteEvents.on("configChanged", () => {
-    updateLabel();
-  });
+  sliderElem.addEventListener("change", updateLabel);
+  siteEvents.on("configChanged", updateLabel);
 
-  addSelectorListener("playerBarRightControls", "#bytm-vol-slider-cont", {
-    listener: (volumeCont) => volumeCont.appendChild(labelContElem),
-  });
+  addSelectorListener(
+    "playerBarRightControls",
+    type === "normal" ? ".bytm-vol-slider-cont" : "ytmusic-player-expanding-menu .bytm-vol-slider-cont",
+    {
+      listener: (volumeCont) => volumeCont.appendChild(labelContElem),
+    }
+  );
 
   let lastSliderVal = Number(sliderElem.value);
 
@@ -209,7 +238,7 @@ async function checkSharedVolume() {
 
 export async function volumeSharedBetweenTabsDisabled() {
   await GM.deleteValue("bytm-shared-volume");
-  document.querySelector<HTMLElement>("#bytm-vol-slider-shared")?.remove();
+  document.querySelectorAll<HTMLElement>("#bytm-vol-slider-shared").forEach(el => el.remove());
 }
 
 //#region initial volume