Files
Psychotoxical-psysonic/src/store/lastfmLovedCacheStorage.ts
T
cucadmuh 75e2c7f9c6 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)
2026-06-03 21:55:20 +03:00

56 lines
1.8 KiB
TypeScript

/**
* 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
}
}