feat: persist station sync catalogs and status

This commit is contained in:
2026-04-29 16:54:05 +02:00
parent 8bd9106ff3
commit 10a239a155
7 changed files with 642 additions and 59 deletions
+73 -4
View File
@@ -3,7 +3,7 @@
//
// This value is rewritten automatically before each build so deployed clients
// refresh to the newest shell and cached assets.
const CACHE_NAME = 'radioplayer-pwa-v5-1777473175316';
const CACHE_NAME = 'radioplayer-pwa-v5-1777474420392';
const STATION_SYNC_CACHE_NAME = 'radioplayer-station-sync-v1';
const MANAGED_CATALOG_CACHE_NAME = 'radioplayer-managed-catalog-v1';
const RADIO_BROWSER_API_ENDPOINT = 'https://de1.api.radio-browser.info/json/stations/search';
@@ -377,10 +377,23 @@ async function refreshManagedCatalogCache() {
const response = await fetch(url, { cache: 'no-store' });
if (isCacheableResponse(response)) {
await managedCatalogCache.put(url, response);
return { updated: true, error: null };
}
return {
updated: false,
error: `Unexpected managed catalog response: ${response.status} ${response.statusText}`.trim(),
};
} catch {
// Network unavailable — keep existing cache as-is.
}
return { updated: false, error: 'Managed catalog request failed.' };
}
async function notifyClients(message) {
const clients = await self.clients.matchAll({ type: 'window', includeUncontrolled: true });
await Promise.allSettled(clients.map((client) => client.postMessage(message)));
}
async function respondWithManagedCatalog(request) {
@@ -530,7 +543,23 @@ self.addEventListener('activate', (event) => {
self.addEventListener('sync', (event) => {
if (event.tag !== STATION_SYNC_TAG) return;
event.waitUntil(syncRadioStations('background-sync'));
event.waitUntil(
syncRadioStations('background-sync')
.then((meta) => notifyClients({
type: 'station-catalog-updated',
reason: 'background-sync',
meta,
}))
.catch(async (error) => {
await notifyClients({
type: 'station-catalog-update-failed',
reason: 'background-sync',
error: error instanceof Error ? error.message : 'Unknown error',
failedAt: new Date().toISOString(),
});
throw error;
})
);
});
self.addEventListener('message', (event) => {
@@ -544,6 +573,14 @@ self.addEventListener('message', (event) => {
? await syncRadioStations('country-selection-update', syncSettings.selectedCountryCodes)
: null;
if (syncResult) {
await notifyClients({
type: 'station-catalog-updated',
reason: 'country-selection-update',
meta: syncResult,
});
}
event.ports?.[0]?.postMessage({
ok: true,
selectedCountryCodes: syncSettings.selectedCountryCodes,
@@ -560,11 +597,43 @@ self.addEventListener('message', (event) => {
self.addEventListener('periodicsync', (event) => {
if (event.tag === STATION_PERIODIC_SYNC_TAG) {
event.waitUntil(syncRadioStations('periodic-sync'));
event.waitUntil(
syncRadioStations('periodic-sync')
.then((meta) => notifyClients({
type: 'station-catalog-updated',
reason: 'periodic-sync',
meta,
}))
.catch(async (error) => {
await notifyClients({
type: 'station-catalog-update-failed',
reason: 'periodic-sync',
error: error instanceof Error ? error.message : 'Unknown error',
failedAt: new Date().toISOString(),
});
throw error;
})
);
return;
}
if (event.tag === MANAGED_CATALOG_PERIODIC_SYNC_TAG) {
event.waitUntil(refreshManagedCatalogCache());
event.waitUntil(
refreshManagedCatalogCache().then((result) => {
if (!result.updated) {
return notifyClients({
type: 'managed-catalog-update-failed',
reason: 'periodic-sync',
error: result.error || 'Unknown error',
failedAt: new Date().toISOString(),
});
}
return notifyClients({
type: 'managed-catalog-updated',
reason: 'periodic-sync',
});
})
);
}
});