import { useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { invoke } from '@tauri-apps/api/core'; import { open as openDialog } from '@tauri-apps/plugin-dialog'; import { Download, FolderOpen, Trash2, X } from 'lucide-react'; import { useAuthStore } from '../../store/authStore'; import { countHotCacheTracks } from '../../store/hotCacheStore'; import { useLocalPlaybackStore } from '../../store/localPlaybackStore'; import { formatBytes, snapHotCacheMb } from '../../utils/format/formatBytes'; import SettingsSubSection from '../SettingsSubSection'; import CoverCacheStrategySection from './CoverCacheStrategySection'; export function StorageTab() { const { t } = useTranslation(); const auth = useAuthStore(); const clearHotCacheDisk = useLocalPlaybackStore(s => s.purgeEphemeralDisk); const localPlaybackEntries = useLocalPlaybackStore(s => s.entries); const [hotCacheBytes, setHotCacheBytes] = useState(null); const mediaDir = auth.mediaDir || null; /** Match ephemeral disk usage (all servers); resolve UUID vs URL index keys. */ const hotCacheTrackCount = useMemo( () => countHotCacheTracks(localPlaybackEntries), [localPlaybackEntries], ); const refreshHotCacheSize = useCallback(() => { invoke('get_media_tier_size', { tier: 'ephemeral', mediaDir }) .then(setHotCacheBytes) .catch(() => setHotCacheBytes(0)); }, [mediaDir]); useEffect(() => { refreshHotCacheSize(); }, [refreshHotCacheSize]); useEffect(() => { if (!auth.hotCacheEnabled) return; refreshHotCacheSize(); const interval = window.setInterval(refreshHotCacheSize, 15_000); return () => window.clearInterval(interval); }, [auth.hotCacheEnabled, refreshHotCacheSize]); useEffect(() => { if (!auth.hotCacheEnabled) return; const handle = window.setTimeout(refreshHotCacheSize, 400); return () => window.clearTimeout(handle); }, [localPlaybackEntries, auth.hotCacheEnabled, refreshHotCacheSize]); const pickMediaDir = async () => { const selected = await openDialog({ directory: true, multiple: false, title: t('settings.mediaDirChange'), }); if (selected && typeof selected === 'string') { auth.setMediaDir(selected); refreshHotCacheSize(); } }; const pickDownloadFolder = async () => { const selected = await openDialog({ directory: true, multiple: false, title: t('settings.pickFolderTitle') }); if (selected && typeof selected === 'string') { auth.setDownloadFolder(selected); } }; return ( <> } >
{t('settings.mediaDirDesc')}
{auth.mediaDir && ( )}
{auth.mediaDir && (
{t('settings.mediaDirHint')}
)}
} >
{t('settings.hotCacheTitle')}
{t('settings.hotCacheDisclaimer')}
{auth.hotCacheEnabled && (
{t('settings.cacheUsedHot')} {hotCacheBytes !== null ? formatBytes(hotCacheBytes) : '…'}
{t('settings.hotCacheTrackCount')} {hotCacheTrackCount}
{t('settings.hotCacheMaxMb')}
auth.setHotCacheMaxMb(parseInt(e.target.value, 10))} style={{ flex: 1, minWidth: 80, maxWidth: 200 }} id="hot-cache-max-mb-slider" /> {snapHotCacheMb(auth.hotCacheMaxMb)} MB
{t('settings.hotCacheDebounce')}
auth.setHotCacheDebounceSec(parseInt(e.target.value, 10))} style={{ flex: 1, minWidth: 80, maxWidth: 200 }} id="hot-cache-debounce-slider" /> {Math.min(600, Math.max(0, auth.hotCacheDebounceSec)) === 0 ? t('settings.hotCacheDebounceImmediate') : t('settings.hotCacheDebounceSeconds', { n: Math.min(600, Math.max(0, auth.hotCacheDebounceSec)) })}
)}
} >
{t('settings.downloadsFolderDesc')}
{auth.downloadFolder && ( )}
); }