/** * 歌词管理模块 (Deno 版本) * 负责歌词的获取、解析和缓存 */ import { MusicStatus } from "./apple_music.ts"; export interface LyricsData { current_lyric_time: number | null; current_lyric: string | null; next_lyric: string | null; next_next_lyric: string | null; track_name: string | null; artist_name: string | null; } interface LyricsLine { time: number; text: string; } interface LyricsCache { track_name: string | null; artist: string | null; lyrics_text: string | null; source: string | null; deleted: boolean; } // 全局歌词缓存 let lyricsCache: LyricsCache = { track_name: null, artist: null, lyrics_text: null, source: null, deleted: false, }; const DB_PATH = "./lyrics.db"; /** * 初始化数据库 */ export async function initDB(): Promise { try { // 确保歌词目录存在 await Deno.mkdir("./lyrics", { recursive: true }); console.log(`数据库初始化完成: ${DB_PATH}`); } catch (error) { console.error(`数据库初始化失败: ${error}`); } } /** * 清空歌词缓存 */ export function clearLyricsCache(): void { lyricsCache = { track_name: null, artist: null, lyrics_text: null, source: null, deleted: false, }; } /** * 从数据库加载歌词 */ async function loadLyricsFromDB( trackName: string, artist: string ): Promise { try { const filePath = `./lyrics/${encodeURIComponent( trackName )}_${encodeURIComponent(artist)}.lrc`; const content = await Deno.readTextFile(filePath); return content; } catch (error) { return null; } } /** * 保存歌词到数据库 */ async function saveLyrics( trackName: string, artist: string, lyricsText: string ): Promise { try { const filePath = `./lyrics/${encodeURIComponent( trackName )}_${encodeURIComponent(artist)}.lrc`; await Deno.writeTextFile(filePath, lyricsText); } catch (error) { console.error(`保存歌词失败: ${error}`); } } /** * 从网易云音乐 API 搜索歌词 */ async function searchLyrics( trackName: string, artistName: string ): Promise { try { const searchVariants = [ { title: trackName, artist: artistName }, { title: trackName, artist: "" }, { title: trackName.replace(/[vV]er\.\s*\d*/g, ""), artist: artistName }, { title: trackName.replace(/\([^)]*\)/g, "").trim(), artist: artistName }, ]; for (const variant of searchVariants) { try { const encodedTitle = encodeURIComponent(variant.title); const encodedArtist = encodeURIComponent(variant.artist); let url = `http://123.57.93.143:28883/lyrics?title=${encodedTitle}`; if (encodedArtist) { url += `&artist=${encodedArtist}`; } const response = await fetch(url, { headers: { Authorization: "fzt_tom", "User-Agent": "MacLyric/1.0", }, }); if (response.ok) { const lyricsText = await response.text(); if (lyricsText) { return lyricsText; } } } catch (error) { console.warn(`搜索歌词变体失败: ${error}`); continue; } } return null; } catch (error) { console.error(`搜索歌词时出错: ${error}`); return null; } } /** * 解析 LRC 格式歌词 */ function parseLrcLyrics(lyricsText: string): LyricsLine[] { const lines = lyricsText.split("\n"); const lyricsLines: LyricsLine[] = []; for (const line of lines) { const match = line.match(/^\[(\d{2}):(\d{2})\.(\d{2,3})\](.*)$/); if (match) { const minutes = parseInt(match[1]); const seconds = parseInt(match[2]); const milliseconds = parseInt(match[3].padEnd(3, "0")); const text = match[4].trim(); const time = minutes * 60 + seconds + milliseconds / 1000; lyricsLines.push({ time, text }); } } return lyricsLines.sort((a, b) => a.time - b.time); } /** * 格式化歌词数据 */ function formatLrcLyrics( lyricsText: string, currentPosition?: number ): LyricsData { const lyricsLines = parseLrcLyrics(lyricsText); if (lyricsLines.length === 0) { return { current_lyric_time: null, current_lyric: null, next_lyric: null, next_next_lyric: null, track_name: null, artist_name: null, }; } if (currentPosition === undefined) { return { current_lyric_time: lyricsLines[0].time, current_lyric: lyricsLines[0].text, next_lyric: lyricsLines.length > 1 ? lyricsLines[1].text : null, next_next_lyric: lyricsLines.length > 2 ? lyricsLines[2].text : null, track_name: null, artist_name: null, }; } let currentIndex = -1; for (let i = 0; i < lyricsLines.length; i++) { if (lyricsLines[i].time <= currentPosition) { currentIndex = i; } else { break; } } const currentLyric = currentIndex >= 0 ? lyricsLines[currentIndex] : null; const nextLyric = currentIndex + 1 < lyricsLines.length ? lyricsLines[currentIndex + 1] : null; const nextNextLyric = currentIndex + 2 < lyricsLines.length ? lyricsLines[currentIndex + 2] : null; return { current_lyric_time: currentLyric?.time || null, current_lyric: currentLyric?.text || null, next_lyric: nextLyric?.text || null, next_next_lyric: nextNextLyric?.text || null, track_name: null, artist_name: null, }; } /** * 获取当前歌词数据 */ export async function getLyricsData(status: MusicStatus): Promise { // 如果没有播放,清空缓存并返回空 if (status.status !== "playing" && status.status !== "paused") { clearLyricsCache(); return { current_lyric_time: null, current_lyric: null, next_lyric: null, next_next_lyric: null, track_name: null, artist_name: null, }; } const trackName = status.track_name; const artist = status.artist; const position = status.position || 0; // 检查是否切换了歌曲 if (lyricsCache.track_name !== trackName || lyricsCache.artist !== artist) { console.log(`歌曲切换,重新获取歌词: ${trackName} - ${artist}`); // 清空缓存 lyricsCache.track_name = trackName; lyricsCache.artist = artist; lyricsCache.lyrics_text = null; lyricsCache.deleted = false; // 1. 先尝试从数据库获取 const lyricsText = await loadLyricsFromDB(trackName || "", artist || ""); if (lyricsText) { lyricsCache.lyrics_text = lyricsText; lyricsCache.source = "db"; } // 2. 如果本地没有,且不是被删除的歌词,尝试从网易云音乐API获取歌词 else if (!lyricsCache.lyrics_text && !lyricsCache.deleted) { const lyricsText = await searchLyrics(trackName || "", artist || ""); if (lyricsText) { // 保存到数据库 await saveLyrics(trackName || "", artist || "", lyricsText); lyricsCache.lyrics_text = lyricsText; lyricsCache.source = "netease"; } } } // 如果有缓存的歌词,直接解析 if (lyricsCache.lyrics_text) { const lyricsData = formatLrcLyrics(lyricsCache.lyrics_text, position); return { ...lyricsData, track_name: trackName || null, artist_name: artist || null, }; } // 没有歌词 return { current_lyric_time: null, current_lyric: null, next_lyric: null, next_next_lyric: null, track_name: trackName || null, artist_name: artist || null, }; }