fix(lyrics): improve LRCLIB lookup reliability

- Retry LRCLIB without album_name when exact match fails (404) —
  album name mismatch was the most common cause of falling back to plain
- Capture plainLyrics from LRCLIB and prefer it over Navidrome plain
  (LRCLIB plain text is usually higher quality)
- Use only first artist for LRCLIB lookup (multi-artist strings like
  'Artist A / Artist B' cause 404)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Sonnet 4.6 committed 2026-04-27 19:27:19 +02:00
1 parent 16b7faee2b
commit ec681b9057
1 file changed
+21 -9
+21 -9
View File
@@ -137,13 +137,26 @@ async function _loadNpLyrics(songId) {
return;
}
// 2. Fallback: fetch synced lyrics from LRCLIB
// 2. Fallback: fetch lyrics from LRCLIB
// Use only first artist (multi-artist strings like "A / B" break lookup)
const firstArtist = (s?.artist||'').split(/[/,]/)[0].trim();
let lrcText = null;
let lrclibPlain = null;
try {
const p = new URLSearchParams({ artist_name: s?.artist||'', track_name: s?.title||'' });
if(s?.album) p.set('album_name', s.album);
const r = await fetch(`https://lrclib.net/api/get?${p}`, { signal: AbortSignal.timeout(8000) });
if(r.ok) { const d = await r.json(); lrcText = d.syncedLyrics || null; }
// Try with album first, then without (album mismatch causes 404)
const attempts = [
new URLSearchParams({ artist_name: firstArtist, track_name: s?.title||'', ...(s?.album ? { album_name: s.album } : {}) }),
...(s?.album ? [new URLSearchParams({ artist_name: firstArtist, track_name: s?.title||'' })] : []),
];
for(const p of attempts) {
const r = await fetch(`https://lrclib.net/api/get?${p}`, { signal: AbortSignal.timeout(6000) });
if(r.ok) {
const d = await r.json();
lrcText = d.syncedLyrics || null;
lrclibPlain = d.plainLyrics || null;
break;
}
}
} catch {}
content.innerHTML = '';
@@ -152,10 +165,9 @@ async function _loadNpLyrics(songId) {
if(parsed.length) { _renderSyncedLines(content, parsed); return; }
}
// 3. Plain text fallback
const plain = track?.line?.length
? track.line.map(l => l.value).join('\n')
: null;
// 3. Plain text — prefer LRCLIB plain over Navidrome plain (usually better quality)
const plain = lrclibPlain
|| (track?.line?.length ? track.line.map(l => l.value).join('\n') : null);
if(plain) {
const el = document.createElement('div');
el.className = 'lyrics-plain';