mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-21 23:05:46 +00:00
75e2c7f9c6
* 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)
56 lines
1.8 KiB
TypeScript
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
|
|
}
|
|
}
|