fix: clean rewrite of audio recovery matching Kima Hub design
playCurrent(): - Remove canplay listener from before play() — it caused a race where both the listener and the initial play() fired simultaneously - canplay is now only registered in the catch (failure path only), eliminating the double-play race entirely - AbortError: reload src+load() with _trackChanging=true (OS interruption recovery); canplay fires once buffered and retries play() - Other errors: reset _trackChanging, let canplay retry (not throttled by Android background timers unlike setTimeout) - Add 10s safety net to reset _trackChanging if Doze kills everything (matches Kima Hub's reload failsafe) main.js error handler: - Skip when _trackChanging=true (playCurrent already recovering) to prevent conflicting dual recovery attempts - _onForeground: reset _trackChanging on play() failure so the flag can't get stuck when foreground recovery also fails index.html: - Add crossorigin=anonymous: Navidrome and NovaSonic backend both send Access-Control-Allow-Origin:* so this is safe, and it enables proper cross-context HTTP caching for cover art and audio responses Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
0344dcdcb6
commit
688348545d
3 files changed
+32
-34
No files matched your search
+6
-4
@@ -148,13 +148,15 @@ window.addEventListener('load', () => {
|
||||
let _errRetries = 0, _errTimer = null;
|
||||
S.audio.addEventListener('play', () => { _errRetries = 0; clearTimeout(_errTimer); }, { capture: true });
|
||||
S.audio.addEventListener('error', () => {
|
||||
if(!S.queue[S.qIdx]) return;
|
||||
// Skip if playCurrent() is already handling recovery (_trackChanging = true means
|
||||
// we're mid-transition or waiting for canplay — don't conflict with that)
|
||||
if(!S.queue[S.qIdx] || S._trackChanging) return;
|
||||
_errRetries++;
|
||||
const delay = Math.min(1000 * Math.pow(2, _errRetries - 1), 8000); // 1s, 2s, 4s, 8s
|
||||
clearTimeout(_errTimer);
|
||||
_errTimer = setTimeout(() => {
|
||||
if(!S.queue[S.qIdx]) return;
|
||||
S._trackChanging = true; // prevent load()'s pause event from dismissing Samsung notification
|
||||
if(!S.queue[S.qIdx] || S._trackChanging) return;
|
||||
S._trackChanging = true;
|
||||
S.audio.load();
|
||||
S.audio.play().catch(() => { S._trackChanging = false; });
|
||||
}, delay);
|
||||
@@ -171,7 +173,7 @@ window.addEventListener('load', () => {
|
||||
navigator.mediaSession.playbackState = S.audio.paused ? 'paused' : 'playing';
|
||||
// If audio was playing before backgrounding but is now paused (OS kill), try to resume
|
||||
if(!S.audio.paused) return;
|
||||
if(s && S.audio.src) S.audio.play().catch(() => {});
|
||||
if(s && S.audio.src) S.audio.play().catch(() => { S._trackChanging = false; });
|
||||
}
|
||||
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
|
||||
Reference in new issue
Block a user