don't use cache on localhost; improve offline reliability

Hunter
Tuesday, April 7th, 2026 at 1:04 AM

build.py+6-6
resources/script.js+15 

build.py
103  	return f"{app_name}-v1"
104  
105  
    -def generate_pwa_manifests(app_name=None, base_path=None):
    -	"""Generate PWA manifest files based on tracks.json
106 +def build_pwa(app_name=None, base_path=None):
107 +	"""Generate manifest.json and service-worker.js based on tracks.json
108  
109  	Args:
110  		app_name: Name of the app. If None, will be prompted via get_configuration()

119  	cache_name = _next_cache_name(app_name, SCRIPT_DIR / "manifest.json")
120  	app_description = f"{app_name}"
121  
    -	print("Generating PWA manifests...")
122 +	print("Building PWA files...")
123  	print(f"  Cache name: {cache_name}")
124  
125  	# Load tracks.json

309  		f.write(service_worker_content)
310  	print("✓ Generated service-worker.js")
311  	print()
    -	print("PWA manifests generated successfully!")
312 +	print("PWA build complete!")
313  
314  
315  if __name__ == "__main__":
    -	# When run directly, get configuration and generate manifests
316 +	# When run directly, get configuration and build PWA files
317  	app_name, base_path = get_configuration()
    -	generate_pwa_manifests(app_name, base_path)
318 +	build_pwa(app_name, base_path)
resources/script.js
  9  				console.log('Service Worker registration failed:', error);
 10  			});
 11  	});
 12 +} else if ('serviceWorker' in navigator && (location.hostname === 'localhost' || location.hostname === '127.0.0.1')) {
 13 +	// On localhost, unregister any existing service worker and clear caches
 14 +	navigator.serviceWorker.getRegistrations().then(registrations => {
 15 +		registrations.forEach(r => r.unregister());
 16 +	});
 17 +	caches.keys().then(keys => {
 18 +		keys.forEach(k => caches.delete(k));
 19 +	});
 20  }
 21  
 22  const playPauseBtn = document.getElementById('playPause');

 92  		if (!response.ok) return null;
 93  		return response.json();
 94  	})
 95 +	.catch(() => null)
 96  	.then(manifest => {
 97  		if (manifest) {
 98  			CACHE_NAME = manifest.cache_name || manifest.name || CACHE_NAME;

116  					if (!r.ok) throw new Error('tracks.json not found');
117  					return r.json();
118  				})
119 +				.catch(() => {
120 +					// Offline fallback: try loading from cache directly
121 +					return caches.open(CACHE_NAME)
122 +						.then(cache => cache.match('mix/tracks.json'))
123 +						.then(r => r ? r.json() : Promise.reject('tracks.json not in cache'));
124 +				})
125  		]);
126  	})
127  	.then((results) => {