Ver código fonte

feat: finish volume label & fix recursion problem

Sven 1 ano atrás
pai
commit
797f543f47
4 arquivos alterados com 87 adições e 40 exclusões
  1. 4 3
      src/features/index.ts
  2. 22 0
      src/features/layout.css
  3. 60 35
      src/features/layout.ts
  4. 1 2
      src/index.ts

+ 4 - 3
src/features/index.ts

@@ -68,16 +68,17 @@ export const featInfo = {
     min: 50,
     max: 500,
     step: 5,
-    default: 160,
+    default: 150,
     unit: "px",
   },
   volumeSliderStep: {
-    desc: "Volume slider sensitivity - the smaller this number, the finer the volume control",
+    desc: "Volume sensitivity (by how little percent the volume slider can be changed)",
     type: "slider",
     category: "layout",
     min: 1,
-    max: 20,
+    max: 25,
     default: 2,
+    unit: "%",
   },
   watermarkEnabled: {
     desc: `Show a ${scriptInfo.name} watermark under the YTM logo`,

+ 22 - 0
src/features/layout.css

@@ -198,3 +198,25 @@ ytmusic-responsive-list-item-renderer .left-items {
 .bytm-carousel-shelf-anchor {
   margin: 0 var(--ytmusic-responsive-list-item-thumbnail-margin-right, 16px) 0 0;
 }
+
+/* #MARKER volume slider */
+
+#bytm-vol-slider-cont {
+  position: relative;
+}
+
+.bytm-vol-slider-label {
+  opacity: 0.000001;
+  position: absolute;
+  font-size: 14px;
+  padding: 8px 12px;
+  top: 50%;
+  left: 0;
+  transform: translate(calc(-50% - 10px), -50%);
+  text-align: right;
+  transition: opacity 0.2s ease;
+}
+
+.bytm-vol-slider-label.bytm-visible {
+  opacity: 1;
+}

+ 60 - 35
src/features/layout.ts

@@ -163,7 +163,6 @@ export function removeUpgradeTab() {
       log("Removed large upgrade tab");
     },
   });
-  // TODO:FIXME: doesn't work fsr
   onSelector("ytmusic-app-layout #mini-guide ytmusic-guide-renderer #sections ytmusic-guide-section-renderer[is-primary] #items ytmusic-guide-entry-renderer:nth-child(4)", {
     listener: (tabElemSmall) => {
       tabElemSmall.remove();
@@ -175,7 +174,8 @@ export function removeUpgradeTab() {
 //#MARKER volume slider
 
 export function initVolumeFeatures() {
-  onSelector("tp-yt-paper-slider#volume-slider", {
+  // not technically an input element but behaves pretty much the same
+  onSelector<HTMLInputElement>("tp-yt-paper-slider#volume-slider", {
     listener: (sliderElem) => {
       const volSliderCont = document.createElement("div");
       volSliderCont.id = "bytm-vol-slider-cont";
@@ -186,44 +186,74 @@ export function initVolumeFeatures() {
         setVolSliderSize();
 
       if(features.volumeSliderLabel)
-        addVolumeSliderLabel();
+        addVolumeSliderLabel(sliderElem, volSliderCont);
 
-      setVolSliderStep();
+      setVolSliderStep(sliderElem);
     },
   });
 }
 
-const volSliderSelector = "tp-yt-paper-slider#volume-slider";
-
 /** Adds a percentage label to the volume slider and tooltip */
-function addVolumeSliderLabel() {
-  onSelector<HTMLInputElement>(volSliderSelector, {
-    listener: (sliderElem) => {
-      const labelElem = document.createElement("div");
-      labelElem.className = "bytm-vol-slider-label";
-      labelElem.innerText = `${sliderElem.value}%`;
+function addVolumeSliderLabel(sliderElem: HTMLInputElement, sliderCont: HTMLDivElement) {
+  const labelElem = document.createElement("div");
+  labelElem.className = "bytm-vol-slider-label";
+  labelElem.innerText = `${sliderElem.value}%`;
 
-      sliderElem.addEventListener("change", () => {
-        const label = `${sliderElem.value}%`;
-        const sensText = features.volumeSliderStep !== featInfo.volumeSliderStep.default ? ` (Sensitivity: ${sliderElem.step})` : "";
-        const labelFull = `Volume: ${label}${sensText}`;
+  // prevent video from minimizing
+  labelElem.addEventListener("click", (e) => e.stopPropagation());
 
-        sliderElem.setAttribute("title", labelFull); // TODO: probably needs to be on the parent
-        sliderElem.setAttribute("aria-valuetext", labelFull);
+  const getLabelTexts = (slider: HTMLInputElement) => {
+    const labelShort = `${slider.value}%`;
+    const sensText = features.volumeSliderStep !== featInfo.volumeSliderStep.default ? ` (Sensitivity: ${slider.step}%)` : "";
+    const labelFull = `Volume: ${labelShort}${sensText}`;
 
-        const labelElem2 = document.querySelector<HTMLDivElement>(".bytm-vol-slider-label");
-        if(labelElem2)
-          labelElem2.innerText = label;
-      });
+    return { labelShort, labelFull };
+  };
 
-      onSelector("#bytm-vol-slider-cont", {
-        listener: (volumeCont) => {
-          volumeCont.appendChild(labelElem);
-          log("Added volume slider label", labelElem);
-        },
-      });
+  const { labelFull } = getLabelTexts(sliderElem);
+  sliderCont.setAttribute("title", labelFull);
+  sliderElem.setAttribute("title", labelFull);
+  sliderElem.setAttribute("aria-valuetext", labelFull);
+
+  const updateLabel = () => {
+    const { labelShort, labelFull } = getLabelTexts(sliderElem);
+
+    sliderCont.setAttribute("title", labelFull);
+    sliderElem.setAttribute("title", labelFull);
+    sliderElem.setAttribute("aria-valuetext", labelFull);
+
+    const labelElem2 = document.querySelector<HTMLDivElement>(".bytm-vol-slider-label");
+    if(labelElem2)
+      labelElem2.innerText = labelShort;
+  };
+
+  sliderElem.addEventListener("change", () => updateLabel());
+
+  onSelector("#bytm-vol-slider-cont", {
+    listener: (volumeCont) => {
+      volumeCont.appendChild(labelElem);
+      log("Added volume slider label", labelElem);
     },
   });
+
+  let lastSliderVal = Number(sliderElem.value);
+
+  // show label if hovering over slider or slider is focused
+  const sliderHoverObserver = new MutationObserver(() => {
+    if(sliderElem.classList.contains("on-hover") || document.activeElement === sliderElem)
+      labelElem.classList.add("bytm-visible");
+    else if(labelElem.classList.contains("bytm-visible") || document.activeElement !== sliderElem)
+      labelElem.classList.remove("bytm-visible");
+
+    if(Number(sliderElem.value) !== lastSliderVal) {
+      lastSliderVal = Number(sliderElem.value);
+      updateLabel();
+    }
+  });
+
+  sliderHoverObserver.observe(sliderElem, {
+    attributes: true,
+  });
 }
 
 /** Sets the volume slider to a set size */
@@ -241,12 +271,8 @@ function setVolSliderSize() {
 }
 
 /** Sets the `step` attribute of the volume slider */
-function setVolSliderStep() {
-  onSelector<HTMLInputElement>(volSliderSelector, {
-    listener: (sliderElem) => {
-      sliderElem.setAttribute("step", String(features.volumeSliderStep));
-    },
-  });
+function setVolSliderStep(sliderElem: HTMLInputElement) {
+  sliderElem.setAttribute("step", String(features.volumeSliderStep));
 }
 
 //#MARKER queue buttons
@@ -297,7 +323,6 @@ async function addQueueButtons(queueItem: HTMLElement) {
   if(!song || !artist)
     return false;
 
-
   const lyricsIconUrl = await getResourceUrl("lyrics");
   const deleteIconUrl = await getResourceUrl("delete");
 

+ 1 - 2
src/index.ts

@@ -111,8 +111,7 @@ async function onDomLoad() {
       if(features.anchorImprovements)
         addAnchorImprovements();
 
-      // TODO:
-      void initVolumeFeatures;
+      initVolumeFeatures();
     }
 
     if(["ytm", "yt"].includes(domain)) {