import * as FileSystem from 'expo-file-system'; import * as SecureStore from 'expo-secure-store'; export type Quality = 'original' | 'high' | 'medium' | 'low'; export const QUALITIES: readonly Quality[] = ['original', 'high', 'medium', 'low']; /** Качество звука по типу сети и для загрузок (настройка устройства, на сервер не уходит). */ export interface QualityPrefs { wifi: Quality; cellular: Quality; download: Quality; } const QUALITY_KEY = 'pipu.quality'; const CLEAR_CACHE_KEY = 'pipu.cache.clear'; const DEFAULT_QUALITY: QualityPrefs = { wifi: 'high', cellular: 'medium', download: 'high' }; let quality: QualityPrefs = DEFAULT_QUALITY; let loaded: Promise | null = null; const listeners = new Set<() => void>(); export const qualityPrefs = { get: () => quality, subscribe(fn: () => void) { listeners.add(fn); return () => listeners.delete(fn); }, async load(): Promise { loaded ??= SecureStore.getItemAsync(QUALITY_KEY) .then((raw) => { if (raw) quality = { ...DEFAULT_QUALITY, ...(JSON.parse(raw) as Partial) }; }) .catch(() => undefined); await loaded; return quality; }, async set(patch: Partial) { quality = { ...quality, ...patch }; for (const fn of listeners) fn(); await SecureStore.setItemAsync(QUALITY_KEY, JSON.stringify(quality)); }, }; /** * Кэш недавних стримов ExoPlayer (KotlinAudio кладёт его в `cacheDir/TrackPlayer`). Пока сервис плеера жив, * SimpleCache держит индекс в памяти — поэтому очистка откладывается до следующего холодного запуска. */ const PLAYER_CACHE = `${FileSystem.cacheDirectory}TrackPlayer`; export const playerCache = { async size(): Promise { const info = await FileSystem.getInfoAsync(PLAYER_CACHE, { size: true }).catch(() => null); return info?.exists ? (info.size ?? 0) : 0; }, async requestClear() { await SecureStore.setItemAsync(CLEAR_CACHE_KEY, '1'); }, async clearPending(): Promise { return (await SecureStore.getItemAsync(CLEAR_CACHE_KEY)) === '1'; }, /** Вызывается до setupPlayer, когда сервис ещё не запущен. */ async clearIfRequested() { if (!(await this.clearPending())) return; await FileSystem.deleteAsync(PLAYER_CACHE, { idempotent: true }).catch(() => undefined); await SecureStore.deleteItemAsync(CLEAR_CACHE_KEY); }, };