Skip to content

Commit c70a266

Browse files
committed
🐞 fix: 修复本地歌词及元信息错误
1 parent a7b34ca commit c70a266

10 files changed

Lines changed: 93 additions & 102 deletions

File tree

.github/workflows/build.yml

Lines changed: 17 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,31 @@ on:
77
branches:
88
- dev
99

10+
env:
11+
NODE_VERSION: 22.x
12+
PNPM_VERSION: 8
13+
1014
jobs:
1115
# Windows x64 架构
12-
release-x64:
13-
name: Build Electron App for Windows (x64)
16+
build-win:
17+
name: Build Electron App for Windows
1418
runs-on: windows-latest
1519

1620
steps:
1721
# 检出 Git 仓库
1822
- name: Check out git repository
1923
uses: actions/checkout@v4
24+
# 设置 pnpm 版本
25+
- name: Setup pnpm
26+
uses: pnpm/action-setup@v3
27+
with:
28+
version: ${{ env.PNPM_VERSION }}
2029
# 安装 Node.js
2130
- name: Install Node.js
22-
uses: actions/setup-node@v4
31+
uses: actions/setup-node@v6
2332
with:
24-
node-version: "22.x"
25-
# 安装 pnpm
26-
- name: Install pnpm
27-
run: npm install -g pnpm
33+
node-version: ${{ env.NODE_VERSION }}
34+
cache: "pnpm"
2835
# 复制环境变量文件
2936
- name: Copy .env.example
3037
run: |
@@ -44,7 +51,7 @@ jobs:
4451
}
4552
# 构建 Electron App (x64)
4653
- name: Build Electron App for Windows x64
47-
run: pnpm run build:win -- --x64 || true
54+
run: pnpm run build:win || true
4855
env:
4956
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5057
# 清理不必要的构建产物(保留 .exe 和 .blockmap 文件)
@@ -54,58 +61,6 @@ jobs:
5461
- name: Upload artifacts
5562
uses: actions/upload-artifact@v4
5663
with:
57-
name: SPlayer-dev-x64
58-
path: |
59-
dist/*x64*.exe
60-
dist/*x64*.exe.blockmap
61-
62-
# Windows ARM64 架构
63-
release-arm64:
64-
name: Build Electron App for Windows (ARM64)
65-
runs-on: windows-11-arm
66-
67-
steps:
68-
# 检出 Git 仓库
69-
- name: Check out git repository
70-
uses: actions/checkout@v4
71-
# 安装 Node.js
72-
- name: Install Node.js
73-
uses: actions/setup-node@v4
74-
with:
75-
node-version: "22.x"
76-
# 安装 pnpm
77-
- name: Install pnpm
78-
run: npm install -g pnpm
79-
# 复制环境变量文件
80-
- name: Copy .env.example
81-
run: |
82-
if (-not (Test-Path .env)) {
83-
Copy-Item .env.example .env
84-
} else {
85-
Write-Host ".env file already exists. Skipping the copy step."
86-
}
87-
# 安装项目依赖
88-
- name: Install Dependencies
89-
run: pnpm install
90-
# 清理旧的构建产物
91-
- name: Clean dist folder
92-
run: |
93-
if (Test-Path dist) {
94-
Remove-Item -Recurse -Force dist
95-
}
96-
# 构建 Electron App (ARM64)
97-
- name: Build Electron App for Windows ARM64
98-
run: pnpm run build:win -- --arm64 || true
99-
env:
100-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
101-
# 清理不必要的构建产物(保留 .exe 和 .blockmap 文件)
102-
- name: Cleanup Artifacts
103-
run: npx del-cli "dist/**/*.yaml" "dist/**/*.yml"
104-
# 上传构建产物(仅上传 ARM64 架构的 .exe 文件)
105-
- name: Upload artifacts
106-
uses: actions/upload-artifact@v4
107-
with:
108-
name: SPlayer-dev-arm64
64+
name: SPlayer-dev
10965
path: |
110-
dist/*arm64*.exe
111-
dist/*arm64*.exe.blockmap
66+
dist/**.exe

.github/workflows/release.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Build & Release SPlayer
1+
name: Build & Release
22

33
on:
44
push:
@@ -29,6 +29,7 @@ jobs:
2929
# 检出 Git 仓库
3030
- name: Check out git repository
3131
uses: actions/checkout@v4
32+
# 设置 pnpm 版本
3233
- name: Setup pnpm
3334
uses: pnpm/action-setup@v3
3435
with:
@@ -94,8 +95,6 @@ jobs:
9495
- name: Install Snapcraft
9596
if: runner.os == 'Linux'
9697
uses: samuelmeuli/action-snapcraft@v2
97-
with:
98-
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_TOKEN }}
9998
# 构建 Electron App
10099
- name: Build Windows x64 & ARM64 App
101100
if: runner.os == 'Windows'
@@ -145,6 +144,7 @@ jobs:
145144
# 创建 GitHub Release 并上传所有产物
146145
- name: Create GitHub Release and Upload Assets
147146
uses: softprops/action-gh-release@v2
147+
continue-on-error: true
148148
with:
149149
token: ${{ secrets.GITHUB_TOKEN }}
150150
# 自动生成 Release 说明

electron-builder.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ const config: Configuration = {
165165
electronDownload: {
166166
mirror: "https://npmmirror.com/mirrors/electron/",
167167
},
168+
// 发布配置
169+
// 先留空,不自动上传
170+
publish: [],
168171
};
169172

170173
export default config;

electron/main/ipcMain.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { getFonts } from "font-list";
1515
import { MainTray } from "./tray";
1616
import { Thumbar } from "./thumbar";
1717
import { StoreType } from "./store";
18-
import { isDev, getFileID, getFileMD5 } from "./utils";
18+
import { isDev, getFileID, getFileMD5, metaDataLyricsArrayToLrc } from "./utils";
1919
import { isShortcutRegistered, registerShortcut, unregisterShortcuts } from "./shortcut";
2020
import { join, basename, resolve, relative, isAbsolute } from "path";
2121
import { download } from "electron-dl";
@@ -199,7 +199,7 @@ const initWinIpcMain = (
199199
name: common.title || basename(filePath),
200200
artists: common.artists?.[0] || common.artist,
201201
album: common.album || "",
202-
alia: common.comment?.[0],
202+
alia: common.comment?.[0]?.text || "",
203203
duration: (format?.duration ?? 0) * 1000,
204204
size: (size / (1024 * 1024)).toFixed(2),
205205
path: filePath,
@@ -226,6 +226,11 @@ const initWinIpcMain = (
226226
fileSize: (await fs.stat(filePath)).size / (1024 * 1024),
227227
// 元信息
228228
common,
229+
// 歌词
230+
lyric:
231+
metaDataLyricsArrayToLrc(common?.lyrics?.[0]?.syncText || []) ||
232+
common?.lyrics?.[0]?.text ||
233+
"",
229234
// 音质信息
230235
format,
231236
// md5
@@ -242,8 +247,12 @@ const initWinIpcMain = (
242247
try {
243248
const filePath = resolve(path).replace(/\\/g, "/");
244249
const { common } = await parseFile(filePath);
245-
const lyric = common?.lyrics;
246-
if (lyric && lyric.length > 0) return String(lyric[0]);
250+
const lyric = common?.lyrics?.[0]?.syncText;
251+
if (lyric && lyric.length > 0) {
252+
return metaDataLyricsArrayToLrc(lyric);
253+
} else if (common?.lyrics?.[0]?.text) {
254+
return common?.lyrics?.[0]?.text;
255+
}
247256
// 如果歌词数据不存在,尝试读取同名的 lrc 文件
248257
else {
249258
const lrcFilePath = filePath.replace(/\.[^.]+$/, ".lrc");

electron/main/utils.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,32 @@ export const getFileMD5 = async (path: string): Promise<string> => {
3030
hash.update(data);
3131
return hash.digest("hex");
3232
};
33+
34+
/**
35+
* 将 music-metadata 库中的歌词数组转换为LRC格式字符串
36+
* @param lyrics 歌词数组,每个元素包含时间戳(毫秒)和歌词文本
37+
* @returns LRC格式的字符串
38+
*/
39+
export const metaDataLyricsArrayToLrc = (
40+
lyrics: {
41+
text: string;
42+
timestamp?: number;
43+
}[],
44+
): string => {
45+
return lyrics
46+
.map(({ timestamp, text }) => {
47+
if (!timestamp) return "";
48+
const totalSeconds = Math.floor(timestamp / 1000);
49+
const minutes = Math.floor(totalSeconds / 60);
50+
const seconds = totalSeconds % 60;
51+
const centiseconds = Math.floor((timestamp % 1000) / 10);
52+
53+
// 格式化为两位数字
54+
const mm = String(minutes).padStart(2, "0");
55+
const ss = String(seconds).padStart(2, "0");
56+
const cs = String(centiseconds).padStart(2, "0");
57+
58+
return `[${mm}:${ss}.${cs}]${text}`;
59+
})
60+
.join("\n");
61+
};

electron/server/netease/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { FastifyInstance, FastifyRequest, FastifyReply } from "fastify";
22
import { pathCase } from "change-case";
3-
import NeteaseCloudMusicApi from "@neteaseapireborn/api";
3+
import NeteaseCloudMusicApi from "@neteasecloudmusicapienhanced/api";
44
import log from "../../main/logger";
55

66
// 获取数据

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"@electron-toolkit/utils": "^4.0.0",
4141
"@imsyy/color-utils": "^1.0.2",
4242
"@material/material-color-utilities": "^0.3.0",
43-
"@neteaseapireborn/api": "^4.29.9",
43+
"@neteasecloudmusicapienhanced/api": "^4.29.11",
4444
"@pixi/app": "^7.4.3",
4545
"@pixi/core": "^7.4.3",
4646
"@pixi/display": "^7.4.3",

pnpm-lock.yaml

Lines changed: 9 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/Modal/SongInfoEditor.vue

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -190,24 +190,24 @@ const getSongInfo = async () => {
190190
common: ICommonTagsResult;
191191
format: IFormat;
192192
md5: string;
193+
lyric?: string;
193194
} = await window.electron.ipcRenderer.invoke("get-music-metadata", path);
194-
// console.log(infoData);
195195
// 解构数据
196-
const { fileName, fileSize, common, format, md5 } = infoData;
196+
const { fileName, fileSize, common, format, md5, lyric } = infoData;
197197
// 更新数据
198198
infoFormData.value = {
199-
fileName,
200-
name: common.title || "",
201-
artist: common.artist || "",
202-
album: common.album || "",
203-
alia: (common.comment?.[0] as string) || "",
204-
lyric: (common.lyrics?.[0] as unknown as string) || "",
205-
type: format.codec,
199+
fileName: String(fileName),
200+
name: String(common.title ?? ""),
201+
artist: String(common.artist ?? ""),
202+
album: String(common.album ?? ""),
203+
alia: String(common.comment?.[0]?.text ?? ""),
204+
lyric: String(lyric ?? ""),
205+
type: String(format.codec ?? ""),
206206
duration: format.duration ? Number(format.duration.toFixed(2)) : 0,
207207
size: fileSize,
208208
br: format.bitrate ? Math.floor(format.bitrate / 1000 || 0) : 0,
209209
frequency: format.sampleRate,
210-
md5,
210+
md5: String(md5),
211211
};
212212
// 获取封面
213213
const coverBuff = common.picture?.[0]?.data || "";

src/utils/player.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,10 @@ class Player {
168168
return { index, lyrics };
169169
}
170170

171-
// 逐字歌词(对唱最多两句同时存在):
171+
// 逐字歌词(并发最多三句同时存在):
172172
// - 计算在播放进度下处于激活区间的句子集合 activeIndices([time, endTime))
173-
// - 若激活数 >= 2,仅保留最后两句作为对唱对(不允许三句同时有效)
174-
// - 索引取该对唱对中较早的一句(保持“上一句”高亮)
173+
// - 若激活数 >= 3,仅保留最后三句作为并发显示(允许三句同时有效);否则保持最后两句
174+
// - 索引取该并发集合中较早的一句(保持“上一句”高亮)
175175
// - 若无激活句:首句之前返回 -1;否则回退到最近一句
176176

177177
const firstStart = lyrics[0]?.time ?? 0;
@@ -199,9 +199,10 @@ class Player {
199199
return { index: activeIndices[0], lyrics };
200200
}
201201

202-
// 激活句 >= 2:限制为最后两句对唱
203-
const pair = activeIndices.slice(-2);
204-
return { index: pair[0], lyrics };
202+
// 激活句 >= 2:如果达到三句或更多,限制为最后三句并发;否则保持最后两句
203+
const concurrent =
204+
activeIndices.length >= 3 ? activeIndices.slice(-3) : activeIndices.slice(-2);
205+
return { index: concurrent[0], lyrics };
205206
}
206207
/**
207208
* 获取在线播放链接

0 commit comments

Comments
 (0)