mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-22 14:35:41 +00:00
ae2e123a14
* feat: add long press to shuffle with a wave animation to singnify how long to press * refactor: long-press shuffle cleanup Follow-up on the long-press shuffle PR: shared hook/overlay, playback parity, pointer events, broader surface coverage, locales, and tests. * docs: credit ImAsra for long-press album shuffle (PR #888) Add CHANGELOG entry and Settings credits for the hold-to-shuffle play interaction shipped in Psychotoxical/psysonic#888. * fix: restore playAlbumShuffled and long-press hook wiring The follow-up merge dropped playAlbumShuffled and reverted the shared long-press hook in album play buttons, breaking tsc and vitest on PR #888. --------- Co-authored-by: cucadmuh <49571317+cucadmuh@users.noreply.github.com>
54 lines
2.1 KiB
TypeScript
54 lines
2.1 KiB
TypeScript
import { getAlbum } from '../../api/subsonicLibrary';
|
|
import { usePlayerStore } from '../../store/playerStore';
|
|
import { songToTrack } from './songToTrack';
|
|
import { useOrbitStore } from '../../store/orbitStore';
|
|
import { fadeOut } from './fadeOut';
|
|
import type { Track } from '../../store/playerStoreTypes';
|
|
import { shuffleArray } from './shuffleArray';
|
|
|
|
async function fetchAlbumTracks(albumId: string): Promise<Track[]> {
|
|
const albumData = await getAlbum(albumId);
|
|
const albumGenre = albumData.album.genre;
|
|
return albumData.songs.map(s => {
|
|
const track = songToTrack(s);
|
|
if (!track.genre && albumGenre) track.genre = albumGenre;
|
|
return track;
|
|
});
|
|
}
|
|
|
|
async function startAlbumPlayback(tracks: Track[]): Promise<void> {
|
|
if (!tracks.length) return;
|
|
|
|
// In Orbit sessions, playAlbum is effectively an append operation (the
|
|
// playerStore bulk-gate also routes replaces into enqueue). Skip the
|
|
// fadeOut entirely — the current track keeps playing, the album goes
|
|
// onto the end of the queue after the user confirms the bulk dialog.
|
|
const orbitRole = useOrbitStore.getState().role;
|
|
if (orbitRole === 'host' || orbitRole === 'guest') {
|
|
usePlayerStore.getState().enqueue(tracks);
|
|
return;
|
|
}
|
|
|
|
const store = usePlayerStore.getState();
|
|
const { isPlaying, volume } = store;
|
|
|
|
if (isPlaying) {
|
|
await fadeOut(store.setVolume, volume, 700);
|
|
// Restore volume only in the Zustand store — do NOT call audio_set_volume here,
|
|
// otherwise the old track glitches back to full volume before playTrack stops it.
|
|
// playTrack reads state.volume and passes it to audio_play, so the new track
|
|
// starts at the correct volume without the Rust engine ever hearing a restore.
|
|
usePlayerStore.setState({ volume });
|
|
}
|
|
|
|
usePlayerStore.getState().playTrack(tracks[0], tracks);
|
|
}
|
|
|
|
export async function playAlbum(albumId: string): Promise<void> {
|
|
await startAlbumPlayback(await fetchAlbumTracks(albumId));
|
|
}
|
|
|
|
export async function playAlbumShuffled(albumId: string): Promise<void> {
|
|
await startAlbumPlayback(shuffleArray(await fetchAlbumTracks(albumId)));
|
|
}
|