@@ -527,8 +527,11 @@ export const usePlayerStore = defineStore('player', () => {
527
527
musicFull . value = value ;
528
528
} ;
529
529
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
+ }
532
535
playList . value = list ;
533
536
localStorage . setItem ( 'playList' , JSON . stringify ( list ) ) ;
534
537
localStorage . setItem ( 'playListIndex' , playListIndex . value . toString ( ) ) ;
@@ -714,7 +717,7 @@ export const usePlayerStore = defineStore('player', () => {
714
717
}
715
718
} ;
716
719
717
- // 修改nextPlay方法,加入定时关闭检查逻辑
720
+ // 修改nextPlay方法,改进播放失败的处理逻辑
718
721
const nextPlay = async ( ) => {
719
722
// 静态标志,防止多次调用造成递归
720
723
if ( ( nextPlay as any ) . isRunning ) {
@@ -744,59 +747,122 @@ export const usePlayerStore = defineStore('player', () => {
744
747
const shouldPlayNext = play . value ;
745
748
console . log ( '切换到下一首,当前播放状态:' , shouldPlayNext ? '播放' : '暂停' ) ;
746
749
750
+ // 保存当前索引,用于错误恢复
751
+ const currentIndex = playListIndex . value ;
747
752
let nowPlayListIndex : number ;
748
753
749
754
if ( playMode . value === 2 ) {
755
+ // 随机播放模式
750
756
do {
751
757
nowPlayListIndex = Math . floor ( Math . random ( ) * playList . value . length ) ;
752
758
} while ( nowPlayListIndex === playListIndex . value && playList . value . length > 1 ) ;
753
759
} else {
760
+ // 顺序播放或循环播放模式
754
761
nowPlayListIndex = ( playListIndex . value + 1 ) % playList . value . length ;
755
762
}
756
763
757
- // 重要:首先更新当前播放索引
764
+ // 记录尝试播放过的索引,防止无限循环
765
+ const attemptedIndices = new Set < number > ( ) ;
766
+ attemptedIndices . add ( nowPlayListIndex ) ;
767
+
768
+ // 更新当前播放索引
758
769
playListIndex . value = nowPlayListIndex ;
759
770
760
771
// 获取下一首歌曲
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
+ }
769
785
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 ) ;
778
788
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
+ }
788
845
}
789
846
}
790
847
791
848
// 歌曲切换成功,触发歌曲变更处理(用于定时关闭功能)
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
+ }
793
858
} catch ( error ) {
794
859
console . error ( '切换下一首出错:' , error ) ;
795
860
} finally {
796
861
( nextPlay as any ) . isRunning = false ;
797
862
}
798
863
} ;
799
864
865
+ // 修改 prevPlay 方法,使用与 nextPlay 相似的逻辑改进
800
866
const prevPlay = async ( ) => {
801
867
// 静态标志,防止多次调用造成递归
802
868
if ( ( prevPlay as any ) . isRunning ) {
@@ -813,6 +879,8 @@ export const usePlayerStore = defineStore('player', () => {
813
879
return ;
814
880
}
815
881
882
+ // 保存当前索引,用于错误恢复
883
+ const currentIndex = playListIndex . value ;
816
884
const nowPlayListIndex =
817
885
( playListIndex . value - 1 + playList . value . length ) % playList . value . length ;
818
886
@@ -821,6 +889,9 @@ export const usePlayerStore = defineStore('player', () => {
821
889
822
890
// 获取上一首歌曲
823
891
const prevSong = playList . value [ nowPlayListIndex ] ;
892
+ let success = false ;
893
+ let retryCount = 0 ;
894
+ const maxRetries = 2 ;
824
895
825
896
// 如果是B站视频,确保重新获取URL
826
897
if ( prevSong . source === 'bilibili' && prevSong . bilibiliData ) {
@@ -829,27 +900,59 @@ export const usePlayerStore = defineStore('player', () => {
829
900
console . log ( '上一首是B站视频,已清除URL强制重新获取' ) ;
830
901
}
831
902
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
+ }
834
947
835
948
if ( success ) {
836
949
await fetchSongs ( playList . value , playListIndex . value - 3 , nowPlayListIndex ) ;
837
950
} 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' ) ) ;
853
956
}
854
957
} catch ( error ) {
855
958
console . error ( '切换上一首出错:' , error ) ;
@@ -981,7 +1084,7 @@ export const usePlayerStore = defineStore('player', () => {
981
1084
localStorage . setItem ( 'favoriteList' , JSON . stringify ( favoriteList . value ) ) ;
982
1085
} ;
983
1086
984
- // 修改:处理音频播放的方法,使用事件触发机制
1087
+ // 修改 playAudio 函数中的错误处理逻辑,避免在操作锁问题时频繁尝试播放
985
1088
const playAudio = async ( ) => {
986
1089
if ( ! playMusicUrl . value || ! playMusic . value ) return null ;
987
1090
@@ -1041,23 +1144,40 @@ export const usePlayerStore = defineStore('player', () => {
1041
1144
console . error ( '播放音频失败:' , error ) ;
1042
1145
setPlayMusic ( false ) ;
1043
1146
1044
- // 避免直接调用 nextPlay,改用延时避免无限循环
1045
1147
// 检查错误是否是由于操作锁引起的
1046
1148
const errorMsg = error instanceof Error ? error . message : String ( error ) ;
1149
+
1150
+ // 操作锁错误处理
1047
1151
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
+ // 延迟较长时间,确保锁已完全释放
1050
1164
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 ) ;
1056
1175
} else {
1057
- // 其他错误,延迟更短时间后切换
1176
+ // 其他错误,切换到下一首
1177
+ console . log ( '播放失败,切换到下一首' ) ;
1058
1178
setTimeout ( ( ) => {
1059
1179
nextPlay ( ) ;
1060
- } , 100 ) ;
1180
+ } , 300 ) ;
1061
1181
}
1062
1182
1063
1183
message . error ( i18n . global . t ( 'player.playFailed' ) ) ;
0 commit comments