mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-07-12 05:07:31 +08:00
fix(player): 修复快速切歌卡死、随机模式洗牌、定时睡眠重启失效
- audioService: 切歌时清除上一首遗留的 canplay/error 监听器,避免过期回调 stop 掉正在播放的新歌导致静音卡死 - playlist: setPlayList 新增 preserveOrder,就地编辑(下一首播放/移除单曲)时随机模式下不再重新洗牌,并同步 originalPlayList - sleepTimer: store 初始化时重建定时器 interval,修复重启后定时关闭到点不停 - preloadService: 清理 3s 验证超时定时器、validatedUrls 加容量上限、预加载调用处补 catch
This commit is contained in:
@@ -19,6 +19,11 @@ class AudioService {
|
||||
private operationLock = false;
|
||||
private operationLockTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
// 当前一次加载(play)挂载在共享 audio 元素上的 canplay/error 监听器的清理函数。
|
||||
// 快速切歌时,上一首尚未结算的监听器必须在新一轮加载或 stop() 时移除,
|
||||
// 否则新歌 canplay 会同时触发旧歌的回调,导致"过期回调 stop 掉正在播放的新歌"卡死。
|
||||
private pendingLoadCleanup: (() => void) | null = null;
|
||||
|
||||
private readonly frequencies = [31, 62, 125, 250, 500, 1000, 2000, 4000, 8000, 16000];
|
||||
|
||||
private defaultEQSettings: { [key: string]: number } = {
|
||||
@@ -434,6 +439,12 @@ class AudioService {
|
||||
return Promise.resolve(this.audio);
|
||||
}
|
||||
|
||||
// 开始新一轮加载前,先移除上一轮尚未结算的加载监听器,避免污染新歌
|
||||
if (this.pendingLoadCleanup) {
|
||||
this.pendingLoadCleanup();
|
||||
this.pendingLoadCleanup = null;
|
||||
}
|
||||
|
||||
return new Promise<HTMLAudioElement>((resolve, reject) => {
|
||||
let retryCount = 0;
|
||||
const maxRetries = 1;
|
||||
@@ -502,8 +513,14 @@ class AudioService {
|
||||
const cleanup = () => {
|
||||
this.audio.removeEventListener('canplay', onCanPlay);
|
||||
this.audio.removeEventListener('error', onError);
|
||||
if (this.pendingLoadCleanup === cleanup) {
|
||||
this.pendingLoadCleanup = null;
|
||||
}
|
||||
};
|
||||
|
||||
// 记录本轮清理函数,供下一次 play()/stop() 在结算前主动移除
|
||||
this.pendingLoadCleanup = cleanup;
|
||||
|
||||
this.audio.addEventListener('canplay', onCanPlay, { once: true });
|
||||
this.audio.addEventListener('error', onError, { once: true });
|
||||
|
||||
@@ -529,6 +546,11 @@ class AudioService {
|
||||
|
||||
public stop() {
|
||||
this.forceResetOperationLock();
|
||||
// 移除尚未结算的加载监听器,避免 stop 后旧的 canplay/error 仍触发过期回调
|
||||
if (this.pendingLoadCleanup) {
|
||||
this.pendingLoadCleanup();
|
||||
this.pendingLoadCleanup = null;
|
||||
}
|
||||
try {
|
||||
this.audio.pause();
|
||||
this.audio.removeAttribute('src');
|
||||
|
||||
Reference in New Issue
Block a user