mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-28 10:57:23 +08:00
feat: 优化音乐播放逻辑
This commit is contained in:
@@ -78,12 +78,8 @@ const setupKeyboardListeners = () => {
|
|||||||
const store = getPlayerStore();
|
const store = getPlayerStore();
|
||||||
switch (e.code) {
|
switch (e.code) {
|
||||||
case 'Space':
|
case 'Space':
|
||||||
if (store.play) {
|
if (store.playMusic?.id) {
|
||||||
store.setPlayMusic(false);
|
void store.setPlay({ ...store.playMusic });
|
||||||
audioService.getCurrentSound()?.pause();
|
|
||||||
} else {
|
|
||||||
store.setPlayMusic(true);
|
|
||||||
audioService.getCurrentSound()?.play();
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -97,6 +93,7 @@ const { message } = createDiscreteApi(['message']);
|
|||||||
let progressAnimationInitialized = false;
|
let progressAnimationInitialized = false;
|
||||||
let globalAnimationFrameId: number | null = null;
|
let globalAnimationFrameId: number | null = null;
|
||||||
const lastSavedTime = ref(0);
|
const lastSavedTime = ref(0);
|
||||||
|
let audioListenersInitialized = false;
|
||||||
|
|
||||||
// 全局停止函数
|
// 全局停止函数
|
||||||
const stopProgressAnimation = () => {
|
const stopProgressAnimation = () => {
|
||||||
@@ -396,6 +393,12 @@ const setupMusicWatchers = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const setupAudioListeners = () => {
|
const setupAudioListeners = () => {
|
||||||
|
// 监听器只注册一次,避免重复绑定和误清理全局恢复监听器
|
||||||
|
if (audioListenersInitialized) {
|
||||||
|
return () => {};
|
||||||
|
}
|
||||||
|
audioListenersInitialized = true;
|
||||||
|
|
||||||
let interval: any = null;
|
let interval: any = null;
|
||||||
// 播放状态恢复定时器:当 interval 因异常被清除时,自动恢复
|
// 播放状态恢复定时器:当 interval 因异常被清除时,自动恢复
|
||||||
let recoveryTimer: any = null;
|
let recoveryTimer: any = null;
|
||||||
@@ -486,9 +489,6 @@ const setupAudioListeners = () => {
|
|||||||
}, 500);
|
}, 500);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 清理所有事件监听器
|
|
||||||
audioService.clearAllListeners();
|
|
||||||
|
|
||||||
// 启动恢复监控
|
// 启动恢复监控
|
||||||
startRecoveryMonitor();
|
startRecoveryMonitor();
|
||||||
|
|
||||||
@@ -1010,13 +1010,8 @@ if (isElectron) {
|
|||||||
windowData.electron.ipcRenderer.on('lyric-control-back', (_, command: string) => {
|
windowData.electron.ipcRenderer.on('lyric-control-back', (_, command: string) => {
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case 'playpause':
|
case 'playpause':
|
||||||
if (getPlayerStore().play) {
|
if (getPlayerStore().playMusic?.id) {
|
||||||
getPlayerStore().setPlayMusic(false);
|
void getPlayerStore().setPlay({ ...getPlayerStore().playMusic });
|
||||||
audioService.getCurrentSound()?.pause();
|
|
||||||
} else {
|
|
||||||
getPlayerStore().setPlayMusic(true);
|
|
||||||
|
|
||||||
audioService.getCurrentSound()?.play();
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'prev':
|
case 'prev':
|
||||||
|
|||||||
@@ -642,6 +642,7 @@ class AudioService {
|
|||||||
|
|
||||||
newSound.on('loaderror', (_, error) => {
|
newSound.on('loaderror', (_, error) => {
|
||||||
console.error('Audio load error:', error);
|
console.error('Audio load error:', error);
|
||||||
|
this.emit('loaderror', { track, error });
|
||||||
if (retryCount < maxRetries && !existingSound) {
|
if (retryCount < maxRetries && !existingSound) {
|
||||||
// 预加载的音频通常已经 loaded,不应重试
|
// 预加载的音频通常已经 loaded,不应重试
|
||||||
retryCount++;
|
retryCount++;
|
||||||
@@ -657,6 +658,7 @@ class AudioService {
|
|||||||
|
|
||||||
newSound.on('playerror', (_, error) => {
|
newSound.on('playerror', (_, error) => {
|
||||||
console.error('Audio play error:', error);
|
console.error('Audio play error:', error);
|
||||||
|
this.emit('playerror', { track, error });
|
||||||
if (retryCount < maxRetries) {
|
if (retryCount < maxRetries) {
|
||||||
retryCount++;
|
retryCount++;
|
||||||
console.log(`Retrying playback (${retryCount}/${maxRetries})...`);
|
console.log(`Retrying playback (${retryCount}/${maxRetries})...`);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ pinia.use(({ store }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 导出所有 store
|
// 导出所有 store
|
||||||
|
export * from './modules/favorite';
|
||||||
export * from './modules/intelligenceMode';
|
export * from './modules/intelligenceMode';
|
||||||
export * from './modules/localMusic';
|
export * from './modules/localMusic';
|
||||||
export * from './modules/lyric';
|
export * from './modules/lyric';
|
||||||
@@ -22,6 +23,7 @@ export * from './modules/menu';
|
|||||||
export * from './modules/music';
|
export * from './modules/music';
|
||||||
export * from './modules/player';
|
export * from './modules/player';
|
||||||
export * from './modules/playerCore';
|
export * from './modules/playerCore';
|
||||||
|
export * from './modules/playHistory';
|
||||||
export * from './modules/playlist';
|
export * from './modules/playlist';
|
||||||
export * from './modules/recommend';
|
export * from './modules/recommend';
|
||||||
export * from './modules/search';
|
export * from './modules/search';
|
||||||
|
|||||||
@@ -405,6 +405,12 @@ export const usePlaylistStore = defineStore(
|
|||||||
const nowPlayListIndex = (playListIndex.value + 1) % playList.value.length;
|
const nowPlayListIndex = (playListIndex.value + 1) % playList.value.length;
|
||||||
const nextSong = { ...playList.value[nowPlayListIndex] };
|
const nextSong = { ...playList.value[nowPlayListIndex] };
|
||||||
|
|
||||||
|
// 同一首歌重试时强制刷新在线 URL,避免卡在失效链接上
|
||||||
|
if (singleTrackRetryCount > 0 && !nextSong.playMusicUrl?.startsWith('local://')) {
|
||||||
|
nextSong.playMusicUrl = undefined;
|
||||||
|
nextSong.expiredAt = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`[nextPlay] 尝试播放: ${nextSong.name}, 索引: ${currentIndex} -> ${nowPlayListIndex}, 单曲重试: ${singleTrackRetryCount}/${SINGLE_TRACK_MAX_RETRIES}, 连续失败: ${consecutiveFailCount.value}/${MAX_CONSECUTIVE_FAILS}`
|
`[nextPlay] 尝试播放: ${nextSong.name}, 索引: ${currentIndex} -> ${nowPlayListIndex}, 单曲重试: ${singleTrackRetryCount}/${SINGLE_TRACK_MAX_RETRIES}, 连续失败: ${consecutiveFailCount.value}/${MAX_CONSECUTIVE_FAILS}`
|
||||||
);
|
);
|
||||||
@@ -591,6 +597,20 @@ export const usePlaylistStore = defineStore(
|
|||||||
sound.play();
|
sound.play();
|
||||||
// 在恢复播放时也进行状态检测,防止URL已过期导致无声
|
// 在恢复播放时也进行状态检测,防止URL已过期导致无声
|
||||||
playerCore.checkPlaybackState(playerCore.playMusic);
|
playerCore.checkPlaybackState(playerCore.playMusic);
|
||||||
|
} else {
|
||||||
|
console.warn('[PlaylistStore.setPlay] 无可用音频实例,尝试重建播放链路');
|
||||||
|
const recoverSong = {
|
||||||
|
...playerCore.playMusic,
|
||||||
|
isFirstPlay: true,
|
||||||
|
playMusicUrl: playerCore.playMusic.playMusicUrl?.startsWith('local://')
|
||||||
|
? playerCore.playMusic.playMusicUrl
|
||||||
|
: undefined
|
||||||
|
};
|
||||||
|
const recovered = await playerCore.handlePlayMusic(recoverSong, true);
|
||||||
|
if (!recovered) {
|
||||||
|
playerCore.setIsPlay(false);
|
||||||
|
message.error(i18n.global.t('player.playFailed'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { onMounted, onUnmounted } from 'vue';
|
import { onMounted, onUnmounted } from 'vue';
|
||||||
|
|
||||||
import i18n from '@/../i18n/renderer';
|
import i18n from '@/../i18n/renderer';
|
||||||
import { audioService } from '@/services/audioService';
|
|
||||||
import { usePlayerStore, useSettingsStore } from '@/store';
|
import { usePlayerStore, useSettingsStore } from '@/store';
|
||||||
|
|
||||||
import { isElectron } from '.';
|
import { isElectron } from '.';
|
||||||
@@ -80,11 +79,13 @@ export async function handleShortcutAction(action: string) {
|
|||||||
switch (action) {
|
switch (action) {
|
||||||
case 'togglePlay':
|
case 'togglePlay':
|
||||||
if (playerStore.play) {
|
if (playerStore.play) {
|
||||||
await audioService.pause();
|
await playerStore.handlePause();
|
||||||
showToast(t('player.playBar.pause'), 'ri-pause-circle-line');
|
showToast(t('player.playBar.pause'), 'ri-pause-circle-line');
|
||||||
} else {
|
} else {
|
||||||
await audioService.getCurrentSound()?.play();
|
if (playerStore.playMusic?.id) {
|
||||||
showToast(t('player.playBar.play'), 'ri-play-circle-line');
|
await playerStore.setPlay({ ...playerStore.playMusic });
|
||||||
|
showToast(t('player.playBar.play'), 'ri-play-circle-line');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'prevPlay':
|
case 'prevPlay':
|
||||||
|
|||||||
Reference in New Issue
Block a user