From 60d53cf87b3dae057b3d69720ffdc61011afc4d4 Mon Sep 17 00:00:00 2001 From: Julien Maille Date: Thu, 29 Jan 2026 22:07:20 +0100 Subject: [PATCH] Implement quality fallback on playback error (fix for Firefox blob/DASH issues) --- js/events.js | 46 +++++++++++++++++++++++++++++++++++++++++++++- js/player.js | 1 + 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/js/events.js b/js/events.js index b798e4a..a82166a 100644 --- a/js/events.js +++ b/js/events.js @@ -113,10 +113,54 @@ export function initializePlayerEvents(player, audioPlayer, scrobbler, ui) { player.updateMediaSessionPositionState(); }); - audioPlayer.addEventListener('error', (e) => { + audioPlayer.addEventListener('error', async (e) => { console.error('Audio playback error:', e); playPauseBtn.innerHTML = SVG_PLAY; + const currentQuality = player.quality; + + // Check if we can fallback to a lower quality + if ( + player.currentTrack && + currentQuality === 'HI_RES_LOSSLESS' && + !player.currentTrack.isLocal && + !player.currentTrack.isTracker && + !player.isFallbackRetry + ) { + console.warn('Playback failed, attempting fallback to LOSSLESS quality...'); + player.isFallbackRetry = true; // Set flag to prevent infinite loops + + try { + // Force getTrack to fetch new URL for LOSSLESS + const trackId = player.currentTrack.id; + + // Fetch new stream URL + const newStreamUrl = await player.api.getStreamUrl(trackId, 'LOSSLESS'); + + if (newStreamUrl) { + // Reset player state for standard playback (non-DASH if possible) + if (player.dashInitialized) { + player.dashPlayer.reset(); + player.dashInitialized = false; + } + + audioPlayer.src = newStreamUrl; + audioPlayer.load(); + await audioPlayer.play(); + + // Reset flag after successful start + setTimeout(() => { + player.isFallbackRetry = false; + }, 5000); + return; // Successfully handled + } + } catch (fallbackError) { + console.error('Fallback failed:', fallbackError); + } + } + + player.isFallbackRetry = false; + // Skip to next track on error to prevent queue stalling if (player.currentTrack) { console.warn('Skipping to next track due to playback error'); diff --git a/js/player.js b/js/player.js index 37806c9..5c42441 100644 --- a/js/player.js +++ b/js/player.js @@ -26,6 +26,7 @@ export class Player { this.currentTrack = null; this.currentRgValues = null; this.userVolume = parseFloat(localStorage.getItem('volume') || '0.7'); + this.isFallbackRetry = false; // Sleep timer properties this.sleepTimer = null;