Mercurial
annotate mrjunejune/src/public/sw.js @ 242:543df0fe7168
[tools] Add full HLS player support
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Mon, 03 Aug 2026 13:14:41 -0700 |
| parents | 9c2eec61a152 |
| children |
| rev | line source |
|---|---|
| 209 | 1 // Service Worker for MrJuneJune PWA |
|
242
543df0fe7168
[tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents:
241
diff
changeset
|
2 const CACHE_VERSION = 'v4-hlsjs'; |
| 209 | 3 const CACHE_NAME = `mrjunejune-${CACHE_VERSION}`; |
| 4 | |
| 5 // Files to cache immediately on install | |
| 6 const STATIC_CACHE = [ | |
| 7 '/', | |
| 8 '/base.css', | |
| 9 '/public/epi_all_colors.svg', | |
| 10 '/public/fonts/Roboto-Regular.ttf', | |
| 11 '/public/fonts/Roboto-Thin.ttf', | |
| 12 '/public/fonts/more-sugar.regular.otf', | |
| 13 '/public/fonts/more-sugar.thin.otf', | |
| 14 ]; | |
| 15 | |
| 16 // Install event - cache static assets | |
| 17 self.addEventListener('install', (event) => { | |
| 18 console.log('[SW] Installing service worker...'); | |
| 19 | |
| 20 event.waitUntil( | |
| 21 caches.open(CACHE_NAME).then((cache) => { | |
| 22 console.log('[SW] Caching static assets'); | |
| 23 return cache.addAll(STATIC_CACHE); | |
| 24 }).then(() => { | |
| 25 console.log('[SW] Skip waiting'); | |
| 26 return self.skipWaiting(); | |
| 27 }) | |
| 28 ); | |
| 29 }); | |
| 30 | |
| 31 // Activate event - clean up old caches | |
| 32 self.addEventListener('activate', (event) => { | |
| 33 console.log('[SW] Activating service worker...'); | |
| 34 | |
| 35 event.waitUntil( | |
| 36 caches.keys().then((cacheNames) => { | |
| 37 return Promise.all( | |
| 38 cacheNames.map((cacheName) => { | |
| 39 if (cacheName !== CACHE_NAME) { | |
| 40 console.log('[SW] Deleting old cache:', cacheName); | |
| 41 return caches.delete(cacheName); | |
| 42 } | |
| 43 }) | |
| 44 ); | |
| 45 }).then(() => { | |
| 46 console.log('[SW] Claiming clients'); | |
| 47 return self.clients.claim(); | |
| 48 }) | |
| 49 ); | |
| 50 }); | |
| 51 | |
| 52 // Fetch event - serve from cache, fallback to network | |
| 53 self.addEventListener('fetch', (event) => { | |
| 54 const { request } = event; | |
| 55 const url = new URL(request.url); | |
| 56 | |
| 57 // Skip non-GET requests | |
| 58 if (request.method !== 'GET') { | |
| 59 return; | |
| 60 } | |
| 61 | |
| 62 // Skip chrome-extension and other non-http(s) requests | |
| 63 if (!url.protocol.startsWith('http')) { | |
| 64 return; | |
| 65 } | |
| 66 | |
| 67 // Skip API calls and media uploads (always go to network) | |
| 68 if (url.pathname.startsWith('/api/')) { | |
| 69 return; | |
| 70 } | |
| 71 | |
|
242
543df0fe7168
[tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents:
241
diff
changeset
|
72 // The HLS tool and media must always reflect the current player version. |
|
543df0fe7168
[tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents:
241
diff
changeset
|
73 if (url.pathname.startsWith('/tools/hls_player') || |
|
543df0fe7168
[tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents:
241
diff
changeset
|
74 url.pathname.startsWith('/public/hls-sample/')) { |
|
543df0fe7168
[tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents:
241
diff
changeset
|
75 return; |
|
543df0fe7168
[tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents:
241
diff
changeset
|
76 } |
|
543df0fe7168
[tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents:
241
diff
changeset
|
77 |
| 209 | 78 event.respondWith( |
| 79 caches.match(request).then((cachedResponse) => { | |
| 80 if (cachedResponse) { | |
| 81 console.log('[SW] Serving from cache:', url.pathname); | |
| 82 return cachedResponse; | |
| 83 } | |
| 84 | |
| 85 // Not in cache, fetch from network | |
| 86 return fetch(request).then((networkResponse) => { | |
| 87 // Only cache successful responses | |
| 88 if (!networkResponse || networkResponse.status !== 200 || networkResponse.type === 'error') { | |
| 89 return networkResponse; | |
| 90 } | |
| 91 | |
| 92 // Cache specific file types | |
| 93 const shouldCache = | |
| 94 url.pathname.endsWith('.css') || | |
| 95 url.pathname.endsWith('.js') || | |
| 96 url.pathname.endsWith('.svg') || | |
| 97 url.pathname.endsWith('.jpg') || | |
| 98 url.pathname.endsWith('.webp') || | |
| 99 url.pathname.endsWith('.woff') || | |
| 100 url.pathname.endsWith('.woff2') || | |
| 101 url.pathname.endsWith('.ttf') || | |
| 102 url.pathname.endsWith('.otf') || | |
| 103 url.pathname.startsWith('/blog/') || | |
| 104 url.pathname.startsWith('/notes/') || | |
| 105 url.pathname === '/'; | |
| 106 | |
| 107 if (shouldCache) { | |
| 108 const responseToCache = networkResponse.clone(); | |
| 109 caches.open(CACHE_NAME).then((cache) => { | |
| 110 console.log('[SW] Caching new resource:', url.pathname); | |
| 111 cache.put(request, responseToCache); | |
| 112 }); | |
| 113 } | |
| 114 | |
| 115 return networkResponse; | |
| 116 }).catch((error) => { | |
| 117 console.log('[SW] Fetch failed:', error); | |
| 118 | |
| 119 // Return offline page for HTML requests | |
| 120 if (request.headers.get('Accept').includes('text/html')) { | |
| 121 return caches.match('/offline.html'); | |
| 122 } | |
| 123 }); | |
| 124 }) | |
| 125 ); | |
| 126 }); | |
| 127 | |
| 128 // Handle messages from the client | |
| 129 self.addEventListener('message', (event) => { | |
| 130 if (event.data && event.data.type === 'SKIP_WAITING') { | |
| 131 self.skipWaiting(); | |
| 132 } | |
| 133 | |
| 134 if (event.data && event.data.type === 'CLEAR_CACHE') { | |
| 135 event.waitUntil( | |
| 136 caches.keys().then((cacheNames) => { | |
| 137 return Promise.all( | |
| 138 cacheNames.map((cacheName) => caches.delete(cacheName)) | |
| 139 ); | |
| 140 }) | |
| 141 ); | |
| 142 } | |
| 143 }); |