|
1 | 1 | import { app, BrowserWindow, dialog, ipcMain, shell } from "electron"; |
2 | | -import { basename, isAbsolute, join, relative, resolve } from "path"; |
3 | | -import { access, readFile, stat, unlink, writeFile } from "fs/promises"; |
| 2 | +import { basename, dirname, extname, isAbsolute, join, relative, resolve } from "path"; |
| 3 | +import { access, readdir, readFile, stat, unlink, writeFile } from "fs/promises"; |
4 | 4 | import { parseFile } from "music-metadata"; |
5 | 5 | import { getFileID, getFileMD5, metaDataLyricsArrayToLrc } from "../utils/helper"; |
6 | 6 | import { File, Picture, Id3v2Settings } from "node-taglib-sharp"; |
@@ -130,40 +130,61 @@ const initFileIpc = (): void => { |
130 | 130 | "get-music-lyric", |
131 | 131 | async ( |
132 | 132 | _, |
133 | | - path: string, |
| 133 | + musicPath: string, // 参数名改为 musicPath 以示区分 |
134 | 134 | ): Promise<{ |
135 | 135 | lyric: string; |
136 | 136 | format: "lrc" | "ttml"; |
137 | 137 | }> => { |
138 | 138 | try { |
139 | | - const filePath = resolve(path).replace(/\\/g, "/"); |
140 | | - |
141 | | - // 尝试获取同名的歌词文件 |
142 | | - const filePathWithoutExt = filePath.replace(/\.[^.]+$/, ""); |
143 | | - for (const ext of ["ttml", "lrc"] as const) { |
144 | | - const lyricPath = `${filePathWithoutExt}.${ext}`; |
145 | | - const matches = await FastGlob(lyricPath, globOpt()); |
146 | | - ipcLog.info("lyric matches", matches); |
147 | | - if (matches.length > 0) { |
| 139 | + // 获取文件基本信息 |
| 140 | + const absPath = resolve(musicPath); |
| 141 | + const dir = dirname(absPath); |
| 142 | + const ext = extname(absPath); |
| 143 | + const baseName = basename(absPath, ext); |
| 144 | + // 读取目录下所有文件 |
| 145 | + let files: string[] = []; |
| 146 | + try { |
| 147 | + files = await readdir(dir); |
| 148 | + } catch (error) { |
| 149 | + ipcLog.error("❌ Failed to read directory:", dir); |
| 150 | + throw error; |
| 151 | + } |
| 152 | + // 遍历优先级 |
| 153 | + for (const format of ["lrc", "ttml"] as const) { |
| 154 | + // 构造期望目标文件名 |
| 155 | + const targetNameLower = `${baseName}.${format}`.toLowerCase(); |
| 156 | + // 在文件列表中查找是否存在匹配项(忽略大小写) |
| 157 | + const matchedFileName = files.find((file) => file.toLowerCase() === targetNameLower); |
| 158 | + if (matchedFileName) { |
148 | 159 | try { |
149 | | - const lyric = await readFile(matches[0], "utf-8"); |
150 | | - if (lyric && lyric !== "") return { lyric, format: ext }; |
| 160 | + const lyricPath = join(dir, matchedFileName); |
| 161 | + const lyric = await readFile(lyricPath, "utf-8"); |
| 162 | + // 若不为空 |
| 163 | + if (lyric && lyric.trim() !== "") { |
| 164 | + ipcLog.info(`✅ Local lyric found (${format}): ${lyricPath}`); |
| 165 | + return { lyric, format }; |
| 166 | + } |
151 | 167 | } catch { |
152 | | - /* empty */ |
| 168 | + // 读取失败则尝试下一种格式 |
| 169 | + continue; |
153 | 170 | } |
154 | 171 | } |
155 | 172 | } |
156 | | - |
157 | | - // 尝试获取元数据 |
158 | | - const { common } = await parseFile(filePath); |
159 | | - const lyric = common?.lyrics?.[0]?.syncText; |
160 | | - if (lyric && lyric.length > 0) { |
161 | | - return { lyric: metaDataLyricsArrayToLrc(lyric), format: "lrc" }; |
| 173 | + // 如果本地文件没找到,尝试读取内置元数据 (ID3 Tags) |
| 174 | + const { common } = await parseFile(absPath); |
| 175 | + const syncedLyric = common?.lyrics?.[0]?.syncText; |
| 176 | + if (syncedLyric && syncedLyric.length > 0) { |
| 177 | + return { |
| 178 | + lyric: metaDataLyricsArrayToLrc(syncedLyric), |
| 179 | + format: "lrc", |
| 180 | + }; |
162 | 181 | } else if (common?.lyrics?.[0]?.text) { |
163 | | - return { lyric: common?.lyrics?.[0]?.text, format: "lrc" }; |
| 182 | + return { |
| 183 | + lyric: common?.lyrics?.[0]?.text, |
| 184 | + format: "lrc", |
| 185 | + }; |
164 | 186 | } |
165 | | - |
166 | | - // 没有歌词 |
| 187 | + // 都没有找到 |
167 | 188 | return { lyric: "", format: "lrc" }; |
168 | 189 | } catch (error) { |
169 | 190 | ipcLog.error("❌ Error fetching music lyric:", error); |
|
0 commit comments