mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-21 23:05:46 +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.
30 lines
1.0 KiB
TypeScript
30 lines
1.0 KiB
TypeScript
import { useCallback, useEffect } from 'react';
|
|
import { usePreviewStore } from '../store/previewStore';
|
|
import type { SubsonicSong } from '../api/subsonicTypes';
|
|
|
|
export function usePlaylistPreview(): {
|
|
startPreview: (song: SubsonicSong) => void;
|
|
} {
|
|
// Pause/resume of the main player + timer + cancel-on-supersede are all
|
|
// handled in `audio_preview_play` / `audio_preview_stop`. The store mirrors
|
|
// engine events so we just dispatch here and read `previewingId` for UI.
|
|
const startPreview = useCallback((song: SubsonicSong) => {
|
|
usePreviewStore.getState().startPreview({
|
|
id: song.id,
|
|
title: song.title,
|
|
artist: song.artist,
|
|
coverArt: song.coverArt,
|
|
duration: song.duration,
|
|
}, 'suggestions').catch(() => { /* engine errored — store already rolled back */ });
|
|
}, []);
|
|
|
|
// Cancel any in-flight preview when the user navigates away.
|
|
useEffect(() => () => {
|
|
if (usePreviewStore.getState().previewingId) {
|
|
usePreviewStore.getState().stopPreview();
|
|
}
|
|
}, []);
|
|
|
|
return { startPreview };
|
|
}
|