add sync status to lrclib lyrics (#1568)

This commit is contained in:
jeffvli
2026-01-18 15:47:07 -08:00
parent c3d4f6cacd
commit 7f1c4a4d18
7 changed files with 184 additions and 46 deletions
+1
View File
@@ -150,6 +150,7 @@ export async function getSearchResults(
return {
artist: song.artist_names,
id: song.url,
isSync: null,
name: song.full_title,
source: LyricSource.GENIUS,
};
+5
View File
@@ -17,8 +17,12 @@ const TIMEOUT_MS = 5000;
export interface LrcLibSearchResponse {
albumName: string;
artistName: string;
duration?: number;
id: number;
instrumental?: boolean;
name: string;
plainLyrics: null | string;
syncedLyrics: null | string;
}
export interface LrcLibTrackResponse {
@@ -75,6 +79,7 @@ export async function getSearchResults(
return {
artist: song.artistName,
id: String(song.id),
isSync: song.syncedLyrics ? true : false,
name: song.name,
source: LyricSource.LRCLIB,
};
+1
View File
@@ -128,6 +128,7 @@ export async function getSearchResults(
return {
artist,
id: String(song.id),
isSync: null,
name: song.name,
source: LyricSource.NETEASE,
};
+69 -8
View File
@@ -1,4 +1,4 @@
import Fuse, { IFuseOptions } from 'fuse.js';
import Fuse, { FuseResult, IFuseOptions } from 'fuse.js';
import {
InternetProviderLyricSearchResponse,
@@ -15,20 +15,81 @@ export const orderSearchResults = (args: {
fieldNormWeight: 1,
includeScore: true,
keys: [
{ getFn: (song) => song.name, name: 'name', weight: 3 },
{ getFn: (song) => song.artist, name: 'artist' },
{ getFn: (song) => song.name, name: 'name', weight: 2 },
{ getFn: (song) => song.artist, name: 'artist', weight: 2 },
],
threshold: 1.0,
threshold: 0.6,
};
const fuse = new Fuse(results, options);
const searchResults = fuse.search<InternetProviderLyricSearchResponse>({
...(params.artist && { artist: params.artist }),
...(params.name && { name: params.name }),
let searchResults: Array<FuseResult<InternetProviderLyricSearchResponse>>;
if (params.artist && params.name) {
const artistFuse = new Fuse(results, {
includeScore: true,
keys: [{ getFn: (song) => song.artist, name: 'artist' }],
threshold: 0.6,
});
const nameFuse = new Fuse(results, {
includeScore: true,
keys: [{ getFn: (song) => song.name, name: 'name' }],
threshold: 0.6,
});
const artistResults = artistFuse.search(params.artist);
const nameResults = nameFuse.search(params.name);
const artistScores = new Map(artistResults.map((r) => [r.item.id, r.score ?? 1]));
const nameScores = new Map(nameResults.map((r) => [r.item.id, r.score ?? 1]));
const combinedResults = new Map<string, FuseResult<InternetProviderLyricSearchResponse>>();
artistResults.forEach((result) => {
const nameScore = nameScores.get(result.item.id);
if (nameScore !== undefined) {
const combinedScore = Math.max(result.score ?? 1, nameScore);
combinedResults.set(result.item.id, {
...result,
score: combinedScore,
});
}
});
nameResults.forEach((result) => {
if (!combinedResults.has(result.item.id)) {
const artistScore = artistScores.get(result.item.id);
if (artistScore !== undefined) {
const combinedScore = Math.max(result.score ?? 1, artistScore);
combinedResults.set(result.item.id, {
...result,
score: combinedScore,
});
}
}
});
searchResults = Array.from(combinedResults.values());
} else {
searchResults = fuse.search<InternetProviderLyricSearchResponse>({
...(params.artist && { artist: params.artist }),
...(params.name && { name: params.name }),
});
}
const sortedResults = searchResults.sort((a, b) => {
const aIsSync = a.item.isSync === true ? 1 : 0;
const bIsSync = b.item.isSync === true ? 1 : 0;
if (aIsSync !== bIsSync) {
return bIsSync - aIsSync;
}
return (a.score || 0) - (b.score || 0);
});
return searchResults.map((result) => ({
return sortedResults.map((result) => ({
...result.item,
score: result.score,
}));