import { getPlayQueue } from '../api/subsonicPlayQueue'; import { invoke } from '@tauri-apps/api/core'; import i18n from '../i18n'; import { songToTrack } from '../utils/playback/songToTrack'; import { showToast } from '../utils/ui/toast'; import { useAuthStore } from './authStore'; import { bumpPlayGeneration, setIsAudioPaused, } from './engineState'; import { clearPreloadingIds } from './gaplessPreloadState'; import { reseedLoudnessForTrackId } from './loudnessReseed'; import { getPlaybackProgressSnapshot } from './playbackProgress'; import { shouldRebindPlaybackToHotCache } from './playbackUrlRouting'; import type { PlayerState, Track } from './playerStoreTypes'; import { pushQueueUndoFromGetter } from './queueUndo'; import { syncQueueToServer } from './queueSync'; import { clearRadioReconnectTimer, playRadioStream, setRadioVolume, } from './radioPlayer'; import { clearAllPlaybackScheduleTimers } from './scheduleTimers'; import { clearSeekDebounce } from './seekDebounce'; import { clearSeekFallbackRetry, setSeekFallbackVisualTarget, } from './seekFallbackState'; import { clearSeekTarget } from './seekTargetState'; import { refreshWaveformForTrack } from './waveformRefresh'; type SetState = ( partial: Partial | ((state: PlayerState) => Partial), ) => void; type GetState = () => PlayerState; /** * Heterogeneous "misc" cluster — seven small-to-medium actions that * don't fit the more focused factories (transport / queue / Last.fm / * UI state): * * - `playRadio` — switches the player into HTML5 radio mode (Rust * engine stopped, queue cleared, ICY stream resolved + played). * - `previous` — Subsonic-style back: restart current track if past * 3 s, otherwise jump to the previous queue index. * - `setVolume` — clamps + propagates to Rust engine and radio sink. * - `setProgress` — pure UI state update used by progress polling. * - `initializeFromServerQueue` — startup queue restore from * Navidrome's `getPlayQueue` endpoint. * - `reanalyzeLoudnessForTrack` — toast + reseed the loudness cache * for a single track. * - `reseedQueueForInstantMix` — replaces the queue with a single * track when "Instant Mix" is triggered on the currently-playing * song. */ export function createMiscActions(set: SetState, get: GetState): Pick< PlayerState, | 'playRadio' | 'previous' | 'setVolume' | 'setProgress' | 'initializeFromServerQueue' | 'reanalyzeLoudnessForTrack' | 'reseedQueueForInstantMix' > { return { playRadio: async (station) => { const { volume } = get(); bumpPlayGeneration(); clearAllPlaybackScheduleTimers(); set({ scheduledPauseAtMs: null, scheduledPauseStartMs: null, scheduledResumeAtMs: null, scheduledResumeStartMs: null }); setIsAudioPaused(false); clearRadioReconnectTimer(); clearPreloadingIds(); clearSeekFallbackRetry(); clearSeekDebounce(); clearSeekTarget(); // Stop Rust engine in case a regular track was playing. invoke('audio_stop').catch(() => {}); // Resolve PLS/M3U playlist URLs to the actual stream URL before handing // to HTML5