From 2756cb769883d006e72f2708a49d9d3bde5e5ca2 Mon Sep 17 00:00:00 2001 From: Psychotoxical <171614930+Psychotoxical@users.noreply.github.com> Date: Tue, 30 Jun 2026 17:06:03 +0200 Subject: [PATCH] refactor(lib): relocate the local-library subsystem utils/library -> lib/library utils/library is the local-index query/browse/sync engine -- feature-free shared infra consumed by the album, search, genre, artist and offline features. With its last feature edges removed (queue resolver, shuffleArray, albumBrowseCatalogChunk, genreBrowsePlayback all relocated earlier this branch), the whole directory is pure infra and belongs under lib/. Whole-directory move (58 files, 76 consumers rewritten) via resolver-based rewrite: cross-cluster relatives absolutized to @/, intra-cluster siblings kept relative. utils/library is gone; lib/library imports zero @/features. Three stale doc comments in the album/search/artist barrels repointed. tsc 0, lint 0, full suite 2353/2353, production build OK. --- src/app/MainApp.tsx | 2 +- src/components/GenreFilterBar.tsx | 2 +- src/components/SongInfoModal.tsx | 4 ++-- src/components/YearFilterButton.tsx | 2 +- src/cover/prefetchStrategy.ts | 4 ++-- src/cover/useCoverArtPrefetch.ts | 2 +- src/features/album/components/AlbumHeader.tsx | 4 ++-- .../album/components/LosslessAlbumsRail.tsx | 4 ++-- src/features/album/hooks/useAlbumBrowseData.ts | 8 ++++---- src/features/album/hooks/useAlbumBrowseFilters.ts | 2 +- .../album/hooks/useAlbumCatalogYearBounds.ts | 4 ++-- src/features/album/hooks/useAlbumDetailData.ts | 2 +- .../album/hooks/useBrowseAlbumTextSearch.ts | 2 +- src/features/album/hooks/useGenreAlbumBrowse.ts | 4 ++-- src/features/album/index.ts | 2 +- src/features/album/pages/AlbumDetail.tsx | 4 ++-- src/features/album/pages/Albums.tsx | 8 ++++---- src/features/album/pages/LosslessAlbums.tsx | 4 ++-- src/features/album/pages/RandomAlbums.tsx | 2 +- .../album/store/albumBrowseSessionStore.ts | 2 +- .../album/utils/albumBrowseCatalogChunk.ts | 4 ++-- src/features/artist/hooks/useArtistDetailData.ts | 4 ++-- .../artist/hooks/useArtistsBrowseCatalog.ts | 2 +- .../artist/hooks/useBrowseArtistTextSearch.ts | 2 +- src/features/artist/index.ts | 2 +- src/features/artist/pages/ArtistDetail.tsx | 2 +- .../nowPlaying/utils/nowPlayingMetadataResolve.ts | 4 ++-- .../offline/utils/offlineAlbumBrowseCatalog.ts | 2 +- .../offline/utils/offlineLibraryHelpers.ts | 2 +- .../offline/utils/offlineLibraryIndexLoad.ts | 2 +- src/features/offline/utils/offlineLocalBrowse.ts | 12 ++++++------ .../offline/utils/offlineMediaResolve.test.ts | 2 +- src/features/offline/utils/offlineMediaResolve.ts | 2 +- .../offline/utils/offlinePlaylistBrowse.ts | 2 +- src/features/offline/utils/offlineStarredLoad.ts | 2 +- .../offline/utils/resumeIncompleteOfflinePins.ts | 2 +- .../playback/store/playListenSession.test.ts | 4 ++-- src/features/playback/store/playListenSession.ts | 2 +- src/features/playback/store/queueTrackResolver.ts | 4 ++-- .../utils/playback/genreBrowsePlayback.test.ts | 12 ++++++------ .../playback/utils/playback/genreBrowsePlayback.ts | 10 +++++----- .../queue/components/QueueCurrentTrack.tsx | 2 +- .../queue/hooks/useQueueTrackEnrichment.ts | 4 ++-- src/features/search/components/LiveSearch.tsx | 10 +++++----- src/features/search/index.ts | 2 +- src/features/search/pages/SearchBrowsePage.tsx | 14 +++++++------- .../components/AnalyticsStrategySection.tsx | 2 +- .../components/CoverCacheStrategySection.tsx | 4 ++-- .../components/ServerLibraryIndexControls.tsx | 2 +- src/features/settings/components/ServersTab.tsx | 2 +- src/hooks/tauriBridge/useLibraryDevSyncLog.ts | 2 +- src/hooks/useLibraryAnalysisBackfill.ts | 2 +- src/hooks/useLibraryCoverBackfill.ts | 4 ++-- src/hooks/useLibraryIndexSync.ts | 6 +++--- src/hooks/useSongBrowseList.test.ts | 4 ++-- src/hooks/useSongBrowseList.ts | 4 ++-- src/lib/api/navidromeBrowse.ts | 2 +- src/lib/api/subsonicScrobble.ts | 2 +- src/lib/api/subsonicSearch.ts | 2 +- src/lib/api/subsonicStarRating.ts | 4 ++-- src/lib/api/subsonicStatistics.ts | 2 +- .../library/advancedSearchLocal.test.ts | 0 src/{utils => lib}/library/advancedSearchLocal.ts | 0 .../library/albumBrowseCatalogChunk.test.ts | 0 src/{utils => lib}/library/albumBrowseFilters.ts | 0 .../library/albumBrowseGenreOptions.test.ts | 0 src/{utils => lib}/library/albumBrowseLoad.test.ts | 0 src/{utils => lib}/library/albumBrowseLoad.ts | 0 src/{utils => lib}/library/albumBrowseLocal.ts | 0 src/{utils => lib}/library/albumBrowseNetwork.ts | 0 src/{utils => lib}/library/albumBrowseSort.test.ts | 0 src/{utils => lib}/library/albumBrowseSort.ts | 0 .../library/albumBrowseStarredCache.ts | 0 .../library/albumBrowseStarredFetch.ts | 0 src/{utils => lib}/library/albumBrowseTypes.ts | 0 .../library/albumCatalogYearBounds.ts | 0 .../library/albumCompilation.test.ts | 0 src/{utils => lib}/library/albumCompilation.ts | 0 src/{utils => lib}/library/albumYearFilter.test.ts | 0 src/{utils => lib}/library/albumYearFilter.ts | 0 src/{utils => lib}/library/analysisStrategy.ts | 0 .../library/browseTextSearch.test.ts | 0 src/{utils => lib}/library/browseTextSearch.ts | 0 src/{utils => lib}/library/composerBrowse.test.ts | 0 src/{utils => lib}/library/composerBrowse.ts | 0 src/{utils => lib}/library/coverBackfillWake.ts | 0 src/{utils => lib}/library/coverStrategy.ts | 0 .../library/genreAlbumBrowse.test.ts | 0 src/{utils => lib}/library/genreAlbumBrowse.ts | 0 .../library/genreCatalogCountsCache.test.ts | 0 .../library/genreCatalogCountsCache.ts | 2 +- src/{utils => lib}/library/genreColor.ts | 0 src/{utils => lib}/library/genreTags.test.ts | 0 src/{utils => lib}/library/genreTags.ts | 0 .../library/libraryCoverBackfillPolicy.ts | 2 +- src/{utils => lib}/library/libraryDevLog.test.ts | 0 src/{utils => lib}/library/libraryDevLog.ts | 0 src/{utils => lib}/library/libraryReady.test.ts | 0 src/{utils => lib}/library/libraryReady.ts | 2 +- src/{utils => lib}/library/librarySession.test.ts | 0 src/{utils => lib}/library/librarySession.ts | 12 ++++++------ .../library/librarySyncQueue.test.ts | 0 src/{utils => lib}/library/librarySyncQueue.ts | 0 src/{utils => lib}/library/liveSearchDebug.test.ts | 0 src/{utils => lib}/library/liveSearchDebug.ts | 2 +- src/{utils => lib}/library/liveSearchLocal.test.ts | 0 src/{utils => lib}/library/liveSearchLocal.ts | 0 src/{utils => lib}/library/losslessFormats.ts | 0 src/{utils => lib}/library/losslessMode.ts | 0 src/{utils => lib}/library/patchOnUse.test.ts | 0 src/{utils => lib}/library/patchOnUse.ts | 2 +- .../library/searchQueryFtsSafe.test.ts | 0 src/{utils => lib}/library/searchQueryFtsSafe.ts | 0 src/{utils => lib}/library/searchRace.live.test.ts | 0 src/{utils => lib}/library/searchRace.test.ts | 0 src/{utils => lib}/library/searchRace.ts | 0 .../library/starredAlbumIndexSync.ts | 0 src/{utils => lib}/library/trackEnrichment.test.ts | 2 +- src/{utils => lib}/library/trackEnrichment.ts | 6 +++--- src/pages/Composers.tsx | 2 +- src/pages/GenreDetail.tsx | 2 +- src/pages/Genres.tsx | 4 ++-- src/pages/Home.tsx | 2 +- src/pages/NewReleases.tsx | 2 +- src/store/analysisStrategyStore.test.ts | 2 +- src/store/analysisStrategyStore.ts | 2 +- src/store/coverStrategyStore.ts | 2 +- src/utils/queue/timelineBootstrapReady.test.ts | 4 ++-- src/utils/queue/timelineBootstrapReady.ts | 2 +- 129 files changed, 139 insertions(+), 139 deletions(-) rename src/{utils => lib}/library/advancedSearchLocal.test.ts (100%) rename src/{utils => lib}/library/advancedSearchLocal.ts (100%) rename src/{utils => lib}/library/albumBrowseCatalogChunk.test.ts (100%) rename src/{utils => lib}/library/albumBrowseFilters.ts (100%) rename src/{utils => lib}/library/albumBrowseGenreOptions.test.ts (100%) rename src/{utils => lib}/library/albumBrowseLoad.test.ts (100%) rename src/{utils => lib}/library/albumBrowseLoad.ts (100%) rename src/{utils => lib}/library/albumBrowseLocal.ts (100%) rename src/{utils => lib}/library/albumBrowseNetwork.ts (100%) rename src/{utils => lib}/library/albumBrowseSort.test.ts (100%) rename src/{utils => lib}/library/albumBrowseSort.ts (100%) rename src/{utils => lib}/library/albumBrowseStarredCache.ts (100%) rename src/{utils => lib}/library/albumBrowseStarredFetch.ts (100%) rename src/{utils => lib}/library/albumBrowseTypes.ts (100%) rename src/{utils => lib}/library/albumCatalogYearBounds.ts (100%) rename src/{utils => lib}/library/albumCompilation.test.ts (100%) rename src/{utils => lib}/library/albumCompilation.ts (100%) rename src/{utils => lib}/library/albumYearFilter.test.ts (100%) rename src/{utils => lib}/library/albumYearFilter.ts (100%) rename src/{utils => lib}/library/analysisStrategy.ts (100%) rename src/{utils => lib}/library/browseTextSearch.test.ts (100%) rename src/{utils => lib}/library/browseTextSearch.ts (100%) rename src/{utils => lib}/library/composerBrowse.test.ts (100%) rename src/{utils => lib}/library/composerBrowse.ts (100%) rename src/{utils => lib}/library/coverBackfillWake.ts (100%) rename src/{utils => lib}/library/coverStrategy.ts (100%) rename src/{utils => lib}/library/genreAlbumBrowse.test.ts (100%) rename src/{utils => lib}/library/genreAlbumBrowse.ts (100%) rename src/{utils => lib}/library/genreCatalogCountsCache.test.ts (100%) rename src/{utils => lib}/library/genreCatalogCountsCache.ts (97%) rename src/{utils => lib}/library/genreColor.ts (100%) rename src/{utils => lib}/library/genreTags.test.ts (100%) rename src/{utils => lib}/library/genreTags.ts (100%) rename src/{utils => lib}/library/libraryCoverBackfillPolicy.ts (93%) rename src/{utils => lib}/library/libraryDevLog.test.ts (100%) rename src/{utils => lib}/library/libraryDevLog.ts (100%) rename src/{utils => lib}/library/libraryReady.test.ts (100%) rename src/{utils => lib}/library/libraryReady.ts (97%) rename src/{utils => lib}/library/librarySession.test.ts (100%) rename src/{utils => lib}/library/librarySession.ts (92%) rename src/{utils => lib}/library/librarySyncQueue.test.ts (100%) rename src/{utils => lib}/library/librarySyncQueue.ts (100%) rename src/{utils => lib}/library/liveSearchDebug.test.ts (100%) rename src/{utils => lib}/library/liveSearchDebug.ts (94%) rename src/{utils => lib}/library/liveSearchLocal.test.ts (100%) rename src/{utils => lib}/library/liveSearchLocal.ts (100%) rename src/{utils => lib}/library/losslessFormats.ts (100%) rename src/{utils => lib}/library/losslessMode.ts (100%) rename src/{utils => lib}/library/patchOnUse.test.ts (100%) rename src/{utils => lib}/library/patchOnUse.ts (94%) rename src/{utils => lib}/library/searchQueryFtsSafe.test.ts (100%) rename src/{utils => lib}/library/searchQueryFtsSafe.ts (100%) rename src/{utils => lib}/library/searchRace.live.test.ts (100%) rename src/{utils => lib}/library/searchRace.test.ts (100%) rename src/{utils => lib}/library/searchRace.ts (100%) rename src/{utils => lib}/library/starredAlbumIndexSync.ts (100%) rename src/{utils => lib}/library/trackEnrichment.test.ts (99%) rename src/{utils => lib}/library/trackEnrichment.ts (97%) diff --git a/src/app/MainApp.tsx b/src/app/MainApp.tsx index cfc782bf..66c23a31 100644 --- a/src/app/MainApp.tsx +++ b/src/app/MainApp.tsx @@ -22,7 +22,7 @@ import { runLegacyOfflineFileMigration } from '@/features/offline'; import { reconcileLibraryTierForServer } from '@/features/offline'; import { initMiniPlayerBridgeOnMain } from '@/features/miniPlayer'; import { runAdvancedModeMigration } from '../utils/migrations/advancedModeMigration'; -import { bootstrapAllIndexedServers } from '../utils/library/librarySession'; +import { bootstrapAllIndexedServers } from '@/lib/library/librarySession'; import { hydrateQueueFromIndex } from '@/features/playback/store/queueRestore'; import { useLibraryAnalysisBackfill } from '../hooks/useLibraryAnalysisBackfill'; import { useCoverArtPrefetch } from '../cover/useCoverArtPrefetch'; diff --git a/src/components/GenreFilterBar.tsx b/src/components/GenreFilterBar.tsx index dbf567c9..a21f0920 100644 --- a/src/components/GenreFilterBar.tsx +++ b/src/components/GenreFilterBar.tsx @@ -1,5 +1,5 @@ import { getGenres } from '@/lib/api/subsonicGenres'; -import type { GenreFilterOption } from '../utils/library/albumBrowseLoad'; +import type { GenreFilterOption } from '@/lib/library/albumBrowseLoad'; import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; import { createPortal } from 'react-dom'; import { Check, Filter, X } from 'lucide-react'; diff --git a/src/components/SongInfoModal.tsx b/src/components/SongInfoModal.tsx index 2ab44a1e..968db189 100644 --- a/src/components/SongInfoModal.tsx +++ b/src/components/SongInfoModal.tsx @@ -14,13 +14,13 @@ import { copyTextToClipboard } from '../utils/server/serverMagicString'; import { showToast } from '../utils/ui/toast'; import { formatTrackTime } from '@/lib/format/formatDuration'; import { formatLastSeen } from '../utils/componentHelpers/userMgmtHelpers'; -import { libraryIsReady } from '../utils/library/libraryReady'; +import { libraryIsReady } from '@/lib/library/libraryReady'; import { formatQueueMoodLabels, parseTrackEnrichmentFacts, resolveQueueBpm, type ParsedTrackEnrichment, -} from '../utils/library/trackEnrichment'; +} from '@/lib/library/trackEnrichment'; import i18n from '@/lib/i18n'; function formatSize(bytes?: number): string | null { diff --git a/src/components/YearFilterButton.tsx b/src/components/YearFilterButton.tsx index 1c05b1d6..0ac11a36 100644 --- a/src/components/YearFilterButton.tsx +++ b/src/components/YearFilterButton.tsx @@ -12,7 +12,7 @@ import { normalizeAlbumYearToFieldChange, resolveAlbumYearBounds, stepAlbumYearField, -} from '../utils/library/albumYearFilter'; +} from '@/lib/library/albumYearFilter'; interface Props { from: string; diff --git a/src/cover/prefetchStrategy.ts b/src/cover/prefetchStrategy.ts index 28a85351..1cca617a 100644 --- a/src/cover/prefetchStrategy.ts +++ b/src/cover/prefetchStrategy.ts @@ -1,8 +1,8 @@ -import type { CoverCacheStrategy } from '../utils/library/coverStrategy'; +import type { CoverCacheStrategy } from '@/lib/library/coverStrategy'; import { coverStrategyAllowsLibraryBackfill, coverStrategyAllowsRoutePrefetch, -} from '../utils/library/coverStrategy'; +} from '@/lib/library/coverStrategy'; /** @deprecated Use `coverStrategyAllowsRoutePrefetch` */ export function coverPrefetchStrategyAllowsRoutePrefetch( diff --git a/src/cover/useCoverArtPrefetch.ts b/src/cover/useCoverArtPrefetch.ts index 6fef1ac5..1a697c25 100644 --- a/src/cover/useCoverArtPrefetch.ts +++ b/src/cover/useCoverArtPrefetch.ts @@ -1,6 +1,6 @@ import { useEffect } from 'react'; import { coverCacheStats } from '../api/coverCache'; -import { coverStrategyAllowsRoutePrefetch } from '../utils/library/coverStrategy'; +import { coverStrategyAllowsRoutePrefetch } from '@/lib/library/coverStrategy'; import { useCoverStrategyStore } from '../store/coverStrategyStore'; import { useAuthStore } from '../store/authStore'; import { coverPrefetchDrainBatch } from './prefetchRegistry'; diff --git a/src/features/album/components/AlbumHeader.tsx b/src/features/album/components/AlbumHeader.tsx index 23221d91..7d4a4c40 100644 --- a/src/features/album/components/AlbumHeader.tsx +++ b/src/features/album/components/AlbumHeader.tsx @@ -20,8 +20,8 @@ import { sanitizeHtml } from '@/lib/util/sanitizeHtml'; import { OpenArtistRefInline } from '@/features/artist'; import { tooltipAttrs } from '@/ui/tooltipAttrs'; import { offlineActionPolicy, type OfflineActionPolicy } from '@/features/offline'; -import { deriveAlbumGenreTags } from '@/utils/library/genreTags'; -import { genreColor } from '@/utils/library/genreColor'; +import { deriveAlbumGenreTags } from '@/lib/library/genreTags'; +import { genreColor } from '@/lib/library/genreColor'; /** True when the album artist label means "no single artist" — `getArtistInfo` * has nothing meaningful to return for these, so the Artist Bio entry is hidden. diff --git a/src/features/album/components/LosslessAlbumsRail.tsx b/src/features/album/components/LosslessAlbumsRail.tsx index 5d9813b1..ac96b594 100644 --- a/src/features/album/components/LosslessAlbumsRail.tsx +++ b/src/features/album/components/LosslessAlbumsRail.tsx @@ -5,8 +5,8 @@ import { ndListLosslessAlbumsPage } from '@/lib/api/navidromeBrowse'; import AlbumRow from '@/features/album/components/AlbumRow'; import { useAuthStore } from '@/store/authStore'; import { useLibraryIndexStore } from '@/store/libraryIndexStore'; -import { runLocalLosslessAlbums } from '@/utils/library/browseTextSearch'; -import { LOSSLESS_MODE_QUERY } from '@/utils/library/losslessMode'; +import { runLocalLosslessAlbums } from '@/lib/library/browseTextSearch'; +import { LOSSLESS_MODE_QUERY } from '@/lib/library/losslessMode'; interface Props { disableArtwork?: boolean; diff --git a/src/features/album/hooks/useAlbumBrowseData.ts b/src/features/album/hooks/useAlbumBrowseData.ts index 1b137b54..db5ece3b 100644 --- a/src/features/album/hooks/useAlbumBrowseData.ts +++ b/src/features/album/hooks/useAlbumBrowseData.ts @@ -13,8 +13,8 @@ import { } from '@/cover/coverTraffic'; import { coverEnsureQueueBacklog, coverEnsureResumePump, coverEnsureSubscribeBacklogDrain } from '@/cover/ensureQueue'; import { dedupeById } from '@/lib/util/dedupeById'; -import { albumBrowseCompScanComplete, albumBrowseCompFilterClientOnly } from '@/utils/library/albumCompilation'; -import type { AlbumCompFilter } from '@/utils/library/albumCompilation'; +import { albumBrowseCompScanComplete, albumBrowseCompFilterClientOnly } from '@/lib/library/albumCompilation'; +import type { AlbumCompFilter } from '@/lib/library/albumCompilation'; import { albumBrowseHasGenreFilter, albumBrowseHasServerFilters, @@ -24,12 +24,12 @@ import { fetchLocalAlbumCatalogChunk, type AlbumBrowseQuery, type GenreFilterOption, -} from '@/utils/library/albumBrowseLoad'; +} from '@/lib/library/albumBrowseLoad'; import { libraryScopeForServer } from '@/lib/api/subsonicClient'; import { ALBUM_YEAR_FILTER_DEBOUNCE_MS, resolveAlbumYearBounds, -} from '@/utils/library/albumYearFilter'; +} from '@/lib/library/albumYearFilter'; import { loadOfflineAlbumBrowseInitial } from '@/features/offline'; import { useOfflineBrowseReloadToken } from '@/features/offline'; import { diff --git a/src/features/album/hooks/useAlbumBrowseFilters.ts b/src/features/album/hooks/useAlbumBrowseFilters.ts index 3afb84d8..b799bd39 100644 --- a/src/features/album/hooks/useAlbumBrowseFilters.ts +++ b/src/features/album/hooks/useAlbumBrowseFilters.ts @@ -14,7 +14,7 @@ import { isAlbumDetailPath, useAlbumBrowseSessionStore, } from '@/features/album/store/albumBrowseSessionStore'; -import type { AlbumBrowseSort } from '@/utils/library/browseTextSearch'; +import type { AlbumBrowseSort } from '@/lib/library/browseTextSearch'; import { shouldRestoreAlbumBrowseSession } from '@/utils/navigation/albumDetailNavigation'; import { useLiveSearchScopeStore } from '@/store/liveSearchScopeStore'; diff --git a/src/features/album/hooks/useAlbumCatalogYearBounds.ts b/src/features/album/hooks/useAlbumCatalogYearBounds.ts index 7a80abb6..9f7148f9 100644 --- a/src/features/album/hooks/useAlbumCatalogYearBounds.ts +++ b/src/features/album/hooks/useAlbumCatalogYearBounds.ts @@ -3,8 +3,8 @@ import { ALBUM_YEAR_MAX, ALBUM_YEAR_MIN, type AlbumCatalogYearRange, -} from '@/utils/library/albumYearFilter'; -import { fetchAlbumCatalogYearBounds } from '@/utils/library/albumCatalogYearBounds'; +} from '@/lib/library/albumYearFilter'; +import { fetchAlbumCatalogYearBounds } from '@/lib/library/albumCatalogYearBounds'; const DEFAULT: AlbumCatalogYearRange = { min: ALBUM_YEAR_MIN, max: ALBUM_YEAR_MAX }; diff --git a/src/features/album/hooks/useAlbumDetailData.ts b/src/features/album/hooks/useAlbumDetailData.ts index 9398ac04..f2b24829 100644 --- a/src/features/album/hooks/useAlbumDetailData.ts +++ b/src/features/album/hooks/useAlbumDetailData.ts @@ -17,7 +17,7 @@ import { offlineLocalBrowseEnabled, } from '@/features/offline'; import { readDetailServerId } from '@/utils/navigation/detailServerScope'; -import { libraryIsReady } from '@/utils/library/libraryReady'; +import { libraryIsReady } from '@/lib/library/libraryReady'; import { shouldAttemptSubsonicForActiveServer, shouldAttemptSubsonicForServer, diff --git a/src/features/album/hooks/useBrowseAlbumTextSearch.ts b/src/features/album/hooks/useBrowseAlbumTextSearch.ts index 98e8d6b7..d8c20e4c 100644 --- a/src/features/album/hooks/useBrowseAlbumTextSearch.ts +++ b/src/features/album/hooks/useBrowseAlbumTextSearch.ts @@ -7,7 +7,7 @@ import { raceBrowseWithLocalFallback, runLocalBrowseAlbums, runNetworkBrowseAlbums, -} from '@/utils/library/browseTextSearch'; +} from '@/lib/library/browseTextSearch'; import { useOfflineBrowseContext } from '@/features/offline'; import { offlineLocalBrowseEnabled, searchOfflineLocalAlbums } from '@/features/offline'; diff --git a/src/features/album/hooks/useGenreAlbumBrowse.ts b/src/features/album/hooks/useGenreAlbumBrowse.ts index 8f6bbe7c..3c0b945e 100644 --- a/src/features/album/hooks/useGenreAlbumBrowse.ts +++ b/src/features/album/hooks/useGenreAlbumBrowse.ts @@ -1,12 +1,12 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import type { SubsonicAlbum } from '@/lib/api/subsonicTypes'; import { dedupeById } from '@/lib/util/dedupeById'; -import type { AlbumBrowseSort } from '@/utils/library/albumBrowseSort'; +import type { AlbumBrowseSort } from '@/lib/library/albumBrowseSort'; import { fetchGenreAlbumPage, GENRE_ALBUM_CATALOG_CHUNK, GENRE_ALBUM_FIRST_PAGE, -} from '@/utils/library/genreAlbumBrowse'; +} from '@/lib/library/genreAlbumBrowse'; import { useClientSliceInfiniteScroll } from '@/hooks/useClientSliceInfiniteScroll'; import { useInpageScrollSentinel } from '@/hooks/useInpageScrollSentinel'; diff --git a/src/features/album/index.ts b/src/features/album/index.ts index 86f6153c..89f641af 100644 --- a/src/features/album/index.ts +++ b/src/features/album/index.ts @@ -5,7 +5,7 @@ * the album session store, per-album offline status, and album export helpers. * * Stays OUT (library-core / cross-cutting, consumed by this feature, not owned): - * the `utils/library/album*` browse query engine (shared with offline + other + * the `lib/library/album*` browse query engine (shared with offline + other * browse surfaces → M4), `albumDetailNavigation` (cross-cutting nav → M4), * `playAlbum` (playback action → playback), `starredAlbumIndexSync` (index * sync, core), the album context-menu items (context-menu subsystem), the diff --git a/src/features/album/pages/AlbumDetail.tsx b/src/features/album/pages/AlbumDetail.tsx index 4c73a115..37f55d2c 100644 --- a/src/features/album/pages/AlbumDetail.tsx +++ b/src/features/album/pages/AlbumDetail.tsx @@ -43,8 +43,8 @@ import { usePerfProbeFlags } from '@/utils/perf/perfFlags'; import { albumGridWarmCovers } from '@/cover/layoutSizes'; import { VirtualCardGrid } from '@/components/VirtualCardGrid'; import LosslessModeBanner from '@/components/LosslessModeBanner'; -import { isLosslessSuffix } from '@/utils/library/losslessFormats'; -import { isLosslessMode } from '@/utils/library/losslessMode'; +import { isLosslessSuffix } from '@/lib/library/losslessFormats'; +import { isLosslessMode } from '@/lib/library/losslessMode'; import { readDetailServerId } from '@/utils/navigation/detailServerScope'; import { useOfflineBrowseContext } from '@/features/offline'; import { offlineActionPolicy } from '@/features/offline'; diff --git a/src/features/album/pages/Albums.tsx b/src/features/album/pages/Albums.tsx index eb59a887..2e648d97 100644 --- a/src/features/album/pages/Albums.tsx +++ b/src/features/album/pages/Albums.tsx @@ -43,15 +43,15 @@ import { peekAlbumBrowseScrollRestore } from '@/features/album/store/albumBrowse import { readAlbumBrowseRestore } from '@/utils/navigation/albumDetailNavigation'; import { albumArtistDisplayName } from '@/features/album/utils/deriveAlbumHeaderArtistRefs'; import { useAlbumCatalogYearBounds } from '@/features/album/hooks/useAlbumCatalogYearBounds'; -import type { AlbumBrowseSort } from '@/utils/library/albumBrowseSort'; -import { LOSSLESS_MODE_QUERY } from '@/utils/library/losslessMode'; -import { resolveAlbumYearBounds } from '@/utils/library/albumYearFilter'; +import type { AlbumBrowseSort } from '@/lib/library/albumBrowseSort'; +import { LOSSLESS_MODE_QUERY } from '@/lib/library/losslessMode'; +import { resolveAlbumYearBounds } from '@/lib/library/albumYearFilter'; import { filterAlbumsByCompilation, filterAlbumsByGenres, filterAlbumsByStarred, filterAlbumsByYearBounds, -} from '@/utils/library/albumBrowseFilters'; +} from '@/lib/library/albumBrowseFilters'; import { useScopedBrowseSearchQuery } from '@/store/liveSearchScopeStore'; type SortType = AlbumBrowseSort; diff --git a/src/features/album/pages/LosslessAlbums.tsx b/src/features/album/pages/LosslessAlbums.tsx index 2f4d9e63..ffef7b57 100644 --- a/src/features/album/pages/LosslessAlbums.tsx +++ b/src/features/album/pages/LosslessAlbums.tsx @@ -4,7 +4,7 @@ import type { SubsonicAlbum } from '@/lib/api/subsonicTypes'; import { songToTrack } from '@/features/playback/utils/playback/songToTrack'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import AlbumCard from '@/features/album/components/AlbumCard'; -import { LOSSLESS_MODE_QUERY } from '@/utils/library/losslessMode'; +import { LOSSLESS_MODE_QUERY } from '@/lib/library/losslessMode'; import { ndListLosslessAlbumsPage } from '@/lib/api/navidromeBrowse'; import { useTranslation } from 'react-i18next'; import { useAuthStore } from '@/store/authStore'; @@ -38,7 +38,7 @@ import { runLocalAlbumBrowsePage, sortSubsonicAlbums, type AlbumBrowseSort, -} from '@/utils/library/browseTextSearch'; +} from '@/lib/library/browseTextSearch'; /** Local index page size — SQLite is cheap; larger pages than the network walk. */ const LOCAL_PAGE_SIZE = 30; diff --git a/src/features/album/pages/RandomAlbums.tsx b/src/features/album/pages/RandomAlbums.tsx index 98940a3a..8344c488 100644 --- a/src/features/album/pages/RandomAlbums.tsx +++ b/src/features/album/pages/RandomAlbums.tsx @@ -15,7 +15,7 @@ import { useLocation, useNavigate } from 'react-router-dom'; import { useAuthStore } from '@/store/authStore'; import { useLibraryIndexStore } from '@/store/libraryIndexStore'; import { filterAlbumsByMixRatings, getMixMinRatingsConfigFromAuth } from '@/utils/mix/mixRatingFilter'; -import { runLocalRandomAlbums, runLocalAlbumsByGenres } from '@/utils/library/browseTextSearch'; +import { runLocalRandomAlbums, runLocalAlbumsByGenres } from '@/lib/library/browseTextSearch'; import { useOfflineStore } from '@/features/offline'; import { useDownloadModalStore } from '@/features/offline'; import { invoke } from '@tauri-apps/api/core'; diff --git a/src/features/album/store/albumBrowseSessionStore.ts b/src/features/album/store/albumBrowseSessionStore.ts index 4110f31d..9ba6e490 100644 --- a/src/features/album/store/albumBrowseSessionStore.ts +++ b/src/features/album/store/albumBrowseSessionStore.ts @@ -1,6 +1,6 @@ import { create } from 'zustand'; import type { SubsonicAlbum } from '@/lib/api/subsonicTypes'; -import type { AlbumBrowseSort } from '@/utils/library/browseTextSearch'; +import type { AlbumBrowseSort } from '@/lib/library/browseTextSearch'; export const DEFAULT_ALBUM_BROWSE_SORT: AlbumBrowseSort = 'alphabeticalByName'; diff --git a/src/features/album/utils/albumBrowseCatalogChunk.ts b/src/features/album/utils/albumBrowseCatalogChunk.ts index acc1fef6..7b745a2f 100644 --- a/src/features/album/utils/albumBrowseCatalogChunk.ts +++ b/src/features/album/utils/albumBrowseCatalogChunk.ts @@ -2,8 +2,8 @@ import type { SubsonicAlbum } from '@/lib/api/subsonicTypes'; import { dedupeById } from '@/lib/util/dedupeById'; import { isOfflineBrowseActive } from '@/features/offline'; import { loadOfflineAlbumCatalogChunk } from '@/features/offline'; -import type { AlbumBrowseQuery } from '@/utils/library/albumBrowseTypes'; -import { fetchLocalAlbumCatalogChunk } from '@/utils/library/albumBrowseLoad'; +import type { AlbumBrowseQuery } from '@/lib/library/albumBrowseTypes'; +import { fetchLocalAlbumCatalogChunk } from '@/lib/library/albumBrowseLoad'; export type AlbumCatalogChunk = { albums: SubsonicAlbum[]; diff --git a/src/features/artist/hooks/useArtistDetailData.ts b/src/features/artist/hooks/useArtistDetailData.ts index 91b2ceb5..9162023e 100644 --- a/src/features/artist/hooks/useArtistDetailData.ts +++ b/src/features/artist/hooks/useArtistDetailData.ts @@ -11,8 +11,8 @@ import { loadArtistFromLibraryIndex } from '@/features/offline'; import { useOfflineBrowseContext } from '@/features/offline'; import { loadArtistFromLocalPlayback, offlineLocalBrowseEnabled } from '@/features/offline'; import { readDetailServerId } from '@/utils/navigation/detailServerScope'; -import { runLocalArtistLosslessBrowse } from '@/utils/library/browseTextSearch'; -import { isLosslessSuffix } from '@/utils/library/losslessFormats'; +import { runLocalArtistLosslessBrowse } from '@/lib/library/browseTextSearch'; +import { isLosslessSuffix } from '@/lib/library/losslessFormats'; export interface UseArtistDetailDataOptions { /** When true, albums and top tracks are limited to lossless containers (local index preferred). */ diff --git a/src/features/artist/hooks/useArtistsBrowseCatalog.ts b/src/features/artist/hooks/useArtistsBrowseCatalog.ts index c24d1344..1ede8173 100644 --- a/src/features/artist/hooks/useArtistsBrowseCatalog.ts +++ b/src/features/artist/hooks/useArtistsBrowseCatalog.ts @@ -5,7 +5,7 @@ import { dedupeById } from '@/lib/util/dedupeById'; import { fetchLocalArtistCatalogChunk, fetchNetworkStarredArtists, -} from '@/utils/library/browseTextSearch'; +} from '@/lib/library/browseTextSearch'; import { useOfflineBrowseContext } from '@/features/offline'; import { useOfflineBrowseReloadToken } from '@/features/offline'; import { diff --git a/src/features/artist/hooks/useBrowseArtistTextSearch.ts b/src/features/artist/hooks/useBrowseArtistTextSearch.ts index da9e2a50..8f0d5f82 100644 --- a/src/features/artist/hooks/useBrowseArtistTextSearch.ts +++ b/src/features/artist/hooks/useBrowseArtistTextSearch.ts @@ -8,7 +8,7 @@ import { runLocalBrowseArtists, runNetworkBrowseArtists, type LibrarySearchSurface, -} from '@/utils/library/browseTextSearch'; +} from '@/lib/library/browseTextSearch'; import { useOfflineBrowseContext } from '@/features/offline'; import { offlineLocalBrowseEnabled, searchOfflineLocalArtists } from '@/features/offline'; diff --git a/src/features/artist/index.ts b/src/features/artist/index.ts index 4928cd58..5e1b28df 100644 --- a/src/features/artist/index.ts +++ b/src/features/artist/index.ts @@ -3,7 +3,7 @@ * `pages/*` paths, not re-exported), artist cards/rows/avatars, the detail hero + * similar-artists + top-tracks UI, the artist Subsonic API, browse catalog/ * filter/scroll hooks, per-artist offline status, and the open-artist-ref nav - * cluster. `sortArtistAlbums` moved in from `utils/library/` (artist-only sort, + * cluster. `sortArtistAlbums` moved in from `lib/library/` (artist-only sort, * not the shared index query engine). * * Stays OUT (other owners): `deriveAlbumHeaderArtistRefs` (album header), diff --git a/src/features/artist/pages/ArtistDetail.tsx b/src/features/artist/pages/ArtistDetail.tsx index 3baf8a64..1dde0a26 100644 --- a/src/features/artist/pages/ArtistDetail.tsx +++ b/src/features/artist/pages/ArtistDetail.tsx @@ -36,7 +36,7 @@ import { artistDetailCoverWarmAlbums } from '@/features/artist/components/topSon import { useLibraryCoverPrefetch } from '@/cover/useLibraryCoverPrefetch'; import { useWarmGridCovers } from '@/hooks/useWarmGridCovers'; import { VirtualCardGrid } from '@/components/VirtualCardGrid'; -import { LOSSLESS_MODE_QUERY } from '@/utils/library/losslessMode'; +import { LOSSLESS_MODE_QUERY } from '@/lib/library/losslessMode'; import { sortArtistAlbumsByYear } from '@/features/artist/utils/sortArtistAlbums'; import { readDetailServerId } from '@/utils/navigation/detailServerScope'; diff --git a/src/features/nowPlaying/utils/nowPlayingMetadataResolve.ts b/src/features/nowPlaying/utils/nowPlayingMetadataResolve.ts index 69c076a4..bbb6d4bf 100644 --- a/src/features/nowPlaying/utils/nowPlayingMetadataResolve.ts +++ b/src/features/nowPlaying/utils/nowPlayingMetadataResolve.ts @@ -22,8 +22,8 @@ import { getAlbumForServer, getSongForServer } from '@/lib/api/subsonicLibrary'; import type { SubsonicAlbum, SubsonicSong } from '@/lib/api/subsonicTypes'; import { shouldAttemptSubsonicForServer } from '@/utils/network/subsonicNetworkGuard'; import { loadAlbumFromLibraryIndex, loadArtistFromLibraryIndex } from '@/features/offline'; -import { trackToSong } from '@/utils/library/advancedSearchLocal'; -import { libraryIsReady } from '@/utils/library/libraryReady'; +import { trackToSong } from '@/lib/library/advancedSearchLocal'; +import { libraryIsReady } from '@/lib/library/libraryReady'; const TOP_SONGS_LIMIT = 5; diff --git a/src/features/offline/utils/offlineAlbumBrowseCatalog.ts b/src/features/offline/utils/offlineAlbumBrowseCatalog.ts index bb1f53b3..3d7a59be 100644 --- a/src/features/offline/utils/offlineAlbumBrowseCatalog.ts +++ b/src/features/offline/utils/offlineAlbumBrowseCatalog.ts @@ -1,5 +1,5 @@ import type { SubsonicAlbum } from '@/lib/api/subsonicTypes'; -import type { AlbumBrowseQuery } from '@/utils/library/albumBrowseTypes'; +import type { AlbumBrowseQuery } from '@/lib/library/albumBrowseTypes'; import { isOfflineBrowseActive } from '@/features/offline/utils/offlineBrowseMode'; import { fetchOfflineLocalAlbumCatalogChunk, diff --git a/src/features/offline/utils/offlineLibraryHelpers.ts b/src/features/offline/utils/offlineLibraryHelpers.ts index 7f0e4aea..d5d6f17e 100644 --- a/src/features/offline/utils/offlineLibraryHelpers.ts +++ b/src/features/offline/utils/offlineLibraryHelpers.ts @@ -7,7 +7,7 @@ import type { LocalPlaybackEntry, PinnedGroup, PinSource } from '@/store/localPl import { useLocalPlaybackStore } from '@/store/localPlaybackStore'; import { findLocalPlaybackEntry, hasLocalLibraryBytes } from '@/store/localPlaybackResolve'; import { useOfflineStore, type OfflineAlbumMeta } from '@/features/offline/store/offlineStore'; -import { resolveTrackCoverArtId, trackToSong } from '@/utils/library/advancedSearchLocal'; +import { resolveTrackCoverArtId, trackToSong } from '@/lib/library/advancedSearchLocal'; import { canonicalQueueServerKey, resolveIndexKey } from '@/utils/server/serverIndexKey'; import type { Track } from '@/features/playback/store/playerStoreTypes'; import { findServerByIdOrIndexKey, resolveServerIdForIndexKey } from '@/utils/server/serverLookup'; diff --git a/src/features/offline/utils/offlineLibraryIndexLoad.ts b/src/features/offline/utils/offlineLibraryIndexLoad.ts index 7aa1f55c..0a660be8 100644 --- a/src/features/offline/utils/offlineLibraryIndexLoad.ts +++ b/src/features/offline/utils/offlineLibraryIndexLoad.ts @@ -8,7 +8,7 @@ import { albumToAlbum, artistToArtist, trackToSong, -} from '@/utils/library/advancedSearchLocal'; +} from '@/lib/library/advancedSearchLocal'; export async function loadAlbumFromLibraryIndex( serverId: string, diff --git a/src/features/offline/utils/offlineLocalBrowse.ts b/src/features/offline/utils/offlineLocalBrowse.ts index ef810154..9214e269 100644 --- a/src/features/offline/utils/offlineLocalBrowse.ts +++ b/src/features/offline/utils/offlineLocalBrowse.ts @@ -9,17 +9,17 @@ import { artistToArtist, resolveTrackCoverArtId, trackToSong, -} from '@/utils/library/advancedSearchLocal'; -import { albumIsCompilationFromTrackDtos } from '@/utils/library/albumCompilation'; +} from '@/lib/library/advancedSearchLocal'; +import { albumIsCompilationFromTrackDtos } from '@/lib/library/albumCompilation'; import { filterAlbumsByCompilation, filterAlbumsByGenres, filterAlbumsByStarred, filterAlbumsByYearBounds, -} from '@/utils/library/albumBrowseFilters'; -import type { AlbumBrowseQuery } from '@/utils/library/albumBrowseTypes'; -import { sortSubsonicAlbums } from '@/utils/library/albumBrowseSort'; -import { isLosslessSuffix } from '@/utils/library/losslessFormats'; +} from '@/lib/library/albumBrowseFilters'; +import type { AlbumBrowseQuery } from '@/lib/library/albumBrowseTypes'; +import { sortSubsonicAlbums } from '@/lib/library/albumBrowseSort'; +import { isLosslessSuffix } from '@/lib/library/losslessFormats'; import { entryBelongsToServer } from '@/store/localPlaybackResolve'; function sortBrowsableSongs(songs: SubsonicSong[]): SubsonicSong[] { diff --git a/src/features/offline/utils/offlineMediaResolve.test.ts b/src/features/offline/utils/offlineMediaResolve.test.ts index fa3e8487..10841ae8 100644 --- a/src/features/offline/utils/offlineMediaResolve.test.ts +++ b/src/features/offline/utils/offlineMediaResolve.test.ts @@ -62,7 +62,7 @@ vi.mock('@/lib/api/subsonicPlaylists', () => ({ getPlaylistForServerMock(serverId, playlistId), })); -vi.mock('@/utils/library/libraryReady', () => ({ +vi.mock('@/lib/library/libraryReady', () => ({ libraryIsReady: (serverId: string) => libraryIsReadyMock(serverId), })); diff --git a/src/features/offline/utils/offlineMediaResolve.ts b/src/features/offline/utils/offlineMediaResolve.ts index 5e7a2722..76205c12 100644 --- a/src/features/offline/utils/offlineMediaResolve.ts +++ b/src/features/offline/utils/offlineMediaResolve.ts @@ -10,7 +10,7 @@ import type { import { useAuthStore } from '@/store/authStore'; import { shouldAttemptSubsonicForServer } from '@/utils/network/subsonicNetworkGuard'; import { isOfflineBrowseActive } from '@/features/offline/utils/offlineBrowseMode'; -import { libraryIsReady } from '@/utils/library/libraryReady'; +import { libraryIsReady } from '@/lib/library/libraryReady'; import { registerMediaResolver } from '@/store/mediaResolver'; import { loadAlbumFromLibraryIndex, diff --git a/src/features/offline/utils/offlinePlaylistBrowse.ts b/src/features/offline/utils/offlinePlaylistBrowse.ts index 98b12dd1..60f4dc7a 100644 --- a/src/features/offline/utils/offlinePlaylistBrowse.ts +++ b/src/features/offline/utils/offlinePlaylistBrowse.ts @@ -3,7 +3,7 @@ import type { SubsonicPlaylist, SubsonicSong } from '@/lib/api/subsonicTypes'; import { useLibraryIndexStore } from '@/store/libraryIndexStore'; import type { PinnedGroup } from '@/store/localPlaybackStore'; import { useLocalPlaybackStore } from '@/store/localPlaybackStore'; -import { trackToSong } from '@/utils/library/advancedSearchLocal'; +import { trackToSong } from '@/lib/library/advancedSearchLocal'; import { isManualOfflinePlaylist } from '@/features/offline/utils/pinnedOfflineSync'; import { hasLocalLibraryBytes, diff --git a/src/features/offline/utils/offlineStarredLoad.ts b/src/features/offline/utils/offlineStarredLoad.ts index 7abb10a4..d2f006b1 100644 --- a/src/features/offline/utils/offlineStarredLoad.ts +++ b/src/features/offline/utils/offlineStarredLoad.ts @@ -10,7 +10,7 @@ import { isActiveServerReachable } from '@/utils/network/activeServerReachabilit import { albumToAlbum, trackToSong, -} from '@/utils/library/advancedSearchLocal'; +} from '@/lib/library/advancedSearchLocal'; import { dedupeById } from '@/lib/util/dedupeById'; import { isOfflineBrowseActive } from '@/features/offline/utils/offlineBrowseMode'; import { favoritesServerIds } from '@/features/offline/utils/favoritesOfflineBrowse'; diff --git a/src/features/offline/utils/resumeIncompleteOfflinePins.ts b/src/features/offline/utils/resumeIncompleteOfflinePins.ts index 62d1d4ad..13c55ac0 100644 --- a/src/features/offline/utils/resumeIncompleteOfflinePins.ts +++ b/src/features/offline/utils/resumeIncompleteOfflinePins.ts @@ -4,7 +4,7 @@ import type { SubsonicSong } from '@/lib/api/subsonicTypes'; import { useAuthStore } from '@/store/authStore'; import type { OfflineAlbumMeta } from '@/features/offline/store/offlineStore'; import { useOfflineStore } from '@/features/offline/store/offlineStore'; -import { trackToSong } from '@/utils/library/advancedSearchLocal'; +import { trackToSong } from '@/lib/library/advancedSearchLocal'; import { isActiveServerReachable, onActiveServerBecameReachable } from '@/utils/network/activeServerReachability'; import { shouldAttemptSubsonicForServer } from '@/utils/network/subsonicNetworkGuard'; import { resolveServerIdForIndexKey } from '@/utils/server/serverLookup'; diff --git a/src/features/playback/store/playListenSession.test.ts b/src/features/playback/store/playListenSession.test.ts index 6973fd77..767aa252 100644 --- a/src/features/playback/store/playListenSession.test.ts +++ b/src/features/playback/store/playListenSession.test.ts @@ -14,7 +14,7 @@ import { } from '@/features/playback/store/playListenSession'; import { onPlaySessionRecorded } from '@/features/playback/store/playSessionRecorded'; -vi.mock('@/utils/library/libraryReady', () => ({ +vi.mock('@/lib/library/libraryReady', () => ({ libraryIsReady: vi.fn(async () => true), })); @@ -178,7 +178,7 @@ describe('playListenSession', () => { }); it('skips when library is not ready', async () => { - const { libraryIsReady } = await import('@/utils/library/libraryReady'); + const { libraryIsReady } = await import('@/lib/library/libraryReady'); vi.mocked(libraryIsReady).mockResolvedValueOnce(false); vi.useFakeTimers(); await playListenSessionOpen(testTrack, 'server-1'); diff --git a/src/features/playback/store/playListenSession.ts b/src/features/playback/store/playListenSession.ts index d775a908..7a3ffa84 100644 --- a/src/features/playback/store/playListenSession.ts +++ b/src/features/playback/store/playListenSession.ts @@ -5,7 +5,7 @@ import { libraryRecordPlaySession, type PlaySessionEndReason, } from '@/lib/api/library'; -import { libraryIsReady } from '@/utils/library/libraryReady'; +import { libraryIsReady } from '@/lib/library/libraryReady'; import { getPlaybackServerId } from '@/features/playback/utils/playback/playbackServer'; import { emitPlaySessionRecorded } from '@/features/playback/store/playSessionRecorded'; import { useLibraryIndexStore } from '@/store/libraryIndexStore'; diff --git a/src/features/playback/store/queueTrackResolver.ts b/src/features/playback/store/queueTrackResolver.ts index c03b2cd1..3560fbe6 100644 --- a/src/features/playback/store/queueTrackResolver.ts +++ b/src/features/playback/store/queueTrackResolver.ts @@ -5,8 +5,8 @@ import type { QueueItemRef, Track } from '@/features/playback/store/playerStoreT import { songToTrack } from '@/features/playback/utils/playback/songToTrack'; import { resolveServerIdForIndexKey } from '@/utils/server/serverLookup'; import { canonicalQueueServerKey } from '@/utils/server/serverIndexKey'; -import { trackToSong } from '@/utils/library/advancedSearchLocal'; -import { libraryIsReady } from '@/utils/library/libraryReady'; +import { trackToSong } from '@/lib/library/advancedSearchLocal'; +import { libraryIsReady } from '@/lib/library/libraryReady'; /** * Queue track resolver (thin-state phase 2). Resolves `QueueItemRef`s to full diff --git a/src/features/playback/utils/playback/genreBrowsePlayback.test.ts b/src/features/playback/utils/playback/genreBrowsePlayback.test.ts index a035c450..9305e8ab 100644 --- a/src/features/playback/utils/playback/genreBrowsePlayback.test.ts +++ b/src/features/playback/utils/playback/genreBrowsePlayback.test.ts @@ -22,23 +22,23 @@ vi.mock('@/lib/api/subsonicClient', () => ({ libraryScopeForServer: vi.fn(() => 'music'), })); -vi.mock('@/utils/library/libraryReady', () => ({ +vi.mock('@/lib/library/libraryReady', () => ({ libraryIsReady: vi.fn(), })); // Spread the real leaf module so other consumers pulled in transitively (the // album barrel reaches this via the artist↔album edge → useGenreAlbumBrowse needs // GENRE_ALBUM_FIRST_PAGE); only fetchGenreAlbumTotal is stubbed here. -vi.mock('@/utils/library/genreAlbumBrowse', async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock('@/lib/library/genreAlbumBrowse', async (importOriginal) => ({ + ...(await importOriginal()), fetchGenreAlbumTotal: vi.fn(), })); import { libraryAdvancedSearch, libraryGetGenreAlbumCounts } from '@/lib/api/library'; import { fetchAllSongsByGenre, getGenres } from '@/lib/api/subsonicGenres'; -import { fetchGenreAlbumTotal } from '@/utils/library/genreAlbumBrowse'; -import { resetGenreCatalogCountsCacheForTests } from '@/utils/library/genreCatalogCountsCache'; -import { libraryIsReady } from '@/utils/library/libraryReady'; +import { fetchGenreAlbumTotal } from '@/lib/library/genreAlbumBrowse'; +import { resetGenreCatalogCountsCacheForTests } from '@/lib/library/genreCatalogCountsCache'; +import { libraryIsReady } from '@/lib/library/libraryReady'; describe('genreBrowsePlayback', () => { beforeEach(() => { diff --git a/src/features/playback/utils/playback/genreBrowsePlayback.ts b/src/features/playback/utils/playback/genreBrowsePlayback.ts index 0e1e6c97..a901c46f 100644 --- a/src/features/playback/utils/playback/genreBrowsePlayback.ts +++ b/src/features/playback/utils/playback/genreBrowsePlayback.ts @@ -8,8 +8,8 @@ import { libraryScopeForServer } from '@/lib/api/subsonicClient'; import type { Track } from '@/features/playback/store/playerStoreTypes'; import { songToTrack } from '@/features/playback/utils/playback/songToTrack'; import { shuffleArray } from '@/lib/util/shuffleArray'; -import { trackToSong } from '@/utils/library/advancedSearchLocal'; -import { type AlbumBrowseSort } from '@/utils/library/albumBrowseSort'; +import { trackToSong } from '@/lib/library/advancedSearchLocal'; +import { type AlbumBrowseSort } from '@/lib/library/albumBrowseSort'; import { genreCatalogCacheKey, getInflightGenreCatalog, @@ -17,9 +17,9 @@ import { peekGenreCatalogCache, trackInflightGenreCatalog, writeGenreCatalogCache, -} from '@/utils/library/genreCatalogCountsCache'; -import { fetchGenreAlbumTotal } from '@/utils/library/genreAlbumBrowse'; -import { libraryIsReady } from '@/utils/library/libraryReady'; +} from '@/lib/library/genreCatalogCountsCache'; +import { fetchGenreAlbumTotal } from '@/lib/library/genreAlbumBrowse'; +import { libraryIsReady } from '@/lib/library/libraryReady'; /** Drop genres with no indexed albums/tracks (stale server list or orphan rows). */ export function filterGenresWithContent(genres: SubsonicGenre[]): SubsonicGenre[] { diff --git a/src/features/queue/components/QueueCurrentTrack.tsx b/src/features/queue/components/QueueCurrentTrack.tsx index f5656b47..724667e0 100644 --- a/src/features/queue/components/QueueCurrentTrack.tsx +++ b/src/features/queue/components/QueueCurrentTrack.tsx @@ -10,7 +10,7 @@ import { } from '@/utils/componentHelpers/queuePanelHelpers'; import { loudnessGainPlaceholderUntilCacheDb } from '@/features/playback/utils/audio/loudnessPlaceholder'; import { effectiveLoudnessPreAnalysisAttenuationDb } from '@/utils/audio/loudnessPreAnalysisSlider'; -import { formatQueueBpmTech, formatQueueMoodLabels } from '@/utils/library/trackEnrichment'; +import { formatQueueBpmTech, formatQueueMoodLabels } from '@/lib/library/trackEnrichment'; import { useQueueTrackEnrichment } from '@/features/queue/hooks/useQueueTrackEnrichment'; import { QueueLufsTargetMenu } from '@/features/queue/components/QueueLufsTargetMenu'; import { PlaybackBufferingOverlay } from '@/components/playback/PlaybackBufferingOverlay'; diff --git a/src/features/queue/hooks/useQueueTrackEnrichment.ts b/src/features/queue/hooks/useQueueTrackEnrichment.ts index 6e3b25e2..38d8e655 100644 --- a/src/features/queue/hooks/useQueueTrackEnrichment.ts +++ b/src/features/queue/hooks/useQueueTrackEnrichment.ts @@ -8,8 +8,8 @@ import { OXIMEDIA_MOOD_UI_ENABLED, parseTrackEnrichmentFacts, type ParsedTrackEnrichment, -} from '@/utils/library/trackEnrichment'; -import { libraryIsReady } from '@/utils/library/libraryReady'; +} from '@/lib/library/trackEnrichment'; +import { libraryIsReady } from '@/lib/library/libraryReady'; import { normalizeAnalysisTrackId } from '@/features/playback/utils/playback/queueIdentity'; const EMPTY: ParsedTrackEnrichment = { diff --git a/src/features/search/components/LiveSearch.tsx b/src/features/search/components/LiveSearch.tsx index 626d0976..ad45b70c 100644 --- a/src/features/search/components/LiveSearch.tsx +++ b/src/features/search/components/LiveSearch.tsx @@ -9,17 +9,17 @@ import { mergeLiveSearchResults, runLocalLiveSearch, runNetworkLiveSearch, -} from '@/utils/library/liveSearchLocal'; -import { raceLiveSearch } from '@/utils/library/searchRace'; -import { libraryIsReady } from '@/utils/library/libraryReady'; +} from '@/lib/library/liveSearchLocal'; +import { raceLiveSearch } from '@/lib/library/searchRace'; +import { libraryIsReady } from '@/lib/library/libraryReady'; import { emitLiveSearchDebug, searchHitCounts, searchResultSamples, -} from '@/utils/library/liveSearchDebug'; +} from '@/lib/library/liveSearchDebug'; import { logLibrarySearch, -} from '@/utils/library/libraryDevLog'; +} from '@/lib/library/libraryDevLog'; import React, { useState, useEffect, useRef, useCallback } from 'react'; import { useNavigate, useLocation } from 'react-router-dom'; import { useNavigateToAlbum } from '@/features/album'; diff --git a/src/features/search/index.ts b/src/features/search/index.ts index 80b8ffb4..b76ad5e7 100644 --- a/src/features/search/index.ts +++ b/src/features/search/index.ts @@ -3,7 +3,7 @@ * search/browse page (lazy via the deep path `pages/SearchBrowsePage`), live * search scope UI/state, and the share-link search/queue-preview surfaces. * - * The local-index query engine (`utils/library/*search*`), the shared Subsonic + * The local-index query engine (`lib/library/*search*`), the shared Subsonic * search API, the cross-cutting `liveSearchScopeStore`, and the * `advancedSearch*` session/scroll state live outside this feature * (library-core / cross-cutting) — this feature consumes them. diff --git a/src/features/search/pages/SearchBrowsePage.tsx b/src/features/search/pages/SearchBrowsePage.tsx index b1f84d7a..50b2e864 100644 --- a/src/features/search/pages/SearchBrowsePage.tsx +++ b/src/features/search/pages/SearchBrowsePage.tsx @@ -42,19 +42,19 @@ import { runNetworkAdvancedTextSearch, runNetworkAdvancedYearAlbums, tryRunLocalAdvancedSearch, -} from '@/utils/library/advancedSearchLocal'; -import { isLosslessSuffix } from '@/utils/library/losslessFormats'; -import { LOSSLESS_MODE_QUERY } from '@/utils/library/losslessMode'; -import { OXIMEDIA_MOOD_SEARCH_ENABLED } from '@/utils/library/trackEnrichment'; -import { raceSearchSources } from '@/utils/library/searchRace'; -import { logLibrarySearch } from '@/utils/library/libraryDevLog'; +} from '@/lib/library/advancedSearchLocal'; +import { isLosslessSuffix } from '@/lib/library/losslessFormats'; +import { LOSSLESS_MODE_QUERY } from '@/lib/library/losslessMode'; +import { OXIMEDIA_MOOD_SEARCH_ENABLED } from '@/lib/library/trackEnrichment'; +import { raceSearchSources } from '@/lib/library/searchRace'; +import { logLibrarySearch } from '@/lib/library/libraryDevLog'; import { browseRaceCountsFullSearch, loadMoreLocalBrowseSongs, raceBrowseWithLocalFallback, runLocalBrowseFullSearch, runNetworkBrowseFullSearch, -} from '@/utils/library/browseTextSearch'; +} from '@/lib/library/browseTextSearch'; import { useLibraryIndexStore } from '@/store/libraryIndexStore'; import { MOOD_GROUP_IDS } from '@/config/moodGroups'; import { usePerfProbeFlags } from '@/utils/perf/perfFlags'; diff --git a/src/features/settings/components/AnalyticsStrategySection.tsx b/src/features/settings/components/AnalyticsStrategySection.tsx index d80ef28d..48db3573 100644 --- a/src/features/settings/components/AnalyticsStrategySection.tsx +++ b/src/features/settings/components/AnalyticsStrategySection.tsx @@ -29,7 +29,7 @@ import { ADVANCED_PARALLELISM_MAX, ADVANCED_PARALLELISM_MIN, type AnalyticsStrategy, -} from '@/utils/library/analysisStrategy'; +} from '@/lib/library/analysisStrategy'; type ClearTarget = { serverId: string; diff --git a/src/features/settings/components/CoverCacheStrategySection.tsx b/src/features/settings/components/CoverCacheStrategySection.tsx index b136d832..ee5d3e61 100644 --- a/src/features/settings/components/CoverCacheStrategySection.tsx +++ b/src/features/settings/components/CoverCacheStrategySection.tsx @@ -19,11 +19,11 @@ import { serverIndexKeyForProfile } from '@/utils/server/serverIndexKey'; import { showToast } from '@/utils/ui/toast'; import { formatBytes } from '@/lib/format/formatBytes'; import { clearImageCache, getImageCacheSize } from '@/utils/imageCache'; -import { wakeLibraryCoverBackfill } from '@/utils/library/coverBackfillWake'; +import { wakeLibraryCoverBackfill } from '@/lib/library/coverBackfillWake'; import { COVER_CACHE_STRATEGIES, type CoverCacheStrategy, -} from '@/utils/library/coverStrategy'; +} from '@/lib/library/coverStrategy'; type ClearTarget = | { kind: 'image' } diff --git a/src/features/settings/components/ServerLibraryIndexControls.tsx b/src/features/settings/components/ServerLibraryIndexControls.tsx index 81495e01..c3f0bf96 100644 --- a/src/features/settings/components/ServerLibraryIndexControls.tsx +++ b/src/features/settings/components/ServerLibraryIndexControls.tsx @@ -4,7 +4,7 @@ import type { SyncStateDto } from '@/lib/api/library'; import { libraryStatusDisplayTrackCount, libraryStatusIsReady, -} from '@/utils/library/libraryReady'; +} from '@/lib/library/libraryReady'; import type { LibraryServerConnection } from '@/hooks/useLibraryIndexSync'; interface ServerLibraryIndexControlsProps { diff --git a/src/features/settings/components/ServersTab.tsx b/src/features/settings/components/ServersTab.tsx index 2b8005fb..7490f2d8 100644 --- a/src/features/settings/components/ServersTab.tsx +++ b/src/features/settings/components/ServersTab.tsx @@ -8,7 +8,7 @@ import { formatServerSoftware, isNavidromeAudiomuseSoftwareEligible, type Instan import { buildCapabilityContext } from '@/serverCapabilities/context'; import { useLibraryIndexStore } from '@/store/libraryIndexStore'; import { libraryDeleteServerData, librarySyncClearSession } from '@/lib/api/library'; -import { bootstrapIndexedServer } from '@/utils/library/librarySession'; +import { bootstrapIndexedServer } from '@/lib/library/librarySession'; import { useLibraryIndexSync } from '@/hooks/useLibraryIndexSync'; import ServerLibraryIndexControls from '@/features/settings/components/ServerLibraryIndexControls'; import type { ServerProfile } from '@/store/authStoreTypes'; diff --git a/src/hooks/tauriBridge/useLibraryDevSyncLog.ts b/src/hooks/tauriBridge/useLibraryDevSyncLog.ts index 33906a6f..e481f9cd 100644 --- a/src/hooks/tauriBridge/useLibraryDevSyncLog.ts +++ b/src/hooks/tauriBridge/useLibraryDevSyncLog.ts @@ -15,7 +15,7 @@ import { logLibrarySync, normalizeIngestMetrics, timed, -} from '../../utils/library/libraryDevLog'; +} from '@/lib/library/libraryDevLog'; /** * DevTools: log library sync progress + idle with ingest strategy from status. diff --git a/src/hooks/useLibraryAnalysisBackfill.ts b/src/hooks/useLibraryAnalysisBackfill.ts index 848bb571..69b4f33e 100644 --- a/src/hooks/useLibraryAnalysisBackfill.ts +++ b/src/hooks/useLibraryAnalysisBackfill.ts @@ -6,7 +6,7 @@ import { import { librarySqlServerId } from '../api/coverCache'; import { useAuthStore } from '../store/authStore'; import { useAnalysisStrategyStore } from '../store/analysisStrategyStore'; -import { DEFAULT_ADVANCED_PARALLELISM } from '../utils/library/analysisStrategy'; +import { DEFAULT_ADVANCED_PARALLELISM } from '@/lib/library/analysisStrategy'; import { serverIndexKeyForProfile } from '../utils/server/serverIndexKey'; const DISABLED_CONFIGURE = { diff --git a/src/hooks/useLibraryCoverBackfill.ts b/src/hooks/useLibraryCoverBackfill.ts index eae2eb8f..8c8d3c10 100644 --- a/src/hooks/useLibraryCoverBackfill.ts +++ b/src/hooks/useLibraryCoverBackfill.ts @@ -7,10 +7,10 @@ import { libraryCoverBackfillSetBaseUrl, librarySqlServerId, } from '../api/coverCache'; -import { coverStrategyAllowsLibraryBackfill } from '../utils/library/coverStrategy'; +import { coverStrategyAllowsLibraryBackfill } from '@/lib/library/coverStrategy'; import { useAuthStore } from '../store/authStore'; import { useCoverStrategyStore } from '../store/coverStrategyStore'; -import { subscribeLibraryCoverBackfillWake } from '../utils/library/coverBackfillWake'; +import { subscribeLibraryCoverBackfillWake } from '@/lib/library/coverBackfillWake'; import { serverIndexKeyForProfile } from '../utils/server/serverIndexKey'; import { subscribeConnectCache } from '../utils/server/serverEndpoint'; diff --git a/src/hooks/useLibraryIndexSync.ts b/src/hooks/useLibraryIndexSync.ts index e519a6ef..37dfe185 100644 --- a/src/hooks/useLibraryIndexSync.ts +++ b/src/hooks/useLibraryIndexSync.ts @@ -15,9 +15,9 @@ import { bootstrapAllIndexedServers, bootstrapIndexedServer, type BindServerResult, -} from '../utils/library/librarySession'; -import { enqueueLibrarySync } from '../utils/library/librarySyncQueue'; -import { syncIngestDisplayCount } from '../utils/library/libraryReady'; +} from '@/lib/library/librarySession'; +import { enqueueLibrarySync } from '@/lib/library/librarySyncQueue'; +import { syncIngestDisplayCount } from '@/lib/library/libraryReady'; export type LibraryServerConnection = 'online' | 'offline' | 'unknown'; diff --git a/src/hooks/useSongBrowseList.test.ts b/src/hooks/useSongBrowseList.test.ts index 04e6e01d..886d6b65 100644 --- a/src/hooks/useSongBrowseList.test.ts +++ b/src/hooks/useSongBrowseList.test.ts @@ -14,7 +14,7 @@ vi.mock('@/lib/api/navidromeBrowse', () => ({ ndListSongs: vi.fn(async () => []), })); -vi.mock('../utils/library/advancedSearchLocal', () => ({ +vi.mock('@/lib/library/advancedSearchLocal', () => ({ runLocalSongBrowse: vi.fn(async () => []), })); @@ -25,7 +25,7 @@ vi.mock('@/features/offline/hooks/useOfflineBrowseReloadToken', () => ({ useOfflineBrowseReloadToken: () => undefined, })); -vi.mock('../utils/library/browseTextSearch', () => ({ +vi.mock('@/lib/library/browseTextSearch', () => ({ BROWSE_TEXT_DEBOUNCE_NETWORK_MS: 10, BROWSE_TEXT_DEBOUNCE_RACE_MS: 10, browseRaceCountsSongs: vi.fn(), diff --git a/src/hooks/useSongBrowseList.ts b/src/hooks/useSongBrowseList.ts index ca4cc9ae..dd93a555 100644 --- a/src/hooks/useSongBrowseList.ts +++ b/src/hooks/useSongBrowseList.ts @@ -2,7 +2,7 @@ import { searchSongsPaged } from '@/lib/api/subsonicSearch'; import type { SubsonicSong } from '@/lib/api/subsonicTypes'; import { useCallback, useEffect, useRef, useState } from 'react'; import { ndListSongs } from '@/lib/api/navidromeBrowse'; -import { runLocalSongBrowse } from '../utils/library/advancedSearchLocal'; +import { runLocalSongBrowse } from '@/lib/library/advancedSearchLocal'; import { BROWSE_TEXT_DEBOUNCE_NETWORK_MS, BROWSE_TEXT_DEBOUNCE_RACE_MS, @@ -11,7 +11,7 @@ import { raceBrowseWithLocalFallback, runLocalBrowseSongPage, runNetworkBrowseSongPage, -} from '../utils/library/browseTextSearch'; +} from '@/lib/library/browseTextSearch'; import { useAuthStore } from '../store/authStore'; import { useLibraryIndexStore } from '../store/libraryIndexStore'; import { useOfflineBrowseContext } from '@/features/offline'; diff --git a/src/lib/api/navidromeBrowse.ts b/src/lib/api/navidromeBrowse.ts index 897c64ae..a6788d4a 100644 --- a/src/lib/api/navidromeBrowse.ts +++ b/src/lib/api/navidromeBrowse.ts @@ -1,5 +1,5 @@ import type { SubsonicAlbum, SubsonicArtist, SubsonicSong } from '@/lib/api/subsonicTypes'; -import { parseItemGenres } from '@/utils/library/genreTags'; +import { parseItemGenres } from '@/lib/library/genreTags'; import { invoke } from '@tauri-apps/api/core'; import { useAuthStore } from '@/store/authStore'; import { ndLogin } from '@/lib/api/navidromeAdmin'; diff --git a/src/lib/api/subsonicScrobble.ts b/src/lib/api/subsonicScrobble.ts index 7b7c7b29..897ed8e8 100644 --- a/src/lib/api/subsonicScrobble.ts +++ b/src/lib/api/subsonicScrobble.ts @@ -1,6 +1,6 @@ import { api, apiForServer } from '@/lib/api/subsonicClient'; import type { PlaybackReportState, SubsonicNowPlaying } from '@/lib/api/subsonicTypes'; -import { patchLibraryTrackOnUse } from '@/utils/library/patchOnUse'; +import { patchLibraryTrackOnUse } from '@/lib/library/patchOnUse'; import { shouldAttemptSubsonicForServer } from '@/utils/network/subsonicNetworkGuard'; async function scrobbleOnServer( diff --git a/src/lib/api/subsonicSearch.ts b/src/lib/api/subsonicSearch.ts index 44d1dc97..45d0ad85 100644 --- a/src/lib/api/subsonicSearch.ts +++ b/src/lib/api/subsonicSearch.ts @@ -1,5 +1,5 @@ import { api, libraryFilterParams } from '@/lib/api/subsonicClient'; -import { searchQueryIsFtsSafe } from '@/utils/library/searchQueryFtsSafe'; +import { searchQueryIsFtsSafe } from '@/lib/library/searchQueryFtsSafe'; import type { SearchResults, SubsonicAlbum, diff --git a/src/lib/api/subsonicStarRating.ts b/src/lib/api/subsonicStarRating.ts index 5fa25152..acfd9192 100644 --- a/src/lib/api/subsonicStarRating.ts +++ b/src/lib/api/subsonicStarRating.ts @@ -1,12 +1,12 @@ import { api, apiForServer, libraryFilterParams, libraryFilterParamsForServer } from '@/lib/api/subsonicClient'; import { invalidateEntityUserRatingCaches } from '@/lib/api/subsonicRatings'; import { useAuthStore } from '@/store/authStore'; -import { patchLibraryTrackOnUse, type StarPatchMeta } from '@/utils/library/patchOnUse'; +import { patchLibraryTrackOnUse, type StarPatchMeta } from '@/lib/library/patchOnUse'; import { useLibraryIndexStore } from '@/store/libraryIndexStore'; import { invalidateStarredAlbumBrowse, refreshStarredAlbumIndexFromServer, -} from '@/utils/library/starredAlbumIndexSync'; +} from '@/lib/library/starredAlbumIndexSync'; import type { EntityRatingSupportLevel, StarredResults, diff --git a/src/lib/api/subsonicStatistics.ts b/src/lib/api/subsonicStatistics.ts index 47911926..77c9f45a 100644 --- a/src/lib/api/subsonicStatistics.ts +++ b/src/lib/api/subsonicStatistics.ts @@ -1,5 +1,5 @@ import { useAuthStore } from '@/store/authStore'; -import { genreTagsFor } from '@/utils/library/genreTags'; +import { genreTagsFor } from '@/lib/library/genreTags'; import { getArtists } from '@/lib/api/subsonicArtists'; import { getAlbumList, getRandomSongs } from '@/lib/api/subsonicLibrary'; import type { diff --git a/src/utils/library/advancedSearchLocal.test.ts b/src/lib/library/advancedSearchLocal.test.ts similarity index 100% rename from src/utils/library/advancedSearchLocal.test.ts rename to src/lib/library/advancedSearchLocal.test.ts diff --git a/src/utils/library/advancedSearchLocal.ts b/src/lib/library/advancedSearchLocal.ts similarity index 100% rename from src/utils/library/advancedSearchLocal.ts rename to src/lib/library/advancedSearchLocal.ts diff --git a/src/utils/library/albumBrowseCatalogChunk.test.ts b/src/lib/library/albumBrowseCatalogChunk.test.ts similarity index 100% rename from src/utils/library/albumBrowseCatalogChunk.test.ts rename to src/lib/library/albumBrowseCatalogChunk.test.ts diff --git a/src/utils/library/albumBrowseFilters.ts b/src/lib/library/albumBrowseFilters.ts similarity index 100% rename from src/utils/library/albumBrowseFilters.ts rename to src/lib/library/albumBrowseFilters.ts diff --git a/src/utils/library/albumBrowseGenreOptions.test.ts b/src/lib/library/albumBrowseGenreOptions.test.ts similarity index 100% rename from src/utils/library/albumBrowseGenreOptions.test.ts rename to src/lib/library/albumBrowseGenreOptions.test.ts diff --git a/src/utils/library/albumBrowseLoad.test.ts b/src/lib/library/albumBrowseLoad.test.ts similarity index 100% rename from src/utils/library/albumBrowseLoad.test.ts rename to src/lib/library/albumBrowseLoad.test.ts diff --git a/src/utils/library/albumBrowseLoad.ts b/src/lib/library/albumBrowseLoad.ts similarity index 100% rename from src/utils/library/albumBrowseLoad.ts rename to src/lib/library/albumBrowseLoad.ts diff --git a/src/utils/library/albumBrowseLocal.ts b/src/lib/library/albumBrowseLocal.ts similarity index 100% rename from src/utils/library/albumBrowseLocal.ts rename to src/lib/library/albumBrowseLocal.ts diff --git a/src/utils/library/albumBrowseNetwork.ts b/src/lib/library/albumBrowseNetwork.ts similarity index 100% rename from src/utils/library/albumBrowseNetwork.ts rename to src/lib/library/albumBrowseNetwork.ts diff --git a/src/utils/library/albumBrowseSort.test.ts b/src/lib/library/albumBrowseSort.test.ts similarity index 100% rename from src/utils/library/albumBrowseSort.test.ts rename to src/lib/library/albumBrowseSort.test.ts diff --git a/src/utils/library/albumBrowseSort.ts b/src/lib/library/albumBrowseSort.ts similarity index 100% rename from src/utils/library/albumBrowseSort.ts rename to src/lib/library/albumBrowseSort.ts diff --git a/src/utils/library/albumBrowseStarredCache.ts b/src/lib/library/albumBrowseStarredCache.ts similarity index 100% rename from src/utils/library/albumBrowseStarredCache.ts rename to src/lib/library/albumBrowseStarredCache.ts diff --git a/src/utils/library/albumBrowseStarredFetch.ts b/src/lib/library/albumBrowseStarredFetch.ts similarity index 100% rename from src/utils/library/albumBrowseStarredFetch.ts rename to src/lib/library/albumBrowseStarredFetch.ts diff --git a/src/utils/library/albumBrowseTypes.ts b/src/lib/library/albumBrowseTypes.ts similarity index 100% rename from src/utils/library/albumBrowseTypes.ts rename to src/lib/library/albumBrowseTypes.ts diff --git a/src/utils/library/albumCatalogYearBounds.ts b/src/lib/library/albumCatalogYearBounds.ts similarity index 100% rename from src/utils/library/albumCatalogYearBounds.ts rename to src/lib/library/albumCatalogYearBounds.ts diff --git a/src/utils/library/albumCompilation.test.ts b/src/lib/library/albumCompilation.test.ts similarity index 100% rename from src/utils/library/albumCompilation.test.ts rename to src/lib/library/albumCompilation.test.ts diff --git a/src/utils/library/albumCompilation.ts b/src/lib/library/albumCompilation.ts similarity index 100% rename from src/utils/library/albumCompilation.ts rename to src/lib/library/albumCompilation.ts diff --git a/src/utils/library/albumYearFilter.test.ts b/src/lib/library/albumYearFilter.test.ts similarity index 100% rename from src/utils/library/albumYearFilter.test.ts rename to src/lib/library/albumYearFilter.test.ts diff --git a/src/utils/library/albumYearFilter.ts b/src/lib/library/albumYearFilter.ts similarity index 100% rename from src/utils/library/albumYearFilter.ts rename to src/lib/library/albumYearFilter.ts diff --git a/src/utils/library/analysisStrategy.ts b/src/lib/library/analysisStrategy.ts similarity index 100% rename from src/utils/library/analysisStrategy.ts rename to src/lib/library/analysisStrategy.ts diff --git a/src/utils/library/browseTextSearch.test.ts b/src/lib/library/browseTextSearch.test.ts similarity index 100% rename from src/utils/library/browseTextSearch.test.ts rename to src/lib/library/browseTextSearch.test.ts diff --git a/src/utils/library/browseTextSearch.ts b/src/lib/library/browseTextSearch.ts similarity index 100% rename from src/utils/library/browseTextSearch.ts rename to src/lib/library/browseTextSearch.ts diff --git a/src/utils/library/composerBrowse.test.ts b/src/lib/library/composerBrowse.test.ts similarity index 100% rename from src/utils/library/composerBrowse.test.ts rename to src/lib/library/composerBrowse.test.ts diff --git a/src/utils/library/composerBrowse.ts b/src/lib/library/composerBrowse.ts similarity index 100% rename from src/utils/library/composerBrowse.ts rename to src/lib/library/composerBrowse.ts diff --git a/src/utils/library/coverBackfillWake.ts b/src/lib/library/coverBackfillWake.ts similarity index 100% rename from src/utils/library/coverBackfillWake.ts rename to src/lib/library/coverBackfillWake.ts diff --git a/src/utils/library/coverStrategy.ts b/src/lib/library/coverStrategy.ts similarity index 100% rename from src/utils/library/coverStrategy.ts rename to src/lib/library/coverStrategy.ts diff --git a/src/utils/library/genreAlbumBrowse.test.ts b/src/lib/library/genreAlbumBrowse.test.ts similarity index 100% rename from src/utils/library/genreAlbumBrowse.test.ts rename to src/lib/library/genreAlbumBrowse.test.ts diff --git a/src/utils/library/genreAlbumBrowse.ts b/src/lib/library/genreAlbumBrowse.ts similarity index 100% rename from src/utils/library/genreAlbumBrowse.ts rename to src/lib/library/genreAlbumBrowse.ts diff --git a/src/utils/library/genreCatalogCountsCache.test.ts b/src/lib/library/genreCatalogCountsCache.test.ts similarity index 100% rename from src/utils/library/genreCatalogCountsCache.test.ts rename to src/lib/library/genreCatalogCountsCache.test.ts diff --git a/src/utils/library/genreCatalogCountsCache.ts b/src/lib/library/genreCatalogCountsCache.ts similarity index 97% rename from src/utils/library/genreCatalogCountsCache.ts rename to src/lib/library/genreCatalogCountsCache.ts index 8b486567..2bdc0bd8 100644 --- a/src/utils/library/genreCatalogCountsCache.ts +++ b/src/lib/library/genreCatalogCountsCache.ts @@ -1,5 +1,5 @@ import type { SubsonicGenre } from '@/lib/api/subsonicTypes'; -import { resolveServerIdForIndexKey } from '../server/serverLookup'; +import { resolveServerIdForIndexKey } from '@/utils/server/serverLookup'; /** Fresh hits skip SQLite entirely. */ const FRESH_TTL_MS = 60 * 60 * 1000; diff --git a/src/utils/library/genreColor.ts b/src/lib/library/genreColor.ts similarity index 100% rename from src/utils/library/genreColor.ts rename to src/lib/library/genreColor.ts diff --git a/src/utils/library/genreTags.test.ts b/src/lib/library/genreTags.test.ts similarity index 100% rename from src/utils/library/genreTags.test.ts rename to src/lib/library/genreTags.test.ts diff --git a/src/utils/library/genreTags.ts b/src/lib/library/genreTags.ts similarity index 100% rename from src/utils/library/genreTags.ts rename to src/lib/library/genreTags.ts diff --git a/src/utils/library/libraryCoverBackfillPolicy.ts b/src/lib/library/libraryCoverBackfillPolicy.ts similarity index 93% rename from src/utils/library/libraryCoverBackfillPolicy.ts rename to src/lib/library/libraryCoverBackfillPolicy.ts index 8666c3e8..eec55e84 100644 --- a/src/utils/library/libraryCoverBackfillPolicy.ts +++ b/src/lib/library/libraryCoverBackfillPolicy.ts @@ -1,4 +1,4 @@ -import { coverEnsureQueueBacklog } from '../../cover/ensureQueue'; +import { coverEnsureQueueBacklog } from '@/cover/ensureQueue'; /** Target in-flight + queued ensures ≈ workers × multiplier (mirror analysis backfill). */ export const LIBRARY_COVER_BACKLOG_DEPTH_MULTIPLIER = 3; diff --git a/src/utils/library/libraryDevLog.test.ts b/src/lib/library/libraryDevLog.test.ts similarity index 100% rename from src/utils/library/libraryDevLog.test.ts rename to src/lib/library/libraryDevLog.test.ts diff --git a/src/utils/library/libraryDevLog.ts b/src/lib/library/libraryDevLog.ts similarity index 100% rename from src/utils/library/libraryDevLog.ts rename to src/lib/library/libraryDevLog.ts diff --git a/src/utils/library/libraryReady.test.ts b/src/lib/library/libraryReady.test.ts similarity index 100% rename from src/utils/library/libraryReady.test.ts rename to src/lib/library/libraryReady.test.ts diff --git a/src/utils/library/libraryReady.ts b/src/lib/library/libraryReady.ts similarity index 97% rename from src/utils/library/libraryReady.ts rename to src/lib/library/libraryReady.ts index a3cae8af..27f5431c 100644 --- a/src/utils/library/libraryReady.ts +++ b/src/lib/library/libraryReady.ts @@ -5,7 +5,7 @@ * index when it's enabled and synced enough for trustworthy results. */ import { libraryGetStatus, type SyncStateDto } from '@/lib/api/library'; -import { useLibraryIndexStore } from '../../store/libraryIndexStore'; +import { useLibraryIndexStore } from '@/store/libraryIndexStore'; /** Spec §9.3 — shared by Live Search, Advanced Search, browse, … */ export function libraryStatusIsReady(status: SyncStateDto): boolean { diff --git a/src/utils/library/librarySession.test.ts b/src/lib/library/librarySession.test.ts similarity index 100% rename from src/utils/library/librarySession.test.ts rename to src/lib/library/librarySession.test.ts diff --git a/src/utils/library/librarySession.ts b/src/lib/library/librarySession.ts similarity index 92% rename from src/utils/library/librarySession.ts rename to src/lib/library/librarySession.ts index 73defc14..9de4adc3 100644 --- a/src/utils/library/librarySession.ts +++ b/src/lib/library/librarySession.ts @@ -3,12 +3,12 @@ import { librarySyncBindSession, } from '@/lib/api/library'; import { enqueueLibrarySync, queueInitialSyncIfNeeded } from './librarySyncQueue'; -import type { ServerProfile } from '../../store/authStoreTypes'; -import { useAuthStore } from '../../store/authStore'; -import { useLibraryIndexStore } from '../../store/libraryIndexStore'; -import { ensureConnectUrlResolved } from '../server/serverEndpoint'; -import { serverIndexKeyForProfile } from '../server/serverIndexKey'; -import { syncServerHttpContextForProfile } from '../server/syncServerHttpContext'; +import type { ServerProfile } from '@/store/authStoreTypes'; +import { useAuthStore } from '@/store/authStore'; +import { useLibraryIndexStore } from '@/store/libraryIndexStore'; +import { ensureConnectUrlResolved } from '@/utils/server/serverEndpoint'; +import { serverIndexKeyForProfile } from '@/utils/server/serverIndexKey'; +import { syncServerHttpContextForProfile } from '@/utils/server/syncServerHttpContext'; import { libraryDevEnabled, logLibraryStatus, logLibrarySync, timed } from './libraryDevLog'; export type BindServerResult = 'bound' | 'offline' | 'error'; diff --git a/src/utils/library/librarySyncQueue.test.ts b/src/lib/library/librarySyncQueue.test.ts similarity index 100% rename from src/utils/library/librarySyncQueue.test.ts rename to src/lib/library/librarySyncQueue.test.ts diff --git a/src/utils/library/librarySyncQueue.ts b/src/lib/library/librarySyncQueue.ts similarity index 100% rename from src/utils/library/librarySyncQueue.ts rename to src/lib/library/librarySyncQueue.ts diff --git a/src/utils/library/liveSearchDebug.test.ts b/src/lib/library/liveSearchDebug.test.ts similarity index 100% rename from src/utils/library/liveSearchDebug.test.ts rename to src/lib/library/liveSearchDebug.test.ts diff --git a/src/utils/library/liveSearchDebug.ts b/src/lib/library/liveSearchDebug.ts similarity index 94% rename from src/utils/library/liveSearchDebug.ts rename to src/lib/library/liveSearchDebug.ts index 4ba9a932..b64f0293 100644 --- a/src/utils/library/liveSearchDebug.ts +++ b/src/lib/library/liveSearchDebug.ts @@ -1,6 +1,6 @@ import { invoke } from '@tauri-apps/api/core'; import type { SearchResults } from '@/lib/api/subsonicTypes'; -import { useAuthStore } from '../../store/authStore'; +import { useAuthStore } from '@/store/authStore'; export function searchHitCounts(result: SearchResults): string { return `${result.artists.length}/${result.albums.length}/${result.songs.length}`; diff --git a/src/utils/library/liveSearchLocal.test.ts b/src/lib/library/liveSearchLocal.test.ts similarity index 100% rename from src/utils/library/liveSearchLocal.test.ts rename to src/lib/library/liveSearchLocal.test.ts diff --git a/src/utils/library/liveSearchLocal.ts b/src/lib/library/liveSearchLocal.ts similarity index 100% rename from src/utils/library/liveSearchLocal.ts rename to src/lib/library/liveSearchLocal.ts diff --git a/src/utils/library/losslessFormats.ts b/src/lib/library/losslessFormats.ts similarity index 100% rename from src/utils/library/losslessFormats.ts rename to src/lib/library/losslessFormats.ts diff --git a/src/utils/library/losslessMode.ts b/src/lib/library/losslessMode.ts similarity index 100% rename from src/utils/library/losslessMode.ts rename to src/lib/library/losslessMode.ts diff --git a/src/utils/library/patchOnUse.test.ts b/src/lib/library/patchOnUse.test.ts similarity index 100% rename from src/utils/library/patchOnUse.test.ts rename to src/lib/library/patchOnUse.test.ts diff --git a/src/utils/library/patchOnUse.ts b/src/lib/library/patchOnUse.ts similarity index 94% rename from src/utils/library/patchOnUse.ts rename to src/lib/library/patchOnUse.ts index 375b613b..ef39dd16 100644 --- a/src/utils/library/patchOnUse.ts +++ b/src/lib/library/patchOnUse.ts @@ -1,5 +1,5 @@ import { libraryPatchTrack } from '@/lib/api/library'; -import { useLibraryIndexStore } from '../../store/libraryIndexStore'; +import { useLibraryIndexStore } from '@/store/libraryIndexStore'; type TrackPatch = { /** ms epoch when starred, or `null` to clear (unstar). */ diff --git a/src/utils/library/searchQueryFtsSafe.test.ts b/src/lib/library/searchQueryFtsSafe.test.ts similarity index 100% rename from src/utils/library/searchQueryFtsSafe.test.ts rename to src/lib/library/searchQueryFtsSafe.test.ts diff --git a/src/utils/library/searchQueryFtsSafe.ts b/src/lib/library/searchQueryFtsSafe.ts similarity index 100% rename from src/utils/library/searchQueryFtsSafe.ts rename to src/lib/library/searchQueryFtsSafe.ts diff --git a/src/utils/library/searchRace.live.test.ts b/src/lib/library/searchRace.live.test.ts similarity index 100% rename from src/utils/library/searchRace.live.test.ts rename to src/lib/library/searchRace.live.test.ts diff --git a/src/utils/library/searchRace.test.ts b/src/lib/library/searchRace.test.ts similarity index 100% rename from src/utils/library/searchRace.test.ts rename to src/lib/library/searchRace.test.ts diff --git a/src/utils/library/searchRace.ts b/src/lib/library/searchRace.ts similarity index 100% rename from src/utils/library/searchRace.ts rename to src/lib/library/searchRace.ts diff --git a/src/utils/library/starredAlbumIndexSync.ts b/src/lib/library/starredAlbumIndexSync.ts similarity index 100% rename from src/utils/library/starredAlbumIndexSync.ts rename to src/lib/library/starredAlbumIndexSync.ts diff --git a/src/utils/library/trackEnrichment.test.ts b/src/lib/library/trackEnrichment.test.ts similarity index 99% rename from src/utils/library/trackEnrichment.test.ts rename to src/lib/library/trackEnrichment.test.ts index bd9a8c40..abaf3e70 100644 --- a/src/utils/library/trackEnrichment.test.ts +++ b/src/lib/library/trackEnrichment.test.ts @@ -9,7 +9,7 @@ import { resolveDisplayBpm, topMoodLabelIds, } from './trackEnrichment'; -import { topDistinctOximediaMoodTagIds, topOximediaMoodTagIds } from '../../config/moodGroups'; +import { topDistinctOximediaMoodTagIds, topOximediaMoodTagIds } from '@/config/moodGroups'; const t = ((key: string, opts?: Record) => { if (key === 'queue.bpm') return `${opts?.bpm} BPM`; diff --git a/src/utils/library/trackEnrichment.ts b/src/lib/library/trackEnrichment.ts similarity index 97% rename from src/utils/library/trackEnrichment.ts rename to src/lib/library/trackEnrichment.ts index c8a3a938..2312d8a5 100644 --- a/src/utils/library/trackEnrichment.ts +++ b/src/lib/library/trackEnrichment.ts @@ -5,7 +5,7 @@ import { topDistinctOximediaMoodTagIds, topDistinctOximediaMoodTagIdsFromValenceArousal, moodScoresFromValenceArousal, -} from '../../config/moodGroups'; +} from '@/config/moodGroups'; /** Oximedia mood labels in queue/Song Info — off until a reliable model ships. */ export const OXIMEDIA_MOOD_UI_ENABLED = false; @@ -15,7 +15,7 @@ export const OXIMEDIA_ENRICHMENT_SOURCE_KIND = 'analysis'; export const OXIMEDIA_ENRICHMENT_SOURCE_ID = 'oximedia-60s-center'; /** Oximedia mood label ids — see `src/config/moodGroups.ts` and Rust `mood_groups`. */ -export type { OximediaMoodTagId } from '../../config/moodGroups'; +export type { OximediaMoodTagId } from '@/config/moodGroups'; export interface ParsedTrackEnrichment { serverBpm: number | null; @@ -115,7 +115,7 @@ export function deriveMoodScores(valence: number, arousal: number): Record { beforeEach(() => { diff --git a/src/store/analysisStrategyStore.ts b/src/store/analysisStrategyStore.ts index e07c4772..ef74aafe 100644 --- a/src/store/analysisStrategyStore.ts +++ b/src/store/analysisStrategyStore.ts @@ -5,7 +5,7 @@ import { DEFAULT_ADVANCED_PARALLELISM, DEFAULT_ANALYTICS_STRATEGY, type AnalyticsStrategy, -} from '../utils/library/analysisStrategy'; +} from '@/lib/library/analysisStrategy'; import { useAuthStore } from './authStore'; import { serverIndexKeyFromUrl } from '../utils/server/serverIndexKey'; import type { ServerProfile } from './authStoreTypes'; diff --git a/src/store/coverStrategyStore.ts b/src/store/coverStrategyStore.ts index 2eace02a..3faa594d 100644 --- a/src/store/coverStrategyStore.ts +++ b/src/store/coverStrategyStore.ts @@ -4,7 +4,7 @@ import { DEFAULT_COVER_CACHE_STRATEGY, coverStrategyFromLegacyPrefetch, type CoverCacheStrategy, -} from '../utils/library/coverStrategy'; +} from '@/lib/library/coverStrategy'; import { useAuthStore } from './authStore'; import { serverIndexKeyFromUrl } from '../utils/server/serverIndexKey'; import type { ServerProfile } from './authStoreTypes'; diff --git a/src/utils/queue/timelineBootstrapReady.test.ts b/src/utils/queue/timelineBootstrapReady.test.ts index 0b2531b2..5f527aec 100644 --- a/src/utils/queue/timelineBootstrapReady.test.ts +++ b/src/utils/queue/timelineBootstrapReady.test.ts @@ -3,11 +3,11 @@ import { useAuthStore } from '../../store/authStore'; import { useLibraryIndexStore } from '../../store/libraryIndexStore'; import { timelineBootstrapIndexReady } from './timelineBootstrapReady'; -vi.mock('../library/libraryReady', () => ({ +vi.mock('@/lib/library/libraryReady', () => ({ libraryIsReady: vi.fn(), })); -import { libraryIsReady } from '../library/libraryReady'; +import { libraryIsReady } from '@/lib/library/libraryReady'; describe('timelineBootstrapIndexReady', () => { beforeEach(() => { diff --git a/src/utils/queue/timelineBootstrapReady.ts b/src/utils/queue/timelineBootstrapReady.ts index 4d42deec..c1856846 100644 --- a/src/utils/queue/timelineBootstrapReady.ts +++ b/src/utils/queue/timelineBootstrapReady.ts @@ -1,6 +1,6 @@ import { useAuthStore } from '../../store/authStore'; import { useLibraryIndexStore } from '../../store/libraryIndexStore'; -import { libraryIsReady } from '../library/libraryReady'; +import { libraryIsReady } from '@/lib/library/libraryReady'; /** * Timeline cold bootstrap reads local `play_session` (cross-server). Gate on at