//! Audio and video playback settings commands. //! //! TRACES: UR-022, UR-027, UR-031, UR-032, UR-033 | DR-025, DR-030, DR-034, DR-035, DR-036, IR-020 use tauri::State; use super::{PlayerStateWrapper, VideoSettingsWrapper}; use crate::player::AutoplaySettings; use crate::settings::{AudioSettings, EqPreset, VideoSettings}; #[tauri::command] #[specta::specta] pub async fn player_set_audio_settings( player: State<'_, PlayerStateWrapper>, settings: AudioSettings, ) -> Result { // Validate/normalise domain values before applying: clamp crossfade to its // range and normalise the equalizer band vector (length + gain clamps). let validated = settings .with_crossfade_clamped() .with_equalizer_normalised(); let mut controller = player.0.lock().await; controller .set_audio_settings(&validated) .map_err(|e| e.to_string())?; Ok(controller.audio_settings()) } /// The built-in equalizer presets and their per-band gain curves (dB), for the /// settings UI. The curve numbers are domain data defined by the band layout, /// so the frontend reads them here rather than encoding them. /// /// TRACES: UR-027 | DR-030 #[tauri::command] #[specta::specta] pub async fn player_get_eq_presets() -> Result)>, String> { Ok(EqPreset::ALL .iter() .map(|p| (*p, p.gains().to_vec())) .collect()) } #[tauri::command] #[specta::specta] pub async fn player_get_audio_settings( player: State<'_, PlayerStateWrapper>, ) -> Result { let controller = player.0.lock().await; Ok(controller.audio_settings()) } #[tauri::command] #[specta::specta] pub async fn player_set_video_settings( video_settings: State<'_, VideoSettingsWrapper>, player: State<'_, PlayerStateWrapper>, settings: VideoSettings, ) -> Result { let validated = settings.with_countdown_clamped(); { let mut current = video_settings.0.lock().map_err(|e| e.to_string())?; *current = validated.clone(); } // Drop MutexGuard before await // Sync to PlayerController's autoplay settings so on_playback_ended() uses current values let controller = player.0.lock().await; controller.set_autoplay_settings(AutoplaySettings { enabled: validated.auto_play_next_episode, countdown_seconds: validated.auto_play_countdown_seconds, max_episodes: validated.auto_play_max_episodes, }); Ok(validated) } #[tauri::command] #[specta::specta] pub async fn player_get_video_settings( video_settings: State<'_, VideoSettingsWrapper>, ) -> Result { let current = video_settings.0.lock().map_err(|e| e.to_string())?; Ok(current.clone()) }