Add managed catalog sync and player UX improvements
This commit is contained in:
@@ -1,10 +1,97 @@
|
||||
const MANAGED_CATALOG_CACHE_PREFIX = 'radioplayer-managed-catalog-';
|
||||
const MANAGED_CATALOG_SOURCE_HEADER = 'x-radioplayer-managed-source';
|
||||
|
||||
export type ManagedCatalogSource = 'remote' | 'cached-remote' | 'bundled' | 'unknown';
|
||||
|
||||
let lastManagedCatalogSource: ManagedCatalogSource = 'unknown';
|
||||
|
||||
type ManagedCatalogEnvelope = {
|
||||
stations?: unknown;
|
||||
};
|
||||
|
||||
async function loadManagedCatalogFromCache(catalogUrl: string): Promise<Response | null> {
|
||||
if (typeof window === 'undefined' || !('caches' in window)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const cacheKeys = await caches.keys();
|
||||
const managedCacheName = cacheKeys.find((cacheName) => cacheName.startsWith(MANAGED_CATALOG_CACHE_PREFIX));
|
||||
if (!managedCacheName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const managedCache = await caches.open(managedCacheName);
|
||||
return await managedCache.match(catalogUrl) ?? null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeManagedStationsPayload(payload: unknown): unknown[] {
|
||||
if (Array.isArray(payload)) {
|
||||
return payload;
|
||||
}
|
||||
|
||||
if (payload && typeof payload === 'object' && Array.isArray((payload as ManagedCatalogEnvelope).stations)) {
|
||||
return (payload as ManagedCatalogEnvelope).stations as unknown[];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
function setLastManagedCatalogSource(source: ManagedCatalogSource) {
|
||||
lastManagedCatalogSource = source;
|
||||
}
|
||||
|
||||
export function getLastManagedCatalogSource(): ManagedCatalogSource {
|
||||
return lastManagedCatalogSource;
|
||||
}
|
||||
|
||||
export async function loadManagedStations(): Promise<unknown[]> {
|
||||
const response = await fetch(`${import.meta.env.BASE_URL}stations.json`);
|
||||
const remoteCatalogUrl = `${import.meta.env.BASE_URL}api/managed-stations.json`;
|
||||
const bundledCatalogUrl = `${import.meta.env.BASE_URL}stations.json`;
|
||||
const hasServiceWorkerController = typeof navigator !== 'undefined'
|
||||
&& 'serviceWorker' in navigator
|
||||
&& Boolean(navigator.serviceWorker.controller);
|
||||
|
||||
let response = null;
|
||||
|
||||
if (hasServiceWorkerController) {
|
||||
response = await loadManagedCatalogFromCache(remoteCatalogUrl);
|
||||
if (response?.ok) {
|
||||
setLastManagedCatalogSource('cached-remote');
|
||||
}
|
||||
}
|
||||
|
||||
if (!response?.ok) {
|
||||
try {
|
||||
response = await fetch(remoteCatalogUrl);
|
||||
if (response?.ok) {
|
||||
const responseSource = response.headers.get(MANAGED_CATALOG_SOURCE_HEADER);
|
||||
setLastManagedCatalogSource(
|
||||
responseSource === 'remote' || responseSource === 'cached-remote' || responseSource === 'bundled'
|
||||
? responseSource
|
||||
: 'remote',
|
||||
);
|
||||
}
|
||||
} catch {
|
||||
response = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!response?.ok) {
|
||||
response = await fetch(bundledCatalogUrl);
|
||||
if (response?.ok) {
|
||||
setLastManagedCatalogSource('bundled');
|
||||
}
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
setLastManagedCatalogSource('unknown');
|
||||
throw new Error(`Failed to load managed stations: ${response.status}`);
|
||||
}
|
||||
|
||||
const stations = await response.json();
|
||||
return Array.isArray(stations) ? stations : [];
|
||||
return normalizeManagedStationsPayload(stations);
|
||||
}
|
||||
Reference in New Issue
Block a user