fix: lyrics faster + title-only search fallback for metadata mismatches
- Android: add 6s HttpTimeout to LrcLibClient, wrap each step in withTimeoutOrNull
- Both: add title-only lrclib search (step 3) so "Sanctuary (Opening)" is found
even when artist tag differs ("Utada" vs "Hikaru Utada")
- Web: reduce all timeouts 8s → 5s, extract bestMatch helper
Search order: lrclib exact → lrclib artist+title → lrclib title-only → NetEase
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
71667d1a03
commit
d0df01a76d
2 files changed
+84
-51
No files matched your search
+27
-16
@@ -153,44 +153,55 @@ async function _loadNpLyrics(songId) {
|
||||
const album = s?.album || '';
|
||||
const dur = s?.duration || 0;
|
||||
|
||||
const SIG = () => AbortSignal.timeout(5000);
|
||||
const bestMatch = (candidates, durSecs) => {
|
||||
if(!candidates?.length) return null;
|
||||
const synced = candidates.filter(c => c.syncedLyrics);
|
||||
const pool = synced.length ? synced : candidates;
|
||||
if(!durSecs) return pool[0];
|
||||
const pick = pool.sort((a, b) => Math.abs(a.duration - durSecs) - Math.abs(b.duration - durSecs))[0];
|
||||
return Math.abs(pick.duration - durSecs) <= 5 ? pick : (synced[0] || candidates[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) });
|
||||
const r = await fetch(`https://lrclib.net/api/get?${p}`, { signal: SIG() });
|
||||
if(r.ok) result = await r.json();
|
||||
} catch {}
|
||||
|
||||
// 2. Search fallback — handles metadata mismatches (e.g. "Utada" vs "Hikaru Utada")
|
||||
// 2. lrclib artist+title search
|
||||
if(token !== _lyricsLoadToken) 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];
|
||||
}
|
||||
}
|
||||
const r = await fetch(`https://lrclib.net/api/search?${p}`, { signal: SIG() });
|
||||
if(r.ok) result = bestMatch(await r.json(), dur);
|
||||
} catch {}
|
||||
}
|
||||
|
||||
// 3. NetEase fallback — good coverage for Asian/Japanese music
|
||||
// 3. lrclib title-only search — catches "Utada" vs "Hikaru Utada" type mismatches
|
||||
if(token !== _lyricsLoadToken) return;
|
||||
if(!result?.syncedLyrics && !result?.plainLyrics) {
|
||||
try {
|
||||
const p = new URLSearchParams({ track_name: title });
|
||||
const r = await fetch(`https://lrclib.net/api/search?${p}`, { signal: SIG() });
|
||||
if(r.ok) result = bestMatch(await r.json(), dur);
|
||||
} catch {}
|
||||
}
|
||||
|
||||
// 4. NetEase fallback — good coverage for Asian/Japanese music
|
||||
if(token !== _lyricsLoadToken) return;
|
||||
if(!result?.syncedLyrics && !result?.plainLyrics) {
|
||||
try {
|
||||
const q = encodeURIComponent(`${artist} ${title}`.trim());
|
||||
const sr = await fetch(`https://music.163.com/api/search/get?s=${q}&type=1&limit=5`, {
|
||||
headers: { Referer: 'https://music.163.com' },
|
||||
signal: AbortSignal.timeout(8000),
|
||||
signal: SIG(),
|
||||
});
|
||||
if(sr.ok) {
|
||||
const sd = await sr.json();
|
||||
@@ -204,7 +215,7 @@ async function _loadNpLyrics(songId) {
|
||||
if(token !== _lyricsLoadToken) return;
|
||||
const lr = await fetch(
|
||||
`https://music.163.com/api/song/lyric?id=${song.id}&lv=1&kv=1&tv=-1`,
|
||||
{ headers: { Referer: 'https://music.163.com' }, signal: AbortSignal.timeout(8000) },
|
||||
{ headers: { Referer: 'https://music.163.com' }, signal: SIG() },
|
||||
);
|
||||
if(lr.ok) {
|
||||
const ld = await lr.json();
|
||||
|
||||
Reference in new issue
Block a user