Răsfoiți Sursa

feat: add language prop & fix debugger

Sven 2 ani în urmă
părinte
comite
2efe55ba72
5 a modificat fișierele cu 63 adăugiri și 27 ștergeri
  1. 1 1
      .vscode/launch.json
  2. 36 4
      README.md
  3. 16 15
      src/songMeta.ts
  4. 9 7
      src/types.d.ts
  5. 1 0
      tsconfig.json

+ 1 - 1
.vscode/launch.json

@@ -8,7 +8,7 @@
             "type": "node",
             "request": "launch",
             "name": "Launch",
-            "program": "${workspaceFolder}/out/src/index.js",
+            "program": "${workspaceFolder}/src/index.ts",
             "preLaunchTask": "prelaunch",
             "outFiles": ["${workspaceFolder}/out/**/*.js"],
             "console": "integratedTerminal"

+ 36 - 4
README.md

@@ -57,13 +57,29 @@ All routes support gzip and deflate compression.
 >     "top": {
 >         "url": "https://genius.com/Artist-1-song-name-lyrics",
 >         "path": "/Artist-1-song-name-lyrics",
+>         "language": "en",
 >         "meta": {
 >             "title": "Song Name",
 >             "fullTitle": "Song Name by Artist 1 (ft. Artist 2)",
 >             "artists": "Artist 1 (ft. Artist 2)",
 >             "primaryArtist": {
 >                 "name": "Artist 1",
->                 "url": "https://genius.com/artists/Artist-1"
+>                 "url": "https://genius.com/artists/Artist-1",
+>                 "headerImage": "https://images.genius.com/...",
+>                 "image": "https://images.genius.com/..."
+>             },
+>             "featuredArtists": [
+>                 {
+>                     "name": "Featured Artist 1",
+>                     "url": "https://genius.com/artists/Featured-Artist-1",
+>                     "headerImage": "https://images.genius.com/...",
+>                     "image": "https://images.genius.com/..."
+>                 }
+>             ],
+>             "releaseDate": {
+>                 "year": 2018,
+>                 "month": 9,
+>                 "day": 12
 >             }
 >         },
 >         "resources": {
@@ -143,18 +159,34 @@ All routes support gzip and deflate compression.
 >     "matches": 1,
 >     "url": "https://genius.com/Artist-1-song-name-lyrics",
 >     "path": "/Artist-1-song-name-lyrics",
+>     "language": "en",
 >     "meta": {
 >         "title": "Song Name",
 >         "fullTitle": "Song Name by Artist 1 (ft. Artist 2)",
 >         "artists": "Artist 1 (ft. Artist 2)",
 >         "primaryArtist": {
 >             "name": "Artist 1",
->             "url": "https://genius.com/artists/Artist-1"
+>             "url": "https://genius.com/artists/Artist-1",
+>             "headerImage": "https://images.genius.com/...",
+>             "image": "https://images.genius.com/..."
+>         },
+>         "featuredArtists": [
+>             {
+>                 "name": "Featured Artist 1",
+>                 "url": "https://genius.com/artists/Featured-Artist-1",
+>                 "headerImage": "https://images.genius.com/...",
+>                 "image": "https://images.genius.com/..."
+>             }
+>         ],
+>         "releaseDate": {
+>             "year": 2018,
+>             "month": 9,
+>             "day": 12
 >         }
 >     },
 >     "resources": {
->         "thumbnail": "https://images.genius.com/123456789abcdef.300x300x1.png",
->         "image": "https://images.genius.com/123456789abcdef.1000x1000x1.png"
+>         "thumbnail": "https://images.genius.com/8485557225af0345d2c550af8bae731b.300x300x1.png",
+>         "image": "https://images.genius.com/13d7b13ef827a9f007a5d24c115b9ebb.1000x1000x1.png"
 >     },
 >     "lyricsState": "complete",
 >     "id": 42069,

+ 16 - 15
src/songMeta.ts

@@ -4,7 +4,7 @@ import { randomUUID } from "crypto";
 import { JSONCompatible, reserialize } from "svcorelib";
 import { ApiSearchResult, SongMeta } from "./types";
 
-type SearchHit = (SongMeta & { uuid?: string; });
+type MetaSearchHit = SongMeta & { uuid?: string; };
 
 /**
  * Returns meta information about the top results of a search using the genius API
@@ -25,17 +25,18 @@ export async function getMeta({ q, artist, song }: Partial<Record<"q" | "artist"
         if(response.hits.length === 0)
             return null;
 
-        let hits: SearchHit[] = response.hits
+        let hits: MetaSearchHit[] = response.hits
             .filter(h => h.type === "song")
             .map(({ result }) => ({
                 url: result.url,
                 path: result.path,
+                language: result.language ?? null,
                 meta: {
-                    title: normalizeString(result.title) ?? null,
-                    fullTitle: normalizeString(result.full_title) ?? null,
-                    artists: normalizeString(result.artist_names) ?? null,
+                    title: formatStr(result.title),
+                    fullTitle: formatStr(result.full_title),
+                    artists: formatStr(result.artist_names),
                     primaryArtist: {
-                        name: normalizeString(result.primary_artist.name) ?? null,
+                        name: formatStr(result.primary_artist.name) ?? null,
                         url: result.primary_artist.url ?? null,
                         headerImage: result.primary_artist.header_image_url ?? null,
                         image: result.primary_artist.image_url ?? null,
@@ -67,10 +68,10 @@ export async function getMeta({ q, artist, song }: Partial<Record<"q" | "artist"
                 return h;
             }) as (SongMeta & { uuid: string })[];
 
-            const fuseOpts = {
+            const fuseOpts: Fuse.IFuseOptions<MetaSearchHit> = {
                 ignoreLocation: true,
                 includeScore: true,
-                threshold: 0.5,
+                threshold: 0.6,
             };
 
             const titleFuse = new Fuse(hits, { ...fuseOpts, keys: [ "meta.title" ] });
@@ -92,10 +93,10 @@ export async function getMeta({ q, artist, song }: Partial<Record<"q" | "artist"
             addScores(artistFuse.search(artist));
 
             const bestMatches = Object.entries(scoreMap)
-                .sort(([, valA], [, valB]) => valA > valB ? 1 : -1) // TODO: check
+                .sort(([, valA], [, valB]) => valA > valB ? 1 : -1)
                 .map(e => e[0]);
 
-            const oldHits = reserialize(hits as unknown as JSONCompatible) as unknown as SearchHit[];
+            const oldHits = reserialize(hits as unknown as JSONCompatible) as unknown as MetaSearchHit[];
 
             hits = bestMatches
                 .map(uuid => oldHits.find(h => h.uuid === uuid))
@@ -106,11 +107,11 @@ export async function getMeta({ q, artist, song }: Partial<Record<"q" | "artist"
                         return hit;
                     }
                 })
-                .filter(h => h !== undefined) as SearchHit[];
+                .filter(h => h !== undefined) as MetaSearchHit[];
         }
 
         return {
-            top: hits[0] as SearchHit,
+            top: hits[0] as MetaSearchHit,
             all: hits.slice(0, 10),
         };
     }
@@ -120,12 +121,12 @@ export async function getMeta({ q, artist, song }: Partial<Record<"q" | "artist"
 
 /**
  * Removes invisible characters and control characters from a string  
- * Returns null if the input is not a string
+ * @throws Throws TypeError if the input is not a string
  */
-function normalizeString(str: unknown)
+function formatStr(str: unknown): string
 {
     if(!str || typeof str !== "string")
-        return null;
+        throw new TypeError("formatStr(): input is not a string");
 
     return str.replace(/[\u0000-\u001F\u007F-\u009F\u200B]/g, "").replace(/\u00A0/g, " ");
 }

+ 9 - 7
src/types.d.ts

@@ -8,12 +8,13 @@ interface Artist {
 }
 
 export interface SongMeta {
-    url: string | null;
-    path: string | null;
+    url: string;
+    path: string;
+    language: string | null;
     meta: {
-        title: string | null;
-        fullTitle: string | null;
-        artists: string | null;
+        title: string;
+        fullTitle: string;
+        artists: string;
         releaseDate: {
             year: number | null;
             month: number | null;
@@ -26,8 +27,8 @@ export interface SongMeta {
         thumbnail: string | null;
         image: string | null;
     };
-    lyricsState: string | null;
-    id: number | null;
+    lyricsState: string;
+    id: number;
 }
 
 //#SECTION server
@@ -44,6 +45,7 @@ export type ApiSearchResult = {
     };
 };
 
+/** One result returned by the genius API search */
 export type SearchHit = {
     type: "song";
     result: {

+ 1 - 0
tsconfig.json

@@ -6,6 +6,7 @@
     "rootDir": ".",
     "outDir": "./out/",
     "moduleResolution": "node",
+    "sourceMap": true,
     "useDefineForClassFields": true,
     "allowJs": false,
     "importHelpers": true,