chore: bump service worker cache version to v5 and add manifest cache-busting parameter

Increment CACHE_NAME from media-max-shell-v4 to v5 in sw.js. Update service worker registration query parameter from v=4 to v=5 in index.html. Add v=5 cache-busting parameter to manifest.json link tag. Remove duplicate service worker registration script block from template footer
This commit is contained in:
2026-08-17 19:36:04 +02:00
parent 14a4c6ce7b
commit 2096fc5d11
2 changed files with 3 additions and 4 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
const CACHE_NAME = 'media-max-shell-v4';
const CACHE_NAME = 'media-max-shell-v5';
const SHELL = ['/static/media-mark.svg', '/static/media-mark-192.svg', '/static/media-mark-512.svg', '/static/manifest.json'];
self.addEventListener('install', event => {
+2 -3
View File
@@ -14,7 +14,7 @@ document.addEventListener('DOMContentLoaded',()=>{const grid=document.querySelec
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('/sw.js?v=4', {scope: '/'}).catch(function () {});
navigator.serviceWorker.register('/sw.js?v=5', {scope: '/'}).catch(function () {});
});
}
</script>
@@ -35,7 +35,7 @@ if ('serviceWorker' in navigator) {
<script>document.addEventListener('DOMContentLoaded',()=>{const badge=document.querySelector('#raidStatusBadge');if(!badge)return;const side=document.createElement('div');side.className='raid-status-side';const countdown=document.createElement('small');countdown.id='raidRefreshCountdown';countdown.textContent='Update in 5s';badge.replaceWith(side);side.append(badge,countdown);const interval=5000;let next=Date.now()+interval;const reset=()=>{next=Date.now()+interval};window.resetRaidRefreshCountdown=reset;const update=()=>{const seconds=Math.max(0,Math.ceil((next-Date.now())/1000));countdown.textContent=`Update in ${seconds}s`;if(seconds===0)reset()};update();setInterval(update,250);const updated=document.querySelector('#datastoreUpdated');if(updated)new MutationObserver(reset).observe(updated,{childList:true,characterData:true,subtree:true})});</script>
<script>document.addEventListener('DOMContentLoaded',()=>{const icons={total:'mdi:harddisk',used:'mdi:database',free:'mdi:database-outline',percent:'mdi:chart-donut'};document.querySelectorAll('.storage-card .storage-icon').forEach((node,index)=>{const key=['total','used','free','percent'][index];if(!key)return;const image=document.createElement('img');image.src=`https://api.iconify.design/${icons[key]}.svg?color=${key==='used'?'%23f4d267':key==='free'?'%236ae29a':key==='percent'?'%23c59cff':'%2360a9e6'}`;image.alt='';image.setAttribute('aria-hidden','true');node.textContent='';node.appendChild(image)})});</script>
<script>document.addEventListener('DOMContentLoaded',()=>{if(!document.querySelector('link[rel="shortcut icon"]')){const favicon=document.createElement('link');favicon.rel='shortcut icon';favicon.type='image/svg+xml';favicon.href="{{ url_for('static', filename='media-mark.svg') }}?v=media-max";document.head.appendChild(favicon)}});</script>
<html lang="de"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"><meta name="theme-color" content="#1f252d"><meta name="mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-capable" content="yes"><link rel="manifest" href="{{ url_for('static', filename='manifest.json') }}"><link rel="apple-touch-icon" href="{{ url_for('static', filename='media-mark.svg') }}"><link rel="icon" type="image/svg+xml" href="{{ url_for('static', filename='media-mark.svg') }}"><title>Media Max</title>
<html lang="de"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"><meta name="theme-color" content="#1f252d"><meta name="mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-capable" content="yes"><link rel="manifest" href="{{ url_for('static', filename='manifest.json') }}?v=5"><link rel="apple-touch-icon" href="{{ url_for('static', filename='media-mark.svg') }}"><link rel="icon" type="image/svg+xml" href="{{ url_for('static', filename='media-mark.svg') }}"><title>Media Max</title>
<style>
:root{color-scheme:dark;--bg:#181818;--panel:#222;--line:#3a3a3a;--text:#dedede;--muted:#929292;--yellow:#f4c430;--blue:#60a9e6}*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--text);font:13px Inter,system-ui,sans-serif}header{height:58px;display:flex;align-items:center;gap:15px;padding:0 20px;background:#242424;border-bottom:1px solid #343434}.logo{color:var(--yellow);font-size:22px;font-weight:900;letter-spacing:1px}.head-title{font-weight:700}.head-sub{font-size:12px;color:var(--muted);margin-top:2px}.actions{margin-left:auto}button,input,select{font:inherit;color:var(--text);background:#292929;border:1px solid #444;border-radius:5px}button{padding:7px 10px;cursor:pointer}main{padding:14px 20px 30px}.nav{display:flex;gap:4px;margin-bottom:12px;border-bottom:1px solid var(--line)}.nav button{border:0;border-radius:5px 5px 0 0;background:transparent;color:#aaa}.nav button.active{background:#303030;color:#fff}.view{display:none}.view.active{display:block}.toolbar{display:grid;grid-template-columns:minmax(280px,1fr) 190px 190px 170px;gap:8px;margin-bottom:10px}input,select{padding:7px 10px;height:34px}.stats{display:flex;gap:8px;margin-bottom:10px;flex-wrap:wrap}.stat{background:#242424;border:1px solid #363636;padding:5px 9px;border-radius:5px;color:#bbb}.scan{color:#f4c430}.banner{padding:9px 11px;border:1px solid #693b3b;background:#372424;border-radius:5px;margin-bottom:10px;color:#ffd1d1}.tablewrap{border:1px solid #353535;border-radius:6px;overflow:hidden;background:var(--panel)}table{width:100%;border-collapse:collapse;table-layout:fixed}th{padding:8px 10px;background:#282828;border-bottom:1px solid #444;text-align:left;font-size:12px}td{padding:7px 10px;border-bottom:1px solid #343434;vertical-align:middle}.col-title{width:28%}.col-quality{width:12%}.col-state{width:10%}.col-audio{width:17%}.col-subs{width:17%}.col-video{width:8%}.col-size{width:8%}.title{color:var(--blue);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:inline-block;max-width:90%;vertical-align:bottom}.year{color:var(--muted);font-size:11px;margin-left:5px}.badges{display:flex;gap:4px;flex-wrap:wrap}.badge{display:inline-flex;gap:4px;align-items:center;padding:2px 6px;border-radius:999px;border:1px solid #484848;background:#303030;white-space:nowrap;font-size:11px}.quality{background:#0e7138;border-color:#19894b}.state{font-size:11px;font-weight:700;padding:3px 7px;border-radius:4px;display:inline-block}.state.ok{background:#126f39;color:#d9ffe8}.state.warn{background:#77561e;color:#ffebc4}.state.bad{background:#763030;color:#ffd9d9}.state.neutral{background:#3b3b3b;color:#ccc}.muted{color:var(--muted)}.hidden{display:none}.series{border-bottom:1px solid var(--line)}.series:last-child{border:0}.series summary{padding:12px;cursor:pointer;background:#282828;font-weight:700}.series summary:hover{background:#303030}.series table{border-radius:0}.series td:first-child{padding-left:28px}@media(max-width:1100px){.toolbar{grid-template-columns:1fr 1fr}.col-video,.col-size{display:none}}
.brand-mark{width:34px;height:34px;display:grid;place-items:center;filter:drop-shadow(0 0 10px rgba(96,169,230,.24))}.brand-mark svg{width:34px;height:34px}.brand-name{color:var(--yellow);font-size:16px;font-weight:900;letter-spacing:1.5px}.brand{display:flex;align-items:center;gap:9px}
@@ -84,7 +84,6 @@ let autoScanTimer=null;function configureAutoScan(){if(autoScanTimer)clearInterv
const seasonZeroLabel=document.createElement('label');seasonZeroLabel.className='setting-toggle';seasonZeroLabel.htmlFor='showSeasonZero';seasonZeroLabel.innerHTML='<input type="checkbox" id="showSeasonZero"><span>Staffel 0 anzeigen</span>';const seasonZeroHelp=document.createElement('span');seasonZeroHelp.className='setting-help';seasonZeroHelp.textContent='Gilt für Sonarr und die Liste Ohne Deutsch.';if(settingsActions){settingsActions.before(seasonZeroLabel,seasonZeroHelp)}
function applySeasonZeroPreference(){const show=localStorage.getItem('show-season-zero')==='true';const rows=[...document.querySelectorAll('#sonarr tbody tr:not(.season-divider),#missing .missing-series tbody tr:not(.season-divider)')];rows.forEach(row=>{const title=row.querySelector('.title')?.textContent.trim()||'';row.classList.toggle('season-zero-hidden',!show&&/^S00E/i.test(title))});document.querySelectorAll('#sonarr details.series,#missing details.missing-series').forEach(detail=>{const episodeRows=[...detail.querySelectorAll('tbody tr:not(.season-divider)')];detail.classList.toggle('season-zero-empty',episodeRows.length>0&&episodeRows.every(row=>row.classList.contains('season-zero-hidden')))});const missingCount=document.querySelector('#missingCount'),missingNavCount=document.querySelector('#missingNavCount');if(missingCount||missingNavCount){const movies=document.querySelectorAll('#missingMovies tbody tr:not(.hidden)').length,episodes=document.querySelectorAll('#missing .missing-series tbody tr:not(.season-divider):not(.season-zero-hidden)').length,total=movies+episodes;if(missingCount)missingCount.textContent=`${total} Einträge ohne Deutsch`;if(missingNavCount)missingNavCount.textContent=total}const hint=document.querySelector('#seasonZeroHint');if(hint)hint.textContent=show?'Vorhanden oder wird gerade geladen · Staffel 0 eingeblendet':'Vorhanden oder wird gerade geladen · Staffel 0 ausgeblendet'}const seasonZeroToggle=document.querySelector('#showSeasonZero');if(seasonZeroToggle){seasonZeroToggle.checked=localStorage.getItem('show-season-zero')==='true';seasonZeroToggle.addEventListener('change',()=>{localStorage.setItem('show-season-zero',seasonZeroToggle.checked?'true':'false');applySeasonZeroPreference()})}applySeasonZeroPreference();
function syncDashboardMissingCounter(){const visibleMissing=document.querySelectorAll('#missingMovies tbody tr:not(.hidden),#missing .missing-series tbody tr:not(.season-zero-hidden):not(.season-divider)').length;const dashboardMissing=document.querySelector('#dashboardMissing');if(dashboardMissing)dashboardMissing.textContent=visibleMissing}syncDashboardMissingCounter();document.querySelector('#showSeasonZero')?.addEventListener('change',()=>setTimeout(syncDashboardMissingCounter,0));
if('serviceWorker' in navigator)window.addEventListener('load',()=>navigator.serviceWorker.register('/static/sw.js?v=3',{scope:'/'}).catch(()=>{}));
function updateMissingHeading(){const heading=document.querySelector('#missingMovies thead th:first-child');if(heading)heading.textContent=document.documentElement.lang==='en'?'Media':'Medien'}updateMissingHeading();document.querySelector('#languageToggle')?.addEventListener('click',()=>setTimeout(updateMissingHeading,0));
function addMissingSections(){const view=document.querySelector('#missing'),movieTable=document.querySelector('#missingMovies'),seriesItems=[...document.querySelectorAll('#missing .missing-series')];if(!view)return;const makeHeading=(type,de,en)=>{const heading=document.createElement('div');heading.className=`missing-section-heading ${type}`;heading.dataset.de=de;heading.dataset.en=en;heading.textContent=document.documentElement.lang==='en'?en:de;return heading};if(movieTable&&movieTable.querySelector('tbody tr'))movieTable.before(makeHeading('movies','Filme ohne Deutsch','Movies without German'));if(seriesItems.length)seriesItems[0].before(makeHeading('series','Serien ohne Deutsch','Series without German'))}addMissingSections();
</script>