2026-03-16 19:19:22 +01:00
|
|
|
/**
|
|
|
|
|
* diora service worker — caches the app shell for offline use.
|
|
|
|
|
*/
|
|
|
|
|
|
2026-10-04 21:24:59 +02:00
|
|
|
const CACHE = 'diora-v92';
|
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',
|
Home: neue Startseite mit Weiterlesen, Weiterhören, Radio-Favoriten und Ambient; sw v87
- static/js/home.js rendert #tab-home aus dem, was die Seite schon hat:
zuletzt gelesenes Buch (und drei weitere), laufende oder nächste Folge mit
Restzeit und „N neue Folgen“, Favoriten-Sender (sonst die ersten
gespeicherten) und zuletzt gehörter Sender, Drift mit der zuletzt
gewählten Klangwelt und Sleep-Timer. Läuft im Browser, in diora desktop und
in der Android-App (dort mit static/js/ kopiert).
- app.js: Tab 'home' (TOP_TABS), window.__dioraAmbientStart() lädt Drift bei
Bedarf und startet es; die gewählte Klangwelt wird gemerkt und beim Laden
wiederhergestellt.
- podcasts-web.js: Startseite Home, wenn nichts anderes gewählt ist.
- native-podcast.js aus diora-android 7dcc0c6 (Home in der Startseiten-Wahl,
__dioraPodcastView).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 15:34:02 +02:00
|
|
|
'/static/js/home.js',
|
Feed-Reader: Tab „Feeds“ mit Nachrichten (Briefing, Stories) und Blogs
static/js/feeds.js für Web, Desktop und beide Android-Apps:
- Nachrichten: „Seit letztem Mal“ (Top-Themen, dann nach Ressort, „Alles
gelesen“), Stories nach Tag, Ressort-Filter
- Blogs: Ungelesen-Liste, je Blog filterbar, „Alle gelesen“
- Artikel im eigenen Lesemodus (Volltext, Schriftgröße, merken, alle Berichte
einer Story), Browser nur auf Wunsch
- Feeds verwalten: Seite oder Feed suchen, als Nachrichten/Blog abonnieren,
Ressort, Volltext-Regel, OPML-Import pro Ordner, Export, Aufbewahrung
- diora Reader (ohne Tab-Leiste) bekommt eine kleine Leiste Bücher/Feeds
Server: Feed-Namen ohne Slogan, Feeds mit einem Zeitstempel für alle Einträge
(Deutschlandfunk) zählen ab dem ersten Sehen; sw v89
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 20:16:24 +02:00
|
|
|
'/static/js/feeds.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/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-10-03 23:08:57 +02:00
|
|
|
'/static/ambient/index.html',
|
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/') ||
|
Player-Sync: ein Player für alle Geräte (wie Spotify Connect)
Server: PlayerState und PlayerDevice (Migration 0012), /podcasts/player/
(Stand), report/ (das Gerät, das zu spielen anfängt, wird das aktive und
bleibt es auch pausiert, solange es online ist), command/ (Fernbedienung,
transfer auf ein anderes Gerät) und stream/ (Server-Sent Events, zugleich
die Anwesenheit der Geräte). seq steigt in einem UPDATE und nie zurück.
Browser: podcasts-web.js meldet Abspielen, Pause, Springen, Folgen- und
Senderwechsel (alle 10 s beim Spielen), hört den Stream, hört auf, wenn ein
anderes Gerät startet, führt Befehle aus, zeigt das andere Gerät als remote
und übernimmt, was ein verschwundenes Gerät zuletzt hatte. Eine pausierte
Folge folgt einem neueren Stand von anderswo; im Vordergrund wird nach
15 s neu geholt. Podcast-Seite neu kopiert, sw v58.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 15:18:38 +02:00
|
|
|
url.pathname.startsWith('/podcasts/player/') ||
|
2026-03-19 13:39:59 +01:00
|
|
|
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(
|
2026-10-03 23:08:57 +02:00
|
|
|
// ignoreSearch: the Ambient frame loads with ?embed=1&bg=…
|
|
|
|
|
caches.match(event.request, {ignoreSearch: true}).then(function (cached) {
|
2026-03-19 22:05:50 +01:00
|
|
|
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
|
|
|
});
|