diff --git a/components/player/hooks/useHLSPreloader.ts b/components/player/hooks/useHLSPreloader.ts index c698e18..3493652 100644 --- a/components/player/hooks/useHLSPreloader.ts +++ b/components/player/hooks/useHLSPreloader.ts @@ -34,7 +34,13 @@ export function useHLSPreloader({ src, currentTime }: UseHLSPreloaderProps) { const totalDuration = segments[segments.length - 1]?.startTime + segments[segments.length - 1]?.duration || 0; console.log(`[Preloader] Parsed ${segments.length} segments. Total duration: ${totalDuration.toFixed(2)}s`); } catch (error) { - console.error('[Preloader] Error fetching manifest:', error); + // Use warn for expected network errors, error for unexpected issues + const errorMessage = error instanceof Error ? error.message : String(error); + if (errorMessage.includes('503') || errorMessage.includes('Network unavailable')) { + console.warn('[Preloader] Network unavailable, skipping preload:', errorMessage); + } else { + console.error('[Preloader] Error fetching manifest:', error); + } } }; diff --git a/lib/utils/hlsManifestParser.ts b/lib/utils/hlsManifestParser.ts index c0dfe39..d0c77fb 100644 --- a/lib/utils/hlsManifestParser.ts +++ b/lib/utils/hlsManifestParser.ts @@ -12,7 +12,10 @@ export interface Segment { export async function parseHLSManifest(src: string): Promise { const response = await fetch(src); if (!response.ok) { - throw new Error(`Failed to fetch manifest: ${response.status}`); + const errorMsg = response.status === 503 + ? `Network unavailable (Service Worker offline): ${src}` + : `Failed to fetch manifest (${response.status}): ${src}`; + throw new Error(errorMsg); } const manifestText = await response.text(); diff --git a/public/sw.js b/public/sw.js index 6f94d24..43a0c43 100644 --- a/public/sw.js +++ b/public/sw.js @@ -35,18 +35,25 @@ self.addEventListener('fetch', (event) => { const fetchPromise = fetch(event.request).then((networkResponse) => { // Check if network response is valid if (!networkResponse || networkResponse.status !== 200) { + // Return the response as-is so client can see the error status + if (networkResponse) return networkResponse; + // If no response at all, throw to trigger catch block throw new Error('Network response was not ok'); } cache.put(event.request, networkResponse.clone()); return networkResponse; }).catch((err) => { + console.error('[SW] Fetch failed for manifest:', err); // If network fails, return cached response if available if (cachedResponse) { return cachedResponse; } - // If no cache and network fails, throw error so browser handles it - // This allows the client (VideoPlayer) to catch the error and retry with proxy - throw err; + // If no cache, return a proper error Response instead of throwing + // This prevents "Load failed" and lets the client handle it + return new Response('Network error', { + status: 503, + statusText: 'Service Worker: Network Unavailable' + }); }); // Return cache immediately if available, otherwise wait for network @@ -78,8 +85,12 @@ self.addEventListener('fetch', (event) => { return response; }).catch((error) => { console.error('[SW] Failed to fetch segment:', error); - // Throw error to let browser handle it - throw error; + // Return a proper error Response instead of throwing + // This prevents "Load failed" and lets the client handle it + return new Response('Network error', { + status: 503, + statusText: 'Service Worker: Network Unavailable' + }); }); }); })