Bladeren bron

feat: add lyrics url cache

Sv443 1 jaar geleden
bovenliggende
commit
f8f3597127
3 gewijzigde bestanden met toevoegingen van 34 en 11 verwijderingen
  1. 2 2
      src/features/layout.ts
  2. 31 8
      src/features/lyrics.ts
  3. 1 1
      src/utils.ts

+ 2 - 2
src/features/layout.ts

@@ -5,7 +5,7 @@ import { getEvtData, siteEvents } from "../events";
 import type { FeatureConfig } from "../types";
 import { openMenu } from "./menu/menu_old";
 import "./layout.css";
-import { getGeniusUrl, getLyricsBtn, sanitizeArtists, sanitizeSong } from "./lyrics";
+import { getGeniusUrl, createLyricsBtn, sanitizeArtists, sanitizeSong } from "./lyrics";
 
 let features: FeatureConfig;
 
@@ -121,7 +121,7 @@ async function addQueueButtons(queueItem: HTMLElement) {
     return false;
 
   // TODO: display "currently loading" icon
-  const lyricsBtnElem = getLyricsBtn(undefined, false);
+  const lyricsBtnElem = createLyricsBtn(undefined, false);
 
   lyricsBtnElem.title = "Open this song's lyrics in a new tab";
   lyricsBtnElem.style.cursor = "pointer";

+ 31 - 8
src/features/lyrics.ts

@@ -7,6 +7,29 @@ export const geniUrlBase = "https://api.sv443.net/geniurl";
 /** GeniURL endpoint that gives song metadata when provided with a `?q` or `?artist` and `?song` parameter - [more info](https://api.sv443.net/geniurl) */
 const geniURLSearchTopUrl = `${geniUrlBase}/search/top`;
 
+//#MARKER cache
+
+/** Cache with key format `ARTIST - SONG` and lyrics URLs as values. Used to prevent extraneous requests to geniURL. */
+const lyricsUrlCache = new Map<string, string>();
+/** How many cache entries can exist at a time - this is used to cap memory usage */
+const maxLyricsCacheSize = 100;
+
+// TODO: implement this
+/** Returns the lyrics URL from the passed un-/sanitized artist and song name, or undefined if the entry doesn't exist yet */
+export function getLyricsCacheEntry(artists: string, song: string) {
+  return lyricsUrlCache.get(`${sanitizeArtists(artists)} - ${sanitizeSong(song)}`);
+}
+
+/** Adds the provided entry into the lyrics URL cache */
+export function addLyricsCacheEntry(artists: string, song: string, lyricsUrl: string) {
+  lyricsUrlCache.set(`${sanitizeArtists(artists)} - ${sanitizeSong(song)}`, lyricsUrl);
+  // delete oldest entry if cache gets too big
+  if(lyricsUrlCache.size > maxLyricsCacheSize)
+    lyricsUrlCache.delete([...lyricsUrlCache.keys()].at(-1)!);
+}
+
+//#MARKER media control bar
+
 let mcCurrentSongTitle = "";
 let mcLyricsButtonAddTries = 0;
 
@@ -30,7 +53,7 @@ export function addMediaCtrlLyricsBtn(): void {
   (async () => {
     const gUrl = await getCurrentLyricsUrl();
 
-    const linkElem = getLyricsBtn(gUrl ?? undefined);
+    const linkElem = createLyricsBtn(gUrl ?? undefined);
     linkElem.id = "betterytm-lyrics-button";
 
     log(`Inserted lyrics button after ${mcLyricsButtonAddTries} tries:`, linkElem);
@@ -78,6 +101,8 @@ export function addMediaCtrlLyricsBtn(): void {
   obs.observe(songTitleElem, { attributes: true, attributeFilter: [ "title" ] });
 }
 
+//#MARKER utils
+
 /** Removes everything in parentheses from the passed song name */
 export function sanitizeSong(songName: string) {
   const parensRegex = /\(.+\)/gmi;
@@ -137,17 +162,13 @@ export async function getCurrentLyricsUrl() {
 
     return url;
   }
-  catch(err)
-  {
+  catch(err) {
     error("Couldn't resolve lyrics URL:", err);
     return null;
   }
 }
 
-/**
- * @param artist
- * @param song
- */
+/** Fetches the actual lyrics URL from geniURL - **the passed parameters need to be sanitized first!** */
 export async function getGeniusUrl(artist: string, song: string): Promise<string | undefined> {
   try {
     const startTs = Date.now();
@@ -165,6 +186,7 @@ export async function getGeniusUrl(artist: string, song: string): Promise<string
     const url = result.url;
 
     info(`Found lyrics URL (after ${Date.now() - startTs}ms): ${url}`);
+    addLyricsCacheEntry(artist, song, url);
 
     return url;
   }
@@ -174,7 +196,8 @@ export async function getGeniusUrl(artist: string, song: string): Promise<string
   }
 }
 
-export function getLyricsBtn(geniusUrl?: string, hideIfLoading = true): HTMLAnchorElement {
+/** Creates the base lyrics button element */
+export function createLyricsBtn(geniusUrl?: string, hideIfLoading = true): HTMLAnchorElement {
   const linkElem = document.createElement("a");
   linkElem.className = "ytmusic-player-bar bytm-generic-lyrics-btn";
   linkElem.title = geniusUrl ? "Click to open this song's lyrics in a new tab" : "Loading...";

+ 1 - 1
src/utils.ts

@@ -169,7 +169,7 @@ export function openInNewTab(href: string) {
     className: "betterytm-open-in-new-tab",
     target: "_blank",
     rel: "noopener noreferrer",
-    href: href,
+    href,
     style: {
       visibility: "hidden",
     },