/** * 歌词管理模块 (Deno 版本) * 负责歌词的获取、解析和缓存 */ import { MusicStatus } from "./apple_music.ts"; import { DatabaseSync } from 'node:sqlite' const userDataDir = Deno.env.get("USER_DATA_DIR") ?? "."; // 将 DB_PATH 设为 `${userDataDir}/lyrics.db` const DB_PATH = `${userDataDir}/lyrics.db`; 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 = new DatabaseSync(DB_PATH); /** * 初始化数据库 */ export async function initDB(): Promise { try { db.exec(` CREATE TABLE IF NOT EXISTS lyrics ( id INTEGER PRIMARY KEY AUTOINCREMENT, track_name TEXT NOT NULL, artist TEXT NOT NULL, lyrics_text TEXT NOT NULL, source TEXT NOT NULL, deleted BOOLEAN NOT NULL DEFAULT 0 ) `); 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 content = db.prepare(`SELECT lyrics_text FROM lyrics WHERE track_name = ? AND artist = ?`).get(trackName, artist); return String(content?.lyrics_text ?? ''); } catch (error) { return ''; } } /** * 保存歌词到数据库 */ export async function saveLyrics( trackName: string, artist: string, lyricsText: string, source: string ): Promise { try { db.prepare(`DELETE FROM lyrics WHERE track_name = ? AND artist = ?`).run(trackName, artist); db.prepare(`INSERT INTO lyrics (track_name, artist, lyrics_text, source) VALUES (?, ?, ?, ?)`).run(trackName, artist, lyricsText, source); lyricsCache.track_name = trackName ?? null; lyricsCache.artist = artist ?? null; lyricsCache.lyrics_text = lyricsText; lyricsCache.source = source; console.log(`保存歌词成功: ${trackName} - ${artist}`); } catch (error) { console.error(`保存歌词失败: ${error}`); } } /** * 从服务器 API 搜索歌词 */ export 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 ''; } catch (error) { console.error(`搜索歌词时出错: ${error}`); return ''; } } /** * 解析 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 deleteLyrics(trackName: string, artist: string): Promise { try { db.prepare(`DELETE FROM lyrics WHERE track_name = ? AND artist = ?`).run(trackName, artist); console.log(`删除歌词成功: ${trackName} - ${artist}`); } catch (error) { console.error(`删除歌词失败: ${error}`); } } /** * 获取当前歌词数据 */ 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 ?? null; lyricsCache.artist = artist ?? null; 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, "server"); lyricsCache.lyrics_text = lyricsText; lyricsCache.source = "server"; } } } // 如果有缓存的歌词,直接解析 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, }; }