fix: restore direct lrclib lyrics search with fuzzy fallback (both platforms)

Navidrome lyrics plugin does not implement getLyricsBySongId for synced
lyrics — removed all plugin calls. Both Android and web now query
lrclib.net/api/get (exact match) with /api/search fallback for metadata
mismatches (e.g. artist tagged differently in Navidrome vs lrclib).
Also fixes Android lyrics scroll tween<Int> type inference error.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Sonnet 4.6 committed 2026-06-15 20:45:32 +02:00
1 parent 7e20062995
commit 8b9bfd3098
7 files changed
+150 -68

No files matched your search

+43 -15
View File
@@ -147,25 +147,53 @@ async function _loadNpLyrics(songId) {
content.innerHTML = '<div style="text-align:center;padding:60px 0;color:rgba(255,255,255,.3);font-size:14px">Lade Lyrics…</div>';
const token = ++_lyricsLoadToken;
const { getLyricsBySongId } = await import('../api.js');
const s = S.queue[S.qIdx];
const artist = (s?.artist || '').split(/[/,]/)[0].trim();
const title = s?.title || '';
const album = s?.album || '';
const dur = s?.duration || 0;
// 1. Exact match (fast path)
let result = null;
try {
const p = new URLSearchParams({ artist_name: artist, track_name: title });
if(album) p.set('album_name', album);
if(dur) p.set('duration', dur);
const r = await fetch(`https://lrclib.net/api/get?${p}`, { signal: AbortSignal.timeout(8000) });
if(r.ok) result = await r.json();
} catch {}
// 2. Search fallback — handles metadata mismatches (e.g. "Utada" vs "Hikaru Utada")
if(token !== _lyricsLoadToken) return;
// Navidrome plugin (getLyricsBySongId) — plugin handles source lookup + caching
const lyrics = await getLyricsBySongId(songId);
if(token !== _lyricsLoadToken) return;
content.innerHTML = '';
const synced = lyrics.find(t => t.synced && t.line?.length);
const plain = lyrics.find(t => t.line?.length);
if(synced) {
_renderSyncedLines(content, synced.line.map(l => ({ start: l.start, value: l.value || '' })).filter(l => l.value));
return;
if(!result?.syncedLyrics && !result?.plainLyrics) {
try {
const p = new URLSearchParams({ track_name: title });
if(artist) p.set('artist_name', artist);
const r = await fetch(`https://lrclib.net/api/search?${p}`, { signal: AbortSignal.timeout(8000) });
if(r.ok) {
const candidates = await r.json();
if(candidates?.length) {
const synced = candidates.filter(c => c.syncedLyrics);
const pool = synced.length ? synced : candidates;
result = dur
? pool.sort((a, b) => Math.abs(a.duration - dur) - Math.abs(b.duration - dur))[0]
: pool[0];
}
}
} catch {}
}
if(plain) {
if(token !== _lyricsLoadToken) return;
content.innerHTML = '';
if(result?.syncedLyrics) {
const parsed = _parseLrc(result.syncedLyrics);
if(parsed.length) { _renderSyncedLines(content, parsed); return; }
}
if(result?.plainLyrics) {
const el = document.createElement('div');
el.className = 'lyrics-plain';
el.textContent = plain.line.map(l => l.value).join('\n');
el.textContent = result.plainLyrics;
content.appendChild(el);
return;
}