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:
1 parent
7e20062995
commit
8b9bfd3098
7 files changed
+150
-68
No files matched your search
+43
-15
@@ -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;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user