Files
psysonic/src/store/offlineJobStore.ts
T
Psychotoxical ba670bd1e8 feat: fix UI freezes in ZIP and offline cache downloads
ZIP downloads (PlaylistDetail, Albums, NewReleases, RandomAlbums) now use
invoke('download_zip') via Rust streaming instead of fetch+blob+arrayBuffer,
eliminating JS heap saturation on large files. Progress shown in ZipDownloadOverlay.

Offline cache downloads (600+ songs) no longer freeze the UI: transient job
state moved to a separate non-persisted offlineJobStore, reducing localStorage
writes from ~1200 down to 2 for an entire download. Also adds playlist offline
toggle — clicking the cache button when already cached removes it from cache.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 22:33:23 +02:00

47 lines
1.3 KiB
TypeScript

import { create } from 'zustand';
export interface DownloadJob {
trackId: string;
albumId: string;
albumName: string;
trackTitle: string;
trackIndex: number;
totalTracks: number;
status: 'queued' | 'downloading' | 'done' | 'error';
}
interface OfflineJobState {
jobs: DownloadJob[];
bulkProgress: Record<string, { done: number; total: number }>;
cancelDownload: (albumId: string) => void;
cancelAllDownloads: () => void;
}
// Module-level cancellation set — checked by downloadAlbum before each batch.
export const cancelledDownloads = new Set<string>();
export const useOfflineJobStore = create<OfflineJobState>()((set, get) => ({
jobs: [],
bulkProgress: {},
cancelDownload: (albumId) => {
cancelledDownloads.add(albumId);
// Remove queued (not yet started) jobs immediately so the counter drops.
set(state => ({
jobs: state.jobs.filter(j => !(j.albumId === albumId && j.status === 'queued')),
}));
},
cancelAllDownloads: () => {
const unique = [...new Set(
get().jobs
.filter(j => j.status === 'queued' || j.status === 'downloading')
.map(j => j.albumId),
)];
unique.forEach(id => cancelledDownloads.add(id));
set(state => ({
jobs: state.jobs.filter(j => j.status !== 'queued'),
}));
},
}));