Skip to content

Commit 0aae10e

Browse files
committed
🐞 fix: 修复歌词加载过慢仍旧展示上一首 #532
1 parent 242c6f2 commit 0aae10e

11 files changed

Lines changed: 119 additions & 50 deletions

File tree

components.d.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,18 +97,15 @@ declare module 'vue' {
9797
NP: typeof import('naive-ui')['NP']
9898
NPopconfirm: typeof import('naive-ui')['NPopconfirm']
9999
NPopover: typeof import('naive-ui')['NPopover']
100-
NProgress: typeof import('naive-ui')['NProgress']
101100
NQrCode: typeof import('naive-ui')['NQrCode']
102101
NRadio: typeof import('naive-ui')['NRadio']
103102
NRadioGroup: typeof import('naive-ui')['NRadioGroup']
104-
NResult: typeof import('naive-ui')['NResult']
105103
NScrollbar: typeof import('naive-ui')['NScrollbar']
106104
NSelect: typeof import('naive-ui')['NSelect']
107105
NSkeleton: typeof import('naive-ui')['NSkeleton']
108106
NSlider: typeof import('naive-ui')['NSlider']
109107
NSpin: typeof import('naive-ui')['NSpin']
110108
NSwitch: typeof import('naive-ui')['NSwitch']
111-
NTab: typeof import('naive-ui')['NTab']
112109
NTabPane: typeof import('naive-ui')['NTabPane']
113110
NTabs: typeof import('naive-ui')['NTabs']
114111
NTag: typeof import('naive-ui')['NTag']

electron.vite.config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import vue from "@vitejs/plugin-vue";
66
import AutoImport from "unplugin-auto-import/vite";
77
import Components from "unplugin-vue-components/vite";
88
import viteCompression from "vite-plugin-compression";
9-
import VueDevTools from "vite-plugin-vue-devtools";
9+
// import VueDevTools from "vite-plugin-vue-devtools";
1010
import wasm from "vite-plugin-wasm";
1111

1212
export default defineConfig(({ command, mode }) => {
@@ -49,7 +49,7 @@ export default defineConfig(({ command, mode }) => {
4949
root: ".",
5050
plugins: [
5151
vue(),
52-
mode === "development" && VueDevTools(),
52+
// mode === "development" && VueDevTools(),
5353
AutoImport({
5454
imports: [
5555
"vue",

electron/main/ipc/ipc-lyric.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,16 @@ const initLyricIpc = (): void => {
1616
// 切换桌面歌词
1717
ipcMain.on("toggle-desktop-lyric", (_event, val: boolean) => {
1818
if (val) {
19-
lyricWin = lyricWindow.create();
19+
if (!lyricWin) {
20+
lyricWin = lyricWindow.create();
21+
} else {
22+
lyricWin?.show();
23+
}
2024
lyricWin?.setAlwaysOnTop(true, "screen-saver");
2125
} else {
22-
lyricWin?.destroy();
23-
lyricWin = null;
26+
// 关闭:不销毁窗口,直接隐藏,保留位置与状态
27+
if (!lyricWin) return;
28+
lyricWin.hide();
2429
}
2530
});
2631

src/api/song.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export const songLyric = (id: number) => {
7373
*/
7474
export const songLyricTTML = async (id: number) => {
7575
if (isElectron) {
76-
return request({ url: "/lyric/ttml", params: { id } });
76+
return request({ url: "/lyric/ttml", params: { id, noCookie: true } });
7777
} else {
7878
const url = `https://amll-ttml-db.stevexmh.net/ncm/${id}`;
7979
try {

src/components/Player/FullPlayer.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
<!-- 评论 -->
5656
<PlayerComment v-if="isShowComment && !statusStore.pureLyricMode" />
5757
<!-- 歌词 -->
58-
<div v-else-if="musicStore.isHasLrc" class="content-right">
58+
<div class="content-right">
5959
<!-- 数据 -->
6060
<PlayerData
6161
v-if="statusStore.pureLyricMode && musicStore.isHasLrc"
@@ -218,6 +218,7 @@ onBeforeUnmount(() => {
218218
flex-direction: column;
219219
align-items: center;
220220
justify-content: center;
221+
will-change: width, opacity, transform;
221222
transition:
222223
width 0.3s,
223224
opacity 0.5s cubic-bezier(0.34, 1.56, 0.64, 1),
@@ -232,6 +233,7 @@ onBeforeUnmount(() => {
232233
max-width: 50%;
233234
display: flex;
234235
flex-direction: column;
236+
transition: opacity 0.3s;
235237
.player-data {
236238
margin-top: 0;
237239
margin-bottom: 26px;
@@ -272,6 +274,9 @@ onBeforeUnmount(() => {
272274
.content-left {
273275
width: 100%;
274276
}
277+
.content-right {
278+
opacity: 0;
279+
}
275280
}
276281
}
277282
}

src/components/Player/MainAMLyric.vue

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
:key="amLyricsData?.[0]?.words?.length"
55
:class="['lyric-am', { pure: statusStore.pureLyricMode }]"
66
>
7+
<div v-if="statusStore.lyricLoading" class="lyric-loading">歌词正在加载中...</div>
78
<LyricPlayer
9+
v-else
810
ref="lyricPlayerRef"
911
:lyricLines="amLyricsData"
1012
:currentTime="playSeek"
@@ -37,7 +39,6 @@ import { useMusicStore, useSettingStore, useStatusStore } from "@/stores";
3739
import { msToS } from "@/utils/time";
3840
import { getLyricLanguage } from "@/utils/lyric";
3941
import player from "@/utils/player";
40-
import { watch } from "vue";
4142
import LyricMenu from "./LyricMenu.vue";
4243
4344
const musicStore = useMusicStore();
@@ -47,11 +48,15 @@ const settingStore = useSettingStore();
4748
const lyricPlayerRef = ref<any | null>(null);
4849
4950
// 实时播放进度
50-
const playSeek = ref<number>(player.getSeek());
51+
const playSeek = ref<number>(
52+
Math.floor((player.getSeek() + statusStore.getSongOffset(musicStore.playSong?.id)) * 1000),
53+
);
5154
5255
// 实时更新播放进度
5356
const { pause: pauseSeek, resume: resumeSeek } = useRafFn(() => {
54-
const seekInSeconds = player.getSeek();
57+
const songId = musicStore.playSong?.id;
58+
const offsetSeconds = statusStore.getSongOffset(songId);
59+
const seekInSeconds = player.getSeek() + offsetSeconds;
5560
playSeek.value = Math.floor(seekInSeconds * 1000);
5661
});
5762
@@ -164,4 +169,14 @@ onBeforeUnmount(() => {
164169
font-family: var(--ja-font-family);
165170
}
166171
}
172+
173+
.lyric-loading {
174+
width: 100%;
175+
height: 100%;
176+
display: flex;
177+
align-items: center;
178+
justify-content: center;
179+
color: var(--amll-lyric-view-color, #efefef);
180+
font-size: 22px;
181+
}
167182
</style>

src/components/Player/MainLyric.vue

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
@after-enter="lyricsScroll(statusStore.lyricIndex)"
2727
@after-leave="lyricsScroll(statusStore.lyricIndex)"
2828
>
29-
<n-scrollbar ref="lyricScroll" class="lyric-scroll" tabindex="-1">
29+
<div v-if="statusStore.lyricLoading" class="lyric-loading">歌词正在加载中...</div>
30+
<n-scrollbar v-else ref="lyricScroll" class="lyric-scroll" tabindex="-1">
3031
<!-- 逐字歌词 -->
3132
<template v-if="settingStore.showYrc && musicStore.isHasYrc">
3233
<div id="lrc-placeholder" class="placeholder">
@@ -597,3 +598,14 @@ onBeforeUnmount(() => {
597598
}
598599
}
599600
</style>
601+
602+
<style scoped>
603+
.lyric-loading {
604+
width: 100%;
605+
height: 100%;
606+
display: flex;
607+
align-items: center;
608+
justify-content: center;
609+
font-size: 22px;
610+
}
611+
</style>

src/stores/status.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ interface StatusState {
5252
playIndex: number;
5353
/** 歌词播放索引 */
5454
lyricIndex: number;
55+
/** 歌词加载状态 */
56+
lyricLoading: boolean;
5557
/** 当前播放时间 */
5658
currentTime: number;
5759
/** 歌曲总时长 */
@@ -116,6 +118,7 @@ export const useStatusStore = defineStore("status", {
116118
spectrumsData: [],
117119
playIndex: -1,
118120
lyricIndex: -1,
121+
lyricLoading: false,
119122
playRate: 1,
120123
playVolume: 0.7,
121124
playVolumeMute: 0,

src/utils/lyric.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ export const resetSongLyric = () => {
4444
// 重置歌词数据
4545
musicStore.setSongLyric({}, true);
4646
statusStore.usingTTMLLyric = false;
47+
// 标记为加载中(切歌时防止显示上一首歌词)
48+
statusStore.lyricLoading = true;
4749
// 重置歌词索引
4850
statusStore.lyricIndex = -1;
4951
};
@@ -109,6 +111,8 @@ export const parsedLyricsData = (lyricData: any, skipExclude: boolean = false):
109111
);
110112
// 重置歌词索引
111113
statusStore.lyricIndex = -1;
114+
// 歌词已加载完成
115+
statusStore.lyricLoading = false;
112116
};
113117

114118
/**

src/utils/player-utils/lyric.ts

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,50 +13,69 @@ export const getLyricData = async (id: number) => {
1313
const musicStore = useMusicStore();
1414
const settingStore = useSettingStore();
1515
const statusStore = useStatusStore();
16+
// 切歌或重新获取时,先标记为加载中
17+
statusStore.lyricLoading = true;
1618

1719
if (!id) {
1820
statusStore.usingTTMLLyric = false;
1921
resetSongLyric();
22+
statusStore.lyricLoading = false;
2023
return;
2124
}
2225

2326
try {
2427
// 检测本地歌词覆盖
2528
const getLyric = getLyricFun(settingStore.localLyricPath, id);
26-
const [{ lyric: lyricRes, isLocal: lyricLocal }, { lyric: ttmlContent, isLocal: ttmlLocal }] =
27-
await Promise.all([
28-
getLyric("lrc", songLyric),
29-
settingStore.enableTTMLLyric ? getLyric("ttml", songLyricTTML) : getLyric("ttml"),
30-
]);
29+
// 先加载 LRC,不阻塞到 TTML 完成
30+
const lrcPromise = getLyric("lrc", songLyric);
31+
const ttmlPromise = settingStore.enableTTMLLyric ? getLyric("ttml", songLyricTTML) : null;
32+
33+
const { lyric: lyricRes, isLocal: lyricLocal } = await lrcPromise;
3134
parsedLyricsData(lyricRes, lyricLocal && !settingStore.enableExcludeLocalLyrics);
32-
if (ttmlContent) {
33-
const parsedResult = parseTTML(ttmlContent);
34-
if (!parsedResult?.lines?.length) {
35-
statusStore.usingTTMLLyric = false;
36-
return;
37-
}
38-
const skipExcludeLocal = ttmlLocal && !settingStore.enableExcludeLocalLyrics;
39-
const skipExcludeTTML = !settingStore.enableExcludeTTML;
40-
const skipExclude = skipExcludeLocal || skipExcludeTTML;
41-
const ttmlLyric = parseTTMLToAMLL(parsedResult, skipExclude);
42-
const ttmlYrcLyric = parseTTMLToYrc(parsedResult, skipExclude);
43-
console.log("TTML lyrics:", ttmlLyric, ttmlYrcLyric);
44-
// 合并数据
45-
const updates: Partial<{ yrcAMData: LyricLine[]; yrcData: LyricType[] }> = {};
46-
if (ttmlLyric?.length) {
47-
updates.yrcAMData = ttmlLyric;
48-
console.log("✅ TTML AMLL lyrics success");
49-
}
50-
if (ttmlYrcLyric?.length) {
51-
updates.yrcData = ttmlYrcLyric;
52-
console.log("✅ TTML Yrc lyrics success");
53-
}
54-
if (Object.keys(updates).length) {
55-
musicStore.setSongLyric(updates);
56-
statusStore.usingTTMLLyric = true;
57-
} else {
58-
statusStore.usingTTMLLyric = false;
59-
}
35+
// LRC 到达后即可认为加载完成
36+
statusStore.lyricLoading = false;
37+
38+
// TTML 并行加载,完成后增量更新,不阻塞整体流程
39+
if (ttmlPromise) {
40+
statusStore.usingTTMLLyric = false;
41+
void ttmlPromise
42+
.then(({ lyric: ttmlContent, isLocal: ttmlLocal }) => {
43+
if (!ttmlContent) {
44+
statusStore.usingTTMLLyric = false;
45+
return;
46+
}
47+
const parsedResult = parseTTML(ttmlContent);
48+
if (!parsedResult?.lines?.length) {
49+
statusStore.usingTTMLLyric = false;
50+
return;
51+
}
52+
const skipExcludeLocal = ttmlLocal && !settingStore.enableExcludeLocalLyrics;
53+
const skipExcludeTTML = !settingStore.enableExcludeTTML;
54+
const skipExclude = skipExcludeLocal || skipExcludeTTML;
55+
const ttmlLyric = parseTTMLToAMLL(parsedResult, skipExclude);
56+
const ttmlYrcLyric = parseTTMLToYrc(parsedResult, skipExclude);
57+
console.log("TTML lyrics:", ttmlLyric, ttmlYrcLyric);
58+
// 合并数据
59+
const updates: Partial<{ yrcAMData: LyricLine[]; yrcData: LyricType[] }> = {};
60+
if (ttmlLyric?.length) {
61+
updates.yrcAMData = ttmlLyric;
62+
console.log("✅ TTML AMLL lyrics success");
63+
}
64+
if (ttmlYrcLyric?.length) {
65+
updates.yrcData = ttmlYrcLyric;
66+
console.log("✅ TTML Yrc lyrics success");
67+
}
68+
if (Object.keys(updates).length) {
69+
musicStore.setSongLyric(updates);
70+
statusStore.usingTTMLLyric = true;
71+
} else {
72+
statusStore.usingTTMLLyric = false;
73+
}
74+
})
75+
.catch((err) => {
76+
console.error("❌ Error loading TTML lyrics:", err);
77+
statusStore.usingTTMLLyric = false;
78+
});
6079
} else {
6180
statusStore.usingTTMLLyric = false;
6281
}
@@ -66,6 +85,7 @@ export const getLyricData = async (id: number) => {
6685
console.error("❌ Error loading lyrics:", error);
6786
statusStore.usingTTMLLyric = false;
6887
resetSongLyric();
88+
statusStore.lyricLoading = false;
6989
}
7090
};
7191

0 commit comments

Comments
 (0)