Files
Psychotoxical-psysonic/src/store/authAudioSettingsActions.ts
T
Frank Stellmacher b8ddb09b78 refactor(auth): E.44 — extract server-profile + lastfm + audio-settings factories (#609)
Three action-factories peel ~25 setters out of the authStore body,
following the playerStore action-factory pattern from Phase E:

- `createServerProfileActions` — `addServer`, `updateServer`,
  `removeServer` (the non-trivial one — drops every per-server map
  entry for the removed id), `setServers`, `setActiveServer`,
  `setLoggedIn`, `setConnecting`, `setConnectionError`, `logout`.
- `createAuthLastfmActions` — credentials + session connect/disconnect
  + error flag + master scrobbling toggle. Network calls (love /
  scrobble) stay in the playerStore-side `lastfmActions.ts`.
- `createAudioSettingsActions` — replay-gain / normalization /
  loudness mode toggles (each calls `usePlayerStore.getState()
  .updateReplayGainForCurrentTrack()` so a running track catches up),
  plus crossfade / gapless / hi-res / audio-output (no engine
  callback needed).

Pure code-move; no behaviour change. authStore.ts: 518 → 428 LOC (−90).
2026-05-12 23:30:28 +02:00

75 lines
2.9 KiB
TypeScript

import { clampStoredLoudnessPreAnalysisAttenuationRefDb } from '../utils/loudnessPreAnalysisSlider';
import { DEFAULT_LOUDNESS_PRE_ANALYSIS_ATTENUATION_DB } from './authStoreDefaults';
import { usePlayerStore } from './playerStore';
import type { AuthState } from './authStoreTypes';
type SetState = (
partial: Partial<AuthState> | ((state: AuthState) => Partial<AuthState>),
) => void;
/**
* Audio/playback settings. ReplayGain/normalization/loudness mode
* toggles call `usePlayerStore.getState().updateReplayGainForCurrentTrack()`
* so a running track's engine state catches up to the new mode without
* waiting for the next play. The plain crossfade/gapless/hi-res/output
* setters skip that — they don't change the gain state, only the
* neighbouring transitions or device routing.
*/
export function createAudioSettingsActions(set: SetState): Pick<
AuthState,
| 'setReplayGainEnabled'
| 'setNormalizationEngine'
| 'setLoudnessTargetLufs'
| 'setLoudnessPreAnalysisAttenuationDb'
| 'resetLoudnessPreAnalysisAttenuationDbDefault'
| 'setReplayGainMode'
| 'setReplayGainPreGainDb'
| 'setReplayGainFallbackDb'
| 'setCrossfadeEnabled'
| 'setCrossfadeSecs'
| 'setGaplessEnabled'
| 'setEnableHiRes'
| 'setAudioOutputDevice'
> {
return {
setReplayGainEnabled: (v) => {
set({ replayGainEnabled: v });
usePlayerStore.getState().updateReplayGainForCurrentTrack();
},
setNormalizationEngine: (v) => {
set({ normalizationEngine: v });
usePlayerStore.getState().updateReplayGainForCurrentTrack();
},
setLoudnessTargetLufs: (v) => {
set({ loudnessTargetLufs: v });
usePlayerStore.getState().updateReplayGainForCurrentTrack();
},
setLoudnessPreAnalysisAttenuationDb: (v) => {
const n = typeof v === 'number' ? v : Number(v);
if (!Number.isFinite(n)) return;
set({ loudnessPreAnalysisAttenuationDb: clampStoredLoudnessPreAnalysisAttenuationRefDb(n) });
},
resetLoudnessPreAnalysisAttenuationDbDefault: () => {
set({ loudnessPreAnalysisAttenuationDb: DEFAULT_LOUDNESS_PRE_ANALYSIS_ATTENUATION_DB });
usePlayerStore.getState().updateReplayGainForCurrentTrack();
},
setReplayGainMode: (v) => {
set({ replayGainMode: v });
usePlayerStore.getState().updateReplayGainForCurrentTrack();
},
setReplayGainPreGainDb: (v) => {
set({ replayGainPreGainDb: v });
usePlayerStore.getState().updateReplayGainForCurrentTrack();
},
setReplayGainFallbackDb: (v) => {
set({ replayGainFallbackDb: v });
usePlayerStore.getState().updateReplayGainForCurrentTrack();
},
setCrossfadeEnabled: (v) => set({ crossfadeEnabled: v }),
setCrossfadeSecs: (v) => set({ crossfadeSecs: v }),
setGaplessEnabled: (v) => set({ gaplessEnabled: v }),
setEnableHiRes: (v) => set({ enableHiRes: v }),
setAudioOutputDevice: (v) => set({ audioOutputDevice: v }),
};
}