// lyrics parsing and display (synced lyrics only for now) let currentLyrics = []; let lyricIndex = 0; // parse timestamped line array into lyric objects function parseLineArray(lines, timeField = "time") { if (!Array.isArray(lines)) return []; return lines .map((line) => { const text = (line.value || "").trim(); if (text) { const timeMs = parseInt(line[timeField]) || 0; return { time: timeMs / 1000, text }; } }) .filter(Boolean) .sort((a, b) => a.time - b.time); } // parse LRC format lyrics string or structured data function parseLyrics(input) { if (!input) return []; const lines = typeof input === "string" ? input.split("\n") : input.line ? [input] : []; const parsed = []; for (const line of lines) { const lrcMatch = line.match?.(/\[(\d+):(\d+)\.(\d+)\](.*)/); if (lrcMatch) { const [_, m, s, ms, text] = lrcMatch; const time = parseInt(m) * 60 + parseInt(s) + parseInt(ms) / 1000; if (text.trim()) parsed.push({ time, text: text.trim() }); } } return parsed.sort((a, b) => a.time - b.time); } // find first synced lyrics in structured array function parseStructured(array) { if (!Array.isArray(array)) return []; for (const entry of array) { if (entry.synced && entry.line?.length) { const parsed = parseLineArray(entry.line, "start"); if (parsed.length > 0) return parsed; } } return []; } // find lyric at current playback time function getCurrentLyric(currentTime) { if (!currentLyrics.length) return null; while ( lyricIndex < currentLyrics.length - 1 && currentLyrics[lyricIndex + 1].time <= currentTime ) { lyricIndex++; } while (lyricIndex > 0 && currentLyrics[lyricIndex].time > currentTime) { lyricIndex--; } return currentLyrics[lyricIndex].time <= currentTime ? currentLyrics[lyricIndex] : null; } // fetch and display lyrics for current song async function loadLyricsForSong(song) { if (!song || !state.api) return; try { if (song.id) { const response = await state.api.getLyricsBySongId(song.id); const structuredArray = response.lyricsList?.structuredLyrics; if (structuredArray) { currentLyrics = parseStructured(structuredArray); lyricIndex = 0; const lyric = getCurrentLyric(ui.player.currentTime); ui.trackLyric.textContent = lyric ? `♪ ${lyric.text}` : ""; return; } } if (song.artist && song.title) { const response = await state.api.getLyrics(song.artist, song.title); currentLyrics = parseLyrics(response.lyrics.value || response.lyrics); lyricIndex = 0; } } catch (error) { console.error("[Lyrics] Failed to load lyrics:", error); currentLyrics = []; lyricIndex = 0; } const lyric = getCurrentLyric(ui.player.currentTime); ui.trackLyric.textContent = lyric ? `♪ ${lyric.text}` : ""; } // display lyric for current playback time function updateLyricDisplay(currentTime) { const lyric = getCurrentLyric(currentTime); ui.trackLyric.textContent = lyric ? `♪ ${lyric.text}` : ""; } // clear displayed lyrics function clearLyrics() { currentLyrics = []; lyricIndex = 0; ui.trackLyric.textContent = ""; }