🐞 fix: 修复网页端获取 ttml

This commit is contained in:
imsyy
2025-10-30 14:04:08 +08:00
parent 6937a93d17
commit bdfbb4d2b1
8 changed files with 38 additions and 33 deletions

1
components.d.ts vendored
View File

@@ -106,6 +106,7 @@ declare module 'vue' {
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

@@ -78,7 +78,7 @@ export const initNcmAPI = async (fastify: FastifyInstance) => {
return reply.send(data);
} catch (error) {
serverLog.error("❌ TTML Lyric Fetch Error:", error);
return reply.status(500).send(null);
return reply.send(null);
}
},
);

View File

@@ -1,3 +1,4 @@
import { isElectron } from "@/utils/helper";
import { songLevelData } from "@/utils/meta";
import request from "@/utils/request";
@@ -70,8 +71,22 @@ export const songLyric = (id: number) => {
* @param id 音乐 id
* @returns TTML 格式歌词
*/
export const songLyricTTML = (id: number) => {
return request({ url: "/lyric/ttml", params: { id } });
export const songLyricTTML = async (id: number) => {
if (isElectron) {
return request({ url: "/lyric/ttml", params: { id } });
} else {
const url = `https://amll-ttml-db.stevexmh.net/ncm/${id}`;
try {
const response = await fetch(url);
if (response === null || response.status !== 200) {
return null;
}
const data = await response.text();
return data;
} catch {
return null;
}
}
};
/**

View File

@@ -1,7 +1,7 @@
<template>
<Transition>
<Transition name="fade" mode="out-in">
<div
:key="amLyricsData?.[0]?.startTime"
:key="amLyricsData?.[0]?.words?.length"
:class="['lyric-am', { pure: statusStore.pureLyricMode }]"
>
<LyricPlayer

View File

@@ -100,7 +100,7 @@ export const useStatusStore = defineStore("status", {
searchInputValue: "",
showPlayBar: true,
playStatus: false,
playLoading: false,
playLoading: true,
playUblock: false,
playListShow: false,
showFullPlayer: false,

View File

@@ -25,6 +25,7 @@ const init = async () => {
// 加载数据
await dataStore.loadData();
// 初始化播放器
player.initPlayer(
settingStore.autoPlay,

View File

@@ -70,22 +70,10 @@ class Player {
private isStale(sessionId: number): boolean {
return sessionId !== this.playSessionId;
}
/**
* 保护执行:会话过期则早退
*/
private guard<T>(sessionId: number, fn: () => T): T | undefined {
if (this.isStale(sessionId)) return;
return fn();
}
/**
* 重置底层播放器与定时器(幂等)
*/
private resetPlayerCore() {
try {
this.player?.off();
} catch {
/* empty */
}
try {
Howler.stop();
Howler.unload();
@@ -248,9 +236,8 @@ class Player {
// 自动播放
if (autoPlay) await this.play();
// 获取歌曲附加信息 - 非电台和本地
if (type !== "radio" && !path) {
runIdle(() => getLyricData(id));
} else resetSongLyric();
if (type !== "radio" && !path) getLyricData(id);
else resetSongLyric();
// 定时获取状态
if (!this.playerInterval) this.handlePlayStatus();
// 新增播放历史
@@ -258,13 +245,11 @@ class Player {
// 获取歌曲封面主色
if (!path) runIdle(() => getCoverColor(musicStore.songCover));
// 更新 MediaSession
if (!path) runIdle(() => this.updateMediaSession());
if (!path) this.updateMediaSession();
// 开发模式
if (isDev) window.player = this.player;
// 预载下一首播放地址
runIdle(() => {
void this.prefetchNextSongUrl();
});
this.prefetchNextSongUrl();
}
/**
* 播放器事件
@@ -554,7 +539,7 @@ class Player {
const { lyric, format } = await window.electron.ipcRenderer.invoke("get-music-lyric", path);
parseLocalLyric(lyric, format);
// 更新媒体会话
runIdle(() => this.updateMediaSession());
this.updateMediaSession();
} catch (error) {
window.$message.error("获取本地歌曲元信息失败");
console.error("Failed to parse local music info:", error);
@@ -595,7 +580,10 @@ class Player {
try {
// 获取播放数据
const playSongData = getPlaySongData();
if (!playSongData) return;
if (!playSongData) {
statusStore.playLoading = false;
return;
}
const { id, dj, path, type } = playSongData;
// 更改当前播放歌曲
musicStore.playSong = playSongData;
@@ -695,7 +683,7 @@ class Player {
const settingStore = useSettingStore();
// 检查播放器状态
if (!this.player || this.player.state() === "unloaded") {
console.warn("⚠️ Player not ready for play");
window.$message.warning("播放器未加载完成,请稍后重试");
return;
}
// 已在播放
@@ -721,7 +709,6 @@ class Player {
async pause(changeStatus: boolean = true) {
const statusStore = useStatusStore();
const settingStore = useSettingStore();
const localSession = this.playSessionId;
// 播放器未加载完成或不存在
if (!this.player || this.player.state() !== "loaded") {
@@ -734,7 +721,7 @@ class Player {
await new Promise<void>((resolve) => {
this.player.fade(statusStore.playVolume, 0, settingStore.getFadeTime);
this.player.once("fade", () => {
this.guard(localSession, () => this.player.pause());
this.player.pause();
resolve();
});
});

View File

@@ -136,8 +136,8 @@ const recData = ref<RecDataType>({
// 获取全部推荐
const getAllRecData = async () => {
try {
// 延时 50ms
await sleep(50);
// 延时
await sleep(300);
// 歌单
try {
@@ -199,9 +199,10 @@ const getAllRecData = async () => {
}
};
onActivated(getAllRecData);
onMounted(() => {
getAllRecData();
onActivated(getAllRecData);
});
</script>