2026-03-16 19:19:22 +01:00
|
|
|
/**
|
|
|
|
|
* diora service worker — caches the app shell for offline use.
|
|
|
|
|
*/
|
|
|
|
|
|
2026-10-02 12:44:49 +02:00
|
|
|
const CACHE = 'diora-v54';
|
2026-03-16 19:19:22 +01:00
|
|
|
const SHELL = [
|
|
|
|
|
'/static/css/app.css',
|
|
|
|
|
'/static/js/app.js',
|
Podcasts im Browser: die Podcast-Seite der App statt des alten Podcast-Tabs
Der Podcast-Tab der Web-App zeigt jetzt dieselbe Oberfläche wie die
Android-App: native-podcast.js aus diora-android, unverändert kopiert nach
static/podcasts/ (tools/sync_podcast_ui.py, mit Quell-Commit im Kopf),
dazu die Podcast-Teile von native.css.
static/js/podcasts-web.js spielt im Browser die Rolle der App
(window.DioraPodcastHost statt DioraNative):
- Zustand aus /podcasts/state/, in localStorage für einen schnellen Start;
Änderungen sofort lokal und der Reihe nach an den Server (Outbox, übersteht
Neuladen und Offline), wie Podcasts.kt, inkl. „immer sortiert halten“
- eigener Player (nicht das Radio-Audio-Element), Warteschlange = Playlist,
wie RadioService.EpisodeTracker: Stelle fortsetzen, Intro/Outro, Fortschritt
alle 10 s und bei Pause, „gehört“ kurz vor Schluss (auch bei „nächste“),
automatisch weiter, nach Pause etwas zurück (0,8/3/10/20 s), Tempo und
Lautstärke (bis 1) pro Podcast, Sleep-Timer nur während des Abspielens mit
Ausblenden
- Sperrbildschirm und Medientasten über navigator.mediaSession
- Abspiel-Einstellungen dieses Geräts in localStorage (wie PlaybackPrefs)
- keine Downloads (die Oberfläche blendet sie aus)
- Radio und Podcast nie gleichzeitig: eine Folge stoppt das Radio, ein Sender
legt die Folge weg
- Bottom-Sheet und Mini-Player-Dock über der Radio-Leiste; auf breiten
Bildschirmen eine mittige Spalte (760 px)
In der App und der Desktop-App (window.DioraNative vorhanden) tut
podcasts-web.js nichts.
Entfernt: der alte Podcast-Tab (Markup, ~1000 Zeilen in app.js, CSS), die
Podcast-Leiste im Player, INITIAL_PODCAST_FEEDS und das Herunterladen von
Folgen in den Browser-Cache (der Service Worker räumt diora-podcast-v1 ab).
Service-Worker-Cache auf v52, neue Dateien im App-Shell.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 10:26:32 +02:00
|
|
|
'/static/js/podcasts-web.js',
|
|
|
|
|
'/static/podcasts/native-podcast.js',
|
|
|
|
|
'/static/podcasts/podcast-ui.css',
|
|
|
|
|
'/static/podcasts/podcasts-web.css',
|
2026-03-16 19:19:22 +01:00
|
|
|
'/static/manifest.json',
|
2026-09-12 15:05:08 +02:00
|
|
|
'/static/fonts/SourceSerif4-normal-latin.woff2',
|
|
|
|
|
'/static/fonts/SourceSerif4-normal-latin-ext.woff2',
|
|
|
|
|
'/static/fonts/SourceSerif4-italic-latin.woff2',
|
|
|
|
|
'/static/fonts/SourceSerif4-italic-latin-ext.woff2',
|
2026-03-16 19:19:22 +01:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// Install: pre-cache the app shell
|
|
|
|
|
self.addEventListener('install', function (event) {
|
|
|
|
|
event.waitUntil(
|
|
|
|
|
caches.open(CACHE).then(function (cache) {
|
|
|
|
|
return cache.addAll(SHELL);
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
// Activate immediately without waiting for old tabs to close
|
|
|
|
|
self.skipWaiting();
|
|
|
|
|
});
|
|
|
|
|
|
Podcasts im Browser: die Podcast-Seite der App statt des alten Podcast-Tabs
Der Podcast-Tab der Web-App zeigt jetzt dieselbe Oberfläche wie die
Android-App: native-podcast.js aus diora-android, unverändert kopiert nach
static/podcasts/ (tools/sync_podcast_ui.py, mit Quell-Commit im Kopf),
dazu die Podcast-Teile von native.css.
static/js/podcasts-web.js spielt im Browser die Rolle der App
(window.DioraPodcastHost statt DioraNative):
- Zustand aus /podcasts/state/, in localStorage für einen schnellen Start;
Änderungen sofort lokal und der Reihe nach an den Server (Outbox, übersteht
Neuladen und Offline), wie Podcasts.kt, inkl. „immer sortiert halten“
- eigener Player (nicht das Radio-Audio-Element), Warteschlange = Playlist,
wie RadioService.EpisodeTracker: Stelle fortsetzen, Intro/Outro, Fortschritt
alle 10 s und bei Pause, „gehört“ kurz vor Schluss (auch bei „nächste“),
automatisch weiter, nach Pause etwas zurück (0,8/3/10/20 s), Tempo und
Lautstärke (bis 1) pro Podcast, Sleep-Timer nur während des Abspielens mit
Ausblenden
- Sperrbildschirm und Medientasten über navigator.mediaSession
- Abspiel-Einstellungen dieses Geräts in localStorage (wie PlaybackPrefs)
- keine Downloads (die Oberfläche blendet sie aus)
- Radio und Podcast nie gleichzeitig: eine Folge stoppt das Radio, ein Sender
legt die Folge weg
- Bottom-Sheet und Mini-Player-Dock über der Radio-Leiste; auf breiten
Bildschirmen eine mittige Spalte (760 px)
In der App und der Desktop-App (window.DioraNative vorhanden) tut
podcasts-web.js nichts.
Entfernt: der alte Podcast-Tab (Markup, ~1000 Zeilen in app.js, CSS), die
Podcast-Leiste im Player, INITIAL_PODCAST_FEEDS und das Herunterladen von
Folgen in den Browser-Cache (der Service Worker räumt diora-podcast-v1 ab).
Service-Worker-Cache auf v52, neue Dateien im App-Shell.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 10:26:32 +02:00
|
|
|
// Activate: remove stale caches from previous versions (also the old
|
|
|
|
|
// 'diora-podcast-v1' of episodes the web app used to download)
|
2026-03-16 19:19:22 +01:00
|
|
|
self.addEventListener('activate', function (event) {
|
|
|
|
|
event.waitUntil(
|
|
|
|
|
caches.keys().then(function (keys) {
|
|
|
|
|
return Promise.all(
|
Podcasts im Browser: die Podcast-Seite der App statt des alten Podcast-Tabs
Der Podcast-Tab der Web-App zeigt jetzt dieselbe Oberfläche wie die
Android-App: native-podcast.js aus diora-android, unverändert kopiert nach
static/podcasts/ (tools/sync_podcast_ui.py, mit Quell-Commit im Kopf),
dazu die Podcast-Teile von native.css.
static/js/podcasts-web.js spielt im Browser die Rolle der App
(window.DioraPodcastHost statt DioraNative):
- Zustand aus /podcasts/state/, in localStorage für einen schnellen Start;
Änderungen sofort lokal und der Reihe nach an den Server (Outbox, übersteht
Neuladen und Offline), wie Podcasts.kt, inkl. „immer sortiert halten“
- eigener Player (nicht das Radio-Audio-Element), Warteschlange = Playlist,
wie RadioService.EpisodeTracker: Stelle fortsetzen, Intro/Outro, Fortschritt
alle 10 s und bei Pause, „gehört“ kurz vor Schluss (auch bei „nächste“),
automatisch weiter, nach Pause etwas zurück (0,8/3/10/20 s), Tempo und
Lautstärke (bis 1) pro Podcast, Sleep-Timer nur während des Abspielens mit
Ausblenden
- Sperrbildschirm und Medientasten über navigator.mediaSession
- Abspiel-Einstellungen dieses Geräts in localStorage (wie PlaybackPrefs)
- keine Downloads (die Oberfläche blendet sie aus)
- Radio und Podcast nie gleichzeitig: eine Folge stoppt das Radio, ein Sender
legt die Folge weg
- Bottom-Sheet und Mini-Player-Dock über der Radio-Leiste; auf breiten
Bildschirmen eine mittige Spalte (760 px)
In der App und der Desktop-App (window.DioraNative vorhanden) tut
podcasts-web.js nichts.
Entfernt: der alte Podcast-Tab (Markup, ~1000 Zeilen in app.js, CSS), die
Podcast-Leiste im Player, INITIAL_PODCAST_FEEDS und das Herunterladen von
Folgen in den Browser-Cache (der Service Worker räumt diora-podcast-v1 ab).
Service-Worker-Cache auf v52, neue Dateien im App-Shell.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 10:26:32 +02:00
|
|
|
keys.filter(function (key) { return key !== CACHE; })
|
2026-03-16 19:19:22 +01:00
|
|
|
.map(function (key) { return caches.delete(key); })
|
|
|
|
|
);
|
|
|
|
|
}).then(function () {
|
|
|
|
|
return self.clients.claim();
|
2026-05-30 00:19:00 +02:00
|
|
|
}).then(function () {
|
|
|
|
|
// Tell all open tabs to reload so they get the latest cached assets
|
|
|
|
|
return self.clients.matchAll({type: 'window'}).then(function (clients) {
|
|
|
|
|
clients.forEach(function (client) {
|
|
|
|
|
client.postMessage({type: 'SW_ACTIVATED'});
|
|
|
|
|
});
|
|
|
|
|
});
|
2026-03-16 19:19:22 +01:00
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Fetch: serve from cache, fall back to network
|
|
|
|
|
self.addEventListener('fetch', function (event) {
|
|
|
|
|
// Only handle GET requests; let POST/SSE etc. pass through
|
|
|
|
|
if (event.request.method !== 'GET') return;
|
|
|
|
|
|
|
|
|
|
const url = new URL(event.request.url);
|
2026-03-19 13:39:59 +01:00
|
|
|
|
|
|
|
|
// Bypass for API/mutation endpoints
|
2026-03-16 19:19:22 +01:00
|
|
|
if (url.pathname.startsWith('/radio/sse/') ||
|
|
|
|
|
url.pathname.startsWith('/radio/record/') ||
|
|
|
|
|
url.pathname.startsWith('/radio/affiliate/') ||
|
2026-08-31 22:29:13 +02:00
|
|
|
url.pathname.startsWith('/tts/') ||
|
2026-03-19 13:39:59 +01:00
|
|
|
url.pathname.startsWith('/admin/') ||
|
|
|
|
|
url.pathname.startsWith('/podcasts/progress/') ||
|
|
|
|
|
url.pathname.startsWith('/podcasts/queue/') ||
|
|
|
|
|
url.pathname === '/podcasts/feeds/add' ||
|
|
|
|
|
url.pathname.startsWith('/podcasts/feeds/add') ||
|
|
|
|
|
url.pathname.includes('/remove') ||
|
|
|
|
|
url.pathname.startsWith('/podcasts/feeds/refresh')) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-29 23:58:07 +02:00
|
|
|
// Cache-first for pre-defined shell assets
|
2026-03-19 22:05:50 +01:00
|
|
|
const isShell = SHELL.some(function (s) { return url.pathname === s; });
|
|
|
|
|
if (isShell) {
|
|
|
|
|
event.respondWith(
|
|
|
|
|
caches.match(event.request).then(function (cached) {
|
|
|
|
|
return cached || fetch(event.request);
|
|
|
|
|
})
|
|
|
|
|
);
|
2026-05-29 23:58:07 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Navigation requests (the HTML page itself): network-first, fall back to
|
|
|
|
|
// last cached version so the app opens offline after being visited once.
|
|
|
|
|
if (event.request.mode === 'navigate') {
|
|
|
|
|
event.respondWith(
|
|
|
|
|
fetch(event.request).then(function (response) {
|
|
|
|
|
if (response.ok) {
|
|
|
|
|
var clone = response.clone();
|
|
|
|
|
caches.open(CACHE).then(function (cache) { cache.put(event.request, clone); });
|
|
|
|
|
}
|
|
|
|
|
return response;
|
|
|
|
|
}).catch(function () {
|
|
|
|
|
return caches.match(event.request);
|
|
|
|
|
})
|
|
|
|
|
);
|
2026-03-19 22:05:50 +01:00
|
|
|
}
|
2026-03-16 19:19:22 +01:00
|
|
|
});
|