45 lines
1.2 KiB
TypeScript
45 lines
1.2 KiB
TypeScript
import { hasBlob, saveBlob } from '@/lib/offline-db'
|
|
|
|
/**
|
|
* Pre-cache a track's audio blob into IndexedDB.
|
|
* Only stores the blob (no metadata) so pre-cached tracks don't appear
|
|
* in the offline library, but the player still finds them via getTrackBlob().
|
|
* Best-effort — errors are silently swallowed.
|
|
*/
|
|
export async function precacheTrack(
|
|
trackId: string,
|
|
signal?: AbortSignal
|
|
): Promise<void> {
|
|
if (await hasBlob(trackId)) return
|
|
if (signal?.aborted) return
|
|
|
|
const res = await fetch(`/api/music/stream/${trackId}`, { signal })
|
|
if (!res.ok) return
|
|
|
|
const blob = await res.blob()
|
|
if (signal?.aborted) return
|
|
|
|
await saveBlob(trackId, blob)
|
|
}
|
|
|
|
/**
|
|
* Pre-cache the next N tracks in a queue sequentially.
|
|
* Sequential to avoid flooding bandwidth on mobile connections.
|
|
*/
|
|
export async function precacheUpcoming(
|
|
queue: { id: string }[],
|
|
currentIndex: number,
|
|
count: number,
|
|
signal: AbortSignal
|
|
): Promise<void> {
|
|
const upcoming = queue.slice(currentIndex + 1, currentIndex + 1 + count)
|
|
for (const track of upcoming) {
|
|
if (signal.aborted) return
|
|
try {
|
|
await precacheTrack(track.id, signal)
|
|
} catch {
|
|
// best-effort — continue with next track
|
|
}
|
|
}
|
|
}
|