mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 07:15:47 +00:00
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.
This commit is contained in:
+1
-1
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
normalizeAlbumYearToFieldChange,
|
||||
resolveAlbumYearBounds,
|
||||
stepAlbumYearField,
|
||||
} from '../utils/library/albumYearFilter';
|
||||
} from '@/lib/library/albumYearFilter';
|
||||
|
||||
interface Props {
|
||||
from: string;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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 };
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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[];
|
||||
|
||||
@@ -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). */
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
albumToAlbum,
|
||||
artistToArtist,
|
||||
trackToSong,
|
||||
} from '@/utils/library/advancedSearchLocal';
|
||||
} from '@/lib/library/advancedSearchLocal';
|
||||
|
||||
export async function loadAlbumFromLibraryIndex(
|
||||
serverId: string,
|
||||
|
||||
@@ -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[] {
|
||||
|
||||
@@ -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),
|
||||
}));
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<typeof import('@/utils/library/genreAlbumBrowse')>()),
|
||||
vi.mock('@/lib/library/genreAlbumBrowse', async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import('@/lib/library/genreAlbumBrowse')>()),
|
||||
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(() => {
|
||||
|
||||
@@ -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[] {
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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' }
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+1
-1
@@ -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;
|
||||
+1
-1
@@ -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;
|
||||
@@ -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 {
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user