mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 07:15:47 +00:00
16ee1ea373
Four-cut cluster pulling the remaining handler bodies + memo island
out of PlaylistDetail.tsx. 507 → 437 LOC (−70).
runPlaylistLoad — async fetch + populate flow that the load
useEffect drives: getPlaylist → filterSongsToActiveLibrary →
setPlaylist + setSongs + setCustomCoverId from playlist.coverArt +
rebuild ratings + starredSongs from each song's stored userRating /
starred flag. Takes the six setters as deps. Page keeps the
useEffect that calls it on id / lastModified change.
usePlaylistPreview — startPreview callback (dispatches into
previewStore with the 'suggestions' source) plus the unmount-time
stopPreview cleanup. Returns just { startPreview }. No props
needed.
usePlaylistBulkPlayCallbacks — wraps playPlaylistAll /
shufflePlaylistAll / enqueuePlaylistAll utilities behind three
useCallback handles with the right deps array. Takes
{ songsLength, id, tracks, touchPlaylist, playTrack, enqueue }.
usePlaylistDerived — existingIds, tracks (songToTrack), sorted +
filtered displayedSongs via getDisplayedSongs, displayedTracks (with
the cheap aliasing optimization when displayedSongs === songs),
isFiltered. Subscribes to playerStore's userRatingOverrides +
starredOverrides directly so the page no longer threads them through
the memo deps.
PlaylistDetail drops these direct imports — they followed the new
modules: getPlaylist, filterSongsToActiveLibrary, songToTrack,
useMemo, getDisplayedSongs (now type-only),
playPlaylistAll/shuffle/enqueue from playlistBulkPlayActions.
Pure code move otherwise.
39 lines
1.5 KiB
TypeScript
39 lines
1.5 KiB
TypeScript
import type React from 'react';
|
|
import { getPlaylist } from '../api/subsonicPlaylists';
|
|
import { filterSongsToActiveLibrary } from '../api/subsonicLibrary';
|
|
import type { SubsonicPlaylist, SubsonicSong } from '../api/subsonicTypes';
|
|
|
|
export interface RunPlaylistLoadDeps {
|
|
id: string;
|
|
setLoading: (v: boolean) => void;
|
|
setPlaylist: React.Dispatch<React.SetStateAction<SubsonicPlaylist | null>>;
|
|
setSongs: React.Dispatch<React.SetStateAction<SubsonicSong[]>>;
|
|
setCustomCoverId: React.Dispatch<React.SetStateAction<string | null>>;
|
|
setRatings: React.Dispatch<React.SetStateAction<Record<string, number>>>;
|
|
setStarredSongs: React.Dispatch<React.SetStateAction<Set<string>>>;
|
|
}
|
|
|
|
export async function runPlaylistLoad(deps: RunPlaylistLoadDeps): Promise<void> {
|
|
const { id, setLoading, setPlaylist, setSongs, setCustomCoverId, setRatings, setStarredSongs } = deps;
|
|
setLoading(true);
|
|
try {
|
|
const { playlist, songs } = await getPlaylist(id);
|
|
const filteredSongs = await filterSongsToActiveLibrary(songs);
|
|
setPlaylist(playlist);
|
|
setSongs(filteredSongs);
|
|
if (playlist.coverArt) setCustomCoverId(playlist.coverArt);
|
|
const init: Record<string, number> = {};
|
|
const starred = new Set<string>();
|
|
filteredSongs.forEach(s => {
|
|
if (s.userRating) init[s.id] = s.userRating;
|
|
if (s.starred) starred.add(s.id);
|
|
});
|
|
setRatings(init);
|
|
setStarredSongs(starred);
|
|
} catch {
|
|
// intentional swallow; load failure leaves loading false + playlist null
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}
|