add stream caching ("offline mode")

This commit is contained in:
2026-03-16 20:32:33 +01:00
parent 8573b82515
commit 3aa762d544
12 changed files with 153 additions and 17 deletions

View File

@@ -0,0 +1,66 @@
import { browser } from '$app/environment';
import { SvelteSet, SvelteMap } from 'svelte/reactivity';
import type { StreamSummary } from './types.ts';
const STORAGE_KEY = 'cachedStreams';
export const cached = new SvelteSet<string>(
browser ? JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]') : []
);
export const downloading = new SvelteMap<string, number>();
if (browser) {
$effect.root(() => {
$effect(() => {
localStorage.setItem(STORAGE_KEY, JSON.stringify([...cached]));
});
});
}
export async function download(stream: StreamSummary) {
const res = await fetch(`/media/tracks/${stream.filename}`);
if (!res.ok || !res.body) throw new Error('Download failed');
const total = Number(res.headers.get('content-length') || 0);
const reader = res.body.getReader();
const chunks: Uint8Array[] = [];
let received = 0;
downloading.set(stream.id, 0);
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
received += value.length;
if (total) downloading.set(stream.id, Math.round((received / total) * 100));
}
const root = await navigator.storage.getDirectory();
const handle = await root.getFileHandle(stream.id, { create: true });
const writable = await handle.createWritable();
await writable.write(new Blob(chunks));
await writable.close();
downloading.delete(stream.id);
cached.add(stream.id);
}
export async function remove(streamId: string) {
const root = await navigator.storage.getDirectory();
await root.removeEntry(streamId);
cached.delete(streamId);
}
export async function getUrl(streamId: string): Promise<string | null> {
if (!cached.has(streamId)) return null;
try {
const root = await navigator.storage.getDirectory();
const handle = await root.getFileHandle(streamId);
const file = await handle.getFile();
return URL.createObjectURL(file);
} catch {
cached.delete(streamId);
return null;
}
}