mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 07:15:47 +00:00
refactor(lib): relocate shuffleArray to lib/util; albumBrowseCatalogChunk to features/album
shuffleArray is a pure generic Fisher-Yates over T[], misfiled in features/playback. Move to lib/util (next to dedupeById): fixes the existing core->feature edges (utils/componentHelpers/*) and drops one of genreBrowsePlayback's playback deps. albumBrowseCatalogChunk is the feature-layer orchestrator that picks the offline branch on top of the pure lib catalog loaders; its sole consumer lives in features/album and its offline dep is a legal feature->feature edge there. Its .test.ts stays in utils/library -- that test exercises fetchLocalAlbumCatalogChunk from albumBrowseLoad (misnamed), which is not moving. utils/library now has a single remaining feature importer: genreBrowsePlayback (songToTrack + type Track), blocked on the Track domain model living in features/playback. tsc 0, lint 0, targeted suites green.
This commit is contained in:
@@ -3,7 +3,7 @@ import { filterAlbumsToActiveLibrary } from '@/lib/api/subsonicLibrary';
|
||||
import { resolveAlbum, resolveMediaServerId } from '@/features/offline';
|
||||
import type { SubsonicAlbum } from '@/lib/api/subsonicTypes';
|
||||
import { songToTrack } from '@/features/playback/utils/playback/songToTrack';
|
||||
import { shuffleArray } from '@/features/playback/utils/playback/shuffleArray';
|
||||
import { shuffleArray } from '@/lib/util/shuffleArray';
|
||||
import React, { memo, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
@@ -35,7 +35,7 @@ import { useOfflineBrowseReloadToken } from '@/features/offline';
|
||||
import {
|
||||
fetchAlbumBrowseCatalogChunk,
|
||||
mergeAlbumCatalogChunk,
|
||||
} from '@/utils/library/albumBrowseCatalogChunk';
|
||||
} from '@/features/album/utils/albumBrowseCatalogChunk';
|
||||
import { useOfflineBrowseContext } from '@/features/offline';
|
||||
import { useClientSliceInfiniteScroll } from '@/hooks/useClientSliceInfiniteScroll';
|
||||
import { useDebouncedValue } from '@/lib/hooks/useDebouncedValue';
|
||||
|
||||
@@ -5,7 +5,7 @@ import { getAlbumForServer } from '@/lib/api/subsonicLibrary';
|
||||
import { getArtistInfo } from '@/lib/api/subsonicArtists';
|
||||
import type { SubsonicSong } from '@/lib/api/subsonicTypes';
|
||||
import { songToTrack } from '@/features/playback/utils/playback/songToTrack';
|
||||
import { shuffleArray } from '@/features/playback/utils/playback/shuffleArray';
|
||||
import { shuffleArray } from '@/lib/util/shuffleArray';
|
||||
import React, { useEffect, useState, useCallback, useMemo } from 'react';
|
||||
import { useParams, useSearchParams } from 'react-router-dom';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
|
||||
@@ -4,7 +4,7 @@ import { getAlbumList } from '@/lib/api/subsonicLibrary';
|
||||
import { resolveAlbum } from '@/features/offline';
|
||||
import type { SubsonicAlbum } from '@/lib/api/subsonicTypes';
|
||||
import { dedupeById } from '@/lib/util/dedupeById';
|
||||
import { shuffleArray } from '@/features/playback/utils/playback/shuffleArray';
|
||||
import { shuffleArray } from '@/lib/util/shuffleArray';
|
||||
import React, { useEffect, useLayoutEffect, useState, useCallback, useRef } from 'react';
|
||||
import { RefreshCw, Download, HardDriveDownload } from 'lucide-react';
|
||||
import SelectionToggleButton from '@/components/SelectionToggleButton';
|
||||
|
||||
+2
-2
@@ -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 './albumBrowseTypes';
|
||||
import { fetchLocalAlbumCatalogChunk } from './albumBrowseLoad';
|
||||
import type { AlbumBrowseQuery } from '@/utils/library/albumBrowseTypes';
|
||||
import { fetchLocalAlbumCatalogChunk } from '@/utils/library/albumBrowseLoad';
|
||||
|
||||
export type AlbumCatalogChunk = {
|
||||
albums: SubsonicAlbum[];
|
||||
@@ -33,7 +33,7 @@ import {
|
||||
type OfflineLibraryCard,
|
||||
} from '@/features/offline/utils/offlineLibraryHelpers';
|
||||
import { showToast } from '@/utils/ui/toast';
|
||||
import { shuffleArray } from '@/features/playback/utils/playback/shuffleArray';
|
||||
import { shuffleArray } from '@/lib/util/shuffleArray';
|
||||
import { getMediaDir } from '@/utils/media/mediaDir';
|
||||
import { canonicalQueueServerKey, resolveIndexKey } from '@/utils/server/serverIndexKey';
|
||||
import { reconcileAllLibraryTiersFromDisk } from '@/features/offline/utils/libraryTierReconcile';
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
getMixMinRatingsConfigFromAuth,
|
||||
passesMixMinRatings,
|
||||
} from '@/utils/mix/mixRatingFilter';
|
||||
import { shuffleArray } from '@/features/playback/utils/playback/shuffleArray';
|
||||
import { shuffleArray } from '@/lib/util/shuffleArray';
|
||||
import { songToTrack } from '@/features/playback/utils/playback/songToTrack';
|
||||
/**
|
||||
* Infinite queue source strategy (Instant Mix-like):
|
||||
|
||||
@@ -19,7 +19,7 @@ import { resolveAlbumForActiveServer } from '@/store/mediaResolver';
|
||||
import { useOrbitStore } from '@/features/orbit';
|
||||
import { usePlayerStore } from '@/features/playback/store/playerStore';
|
||||
import { playAlbum, playAlbumShuffled } from '@/features/playback/utils/playback/playAlbum';
|
||||
import * as shuffleModule from '@/features/playback/utils/playback/shuffleArray';
|
||||
import * as shuffleModule from '@/lib/util/shuffleArray';
|
||||
|
||||
const albumPayload = {
|
||||
album: {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { orbitSnapshot } from '@/store/orbitRuntime';
|
||||
import { fadeOut } from '@/features/playback/utils/playback/fadeOut';
|
||||
import { shouldAutodjInterruptBlend } from '@/features/playback/utils/playback/autodjManualBlend';
|
||||
import type { Track } from '@/features/playback/store/playerStoreTypes';
|
||||
import { shuffleArray } from '@/features/playback/utils/playback/shuffleArray';
|
||||
import { shuffleArray } from '@/lib/util/shuffleArray';
|
||||
|
||||
export async function fetchAlbumTracks(albumId: string, serverId?: string): Promise<Track[]> {
|
||||
const albumData = await resolveAlbumForActiveServer(albumId, serverId);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { resolveAlbum, resolveArtist, resolveMediaServerId } from '@/store/mediaResolver';
|
||||
import { songToTrack } from '@/features/playback/utils/playback/songToTrack';
|
||||
import { shuffleArray } from '@/features/playback/utils/playback/shuffleArray';
|
||||
import { shuffleArray } from '@/lib/util/shuffleArray';
|
||||
import { usePlayerStore } from '@/features/playback/store/playerStore';
|
||||
/**
|
||||
* All tracks from the artist’s albums, shuffled — same idea as Artist page “shuffle play”.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Track } from '@/features/playback/store/playerStoreTypes';
|
||||
import { shuffleArray } from '@/features/playback/utils/playback/shuffleArray';
|
||||
import { shuffleArray } from '@/lib/util/shuffleArray';
|
||||
|
||||
/**
|
||||
* Shared "play / shuffle / enqueue a fetched track list" core for detail pages whose
|
||||
|
||||
@@ -6,7 +6,7 @@ import { getSimilarSongs } from '@/lib/api/subsonicArtists';
|
||||
import { getMusicFolders } from '@/lib/api/subsonicLibrary';
|
||||
import { search as subsonicSearch } from '@/lib/api/subsonicSearch';
|
||||
import { filterSongsForLuckyMixRatings, getMixMinRatingsConfigFromAuth } from '../../utils/mix/mixRatingFilter';
|
||||
import { shuffleArray } from '@/features/playback/utils/playback/shuffleArray';
|
||||
import { shuffleArray } from '@/lib/util/shuffleArray';
|
||||
import { songToTrack } from '@/features/playback/utils/playback/songToTrack';
|
||||
import { showToast } from '../../utils/ui/toast';
|
||||
import { switchActiveServer } from '../../utils/server/switchActiveServer';
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
* refactor (2026-05-12).
|
||||
*/
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import { shuffleArray } from '@/features/playback/utils/playback/shuffleArray';
|
||||
import { shuffleArray } from '@/lib/util/shuffleArray';
|
||||
|
||||
describe('shuffleArray', () => {
|
||||
afterEach(() => {
|
||||
+1
-1
@@ -17,7 +17,7 @@ import { filterAlbumsByMixRatings, getMixMinRatingsConfigFromAuth } from '../uti
|
||||
import { usePerfProbeFlags } from '../utils/perf/perfFlags';
|
||||
import { bumpPerfCounter } from '../utils/perf/perfTelemetry';
|
||||
import { dedupeById } from '@/lib/util/dedupeById';
|
||||
import { shuffleArray } from '@/features/playback/utils/playback/shuffleArray';
|
||||
import { shuffleArray } from '@/lib/util/shuffleArray';
|
||||
import { useLibraryCoverPrefetch } from '../cover/useLibraryCoverPrefetch';
|
||||
import { primeAlbumCoversForDisplay, warmHomeMainstageCovers } from '../cover/warmDiskPeek';
|
||||
import { readBecauseYouLikeCache } from '../store/becauseYouLikeCache';
|
||||
|
||||
@@ -7,7 +7,7 @@ import type { SubsonicGenre } from '@/lib/api/subsonicTypes';
|
||||
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 '@/features/playback/utils/playback/shuffleArray';
|
||||
import { shuffleArray } from '@/lib/util/shuffleArray';
|
||||
import { trackToSong } from './advancedSearchLocal';
|
||||
import { type AlbumBrowseSort } from './albumBrowseSort';
|
||||
import {
|
||||
|
||||
Reference in New Issue
Block a user