From f63ba5381b039cd72d574e0da30f0b052eab9309 Mon Sep 17 00:00:00 2001 From: nessi Date: Thu, 13 Aug 2026 22:03:53 +0200 Subject: [PATCH] feat: add PWA support with service worker, manifest, and auto-scan configuration for offline capability and mobile installation Add manifest.json with app metadata, theme colors, and icon configuration for installable PWA. Add service worker (sw.js) with shell caching strategy for offline support - caches static assets on install, cleans old caches on activate, and implements network-first fetch with cache fallback for non-API requests. Update index.html with PWA meta tags (theme-color, mobile --- static/manifest.json | 14 ++++++++++++++ static/sw.js | 20 ++++++++++++++++++++ templates/index.html | 10 +++++++++- 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 static/manifest.json create mode 100644 static/sw.js diff --git a/static/manifest.json b/static/manifest.json new file mode 100644 index 0000000..4b8f2ac --- /dev/null +++ b/static/manifest.json @@ -0,0 +1,14 @@ +{ + "name": "Media Language Dashboard", + "short_name": "Media Dashboard", + "description": "Radarr, Sonarr und SABnzbd im Überblick", + "start_url": "/", + "scope": "/", + "display": "standalone", + "background_color": "#151619", + "theme_color": "#1f252d", + "orientation": "any", + "icons": [ + {"src": "/static/media-mark.svg", "sizes": "any", "type": "image/svg+xml", "purpose": "any maskable"} + ] +} diff --git a/static/sw.js b/static/sw.js new file mode 100644 index 0000000..c42edf5 --- /dev/null +++ b/static/sw.js @@ -0,0 +1,20 @@ +const CACHE_NAME = 'media-dashboard-shell-v1'; +const SHELL = ['/static/media-mark.svg', '/static/manifest.json']; + +self.addEventListener('install', event => { + event.waitUntil(caches.open(CACHE_NAME).then(cache => cache.addAll(SHELL))); + self.skipWaiting(); +}); + +self.addEventListener('activate', event => { + event.waitUntil(caches.keys().then(keys => Promise.all(keys.filter(key => key !== CACHE_NAME).map(key => caches.delete(key))))); + self.clients.claim(); +}); + +self.addEventListener('fetch', event => { + const request = event.request; + if (request.method !== 'GET') return; + const url = new URL(request.url); + if (url.pathname.startsWith('/api/')) return; + event.respondWith(fetch(request).catch(() => caches.match(request).then(response => response || caches.match('/static/manifest.json')))); +}); diff --git a/templates/index.html b/templates/index.html index 729fc69..7a0a657 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,11 +1,14 @@ -Language Dashboard +Language Dashboard
MEDIA
Language Dashboard
Audio- und Untertitelspuren aus den Mediendateien
@@ -37,6 +40,11 @@ function statusText(s){if(s.state==='running')return `Scan: ${s.done}/${s.total| const seenRunning={radarr:false,sonarr:false};async function poll(){try{const data=await (await fetch('/api/scan-status')).json();document.querySelector('#radarrStatus').textContent=statusText(data.radarr);const sonarr=document.querySelector('#sonarrStatus');if(sonarr)sonarr.textContent=statusText(data.sonarr);['radarr','sonarr'].forEach(source=>{if(data[source].state==='running')seenRunning[source]=true;if(seenRunning[source]&&['done','error'].includes(data[source].state)){seenRunning[source]=false;setTimeout(()=>location.reload(),700)}})}catch(e){} };setInterval(poll,1200);poll(); document.querySelector('#rescan').onclick=async()=>{const b=document.querySelector('#rescan');b.disabled=true;b.textContent='Scanne …';await fetch('/api/rescan?source='+(b.dataset.source||'radarr'),{method:'POST'});b.disabled=false;b.textContent='↻ Neu scannen';poll()}; +