diff --git a/src/main.js b/src/main.js
index 30da7d6..eea0010 100644
--- a/src/main.js
+++ b/src/main.js
@@ -8,7 +8,7 @@ import {
initProgressScrub, updateProgress, updatePreviewProgress, stopPreview,
toggleRadioMode, starCurrent, downloadCurrent, renderQueue, playPreview,
toggleStar, dlSongLocal, _applyRadioBtn, _restoreLastPlayed, setPlayIcon,
- npToggleStar,
+ npToggleStar, updateMediaSession,
} from './player.js';
import {
navigate, _navGoBack, _navLoad, loadHomeData, onLocalSearch, onMobileSearch,
@@ -106,8 +106,46 @@ window.addEventListener('load', () => {
});
S.previewAudio.addEventListener('timeupdate', updatePreviewProgress);
S.previewAudio.addEventListener('ended', stopPreview);
+
+ // Recovery: try to resume if audio stalls (network hiccup, background throttle)
+ S.audio.addEventListener('stalled', () => { if(!S.audio.paused) S.audio.load(); });
+ S.audio.addEventListener('waiting', () => { /* let browser handle buffering */ });
+ S.audio.addEventListener('error', () => {
+ if(!S.audio.paused && S.queue[S.qIdx]) {
+ const t = setTimeout(() => { S.audio.load(); S.audio.play().catch(()=>{}); }, 2000);
+ S.audio.addEventListener('play', () => clearTimeout(t), { once: true });
+ }
+ });
+
S.audio.volume = 0.8;
+ // Re-register MediaSession handlers when returning from background/screen-off/flip
+ document.addEventListener('visibilitychange', () => {
+ if(document.visibilityState !== 'visible') return;
+ const s = S.queue[S.qIdx];
+ if(!s) return;
+ updateMediaSession(s);
+ if(navigator.mediaSession)
+ navigator.mediaSession.playbackState = S.audio.paused ? 'paused' : 'playing';
+ });
+
+ // Watchdog: detect when audio silently stalled in background (ended event not fired, or frozen)
+ let _wdLast = 0, _wdStalledAt = 0;
+ setInterval(() => {
+ if(!S.audio.src || S.audio.paused) { _wdStalledAt = 0; _wdLast = 0; return; }
+ const dur = S.audio.duration;
+ const cur = S.audio.currentTime;
+ // ended but event didn't fire (background throttling)
+ if(dur > 0 && cur >= dur - 0.5) { onEnded(); _wdStalledAt = 0; _wdLast = 0; return; }
+ if(cur !== _wdLast) { _wdStalledAt = 0; _wdLast = cur; return; }
+ if(!_wdStalledAt) { _wdStalledAt = Date.now(); return; }
+ // frozen for >8s → try to resume
+ if(Date.now() - _wdStalledAt > 8000) {
+ _wdStalledAt = 0;
+ S.audio.play().catch(() => {});
+ }
+ }, 3000);
+
injectPWA();
initProgressScrub();
diff --git a/src/player.js b/src/player.js
index b71d4f5..d522f34 100644
--- a/src/player.js
+++ b/src/player.js
@@ -353,5 +353,9 @@ export function _restoreLastPlayed() {
art.innerHTML = cv ? `` : '