Переглянути джерело

fix: fetch lyrics on click instead of hover

Sven 1 рік тому
батько
коміт
3f657b916a
2 змінених файлів з 62 додано та 32 видалено
  1. 40 32
      src/features/layout.ts
  2. 22 0
      src/utils.ts

+ 40 - 32
src/features/layout.ts

@@ -1,6 +1,6 @@
 import { scriptInfo, triesInterval, triesLimit } from "../constants";
 import { getFeatures } from "../config";
-import { addGlobalStyle, error, getEvtData, insertAfter, log, siteEvents } from "../utils";
+import { addGlobalStyle, error, getAssetUrl, getEvtData, insertAfter, log, openInNewTab, siteEvents } from "../utils";
 import type { FeatureConfig } from "../types";
 import { openMenu } from "./menu/menu_old";
 import "./layout.css";
@@ -94,14 +94,15 @@ export function initQueueButtons() {
   queueItems.forEach(itm => addQueueButtons(itm as HTMLElement));
 }
 
-/** For how long the user needs to hover over the song info to fetch the lyrics */
-const queueBtnLyricsLoadDebounce = 350;
-
+/**
+ * Adds the buttons to each item in the current song queue.  
+ * Also observes for changes to add new buttons to new items in the queue.
+ */
 async function addQueueButtons(queueItem: HTMLElement) {
   const queueBtnsCont = document.createElement("div");
   queueBtnsCont.className = "bytm-queue-btn-container";
 
-  const songInfo = queueItem.querySelector(".song-info");
+  const songInfo = queueItem.querySelector(".song-info") as HTMLElement;
   if(!songInfo)
     return false;
 
@@ -111,37 +112,44 @@ async function addQueueButtons(queueItem: HTMLElement) {
   if(!song || !artist)
     return false;
 
-  // TODO: display "hover to load" and "currently loading" icons
+  // TODO: display "currently loading" icon
   const lyricsBtnElem = getLyricsBtn(undefined, false);
 
-  // load the URL only on hover because of geniURL rate limiting
-  songInfo.addEventListener("mouseenter", async () => {
-    const startTs = Date.now();
-    if(songInfo.classList.contains("bytm-fetched-lyrics-url"))
-      return;
-
-    /** Loads lyrics after `queueBtnLyricsLoadDebounce` time has passed - gets aborted if the mouse leaves before that time passed */
-    const lyricsLoadTimeout = setTimeout(async () => {
-      const lyricsUrl = await getGeniusUrl(sanitizeArtists(artist), sanitizeSong(song));
-
-      if(!lyricsUrl)
-        return false;
-
-      songInfo.classList.add("bytm-fetched-lyrics-url");
-
-      lyricsBtnElem.href = lyricsUrl;
+  lyricsBtnElem.title = "Open this song's lyrics in a new tab";
+  lyricsBtnElem.style.cursor = "pointer";
+  lyricsBtnElem.style.visibility = "initial";
+  lyricsBtnElem.style.display = "inline-flex";
+  lyricsBtnElem.style.pointerEvents = "initial";
+
+  lyricsBtnElem.addEventListener("click", async () => {
+    let lyricsUrl;
+    if(songInfo.dataset.bytmLyrics && songInfo.dataset.bytmLyrics.length > 0)
+      lyricsUrl = songInfo.dataset.bytmLyrics;
+    else if(songInfo.dataset.bytmLoading !== "true") {
+      console.log("##--1", songInfo.dataset);
+      songInfo.dataset.bytmLoading = "true";
+      console.log("##--2", songInfo.dataset);
+      const imgEl = lyricsBtnElem.querySelector("img") as HTMLImageElement;
+      imgEl.src = getAssetUrl("loading.gif");
+
+      lyricsUrl = await getGeniusUrl(sanitizeArtists(artist), sanitizeSong(song));
+
+      songInfo.dataset.bytmLoading = "false";
+      console.log("##--3", songInfo.dataset);
+      imgEl.src = getAssetUrl("external/genius.png");
+
+      if(!lyricsUrl) {
+        if(confirm("Couldn't find a lyrics page for this song.\nDo you want to open genius.com to manually search for it?"))
+          openInNewTab("https://genius.com/search");
+        return;
+      }
+
+      songInfo.dataset.bytmLyrics = lyricsUrl;
+    }
 
-      lyricsBtnElem.title = "Open the current song's lyrics in a new tab";
-      lyricsBtnElem.style.cursor = "pointer";
-      lyricsBtnElem.style.visibility = "initial";
-      lyricsBtnElem.style.display = "inline-flex";
-      lyricsBtnElem.style.pointerEvents = "initial";
-    }, queueBtnLyricsLoadDebounce);
+    console.log("##--4", songInfo.dataset);
 
-    songInfo.addEventListener("mouseleave", () => {
-      if(Date.now() - startTs < queueBtnLyricsLoadDebounce)
-        clearTimeout(lyricsLoadTimeout);
-    });
+    lyricsUrl && openInNewTab(lyricsUrl);
   });
 
   queueBtnsCont.appendChild(lyricsBtnElem);

+ 22 - 0
src/utils.ts

@@ -154,6 +154,28 @@ export function getAssetUrl(path: string) {
   return `https://raw.githubusercontent.com/Sv443/BetterYTM/${branch}/assets/${path}`;
 }
 
+/**
+ * Creates an invisible anchor with _blank target and clicks it.  
+ * This has to be run in relatively quick succession to a user interaction event, else the browser rejects it.
+ */
+export function openInNewTab(href: string) {
+  const openElem = document.createElement("a");
+  Object.assign(openElem, {
+    className: "betterytm-open-in-new-tab",
+    target: "_blank",
+    rel: "noopener noreferrer",
+    href: href,
+    style: {
+      visibility: "hidden",
+    },
+  });
+  document.body.appendChild(openElem);
+  openElem.click();
+  // just to be safe
+  setTimeout(() => openElem.remove(), 200);
+}
+
+
 //#MARKER DOM
 
 /**