feat: 优化播放错误处理

This commit is contained in:
alger
2025-12-17 13:19:10 +08:00
parent 89c6b11110
commit 6bc168c5bd
9 changed files with 60 additions and 57 deletions

View File

@@ -14,6 +14,9 @@ export default {
addCorrection: 'Add {num} seconds', addCorrection: 'Add {num} seconds',
subtractCorrection: 'Subtract {num} seconds', subtractCorrection: 'Subtract {num} seconds',
playFailed: 'Play Failed, Play Next Song', playFailed: 'Play Failed, Play Next Song',
parseFailedPlayNext: 'Song parsing failed, playing next',
consecutiveFailsError:
'Playback error, possibly due to network issues or invalid source. Please switch playlist or try again later',
playMode: { playMode: {
sequence: 'Sequence', sequence: 'Sequence',
loop: 'Loop', loop: 'Loop',

View File

@@ -14,6 +14,9 @@ export default {
addCorrection: '{num}秒早める', addCorrection: '{num}秒早める',
subtractCorrection: '{num}秒遅らせる', subtractCorrection: '{num}秒遅らせる',
playFailed: '現在の楽曲の再生に失敗しました。次の曲を再生します', playFailed: '現在の楽曲の再生に失敗しました。次の曲を再生します',
parseFailedPlayNext: '楽曲の解析に失敗しました。次の曲を再生します',
consecutiveFailsError:
'再生エラーが発生しました。ネットワークの問題または無効な音源の可能性があります。プレイリストを切り替えるか、後でもう一度お試しください',
playMode: { playMode: {
sequence: '順次再生', sequence: '順次再生',
loop: 'リピート再生', loop: 'リピート再生',

View File

@@ -14,6 +14,9 @@ export default {
addCorrection: '{num}초 앞당기기', addCorrection: '{num}초 앞당기기',
subtractCorrection: '{num}초 지연', subtractCorrection: '{num}초 지연',
playFailed: '현재 곡 재생 실패, 다음 곡 재생', playFailed: '현재 곡 재생 실패, 다음 곡 재생',
parseFailedPlayNext: '곡 분석 실패, 다음 곡 재생',
consecutiveFailsError:
'재생 오류가 발생했습니다. 네트워크 문제 또는 유효하지 않은 음원일 수 있습니다. 재생 목록을 변경하거나 나중에 다시 시도하세요',
playMode: { playMode: {
sequence: '순차 재생', sequence: '순차 재생',
loop: '한 곡 반복', loop: '한 곡 반복',

View File

@@ -14,6 +14,8 @@ export default {
addCorrection: '提前 {num} 秒', addCorrection: '提前 {num} 秒',
subtractCorrection: '延迟 {num} 秒', subtractCorrection: '延迟 {num} 秒',
playFailed: '当前歌曲播放失败,播放下一首', playFailed: '当前歌曲播放失败,播放下一首',
parseFailedPlayNext: '歌曲解析失败,播放下一首',
consecutiveFailsError: '播放遇到错误,可能是网络波动或解析源失效,请切换播放列表或稍后重试',
playMode: { playMode: {
sequence: '顺序播放', sequence: '顺序播放',
loop: '单曲循环', loop: '单曲循环',

View File

@@ -14,6 +14,8 @@ export default {
addCorrection: '提前 {num} 秒', addCorrection: '提前 {num} 秒',
subtractCorrection: '延遲 {num} 秒', subtractCorrection: '延遲 {num} 秒',
playFailed: '目前歌曲播放失敗,播放下一首', playFailed: '目前歌曲播放失敗,播放下一首',
parseFailedPlayNext: '歌曲解析失敗,播放下一首',
consecutiveFailsError: '播放遇到錯誤,可能是網路波動或解析源失效,請切換播放清單或稍後重試',
playMode: { playMode: {
sequence: '順序播放', sequence: '順序播放',
loop: '單曲循環', loop: '單曲循環',

View File

@@ -1,12 +1,4 @@
<template> <template>
<div class="traffic-warning-trigger">
<n-button circle secondary class="mac-style-button" @click="showDrawer = true">
<template #icon>
<i class="iconfont ri-information-line"></i>
</template>
</n-button>
</div>
<n-drawer <n-drawer
v-model:show="showDrawer" v-model:show="showDrawer"
:width="isMobile ? '100%' : '800px'" :width="isMobile ? '100%' : '800px'"

View File

@@ -314,20 +314,6 @@ export const usePlayerCoreStore = defineStore(
} }
playbackRequestManager.failRequest(requestId); playbackRequestManager.failRequest(requestId);
// 通知外部播放失败,需要跳到下一首
try {
const { usePlaylistStore } = await import('./playlist');
const playlistStore = usePlaylistStore();
if (Array.isArray(playlistStore.playList) && playlistStore.playList.length > 1) {
message.warning('歌曲解析失败 播放下一首');
setTimeout(() => {
playlistStore.nextPlay();
}, 500);
}
} catch (e) {
console.warn('切换下一首时发生问题:', e);
}
return false; return false;
} }
}; };
@@ -458,19 +444,7 @@ export const usePlayerCoreStore = defineStore(
} }
}, 1000); }, 1000);
} else { } else {
// 非操作锁错误:尝试切到下一首,避免在解析失败时卡住 console.warn('播放音频失败(非操作锁错误),由调用方处理重试');
message.warning('歌曲解析失败 播放下一首');
try {
const { usePlaylistStore } = await import('./playlist');
const playlistStore = usePlaylistStore();
if (Array.isArray(playlistStore.playList) && playlistStore.playList.length > 1) {
setTimeout(() => {
playlistStore.nextPlay();
}, 500);
}
} catch (e) {
console.warn('播放失败回退到下一首时发生问题(可能依赖未加载):', e);
}
} }
message.error(i18n.global.t('player.playFailed')); message.error(i18n.global.t('player.playFailed'));

View File

@@ -31,6 +31,11 @@ export const usePlaylistStore = defineStore(
const originalPlayList = shallowRef<SongResult[]>([]); const originalPlayList = shallowRef<SongResult[]>([]);
const playListDrawerVisible = ref(false); const playListDrawerVisible = ref(false);
// 连续失败计数器(用于防止无限循环)
const consecutiveFailCount = ref(0);
const MAX_CONSECUTIVE_FAILS = 5; // 最大连续失败次数
const SINGLE_TRACK_MAX_RETRIES = 3; // 单曲最大重试次数
// ==================== Computed ==================== // ==================== Computed ====================
const currentPlayList = computed(() => playList.value); const currentPlayList = computed(() => playList.value);
const currentPlayListIndex = computed(() => playListIndex.value); const currentPlayListIndex = computed(() => playListIndex.value);
@@ -343,8 +348,9 @@ export const usePlaylistStore = defineStore(
/** /**
* 下一首 * 下一首
* @param singleTrackRetryCount 单曲重试次数(同一首歌的重试)
*/ */
const _nextPlay = async (retryCount: number = 0, maxRetries: number = 3) => { const _nextPlay = async (singleTrackRetryCount: number = 0) => {
try { try {
if (playList.value.length === 0) { if (playList.value.length === 0) {
return; return;
@@ -353,6 +359,15 @@ export const usePlaylistStore = defineStore(
const playerCore = usePlayerCoreStore(); const playerCore = usePlayerCoreStore();
const sleepTimerStore = useSleepTimerStore(); const sleepTimerStore = useSleepTimerStore();
// 检查是否超过最大连续失败次数
if (consecutiveFailCount.value >= MAX_CONSECUTIVE_FAILS) {
console.error(`[nextPlay] 连续${MAX_CONSECUTIVE_FAILS}首歌曲播放失败,停止播放`);
message.warning(i18n.global.t('player.consecutiveFailsError'));
consecutiveFailCount.value = 0; // 重置计数器
playerCore.setIsPlay(false);
return;
}
// 检查是否是播放列表的最后一首且设置了播放列表结束定时 // 检查是否是播放列表的最后一首且设置了播放列表结束定时
if ( if (
playMode.value === 0 && playMode.value === 0 &&
@@ -368,42 +383,51 @@ export const usePlaylistStore = defineStore(
const nextSong = { ...playList.value[nowPlayListIndex] }; const nextSong = { ...playList.value[nowPlayListIndex] };
console.log( console.log(
`[nextPlay] 尝试播放下一首: ${nextSong.name}, 索引: ${currentIndex} -> ${nowPlayListIndex}, 重试次数: ${retryCount}/${maxRetries}` `[nextPlay] 尝试播放: ${nextSong.name}, 索引: ${currentIndex} -> ${nowPlayListIndex}, 单曲重试: ${singleTrackRetryCount}/${SINGLE_TRACK_MAX_RETRIES}, 连续失败: ${consecutiveFailCount.value}/${MAX_CONSECUTIVE_FAILS}`
); );
// 先尝试播放歌曲,成功后再更新索引 // 先尝试播放歌曲
const success = await playerCore.handlePlayMusic(nextSong, true); const success = await playerCore.handlePlayMusic(nextSong, true);
if (success) { if (success) {
// 播放成功,更新索引并重置重试计数 // 播放成功,重置所有计数器并更新索引
consecutiveFailCount.value = 0;
playListIndex.value = nowPlayListIndex; playListIndex.value = nowPlayListIndex;
console.log(`[nextPlay] 播放成功,索引已更新为: ${nowPlayListIndex}`); console.log(`[nextPlay] 播放成功,索引已更新为: ${nowPlayListIndex}`);
sleepTimerStore.handleSongChange(); sleepTimerStore.handleSongChange();
} else { } else {
console.error(`[nextPlay] 播放下一首失败,当前索引: ${currentIndex}`); console.error(`[nextPlay] 播放失败: ${nextSong.name}`);
// 如果还有重试次数,先更新索引再重试下一首 // 单曲重试逻辑
if (retryCount < maxRetries && playList.value.length > 1) { if (singleTrackRetryCount < SINGLE_TRACK_MAX_RETRIES) {
console.log( console.log(
`[nextPlay] 跳过失败的歌曲,尝试播放下下首,重试 ${retryCount + 1}/${maxRetries}` `[nextPlay] 单曲重试 ${singleTrackRetryCount + 1}/${SINGLE_TRACK_MAX_RETRIES}`
);
// 不更新索引,重试同一首歌
setTimeout(() => {
_nextPlay(singleTrackRetryCount + 1);
}, 1000);
} else {
// 单曲重试次数用尽,递增连续失败计数,尝试下一首
consecutiveFailCount.value++;
console.log(
`[nextPlay] 单曲重试用尽,连续失败计数: ${consecutiveFailCount.value}/${MAX_CONSECUTIVE_FAILS}`
); );
// 更新索引到失败的歌曲位置,这样下次递归调用会继续往下 if (playList.value.length > 1) {
playListIndex.value = nowPlayListIndex; // 更新索引到失败的歌曲位置,这样下次递归调用会继续往下
playListIndex.value = nowPlayListIndex;
message.warning(i18n.global.t('player.parseFailedPlayNext'));
// 延迟后递归调用,尝试播放下一首 // 延迟后尝试下一首(重置单曲重试计数)
setTimeout(() => { setTimeout(() => {
_nextPlay(retryCount + 1, maxRetries); _nextPlay(0);
}, 500); }, 500);
} else {
// 重试次数用尽或只有一首歌
if (retryCount >= maxRetries) {
console.error(`[nextPlay] 连续${maxRetries}首歌曲播放失败,停止尝试`);
message.error('连续多首歌曲播放失败,请检查网络或音源设置');
} else { } else {
// 只有一首歌且失败
message.error(i18n.global.t('player.playFailed')); message.error(i18n.global.t('player.playFailed'));
playerCore.setIsPlay(false);
} }
playerCore.setIsPlay(false);
} }
} }
} catch (error) { } catch (error) {

View File

@@ -88,14 +88,14 @@ export const useSleepTimerStore = defineStore('sleepTimer', () => {
/** /**
* 按歌曲数设置定时关闭 * 按歌曲数设置定时关闭
*/ */
const setSleepTimerBySongs = (songs: number) => { const setSleepTimerBySongs = async (songs: number) => {
clearSleepTimer(); clearSleepTimer();
if (songs <= 0) { if (songs <= 0) {
return false; return false;
} }
const { usePlaylistStore } = require('./playlist'); const { usePlaylistStore } = await import('./playlist');
const playlistStore = usePlaylistStore(); const playlistStore = usePlaylistStore();
sleepTimer.value = { sleepTimer.value = {