From ec681b90575d1e88d67c8da70b5cc9e7ea1acf92 Mon Sep 17 00:00:00 2001 From: Honey Date: Mon, 27 Apr 2026 19:27:19 +0200 Subject: [PATCH] fix(lyrics): improve LRCLIB lookup reliability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- src/nowplaying.js | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/nowplaying.js b/src/nowplaying.js index 4d8786b..fc37bdc 100644 --- a/src/nowplaying.js +++ b/src/nowplaying.js @@ -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';