diff --git a/src/renderer/services/audioService.ts b/src/renderer/services/audioService.ts index 917d5c7..9a76c6f 100644 --- a/src/renderer/services/audioService.ts +++ b/src/renderer/services/audioService.ts @@ -41,6 +41,9 @@ class AudioService { private seekDebounceTimer: NodeJS.Timeout | null = null; + // 添加操作锁防止并发操作 + private operationLock = false; + constructor() { if ('mediaSession' in navigator) { this.initMediaSession(); @@ -358,6 +361,14 @@ class AudioService { // 播放控制相关 play(url?: string, track?: SongResult, isPlay: boolean = true): Promise { + // 如果操作锁已激活,说明有操作正在进行中,直接返回 + if (this.operationLock) { + console.log('audioService: 操作锁激活,忽略当前播放请求'); + return Promise.reject(new Error('操作锁激活,请等待当前操作完成')); + } + + this.operationLock = true; + // 如果没有提供新的 URL 和 track,且当前有音频实例,则继续播放 if (this.currentSound && !url && !track) { // 如果有进行中的seek操作,等待其完成 @@ -366,15 +377,17 @@ class AudioService { this.seekLock = false; } this.currentSound.play(); + this.operationLock = false; return Promise.resolve(this.currentSound); } // 如果没有提供必要的参数,返回错误 if (!url || !track) { + this.operationLock = false; return Promise.reject(new Error('Missing required parameters: url and track')); } - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { let retryCount = 0; const maxRetries = 1; @@ -507,11 +520,15 @@ class AudioService { } } catch (error) { console.error('Error creating audio instance:', error); + this.operationLock = false; reject(error); } }; tryPlay(); + }).finally(() => { + // 无论成功或失败都解除操作锁 + this.operationLock = false; }); } @@ -524,6 +541,13 @@ class AudioService { } stop() { + if (this.operationLock) { + console.log('audioService: 操作锁激活,忽略当前停止请求'); + return; + } + + this.operationLock = true; + if (this.currentSound) { try { // 确保任何进行中的seek操作被取消 @@ -538,11 +562,14 @@ class AudioService { } this.currentSound = null; } + this.currentTrack = null; if ('mediaSession' in navigator) { navigator.mediaSession.playbackState = 'none'; } this.disposeEQ(); + + this.operationLock = false; } setVolume(volume: number) { @@ -553,6 +580,13 @@ class AudioService { } seek(time: number) { + if (this.operationLock) { + console.log('audioService: 操作锁激活,忽略当前seek请求'); + return; + } + + this.operationLock = true; + if (this.currentSound) { try { // 直接执行seek操作,避免任何过滤或判断 @@ -564,9 +598,18 @@ class AudioService { console.error('Seek操作失败:', error); } } + + this.operationLock = false; } pause() { + if (this.operationLock) { + console.log('audioService: 操作锁激活,忽略当前暂停请求'); + return; + } + + this.operationLock = true; + if (this.currentSound) { try { // 如果有进行中的seek操作,等待其完成 @@ -579,6 +622,8 @@ class AudioService { console.error('Error pausing audio:', error); } } + + this.operationLock = false; } clearAllListeners() { diff --git a/src/renderer/utils/appShortcuts.ts b/src/renderer/utils/appShortcuts.ts index 112ddc6..b73fdaa 100644 --- a/src/renderer/utils/appShortcuts.ts +++ b/src/renderer/utils/appShortcuts.ts @@ -7,6 +7,10 @@ import { usePlayerStore, useSettingsStore } from '@/store'; import { isElectron } from '.'; import { showShortcutToast } from './shortcutToast'; +// 添加一个简单的防抖机制 +let actionTimeout: NodeJS.Timeout | null = null; +const ACTION_DELAY = 300; // 毫秒 + interface ShortcutConfig { key: string; enabled: boolean; @@ -27,6 +31,17 @@ let appShortcuts: ShortcutsConfig = {}; * @param action 快捷键动作 */ export async function handleShortcutAction(action: string) { + // 如果存在未完成的动作,则忽略当前请求 + if (actionTimeout) { + console.log('忽略快速连续的动作请求:', action); + return; + } + + // 设置防抖锁 + actionTimeout = setTimeout(() => { + actionTimeout = null; + }, ACTION_DELAY); + const playerStore = usePlayerStore(); const settingsStore = useSettingsStore(); @@ -38,61 +53,71 @@ export async function handleShortcutAction(action: string) { showShortcutToast(message, iconName); }; - switch (action) { - case 'togglePlay': - if (playerStore.play) { - await audioService.pause(); - showToast(t('player.playBar.pause'), 'ri-pause-circle-line'); - } else { - await audioService.play(); - showToast(t('player.playBar.play'), 'ri-play-circle-line'); - } - break; - case 'prevPlay': - playerStore.prevPlay(); - showToast(t('player.playBar.prev'), 'ri-skip-back-line'); - break; - case 'nextPlay': - playerStore.nextPlay(); - showToast(t('player.playBar.next'), 'ri-skip-forward-line'); - break; - case 'volumeUp': - if (currentSound && currentSound?.volume() < 1) { - currentSound?.volume((currentSound?.volume() || 0) + 0.1); + try { + switch (action) { + case 'togglePlay': + if (playerStore.play) { + await audioService.pause(); + showToast(t('player.playBar.pause'), 'ri-pause-circle-line'); + } else { + await audioService.play(); + showToast(t('player.playBar.play'), 'ri-play-circle-line'); + } + break; + case 'prevPlay': + await playerStore.prevPlay(); + showToast(t('player.playBar.prev'), 'ri-skip-back-line'); + break; + case 'nextPlay': + await playerStore.nextPlay(); + showToast(t('player.playBar.next'), 'ri-skip-forward-line'); + break; + case 'volumeUp': + if (currentSound && currentSound?.volume() < 1) { + currentSound?.volume((currentSound?.volume() || 0) + 0.1); + showToast( + `${t('player.playBar.volume')}${Math.round((currentSound?.volume() || 0) * 100)}%`, + 'ri-volume-up-line' + ); + } + break; + case 'volumeDown': + if (currentSound && currentSound?.volume() > 0) { + currentSound?.volume((currentSound?.volume() || 0) - 0.1); + showToast( + `${t('player.playBar.volume')}${Math.round((currentSound?.volume() || 0) * 100)}%`, + 'ri-volume-down-line' + ); + } + break; + case 'toggleFavorite': { + const isFavorite = playerStore.favoriteList.includes(Number(playerStore.playMusic.id)); + const numericId = Number(playerStore.playMusic.id); + if (isFavorite) { + playerStore.removeFromFavorite(numericId); + } else { + playerStore.addToFavorite(numericId); + } showToast( - `${t('player.playBar.volume')}${Math.round((currentSound?.volume() || 0) * 100)}%`, - 'ri-volume-up-line' + isFavorite + ? t('player.playBar.favorite', { name: playerStore.playMusic.name }) + : t('player.playBar.unFavorite', { name: playerStore.playMusic.name }), + isFavorite ? 'ri-heart-fill' : 'ri-heart-line' ); + break; } - break; - case 'volumeDown': - if (currentSound && currentSound?.volume() > 0) { - currentSound?.volume((currentSound?.volume() || 0) - 0.1); - showToast( - `${t('player.playBar.volume')}${Math.round((currentSound?.volume() || 0) * 100)}%`, - 'ri-volume-down-line' - ); - } - break; - case 'toggleFavorite': { - const isFavorite = playerStore.favoriteList.includes(Number(playerStore.playMusic.id)); - const numericId = Number(playerStore.playMusic.id); - if (isFavorite) { - playerStore.removeFromFavorite(numericId); - } else { - playerStore.addToFavorite(numericId); - } - showToast( - isFavorite - ? t('player.playBar.favorite', { name: playerStore.playMusic.name }) - : t('player.playBar.unFavorite', { name: playerStore.playMusic.name }), - isFavorite ? 'ri-heart-fill' : 'ri-heart-line' - ); - break; + default: + console.log('未知的快捷键动作:', action); + break; + } + } catch (error) { + console.error(`执行快捷键动作 ${action} 时出错:`, error); + } finally { + // 确保在出错时也能清除超时 + if (actionTimeout) { + clearTimeout(actionTimeout); + actionTimeout = null; } - default: - console.log('未知的快捷键动作:', action); - break; } }