fix "now playing" flicker; fix album art url

Hunter
Tuesday, November 4th, 2025 at 11:12 PM

script.js+9-117

script.js
  99  	// Update media session metadata
 100  	if ('mediaSession' in navigator) {
 101  		// Convert relative path to absolute URL for media session
     -		const albumArtUrl = new URL('resources/album_art.jpg', window.location.href).href;
 102 +		// Use document.baseURI to correctly resolve paths in subdirectories
 103 +		const albumArtUrl = new URL('resources/album_art.jpg', document.baseURI).href;
 104  		navigator.mediaSession.metadata = new MediaMetadata({
 105  			title: song.title,
 106  			artist: song.artist,

 844  			// Create a blob URL that will persist in memory
 845  			const blobUrl = URL.createObjectURL(blob);
 846  
     -			// Create audio element with the fully downloaded blob
     -			const preloadAudio = new Audio();
     -			preloadAudio.preload = 'auto';
     -			preloadAudio.src = blobUrl;
     -
     -			// Wait for the audio element to fully buffer the blob
     -			return new Promise((resolve) => {
     -				const checkBuffered = () => {
     -					// Check if the entire duration is buffered
     -					if (preloadAudio.duration > 0 && preloadAudio.buffered.length > 0) {
     -						const bufferedEnd = preloadAudio.buffered.end(preloadAudio.buffered.length - 1);
     -						if (bufferedEnd >= preloadAudio.duration - 0.1) {
     -							// Fully buffered!
     -							resolve({ preloadAudio, blobUrl, blob });
     -							return;
     -						}
     -					}
     -					// Not fully buffered yet, check again soon
     -					setTimeout(checkBuffered, 100);
     -				};
     -
     -				// Start checking once metadata is loaded
     -				preloadAudio.addEventListener('loadedmetadata', () => {
     -					checkBuffered();
     -				}, { once: true });
     -
     -				// Trigger the loading
     -				preloadAudio.load();
     -			});
     -		})
     -		.then(({ preloadAudio, blobUrl, blob }) => {
     -			// Store both the audio element and blob URL
 847  			preloadedAudio[filename] = {
     -				audio: preloadAudio,
 848  				blobUrl: blobUrl,
 849  				blob: blob
 850  			};

 935  		// Create a blob URL that will persist in memory
 936  		const blobUrl = URL.createObjectURL(blob);
 937  
     -		// Create audio element with the cached blob
     -		const preloadAudio = new Audio();
     -		preloadAudio.preload = 'auto';
     -		preloadAudio.src = blobUrl;
     -
     -		// Wait for the audio element to fully buffer the blob
     -		return new Promise((resolve) => {
     -			const checkBuffered = () => {
     -				// Check if the entire duration is buffered
     -				if (preloadAudio.duration > 0 && preloadAudio.buffered.length > 0) {
     -					const bufferedEnd = preloadAudio.buffered.end(preloadAudio.buffered.length - 1);
     -					if (bufferedEnd >= preloadAudio.duration - 0.1) {
     -						// Fully buffered!
     -						preloadedAudio[filename] = {
     -							audio: preloadAudio,
     -							blobUrl: blobUrl,
     -							blob: blob
     -						};
     -						console.log(`✓ Loaded from cache: ${filename}`);
     -						resolve();
     -						return;
     -					}
     -				}
     -				// Not fully buffered yet, check again soon
     -				setTimeout(checkBuffered, 100);
     -			};
     -
     -			// Start checking once metadata is loaded
     -			preloadAudio.addEventListener('loadedmetadata', () => {
     -				checkBuffered();
     -			}, { once: true });
     -
     -			// Trigger the loading
     -			preloadAudio.load();
     -		});
 938 +		preloadedAudio[filename] = {
 939 +			blobUrl: blobUrl,
 940 +			blob: blob
 941 +		};
 942 +		console.log(`✓ Loaded from cache: ${filename}`);
 943  	} catch (error) {
 944  		console.error(`Failed to load from cache: ${filename}`, error);
 945  		throw error;

1047  			// Create a blob URL that will persist in memory
1048  			const blobUrl = URL.createObjectURL(blob);
1049  
     -			// Create audio element with the fully downloaded blob
     -			const preloadAudio = new Audio();
     -			preloadAudio.preload = 'auto';
     -			preloadAudio.src = blobUrl;
     -
     -			// Wait for the audio element to fully buffer the blob
     -			return new Promise((resolve) => {
     -				const checkBuffered = () => {
     -					// Check if the entire duration is buffered
     -					if (preloadAudio.duration > 0 && preloadAudio.buffered.length > 0) {
     -						const bufferedEnd = preloadAudio.buffered.end(preloadAudio.buffered.length - 1);
     -						if (bufferedEnd >= preloadAudio.duration - 0.1) {
     -							// Fully buffered!
     -							resolve({ preloadAudio, blobUrl, blob });
     -							return;
     -						}
     -					}
     -					// Not fully buffered yet, check again soon
     -					setTimeout(checkBuffered, 100);
     -				};
     -
     -				// Start checking once metadata is loaded
     -				preloadAudio.addEventListener('loadedmetadata', () => {
     -					checkBuffered();
     -				}, { once: true });
     -
     -				// Trigger the loading
     -				preloadAudio.load();
     -			});
     -		})
     -		.then(({ preloadAudio, blobUrl, blob }) => {
     -			// Store both the audio element and blob URL
1050  			preloadedAudio[filename] = {
     -				audio: preloadAudio,
1051  				blobUrl: blobUrl,
1052  				blob: blob
1053  			};
1054  
     -			// Switch to the preloaded version if this is the current song
     -			if (songs[currentSongIndex].filename === filename && audio.src !== blobUrl) {
     -				const currentTime = audio.currentTime;
     -				const wasPlaying = !audio.paused;
     -				audio.src = blobUrl;
     -				audio.currentTime = currentTime;
     -				if (wasPlaying) {
     -					audio.play().catch(err => {
     -						// Ignore play interruption errors (expected during source switching)
     -						if (err.name !== 'AbortError') {
     -							console.error('Error resuming playback:', err);
     -						}
     -					});
     -				}
     -			}
1055 +			// Next time this song plays, it will use the cached version
1056 +			console.log(`✓ Priority preloaded: ${song.artist} – ${song.title}`);
1057  
1058  			// Store in Cache API for offline access
1059  			return storeBlobInCache(filename, blob).then(() => {