diff --git a/src/main.js b/src/main.js index 44ca135..81a1efd 100644 --- a/src/main.js +++ b/src/main.js @@ -152,7 +152,12 @@ window.addEventListener('load', () => { _errRetries++; const delay = Math.min(1000 * Math.pow(2, _errRetries - 1), 8000); // 1s, 2s, 4s, 8s clearTimeout(_errTimer); - _errTimer = setTimeout(() => { S.audio.load(); S.audio.play().catch(() => {}); }, delay); + _errTimer = setTimeout(() => { + if(!S.queue[S.qIdx]) return; + S._trackChanging = true; // prevent load()'s pause event from dismissing Samsung notification + S.audio.load(); + S.audio.play().catch(() => { S._trackChanging = false; }); + }, delay); }); S.audio.volume = 0.5; diff --git a/src/player.js b/src/player.js index d483603..d7aef7d 100644 --- a/src/player.js +++ b/src/player.js @@ -52,6 +52,8 @@ export function playCurrent() { if(S.qIdx < 0 || S.qIdx >= S.queue.length) return; const s = S.queue[S.qIdx]; S._trackChanging = true; + // Explicitly keep Samsung notification alive — set playing BEFORE metadata swap + if(navigator.mediaSession) navigator.mediaSession.playbackState = 'playing'; updatePlayerUI(s); // update metadata/notification BEFORE src change onNpSongChange(s.id); renderQueue(); @@ -59,7 +61,20 @@ export function playCurrent() { const src = (_preId === s.id && _preUrl) ? _preUrl : streamUrl(s.id); _clearPreload(); S.audio.src = src; - S.audio.play().catch(() => { S._trackChanging = false; }); + const _tryPlay = (attempt) => { + S.audio.play().catch(err => { + S._trackChanging = false; + if (err?.name === 'AbortError') return; // src changed mid-flight, stop + if (attempt < 4 && S.queue[S.qIdx]?.id === s.id) { + setTimeout(() => { + if (S.queue[S.qIdx]?.id !== s.id) return; + S._trackChanging = true; + _tryPlay(attempt + 1); + }, Math.min(500 * Math.pow(2, attempt), 8000)); // 500ms, 1s, 2s, 4s, 8s + } + }); + }; + _tryPlay(0); } export function updatePlayerUI(s) {