refactor(lib,playback): fold utils/cache+themes into lib; playbackScheduleFormat→playback (drains utils/format)

This commit is contained in:
Psychotoxical
2026-06-30 20:33:25 +02:00
parent 31d4a87401
commit 6becd57798
47 changed files with 69 additions and 69 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ import { usePlayerStore } from '@/features/playback/store/playerStore';
import { useLyricsStore } from './store/lyricsStore';
import { useThemeStore } from './store/themeStore';
import { useInstalledThemesStore } from './store/installedThemesStore';
import { syncInjectedThemes } from './utils/themes/themeInjection';
import { syncInjectedThemes } from '@/lib/themes/themeInjection';
import { useThemeScheduler } from '@/app/hooks/useThemeScheduler';
import { useFontStore } from './store/fontStore';
import { getWindowKind } from './app/windowKind';
+2 -2
View File
@@ -3,9 +3,9 @@ import { configureStartupSplash } from './startupSplash';
import { setupMusicNetworkRuntime } from './musicNetworkBridge';
import { invoke } from '@tauri-apps/api/core';
import { getWindowKind } from './windowKind';
import { migrateThemeSelection } from '../utils/themes/themeMigration';
import { migrateThemeSelection } from '@/lib/themes/themeMigration';
import { getScheduledTheme, useThemeStore } from '../store/themeStore';
import { syncInjectedThemes } from '../utils/themes/themeInjection';
import { syncInjectedThemes } from '@/lib/themes/themeInjection';
import { useInstalledThemesStore, type InstalledTheme } from '../store/installedThemesStore';
/** Sync backend HTTP User-Agent from the main webview once at startup. */
+2 -2
View File
@@ -9,7 +9,7 @@ vi.mock('./windowKind', () => ({
getWindowKind: vi.fn(() => 'main'),
}));
vi.mock('../utils/themes/startupThemeAppearance', () => ({
vi.mock('@/lib/themes/startupThemeAppearance', () => ({
applyStartupSplashThemeFromStorage: vi.fn(() => 'mocha'),
}));
@@ -18,7 +18,7 @@ vi.mock('@tauri-apps/api/webviewWindow', () => ({
}));
import { getWindowKind } from './windowKind';
import { applyStartupSplashThemeFromStorage } from '../utils/themes/startupThemeAppearance';
import { applyStartupSplashThemeFromStorage } from '@/lib/themes/startupThemeAppearance';
describe('startupSplash', () => {
beforeEach(() => {
+1 -1
View File
@@ -1,5 +1,5 @@
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
import { applyStartupSplashThemeFromStorage } from '../utils/themes/startupThemeAppearance';
import { applyStartupSplashThemeFromStorage } from '@/lib/themes/startupThemeAppearance';
import { getWindowKind } from './windowKind';
export const STARTUP_SPLASH_ID = 'app-startup-splash';
+1 -1
View File
@@ -2,7 +2,7 @@ import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import ConfirmModal from './ConfirmModal';
import { readThemeMigrationNotice, clearThemeMigrationNotice } from '../utils/themes/themeMigration';
import { readThemeMigrationNotice, clearThemeMigrationNotice } from '@/lib/themes/themeMigration';
/**
* One-time, dismissible notice shown after the slim-bundle migration reset a
@@ -1,7 +1,7 @@
import { useEffect, useMemo, useState } from 'react';
import { getArtistInfoForServer } from '@/lib/api/subsonicArtists';
import type { SubsonicArtistInfo, SubsonicOpenArtistRef } from '@/lib/api/subsonicTypes';
import { makeCache } from '@/utils/cache/nowPlayingCache';
import { makeCache } from '@/lib/cache/nowPlayingCache';
const artistInfoCache = makeCache<SubsonicArtistInfo | null>();
@@ -3,7 +3,7 @@ import { Moon, Pause, Play, Sunrise } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { usePlayerStore } from '@/features/playback/store/playerStore';
import { usePlaybackDelayPress } from '@/features/playback/hooks/usePlaybackDelayPress';
import { usePlaybackScheduleRemaining } from '@/utils/format/playbackScheduleFormat';
import { usePlaybackScheduleRemaining } from '@/features/playback/utils/playbackScheduleFormat';
import PlaybackDelayModal from '@/features/playback/components/PlaybackDelayModal';
import PlaybackScheduleBadge from '@/features/playback/components/PlaybackScheduleBadge';
@@ -26,7 +26,7 @@ import { LyricsPane } from '@/features/lyrics';
import { usePlaybackDelayPress } from '@/features/playback/hooks/usePlaybackDelayPress';
import PlaybackDelayModal from '@/features/playback/components/PlaybackDelayModal';
import PlaybackScheduleBadge from '@/features/playback/components/PlaybackScheduleBadge';
import { usePlaybackScheduleRemaining } from '@/utils/format/playbackScheduleFormat';
import { usePlaybackScheduleRemaining } from '@/features/playback/utils/playbackScheduleFormat';
// ── Color extraction ──────────────────────────────────────────────────────────
// Samples a 16×16 canvas to find the most vibrant (highest-saturation,
@@ -5,7 +5,7 @@ import { resolveNpAlbum, resolveNpDiscography, resolveNpSongMeta, resolveNpTopSo
import { fetchBandsintownEvents, type BandsintownEvent } from '@/api/bandsintown';
import type { ArtistStats, TrackStats } from '@/music-network';
import { getMusicNetworkRuntimeOrNull } from '@/music-network';
import { makeCache } from '@/utils/cache/nowPlayingCache';
import { makeCache } from '@/lib/cache/nowPlayingCache';
import { shouldAttemptSubsonicForServer } from '@/utils/network/subsonicNetworkGuard';
import { useConnectionStatus } from '@/hooks/useConnectionStatus';
@@ -7,7 +7,7 @@ import { useAuthStore } from '@/store/authStore';
import { useShallow } from 'zustand/react/shallow';
import type { TFunction } from 'i18next';
import { formatPlaybackScheduleRemaining } from '@/utils/format/playbackScheduleFormat';
import { formatPlaybackScheduleRemaining } from '@/features/playback/utils/playbackScheduleFormat';
import { formatClockTime } from '@/lib/format/formatClockTime';
import {
isValidPlaybackSchedulePreviewTimestamp,
@@ -3,7 +3,7 @@ import { createPortal } from 'react-dom';
import { useTranslation } from 'react-i18next';
import { usePlayerStore } from '@/features/playback/store/playerStore';
import { useShallow } from 'zustand/react/shallow';
import { formatPlaybackScheduleRemaining } from '@/utils/format/playbackScheduleFormat';
import { formatPlaybackScheduleRemaining } from '@/features/playback/utils/playbackScheduleFormat';
import { useWindowVisibility } from '@/lib/hooks/useWindowVisibility';
export interface PlaybackScheduleBadgeProps {
@@ -19,7 +19,7 @@ import { useRadioMetadata } from '@/features/radio';
import { useRadioMprisSync } from '@/features/radio';
import { usePlaybackDelayPress } from '@/features/playback/hooks/usePlaybackDelayPress';
import PlaybackDelayModal from '@/features/playback/components/PlaybackDelayModal';
import { usePlaybackScheduleRemaining } from '@/utils/format/playbackScheduleFormat';
import { usePlaybackScheduleRemaining } from '@/features/playback/utils/playbackScheduleFormat';
import { usePreviewStore } from '@/features/playback/store/previewStore';
import { usePerfProbeFlags } from '@/utils/perf/perfFlags';
import { coerceOpenArtistRefs } from '@/lib/api/openArtistRefs';
@@ -7,7 +7,7 @@ import { useAutodjTransitionUi } from '@/features/playback/store/autodjTransitio
import { usePreviewStore } from '@/features/playback/store/previewStore';
import PlaybackScheduleBadge from '@/features/playback/components/PlaybackScheduleBadge';
import { usePlaybackDelayPress } from '@/features/playback/hooks/usePlaybackDelayPress';
import { usePlaybackScheduleRemaining } from '@/utils/format/playbackScheduleFormat';
import { usePlaybackScheduleRemaining } from '@/features/playback/utils/playbackScheduleFormat';
type RepeatMode = PlayerState['repeatMode'];
type PlayPauseBind = ReturnType<typeof usePlaybackDelayPress>['playPauseBind'];
@@ -8,7 +8,7 @@ import {
import { resolveQueueTrack } from '@/features/playback/store/queueTrackView';
import { invoke } from '@tauri-apps/api/core';
import { getMusicNetworkRuntimeOrNull } from '@/music-network';
import { setDeferHotCachePrefetch } from '@/utils/cache/hotCacheGate';
import { setDeferHotCachePrefetch } from '@/lib/cache/hotCacheGate';
import { notifyLibraryPlaybackHint } from '@/features/playback/store/libraryPlaybackHint';
import {
playListenSessionFinalize,
@@ -1,6 +1,6 @@
import type { Track } from '@/lib/media/trackTypes';
import { invoke } from '@tauri-apps/api/core';
import { setDeferHotCachePrefetch } from '@/utils/cache/hotCacheGate';
import { setDeferHotCachePrefetch } from '@/lib/cache/hotCacheGate';
import {
getPlaybackIndexKey,
playbackCacheKeyForTrack,
@@ -1,7 +1,7 @@
import { playbackReportStart, playbackReportStopped } from '@/features/playback/store/playbackReportSession';
import { invoke } from '@tauri-apps/api/core';
import { getMusicNetworkRuntimeOrNull } from '@/music-network';
import { setDeferHotCachePrefetch } from '@/utils/cache/hotCacheGate';
import { setDeferHotCachePrefetch } from '@/lib/cache/hotCacheGate';
import { orbitBulkGuard, orbitSnapshot } from '@/store/orbitRuntime';
import { sameQueueTrackId } from '@/features/playback/utils/playback/queueIdentity';
import {
@@ -38,7 +38,7 @@ const hoisted = vi.hoisted(() => {
});
vi.mock('@tauri-apps/api/core', () => ({ invoke: hoisted.invokeMock }));
vi.mock('@/utils/cache/hotCacheGate', () => ({ setDeferHotCachePrefetch: hoisted.setDeferHotCachePrefetchMock }));
vi.mock('@/lib/cache/hotCacheGate', () => ({ setDeferHotCachePrefetch: hoisted.setDeferHotCachePrefetchMock }));
vi.mock('@/features/playback/utils/playback/resolvePlaybackUrl', () => ({ resolvePlaybackUrl: hoisted.resolvePlaybackUrlMock }));
vi.mock('@/features/playback/utils/audio/resolveReplayGainDb', () => ({ resolveReplayGainDb: hoisted.resolveReplayGainDbMock }));
vi.mock('@/store/authStore', () => ({ useAuthStore: { getState: () => hoisted.auth } }));
+1 -1
View File
@@ -1,7 +1,7 @@
import { getSong } from '@/lib/api/subsonicLibrary';
import { invoke } from '@tauri-apps/api/core';
import { estimateLivePosition, orbitSnapshot } from '@/store/orbitRuntime';
import { setDeferHotCachePrefetch } from '@/utils/cache/hotCacheGate';
import { setDeferHotCachePrefetch } from '@/lib/cache/hotCacheGate';
import {
getPlaybackCacheServerKey,
getPlaybackIndexKey,
@@ -3,13 +3,13 @@ import { Check, RefreshCw, X } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { useThemeStore } from '@/store/themeStore';
import { useInstalledThemesStore } from '@/store/installedThemesStore';
import { uninstallTheme } from '@/utils/themes/uninstallTheme';
import { installThemeFromRegistry } from '@/utils/themes/installThemeFromRegistry';
import { uninstallTheme } from '@/lib/themes/uninstallTheme';
import { installThemeFromRegistry } from '@/lib/themes/installThemeFromRegistry';
import { useThemeUpdates } from '@/features/settings/hooks/useThemeUpdates';
import { useThemeAnimationRisk } from '@/features/settings/hooks/useThemeAnimationRisk';
import { showToast } from '@/utils/ui/toast';
import { AnimatedThemeBadge } from '@/features/settings/components/AnimatedThemeBadge';
import { FIXED_THEMES } from '@/utils/themes/fixedThemes';
import { FIXED_THEMES } from '@/lib/themes/fixedThemes';
/** Pull a 3-band swatch (bg / card / accent) out of an installed theme's CSS. */
function swatch(css: string): { bg: string; card: string; accent: string } {
@@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next';
import { invoke } from '@tauri-apps/api/core';
import { open } from '@tauri-apps/plugin-dialog';
import { useInstalledThemesStore } from '@/store/installedThemesStore';
import { validateThemePackage, type ValidatedTheme } from '@/utils/themes/validateThemePackage';
import { validateThemePackage, type ValidatedTheme } from '@/lib/themes/validateThemePackage';
import { showToast } from '@/utils/ui/toast';
import ConfirmModal from '@/components/ConfirmModal';
@@ -3,16 +3,16 @@ import { screen, waitFor, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { renderWithProviders } from '@/test/helpers/renderWithProviders';
import { ThemeStoreSection } from '@/features/settings/components/ThemeStoreSection';
import type { FetchRegistryResult, Registry, RegistryTheme } from '@/utils/themes/themeRegistry';
import type { FetchRegistryResult, Registry, RegistryTheme } from '@/lib/themes/themeRegistry';
// Control the registry the store browses so pagination/refresh are deterministic.
vi.mock('@/utils/themes/themeRegistry', () => ({
vi.mock('@/lib/themes/themeRegistry', () => ({
fetchRegistry: vi.fn(),
fetchThemeCss: vi.fn(async () => 'css'),
assetUrl: (p: string) => `https://raw.example/${p}`,
}));
import { fetchRegistry } from '@/utils/themes/themeRegistry';
import { fetchRegistry } from '@/lib/themes/themeRegistry';
const fetchRegistryMock = vi.mocked(fetchRegistry);
@@ -13,9 +13,9 @@ import {
assetUrl,
fetchRegistry,
type RegistryTheme,
} from '@/utils/themes/themeRegistry';
import { installThemeFromRegistry } from '@/utils/themes/installThemeFromRegistry';
import { uninstallTheme } from '@/utils/themes/uninstallTheme';
} from '@/lib/themes/themeRegistry';
import { installThemeFromRegistry } from '@/lib/themes/installThemeFromRegistry';
import { uninstallTheme } from '@/lib/themes/uninstallTheme';
import { isNewer } from '@/utils/componentHelpers/appUpdaterHelpers';
type ModeFilter = 'all' | 'dark' | 'light';
@@ -5,7 +5,7 @@ import { useThemeStore } from '@/store/themeStore';
import { useInstalledThemesStore } from '@/store/installedThemesStore';
import CustomSelect from '@/ui/CustomSelect';
import BackToTopButton from '@/ui/BackToTopButton';
import { FIXED_THEMES } from '@/utils/themes/fixedThemes';
import { FIXED_THEMES } from '@/lib/themes/fixedThemes';
import { InstalledThemes } from '@/features/settings/components/InstalledThemes';
import { ThemeImportSection } from '@/features/settings/components/ThemeImportSection';
import { ThemeStoreSection } from '@/features/settings/components/ThemeStoreSection';
@@ -1,12 +1,12 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { renderHook, waitFor } from '@testing-library/react';
vi.mock('@/utils/themes/themeRegistry', () => ({
vi.mock('@/lib/themes/themeRegistry', () => ({
fetchRegistry: vi.fn(),
getCachedRegistry: vi.fn(() => null),
}));
import { fetchRegistry, type Registry } from '@/utils/themes/themeRegistry';
import { fetchRegistry, type Registry } from '@/lib/themes/themeRegistry';
import { useInstalledThemesStore, type InstalledTheme } from '@/store/installedThemesStore';
import { useThemeUpdates, themeUpdateSignature } from '@/features/settings/hooks/useThemeUpdates';
@@ -1,6 +1,6 @@
import { useEffect, useMemo, useState } from 'react';
import { isNewer } from '@/utils/componentHelpers/appUpdaterHelpers';
import { fetchRegistry, getCachedRegistry, type Registry, type RegistryTheme } from '@/utils/themes/themeRegistry';
import { fetchRegistry, getCachedRegistry, type Registry, type RegistryTheme } from '@/lib/themes/themeRegistry';
import { useInstalledThemesStore } from '@/store/installedThemesStore';
// Refresh the registry from source once per app launch (not just from the
+2 -2
View File
@@ -13,7 +13,7 @@ import {
bumpHotCachePreviousTrackGrace,
clearHotCachePreviousGrace,
getDeferHotCachePrefetch,
} from './utils/cache/hotCacheGate';
} from '@/lib/cache/hotCacheGate';
import {
PREFETCH_AHEAD,
type PrefetchJob,
@@ -27,7 +27,7 @@ import {
scheduleAnalysisQueuePruneFromPlaybackQueue,
resetAnalysisPruneState,
} from './hotCachePrefetch/analysisPrune';
import { reconcileEphemeralCache } from './utils/cache/ephemeralTierReconcile';
import { reconcileEphemeralCache } from '@/lib/cache/ephemeralTierReconcile';
import { hasLocalPersistentPlaybackBytes } from '@/store/localPlaybackResolve';
/** Periodic index↔disk sync (stale rows + empty dirs); unindexed files evicted only on budget pressure. */
@@ -1,6 +1,6 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { reconcileEphemeralCache } from './ephemeralTierReconcile';
import { useLocalPlaybackStore } from '../../store/localPlaybackStore';
import { reconcileEphemeralCache } from '@/lib/cache/ephemeralTierReconcile';
import { useLocalPlaybackStore } from '@/store/localPlaybackStore';
vi.mock('@tauri-apps/api/core', () => ({
invoke: vi.fn(),
@@ -1,6 +1,6 @@
import { invoke } from '@tauri-apps/api/core';
import { useLocalPlaybackStore } from '../../store/localPlaybackStore';
import { parseLocalPlaybackEntryKey } from '../../store/localPlaybackKeys';
import { useLocalPlaybackStore } from '@/store/localPlaybackStore';
import { parseLocalPlaybackEntryKey } from '@/store/localPlaybackKeys';
import { getMediaDir } from '@/lib/media/mediaDir';
export interface EphemeralReconcileResult {
@@ -1,12 +1,12 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
vi.mock('./themeRegistry', () => ({ fetchThemeCss: vi.fn() }));
vi.mock('./themeInjection', () => ({ validateThemeCss: vi.fn() }));
vi.mock('@/lib/themes/themeRegistry', () => ({ fetchThemeCss: vi.fn() }));
vi.mock('@/lib/themes/themeInjection', () => ({ validateThemeCss: vi.fn() }));
import { fetchThemeCss, type RegistryTheme } from './themeRegistry';
import { validateThemeCss } from './themeInjection';
import { useInstalledThemesStore } from '../../store/installedThemesStore';
import { installThemeFromRegistry } from './installThemeFromRegistry';
import { fetchThemeCss, type RegistryTheme } from '@/lib/themes/themeRegistry';
import { validateThemeCss } from '@/lib/themes/themeInjection';
import { useInstalledThemesStore } from '@/store/installedThemesStore';
import { installThemeFromRegistry } from '@/lib/themes/installThemeFromRegistry';
const fetchCss = vi.mocked(fetchThemeCss);
const validate = vi.mocked(validateThemeCss);
@@ -1,6 +1,6 @@
import { fetchThemeCss, type RegistryTheme } from './themeRegistry';
import { validateThemeCss } from './themeInjection';
import { useInstalledThemesStore } from '../../store/installedThemesStore';
import { fetchThemeCss, type RegistryTheme } from '@/lib/themes/themeRegistry';
import { validateThemeCss } from '@/lib/themes/themeInjection';
import { useInstalledThemesStore } from '@/store/installedThemesStore';
export type InstallResult = 'ok' | 'invalid' | 'error';
@@ -1,13 +1,13 @@
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { BUILTIN_SPLASH_PALETTES } from '../../config/startupSplashPalettes';
import { BUILTIN_SPLASH_PALETTES } from '@/config/startupSplashPalettes';
import {
applyStartupSplashPalette,
resolveEffectiveThemeId,
resolveScheduledThemeId,
resolveSplashPalette,
} from './startupThemeAppearance';
} from '@/lib/themes/startupThemeAppearance';
describe('startupThemeAppearance', () => {
beforeEach(() => {
@@ -2,7 +2,7 @@ import {
BUILTIN_SPLASH_PALETTES,
BUILTIN_THEME_IDS,
type StartupSplashPalette,
} from '../../config/startupSplashPalettes';
} from '@/config/startupSplashPalettes';
export type PersistedThemeState = {
enableThemeScheduler: boolean;
@@ -8,8 +8,8 @@ import {
validateThemeCss,
injectTheme,
syncInjectedThemes,
} from './themeInjection';
import type { InstalledTheme } from '../../store/installedThemesStore';
} from '@/lib/themes/themeInjection';
import type { InstalledTheme } from '@/store/installedThemesStore';
const ATTR = 'data-installed-theme';
@@ -1,4 +1,4 @@
import type { InstalledTheme } from '../../store/installedThemesStore';
import type { InstalledTheme } from '@/store/installedThemesStore';
/**
* Runtime CSS injection for installed community themes. Built-in themes are
@@ -12,8 +12,8 @@ import {
migrateThemeSelection,
readThemeMigrationNotice,
clearThemeMigrationNotice,
} from './themeMigration';
import { FIXED_THEMES } from '@/utils/themes/fixedThemes';
} from '@/lib/themes/themeMigration';
import { FIXED_THEMES } from '@/lib/themes/fixedThemes';
const THEME_KEY = 'psysonic_theme';
const INSTALLED_KEY = 'psysonic_installed_themes';
@@ -1,4 +1,4 @@
import { FIXED_THEMES } from '@/utils/themes/fixedThemes';
import { FIXED_THEMES } from '@/lib/themes/fixedThemes';
/**
* Slim-bundle theme migration (C5). Older builds bundled ~80 palettes that now
@@ -3,7 +3,7 @@
* stale-on-error fallback, and malformed-cache tolerance.
*/
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { fetchRegistry, getCachedRegistry } from './themeRegistry';
import { fetchRegistry, getCachedRegistry } from '@/lib/themes/themeRegistry';
const CACHE_KEY = 'psysonic_theme_registry_cache';
const NOW = 1_000_000_000;
@@ -3,9 +3,9 @@
* selection slot that referenced it (active + scheduler day/night).
*/
import { beforeEach, describe, expect, it } from 'vitest';
import { uninstallTheme } from './uninstallTheme';
import { useInstalledThemesStore, type InstalledTheme } from '../../store/installedThemesStore';
import { useThemeStore } from '../../store/themeStore';
import { uninstallTheme } from '@/lib/themes/uninstallTheme';
import { useInstalledThemesStore, type InstalledTheme } from '@/store/installedThemesStore';
import { useThemeStore } from '@/store/themeStore';
function mk(id: string, mode: 'dark' | 'light' = 'dark'): InstalledTheme {
return { id, name: id, author: 'a', version: '1.0.0', description: '', mode, css: `[data-theme='${id}']{--accent:#fff;}`, installedAt: 0 };
@@ -1,5 +1,5 @@
import { useInstalledThemesStore } from '../../store/installedThemesStore';
import { useThemeStore } from '../../store/themeStore';
import { useInstalledThemesStore } from '@/store/installedThemesStore';
import { useThemeStore } from '@/store/themeStore';
/**
* Uninstall a community theme and repair any theme selection that pointed at it.
@@ -1,5 +1,5 @@
import { describe, it, expect } from 'vitest';
import { validateThemePackage } from './validateThemePackage';
import { validateThemePackage } from '@/lib/themes/validateThemePackage';
/** A minimal floor-passing theme.css for `id`. */
function css(id = 'my-theme'): string {
@@ -1,5 +1,5 @@
import { validateThemeCss } from './themeInjection';
import { FIXED_THEMES } from '@/utils/themes/fixedThemes';
import { validateThemeCss } from '@/lib/themes/themeInjection';
import { FIXED_THEMES } from '@/lib/themes/fixedThemes';
/**
* Validation for a locally imported theme package (a .zip holding manifest.json
+2 -2
View File
@@ -2,7 +2,7 @@ import type { QueueItemRef } from '@/lib/media/trackTypes';
import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
import { invoke } from '@tauri-apps/api/core';
import { isHotCachePreviousTrackUnderGrace } from '../utils/cache/hotCacheGate';
import { isHotCachePreviousTrackUnderGrace } from '@/lib/cache/hotCacheGate';
import { emitAnalysisStorageChanged } from './analysisSync';
import { useAuthStore } from './authStore';
import { localPlaybackEntryKey, parseLocalPlaybackEntryKey } from './localPlaybackKeys';
@@ -15,7 +15,7 @@ import {
evictEphemeralOrphansToFit,
getEphemeralDiskBytes,
reconcileEphemeralCache,
} from '../utils/cache/ephemeralTierReconcile';
} from '@/lib/cache/ephemeralTierReconcile';
export type LocalPlaybackTier = 'ephemeral' | 'library' | 'favorite-auto';