🐞 fix: 修复歌词加载过慢仍旧展示上一首 #532

This commit is contained in:
imsyy
2025-11-04 12:01:27 +08:00
parent 242c6f2ca7
commit 0aae10e8a0
11 changed files with 119 additions and 50 deletions

3
components.d.ts vendored
View File

@@ -97,18 +97,15 @@ declare module 'vue' {
NP: typeof import('naive-ui')['NP']
NPopconfirm: typeof import('naive-ui')['NPopconfirm']
NPopover: typeof import('naive-ui')['NPopover']
NProgress: typeof import('naive-ui')['NProgress']
NQrCode: typeof import('naive-ui')['NQrCode']
NRadio: typeof import('naive-ui')['NRadio']
NRadioGroup: typeof import('naive-ui')['NRadioGroup']
NResult: typeof import('naive-ui')['NResult']
NScrollbar: typeof import('naive-ui')['NScrollbar']
NSelect: typeof import('naive-ui')['NSelect']
NSkeleton: typeof import('naive-ui')['NSkeleton']
NSlider: typeof import('naive-ui')['NSlider']
NSpin: typeof import('naive-ui')['NSpin']
NSwitch: typeof import('naive-ui')['NSwitch']
NTab: typeof import('naive-ui')['NTab']
NTabPane: typeof import('naive-ui')['NTabPane']
NTabs: typeof import('naive-ui')['NTabs']
NTag: typeof import('naive-ui')['NTag']

View File

@@ -6,7 +6,7 @@ import vue from "@vitejs/plugin-vue";
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import viteCompression from "vite-plugin-compression";
import VueDevTools from "vite-plugin-vue-devtools";
// import VueDevTools from "vite-plugin-vue-devtools";
import wasm from "vite-plugin-wasm";
export default defineConfig(({ command, mode }) => {
@@ -49,7 +49,7 @@ export default defineConfig(({ command, mode }) => {
root: ".",
plugins: [
vue(),
mode === "development" && VueDevTools(),
// mode === "development" && VueDevTools(),
AutoImport({
imports: [
"vue",

View File

@@ -16,11 +16,16 @@ const initLyricIpc = (): void => {
// 切换桌面歌词
ipcMain.on("toggle-desktop-lyric", (_event, val: boolean) => {
if (val) {
lyricWin = lyricWindow.create();
if (!lyricWin) {
lyricWin = lyricWindow.create();
} else {
lyricWin?.show();
}
lyricWin?.setAlwaysOnTop(true, "screen-saver");
} else {
lyricWin?.destroy();
lyricWin = null;
// 关闭:不销毁窗口,直接隐藏,保留位置与状态
if (!lyricWin) return;
lyricWin.hide();
}
});

View File

@@ -73,7 +73,7 @@ export const songLyric = (id: number) => {
*/
export const songLyricTTML = async (id: number) => {
if (isElectron) {
return request({ url: "/lyric/ttml", params: { id } });
return request({ url: "/lyric/ttml", params: { id, noCookie: true } });
} else {
const url = `https://amll-ttml-db.stevexmh.net/ncm/${id}`;
try {

View File

@@ -55,7 +55,7 @@
<!-- 评论 -->
<PlayerComment v-if="isShowComment && !statusStore.pureLyricMode" />
<!-- 歌词 -->
<div v-else-if="musicStore.isHasLrc" class="content-right">
<div class="content-right">
<!-- 数据 -->
<PlayerData
v-if="statusStore.pureLyricMode && musicStore.isHasLrc"
@@ -218,6 +218,7 @@ onBeforeUnmount(() => {
flex-direction: column;
align-items: center;
justify-content: center;
will-change: width, opacity, transform;
transition:
width 0.3s,
opacity 0.5s cubic-bezier(0.34, 1.56, 0.64, 1),
@@ -232,6 +233,7 @@ onBeforeUnmount(() => {
max-width: 50%;
display: flex;
flex-direction: column;
transition: opacity 0.3s;
.player-data {
margin-top: 0;
margin-bottom: 26px;
@@ -272,6 +274,9 @@ onBeforeUnmount(() => {
.content-left {
width: 100%;
}
.content-right {
opacity: 0;
}
}
}
}

View File

@@ -4,7 +4,9 @@
:key="amLyricsData?.[0]?.words?.length"
:class="['lyric-am', { pure: statusStore.pureLyricMode }]"
>
<div v-if="statusStore.lyricLoading" class="lyric-loading">歌词正在加载中...</div>
<LyricPlayer
v-else
ref="lyricPlayerRef"
:lyricLines="amLyricsData"
:currentTime="playSeek"
@@ -37,7 +39,6 @@ import { useMusicStore, useSettingStore, useStatusStore } from "@/stores";
import { msToS } from "@/utils/time";
import { getLyricLanguage } from "@/utils/lyric";
import player from "@/utils/player";
import { watch } from "vue";
import LyricMenu from "./LyricMenu.vue";
const musicStore = useMusicStore();
@@ -47,11 +48,15 @@ const settingStore = useSettingStore();
const lyricPlayerRef = ref<any | null>(null);
// 实时播放进度
const playSeek = ref<number>(player.getSeek());
const playSeek = ref<number>(
Math.floor((player.getSeek() + statusStore.getSongOffset(musicStore.playSong?.id)) * 1000),
);
// 实时更新播放进度
const { pause: pauseSeek, resume: resumeSeek } = useRafFn(() => {
const seekInSeconds = player.getSeek();
const songId = musicStore.playSong?.id;
const offsetSeconds = statusStore.getSongOffset(songId);
const seekInSeconds = player.getSeek() + offsetSeconds;
playSeek.value = Math.floor(seekInSeconds * 1000);
});
@@ -164,4 +169,14 @@ onBeforeUnmount(() => {
font-family: var(--ja-font-family);
}
}
.lyric-loading {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
color: var(--amll-lyric-view-color, #efefef);
font-size: 22px;
}
</style>

View File

@@ -26,7 +26,8 @@
@after-enter="lyricsScroll(statusStore.lyricIndex)"
@after-leave="lyricsScroll(statusStore.lyricIndex)"
>
<n-scrollbar ref="lyricScroll" class="lyric-scroll" tabindex="-1">
<div v-if="statusStore.lyricLoading" class="lyric-loading">歌词正在加载中...</div>
<n-scrollbar v-else ref="lyricScroll" class="lyric-scroll" tabindex="-1">
<!-- 逐字歌词 -->
<template v-if="settingStore.showYrc && musicStore.isHasYrc">
<div id="lrc-placeholder" class="placeholder">
@@ -597,3 +598,14 @@ onBeforeUnmount(() => {
}
}
</style>
<style scoped>
.lyric-loading {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 22px;
}
</style>

View File

@@ -52,6 +52,8 @@ interface StatusState {
playIndex: number;
/** 歌词播放索引 */
lyricIndex: number;
/** 歌词加载状态 */
lyricLoading: boolean;
/** 当前播放时间 */
currentTime: number;
/** 歌曲总时长 */
@@ -116,6 +118,7 @@ export const useStatusStore = defineStore("status", {
spectrumsData: [],
playIndex: -1,
lyricIndex: -1,
lyricLoading: false,
playRate: 1,
playVolume: 0.7,
playVolumeMute: 0,

View File

@@ -44,6 +44,8 @@ export const resetSongLyric = () => {
// 重置歌词数据
musicStore.setSongLyric({}, true);
statusStore.usingTTMLLyric = false;
// 标记为加载中(切歌时防止显示上一首歌词)
statusStore.lyricLoading = true;
// 重置歌词索引
statusStore.lyricIndex = -1;
};
@@ -109,6 +111,8 @@ export const parsedLyricsData = (lyricData: any, skipExclude: boolean = false):
);
// 重置歌词索引
statusStore.lyricIndex = -1;
// 歌词已加载完成
statusStore.lyricLoading = false;
};
/**

View File

@@ -13,50 +13,69 @@ export const getLyricData = async (id: number) => {
const musicStore = useMusicStore();
const settingStore = useSettingStore();
const statusStore = useStatusStore();
// 切歌或重新获取时,先标记为加载中
statusStore.lyricLoading = true;
if (!id) {
statusStore.usingTTMLLyric = false;
resetSongLyric();
statusStore.lyricLoading = false;
return;
}
try {
// 检测本地歌词覆盖
const getLyric = getLyricFun(settingStore.localLyricPath, id);
const [{ lyric: lyricRes, isLocal: lyricLocal }, { lyric: ttmlContent, isLocal: ttmlLocal }] =
await Promise.all([
getLyric("lrc", songLyric),
settingStore.enableTTMLLyric ? getLyric("ttml", songLyricTTML) : getLyric("ttml"),
]);
// 先加载 LRC不阻塞到 TTML 完成
const lrcPromise = getLyric("lrc", songLyric);
const ttmlPromise = settingStore.enableTTMLLyric ? getLyric("ttml", songLyricTTML) : null;
const { lyric: lyricRes, isLocal: lyricLocal } = await lrcPromise;
parsedLyricsData(lyricRes, lyricLocal && !settingStore.enableExcludeLocalLyrics);
if (ttmlContent) {
const parsedResult = parseTTML(ttmlContent);
if (!parsedResult?.lines?.length) {
statusStore.usingTTMLLyric = false;
return;
}
const skipExcludeLocal = ttmlLocal && !settingStore.enableExcludeLocalLyrics;
const skipExcludeTTML = !settingStore.enableExcludeTTML;
const skipExclude = skipExcludeLocal || skipExcludeTTML;
const ttmlLyric = parseTTMLToAMLL(parsedResult, skipExclude);
const ttmlYrcLyric = parseTTMLToYrc(parsedResult, skipExclude);
console.log("TTML lyrics:", ttmlLyric, ttmlYrcLyric);
// 合并数据
const updates: Partial<{ yrcAMData: LyricLine[]; yrcData: LyricType[] }> = {};
if (ttmlLyric?.length) {
updates.yrcAMData = ttmlLyric;
console.log("✅ TTML AMLL lyrics success");
}
if (ttmlYrcLyric?.length) {
updates.yrcData = ttmlYrcLyric;
console.log("✅ TTML Yrc lyrics success");
}
if (Object.keys(updates).length) {
musicStore.setSongLyric(updates);
statusStore.usingTTMLLyric = true;
} else {
statusStore.usingTTMLLyric = false;
}
// LRC 到达后即可认为加载完成
statusStore.lyricLoading = false;
// TTML 并行加载,完成后增量更新,不阻塞整体流程
if (ttmlPromise) {
statusStore.usingTTMLLyric = false;
void ttmlPromise
.then(({ lyric: ttmlContent, isLocal: ttmlLocal }) => {
if (!ttmlContent) {
statusStore.usingTTMLLyric = false;
return;
}
const parsedResult = parseTTML(ttmlContent);
if (!parsedResult?.lines?.length) {
statusStore.usingTTMLLyric = false;
return;
}
const skipExcludeLocal = ttmlLocal && !settingStore.enableExcludeLocalLyrics;
const skipExcludeTTML = !settingStore.enableExcludeTTML;
const skipExclude = skipExcludeLocal || skipExcludeTTML;
const ttmlLyric = parseTTMLToAMLL(parsedResult, skipExclude);
const ttmlYrcLyric = parseTTMLToYrc(parsedResult, skipExclude);
console.log("TTML lyrics:", ttmlLyric, ttmlYrcLyric);
// 合并数据
const updates: Partial<{ yrcAMData: LyricLine[]; yrcData: LyricType[] }> = {};
if (ttmlLyric?.length) {
updates.yrcAMData = ttmlLyric;
console.log("✅ TTML AMLL lyrics success");
}
if (ttmlYrcLyric?.length) {
updates.yrcData = ttmlYrcLyric;
console.log("✅ TTML Yrc lyrics success");
}
if (Object.keys(updates).length) {
musicStore.setSongLyric(updates);
statusStore.usingTTMLLyric = true;
} else {
statusStore.usingTTMLLyric = false;
}
})
.catch((err) => {
console.error("❌ Error loading TTML lyrics:", err);
statusStore.usingTTMLLyric = false;
});
} else {
statusStore.usingTTMLLyric = false;
}
@@ -66,6 +85,7 @@ export const getLyricData = async (id: number) => {
console.error("❌ Error loading lyrics:", error);
statusStore.usingTTMLLyric = false;
resetSongLyric();
statusStore.lyricLoading = false;
}
};

View File

@@ -647,7 +647,10 @@ class Player {
window.$message.warning("当前列表歌曲无法播放,请更换歌曲");
} else {
window.$message.error("该歌曲暂无音源,跳至下一首");
this.nextOrPrev("next");
// 防止切歌保护状态阻塞跳转
this.switching = false;
await this.nextOrPrev("next");
return;
}
}
} else {
@@ -658,7 +661,10 @@ class Player {
window.$message.warning("当前列表歌曲无法播放,请更换歌曲");
} else {
window.$message.error("该歌曲暂无音源,跳至下一首");
this.nextOrPrev("next");
// 防止切歌保护状态阻塞跳转
this.switching = false;
await this.nextOrPrev("next");
return;
}
}
} else {
@@ -668,7 +674,9 @@ class Player {
return;
} else {
window.$message.error("该歌曲无法播放,跳至下一首");
this.nextOrPrev();
// 防止切歌保护状态阻塞跳转
this.switching = false;
await this.nextOrPrev();
return;
}
}