mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-21 23:05:46 +00:00
fix(player): persist player prefs outside quota-bound queue blob (#958)
* fix(player): persist volume/repeat in dedicated localStorage key Player prefs were bundled with the full queue blob in psysonic-player; after thin-state #872 a large queue can exceed the quota and safeStorage silently drops every write, so volume and repeat mode stopped surviving restarts. Move them to psysonic_player_prefs, gate main-blob writes until rehydrate, and sync volume to the Rust engine on startup. * fix(player): split queue visibility and Last.fm cache from main persist blob Move isQueueVisible and lastfmLovedCache to dedicated localStorage keys so they keep saving when psysonic-player hits the quota on large queues. Include the new keys in settings backup export. * docs: note player prefs persist fix in CHANGELOG and credits (PR #958)
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Last.fm loved-track cache keyed by `${title}::${artist}`. Kept out of the
|
||||
* main `psysonic-player` blob so a large queue cannot block writes (thin-state
|
||||
* #872 quota issue). Same split-storage pattern as `playerPrefsStorage.ts`.
|
||||
*/
|
||||
const CACHE_STORAGE_KEY = 'psysonic_lastfm_loved_cache';
|
||||
const LEGACY_PLAYER_STORAGE_KEY = 'psysonic-player';
|
||||
|
||||
function sanitizeCache(raw: unknown): Record<string, boolean> {
|
||||
if (!raw || typeof raw !== 'object') return {};
|
||||
const out: Record<string, boolean> = {};
|
||||
for (const [key, value] of Object.entries(raw as Record<string, unknown>)) {
|
||||
if (typeof key === 'string' && key.length > 0 && typeof value === 'boolean') {
|
||||
out[key] = value;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function readLegacyCacheFromPlayerBlob(): Record<string, boolean> | null {
|
||||
if (typeof window === 'undefined') return null;
|
||||
try {
|
||||
const raw = window.localStorage.getItem(LEGACY_PLAYER_STORAGE_KEY);
|
||||
if (!raw) return null;
|
||||
const parsed = JSON.parse(raw) as { state?: { lastfmLovedCache?: unknown } };
|
||||
const cache = parsed.state?.lastfmLovedCache;
|
||||
if (!cache) return null;
|
||||
const sanitized = sanitizeCache(cache);
|
||||
return Object.keys(sanitized).length > 0 ? sanitized : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function readInitialLastfmLovedCache(): Record<string, boolean> {
|
||||
if (typeof window === 'undefined') return {};
|
||||
|
||||
try {
|
||||
const raw = window.localStorage.getItem(CACHE_STORAGE_KEY);
|
||||
if (raw) return sanitizeCache(JSON.parse(raw));
|
||||
} catch {
|
||||
// fall through to legacy blob / empty
|
||||
}
|
||||
|
||||
return readLegacyCacheFromPlayerBlob() ?? {};
|
||||
}
|
||||
|
||||
export function persistLastfmLovedCache(cache: Record<string, boolean>): void {
|
||||
if (typeof window === 'undefined') return;
|
||||
try {
|
||||
window.localStorage.setItem(CACHE_STORAGE_KEY, JSON.stringify(sanitizeCache(cache)));
|
||||
} catch {
|
||||
// best-effort
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user