Ver código fonte

fix: arrow key skip (#18)

Sv443 1 ano atrás
pai
commit
99fdc4dea9
7 arquivos alterados com 100 adições e 10 exclusões
  1. 5 2
      README.md
  2. 32 0
      dev/ytForceShowVideoTime.js
  3. 0 0
      dist/BetterYTM.user.js
  4. 1 2
      package.json
  5. 1 0
      src/features/input.ts
  6. 2 1
      src/features/layout.ts
  7. 59 5
      src/utils.ts

+ 5 - 2
README.md

@@ -8,14 +8,17 @@ Configurable layout and UX improvements for YouTube Music
 <br>
 
 ### Features:
+All of these features can be toggled and configured!
 - Input:
     - Use arrow keys to skip forward or backward by 10 seconds
-    - Switch between YouTube and YouTube Music on a video by pressing a hotkey (F9 by default)
+    - Switch between YouTube and YouTube Music on a video by pressing a hotkey (F9 by default) <!-- TODO: make configurable -->
     - TODO: Automatically dismiss "are you still there" popup
 - Layout:
+    - Open any song's lyrics on genius.com which generally has higher quality than YouTube's providers
+    - TODO: Quick actions on songs in a queue, to open their lyrics or remove them from the queue
     - Remove the "Upgrade to YT Music Premium" tab in the title bar
     - Set a custom size and step resolution for the volume slider
-    - Quickly open any song's lyrics on genius.com
+    - TODO: Improvements to clickability of song titles and thumbnails (to open them in a new tab better)
   
 ... and more!
 

+ 32 - 0
dev/ytForceShowVideoTime.js

@@ -0,0 +1,32 @@
+// caveats:
+// only works once for some reason (should be enough tho)
+
+const player = document.querySelector("#movie_player");
+player.dispatchEvent(new MouseEvent("mouseenter", {
+  view: window,
+  bubbles: true,
+  cancelable: false,
+}));
+
+const { x, y, width, height } = player.getBoundingClientRect();
+const screenY = Math.round(y + height / 2);
+const screenX = x + Math.min(50, Math.round(width / 3));
+
+player.dispatchEvent(new MouseEvent("mousemove", {
+  view: window,
+  bubbles: true,
+  cancelable: false,
+  screenY,
+  screenX,
+  movementX: 5,
+  movementY: 0
+}));
+console.log("x:", screenX, "y:", screenY);
+
+setTimeout(() => {
+  player.dispatchEvent(new MouseEvent("mouseleave", {
+    view: window,
+    bubbles: true,
+    cancelable: false,
+  }));
+}, 4000);

Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
dist/BetterYTM.user.js


+ 1 - 2
package.json

@@ -9,10 +9,9 @@
   "type": "module",
   "scripts": {
     "test": "npm run node-ts -- ./test.ts",
-    "build": "webpack",
+    "build": "tsc && webpack",
     "post-build": "npm run node-ts -- ./src/tools/post-build.ts",
     "serve": "npm run node-ts -- ./src/tools/serve.ts",
-    "serve-old": "http-server -s -c 5 -p 8710 .",
     "watch": "nodemon --exec \"npm run build && npm run serve\"",
     "lint": "tsc --noEmit && eslint .",
     "node-ts": "node --no-warnings=ExperimentalWarning --enable-source-maps --loader ts-node/esm"

+ 1 - 0
src/features/input.ts

@@ -35,6 +35,7 @@ function onKeyDown(evt: KeyboardEvent) {
       cancelable: true,
       isTrusted: true,
       repeat: false,
+      view: window,
     };
 
     let invalidKey = false;

+ 2 - 1
src/features/layout.ts

@@ -106,7 +106,7 @@ export function setVolSliderStep() {
 export function initQueueButtons() {
   siteEvents.on("queueChanged", (evt) => {
     for(const queueItm of ((evt.data as HTMLElement).childNodes as NodeListOf<HTMLElement>)) {
-      if(!queueItm.dataset["bytm-has-queue-btns"])
+      if(!queueItm.classList.contains("bytm-has-queue-btns"))
         addQueueButtons(queueItm);
     }
   });
@@ -141,4 +141,5 @@ function addQueueButtons(queueItem: HTMLElement) {
 
   const songInfo = queueItem.querySelector(".song-info")!;
   songInfo.appendChild(queueBtnsCont);
+  queueItem.classList.add("bytm-has-queue-btns");
 }

+ 59 - 5
src/utils.ts

@@ -20,20 +20,37 @@ export function getDomain(): Domain {
 }
 
 /**
- * TODO: this is entirely broken now
  * Returns the current video time in seconds
+ * @param force Set to true to dispatch mouse movement events in case the video time can't be estimated
  * @returns Returns null if the video time is unavailable
  */
-export function getVideoTime() {
+export function getVideoTime(force = false) {
   const domain = getDomain();
 
   try {
     if(domain === "ytm") {
       const pbEl = document.querySelector("#progress-bar") as HTMLProgressElement;
-      return pbEl.value ?? null;
+      return !isNaN(Number(pbEl.value)) ? Number(pbEl.value) : null;
+    }
+    else if(domain === "yt") {
+      // YT doesn't update the progress bar when it's hidden (YTM doesn't hide it) so TODO: come up with some solution here
+
+      // Possible solution:
+      // - Use MutationObserver to detect when attributes of progress bar (selector `div.ytp-progress-bar[role="slider"]`) change
+      // - Wait until the attribute increments, then save the value of `aria-valuenow` and the current system time to memory
+      // - When site switch hotkey is pressed, take saved `aria-valuenow` value and add the difference between saved system time and current system time
+      //   - If no value is present, use the script from `dev/ytForceShowVideoTime.js` to simulate mouse movement to force the element to update
+      // - Subtract one or two seconds to make up for rounding errors
+      // - profit
+
+      // if(!ytCurrentVideoTime) {
+      //   ytForceShowVideoTime();
+      //   const videoTime = document.querySelector("#TODO")?.getAttribute("aria-valuenow") ?? null;
+      // }
+      void [ force, ytForceShowVideoTime ];
+
+      return null;
     }
-    else if(domain === "yt") // YT doesn't update the progress bar when it's hidden (YTM doesn't hide it) so TODO: come up with some solution here
-      return 0;
 
     return null;
   }
@@ -43,6 +60,43 @@ export function getVideoTime() {
   }
 }
 
+/** Sends events that force the video controls to become visible for about 3 seconds */
+function ytForceShowVideoTime() {
+  const player = document.querySelector("#movie_player");
+  if(!player)
+    return false;
+
+  player.dispatchEvent(new MouseEvent("mouseenter", {
+    view: window,
+    bubbles: true,
+    cancelable: false,
+  }));
+
+  const { x, y, width, height } = player.getBoundingClientRect();
+  const screenY = Math.round(y + height / 2);
+  const screenX = x + Math.min(50, Math.round(width / 3));
+
+  player.dispatchEvent(new MouseEvent("mousemove", {
+    view: window,
+    bubbles: true,
+    cancelable: false,
+    screenY,
+    screenX,
+    movementX: 5,
+    movementY: 0
+  }));
+
+  setTimeout(() => {
+    player.dispatchEvent(new MouseEvent("mouseleave", {
+      view: window,
+      bubbles: true,
+      cancelable: false,
+    }));
+  }, 4000);
+
+  return true;
+}
+
 //#SECTION DOM
 
 /**

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff