Skip to content

Commit 8ed13d4

Browse files
committed
🔧 chore: 优化播放器逻辑,改进播放失败处理,支持保持当前索引并增加重试机制
1 parent 3d71a29 commit 8ed13d4

File tree

1 file changed

+178
-58
lines changed

1 file changed

+178
-58
lines changed

src/renderer/store/modules/player.ts

Lines changed: 178 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -527,8 +527,11 @@ export const usePlayerStore = defineStore('player', () => {
527527
musicFull.value = value;
528528
};
529529

530-
const setPlayList = (list: SongResult[]) => {
531-
playListIndex.value = list.findIndex((item) => item.id === playMusic.value.id);
530+
const setPlayList = (list: SongResult[], keepIndex: boolean = false) => {
531+
// 如果指定保持当前索引,则不重新计算索引
532+
if (!keepIndex) {
533+
playListIndex.value = list.findIndex((item) => item.id === playMusic.value.id);
534+
}
532535
playList.value = list;
533536
localStorage.setItem('playList', JSON.stringify(list));
534537
localStorage.setItem('playListIndex', playListIndex.value.toString());
@@ -714,7 +717,7 @@ export const usePlayerStore = defineStore('player', () => {
714717
}
715718
};
716719

717-
// 修改nextPlay方法,加入定时关闭检查逻辑
720+
// 修改nextPlay方法,改进播放失败的处理逻辑
718721
const nextPlay = async () => {
719722
// 静态标志,防止多次调用造成递归
720723
if ((nextPlay as any).isRunning) {
@@ -744,59 +747,122 @@ export const usePlayerStore = defineStore('player', () => {
744747
const shouldPlayNext = play.value;
745748
console.log('切换到下一首,当前播放状态:', shouldPlayNext ? '播放' : '暂停');
746749

750+
// 保存当前索引,用于错误恢复
751+
const currentIndex = playListIndex.value;
747752
let nowPlayListIndex: number;
748753

749754
if (playMode.value === 2) {
755+
// 随机播放模式
750756
do {
751757
nowPlayListIndex = Math.floor(Math.random() * playList.value.length);
752758
} while (nowPlayListIndex === playListIndex.value && playList.value.length > 1);
753759
} else {
760+
// 顺序播放或循环播放模式
754761
nowPlayListIndex = (playListIndex.value + 1) % playList.value.length;
755762
}
756763

757-
// 重要:首先更新当前播放索引
764+
// 记录尝试播放过的索引,防止无限循环
765+
const attemptedIndices = new Set<number>();
766+
attemptedIndices.add(nowPlayListIndex);
767+
768+
// 更新当前播放索引
758769
playListIndex.value = nowPlayListIndex;
759770

760771
// 获取下一首歌曲
761-
const nextSong = playList.value[nowPlayListIndex];
762-
763-
// 如果是B站视频,确保重新获取URL
764-
if (nextSong.source === 'bilibili' && nextSong.bilibiliData) {
765-
// 清除之前的URL,确保重新获取
766-
nextSong.playMusicUrl = undefined;
767-
console.log('下一首是B站视频,已清除URL强制重新获取');
768-
}
772+
let nextSong = playList.value[nowPlayListIndex];
773+
let success = false;
774+
let retryCount = 0;
775+
const maxRetries = Math.min(3, playList.value.length);
776+
777+
// 尝试播放,最多尝试maxRetries次
778+
while (!success && retryCount < maxRetries) {
779+
// 如果是B站视频,确保重新获取URL
780+
if (nextSong.source === 'bilibili' && nextSong.bilibiliData) {
781+
// 清除之前的URL,确保重新获取
782+
nextSong.playMusicUrl = undefined;
783+
console.log(`尝试播放B站视频 (尝试 ${retryCount + 1}/${maxRetries})`);
784+
}
769785

770-
// 尝试播放,并明确传递应该播放的状态
771-
const success = await handlePlayMusic(nextSong, shouldPlayNext);
772-
773-
if (!success) {
774-
console.error('播放下一首失败,将从播放列表中移除此歌曲');
775-
// 从播放列表中移除失败的歌曲
776-
const newPlayList = [...playList.value];
777-
newPlayList.splice(nowPlayListIndex, 1);
786+
// 尝试播放,并明确传递应该播放的状态
787+
success = await handlePlayMusic(nextSong, shouldPlayNext);
778788

779-
if (newPlayList.length > 0) {
780-
// 更新播放列表后,重新尝试播放下一首
781-
setPlayList(newPlayList);
782-
// 延迟一点时间再尝试下一首,避免立即触发可能导致的无限循环
783-
setTimeout(() => {
784-
(nextPlay as any).isRunning = false;
785-
nextPlay();
786-
}, 300);
787-
return;
789+
if (!success) {
790+
retryCount++;
791+
console.error(`播放失败,尝试 ${retryCount}/${maxRetries}`);
792+
793+
if (retryCount >= maxRetries) {
794+
console.error('多次尝试播放失败,将从播放列表中移除此歌曲');
795+
// 从播放列表中移除失败的歌曲
796+
const newPlayList = [...playList.value];
797+
newPlayList.splice(nowPlayListIndex, 1);
798+
799+
if (newPlayList.length > 0) {
800+
// 更新播放列表,但保持当前索引不变
801+
// 这是关键修改,防止索引重置到-1
802+
const keepCurrentIndexPosition = true;
803+
setPlayList(newPlayList, keepCurrentIndexPosition);
804+
805+
// 继续尝试下一首
806+
if (playMode.value === 2) {
807+
// 随机模式,随机选择一首未尝试过的
808+
const availableIndices = Array.from(
809+
{ length: newPlayList.length },
810+
(_, i) => i
811+
).filter(i => !attemptedIndices.has(i));
812+
813+
if (availableIndices.length > 0) {
814+
// 随机选择一个未尝试过的索引
815+
nowPlayListIndex = availableIndices[Math.floor(Math.random() * availableIndices.length)];
816+
} else {
817+
// 如果所有歌曲都尝试过了,选择下一个索引
818+
nowPlayListIndex = (playListIndex.value + 1) % newPlayList.length;
819+
}
820+
} else {
821+
// 顺序播放,选择下一首
822+
// 如果当前索引已经是最后一首,循环到第一首
823+
nowPlayListIndex = playListIndex.value >= newPlayList.length
824+
? 0
825+
: playListIndex.value;
826+
}
827+
828+
playListIndex.value = nowPlayListIndex;
829+
attemptedIndices.add(nowPlayListIndex);
830+
831+
if (newPlayList[nowPlayListIndex]) {
832+
nextSong = newPlayList[nowPlayListIndex];
833+
retryCount = 0; // 重置重试计数器,为新歌曲准备
834+
} else {
835+
// 处理索引无效的情况
836+
console.error('无效的播放索引,停止尝试');
837+
break;
838+
}
839+
} else {
840+
// 播放列表为空,停止尝试
841+
console.error('播放列表为空,停止尝试');
842+
break;
843+
}
844+
}
788845
}
789846
}
790847

791848
// 歌曲切换成功,触发歌曲变更处理(用于定时关闭功能)
792-
handleSongChange();
849+
if (success) {
850+
handleSongChange();
851+
} else {
852+
console.error('所有尝试都失败,无法播放下一首歌曲');
853+
// 如果尝试了所有可能的歌曲仍然失败,恢复到原始索引
854+
playListIndex.value = currentIndex;
855+
setIsPlay(false); // 停止播放
856+
message.error(i18n.global.t('player.playFailed'));
857+
}
793858
} catch (error) {
794859
console.error('切换下一首出错:', error);
795860
} finally {
796861
(nextPlay as any).isRunning = false;
797862
}
798863
};
799864

865+
// 修改 prevPlay 方法,使用与 nextPlay 相似的逻辑改进
800866
const prevPlay = async () => {
801867
// 静态标志,防止多次调用造成递归
802868
if ((prevPlay as any).isRunning) {
@@ -813,6 +879,8 @@ export const usePlayerStore = defineStore('player', () => {
813879
return;
814880
}
815881

882+
// 保存当前索引,用于错误恢复
883+
const currentIndex = playListIndex.value;
816884
const nowPlayListIndex =
817885
(playListIndex.value - 1 + playList.value.length) % playList.value.length;
818886

@@ -821,6 +889,9 @@ export const usePlayerStore = defineStore('player', () => {
821889

822890
// 获取上一首歌曲
823891
const prevSong = playList.value[nowPlayListIndex];
892+
let success = false;
893+
let retryCount = 0;
894+
const maxRetries = 2;
824895

825896
// 如果是B站视频,确保重新获取URL
826897
if (prevSong.source === 'bilibili' && prevSong.bilibiliData) {
@@ -829,27 +900,59 @@ export const usePlayerStore = defineStore('player', () => {
829900
console.log('上一首是B站视频,已清除URL强制重新获取');
830901
}
831902

832-
// 尝试播放,如果失败会返回false
833-
const success = await handlePlayMusic(prevSong);
903+
// 尝试播放,最多尝试maxRetries次
904+
while (!success && retryCount < maxRetries) {
905+
success = await handlePlayMusic(prevSong);
906+
907+
if (!success) {
908+
retryCount++;
909+
console.error(`播放上一首失败,尝试 ${retryCount}/${maxRetries}`);
910+
911+
// 最后一次尝试失败
912+
if (retryCount >= maxRetries) {
913+
console.error('多次尝试播放失败,将从播放列表中移除此歌曲');
914+
// 从播放列表中移除失败的歌曲
915+
const newPlayList = [...playList.value];
916+
newPlayList.splice(nowPlayListIndex, 1);
917+
918+
if (newPlayList.length > 0) {
919+
// 更新播放列表,但保持当前索引不变
920+
const keepCurrentIndexPosition = true;
921+
setPlayList(newPlayList, keepCurrentIndexPosition);
922+
923+
// 恢复到原始索引或继续尝试上一首
924+
if (newPlayList.length === 1) {
925+
// 只剩一首歌,直接播放它
926+
playListIndex.value = 0;
927+
} else {
928+
// 尝试上上一首
929+
const newPrevIndex = (playListIndex.value - 1 + newPlayList.length) % newPlayList.length;
930+
playListIndex.value = newPrevIndex;
931+
}
932+
933+
// 延迟一点时间再尝试,避免可能的无限循环
934+
setTimeout(() => {
935+
(prevPlay as any).isRunning = false;
936+
prevPlay(); // 递归调用,尝试再上一首
937+
}, 300);
938+
return;
939+
} else {
940+
// 播放列表为空,停止尝试
941+
console.error('播放列表为空,停止尝试');
942+
break;
943+
}
944+
}
945+
}
946+
}
834947

835948
if (success) {
836949
await fetchSongs(playList.value, playListIndex.value - 3, nowPlayListIndex);
837950
} else {
838-
console.error('播放上一首失败,将从播放列表中移除此歌曲');
839-
// 从播放列表中移除失败的歌曲
840-
const newPlayList = [...playList.value];
841-
newPlayList.splice(nowPlayListIndex, 1);
842-
843-
if (newPlayList.length > 0) {
844-
// 更新播放列表后,重新尝试播放上一首
845-
setPlayList(newPlayList);
846-
// 延迟一点时间再尝试上一首,避免立即触发可能导致的无限循环
847-
setTimeout(() => {
848-
(prevPlay as any).isRunning = false;
849-
prevPlay();
850-
}, 300);
851-
return;
852-
}
951+
console.error('所有尝试都失败,无法播放上一首歌曲');
952+
// 如果尝试了所有可能的歌曲仍然失败,恢复到原始索引
953+
playListIndex.value = currentIndex;
954+
setIsPlay(false); // 停止播放
955+
message.error(i18n.global.t('player.playFailed'));
853956
}
854957
} catch (error) {
855958
console.error('切换上一首出错:', error);
@@ -981,7 +1084,7 @@ export const usePlayerStore = defineStore('player', () => {
9811084
localStorage.setItem('favoriteList', JSON.stringify(favoriteList.value));
9821085
};
9831086

984-
// 修改:处理音频播放的方法,使用事件触发机制
1087+
// 修改 playAudio 函数中的错误处理逻辑,避免在操作锁问题时频繁尝试播放
9851088
const playAudio = async () => {
9861089
if (!playMusicUrl.value || !playMusic.value) return null;
9871090

@@ -1041,23 +1144,40 @@ export const usePlayerStore = defineStore('player', () => {
10411144
console.error('播放音频失败:', error);
10421145
setPlayMusic(false);
10431146

1044-
// 避免直接调用 nextPlay,改用延时避免无限循环
10451147
// 检查错误是否是由于操作锁引起的
10461148
const errorMsg = error instanceof Error ? error.message : String(error);
1149+
1150+
// 操作锁错误处理
10471151
if (errorMsg.includes('操作锁激活')) {
1048-
console.log('由于操作锁正在使用,将在500ms后重试');
1049-
// 操作锁错误,延迟后再尝试
1152+
console.log('由于操作锁正在使用,将在1000ms后重试');
1153+
1154+
// 强制重置操作锁并延迟再试
1155+
try {
1156+
// 尝试强制重置音频服务的操作锁
1157+
audioService.forceResetOperationLock();
1158+
console.log('已强制重置操作锁');
1159+
} catch (e) {
1160+
console.error('重置操作锁失败:', e);
1161+
}
1162+
1163+
// 延迟较长时间,确保锁已完全释放
10501164
setTimeout(() => {
1051-
// 检查当前播放列表是否有下一首
1052-
if (playList.value.length > 1) {
1053-
nextPlay();
1054-
}
1055-
}, 500);
1165+
// 直接重试当前歌曲,而不是切换到下一首
1166+
playAudio().catch(e => {
1167+
console.error('重试播放失败,切换到下一首:', e);
1168+
1169+
// 只有再次失败才切换到下一首
1170+
if (playList.value.length > 1) {
1171+
nextPlay();
1172+
}
1173+
});
1174+
}, 1000);
10561175
} else {
1057-
// 其他错误,延迟更短时间后切换
1176+
// 其他错误,切换到下一首
1177+
console.log('播放失败,切换到下一首');
10581178
setTimeout(() => {
10591179
nextPlay();
1060-
}, 100);
1180+
}, 300);
10611181
}
10621182

10631183
message.error(i18n.global.t('player.playFailed'));

0 commit comments

Comments
 (0)