jellytau_lib/commands/player/
settings.rs1use std::sync::Arc;
6
7use log::{info, warn};
8use tauri::{Manager, State};
9
10use super::{PlayerStateWrapper, VideoSettingsWrapper};
11use crate::commands::storage::DatabaseWrapper;
12use crate::player::AutoplaySettings;
13use crate::settings::{AudioSettings, EqPreset, StreamingQuality, VideoSettings};
14use crate::storage::db_service::{DatabaseService, Query, QueryParam};
15use crate::utils::lock::MutexSafe;
16
17const STREAMING_QUALITY_KEY: &str = "streaming_quality";
27
28#[tauri::command]
29#[specta::specta]
30pub async fn player_set_audio_settings(
31 player: State<'_, PlayerStateWrapper>,
32 settings: AudioSettings,
33) -> Result<AudioSettings, String> {
34 let validated = settings
37 .with_crossfade_clamped()
38 .with_equalizer_normalised();
39 let mut controller = player.0.lock().await;
40 controller
41 .set_audio_settings(&validated)
42 .map_err(|e| e.to_string())?;
43 Ok(controller.audio_settings())
44}
45
46#[tauri::command]
52#[specta::specta]
53pub async fn player_get_eq_presets() -> Result<Vec<(EqPreset, Vec<f32>)>, String> {
54 Ok(EqPreset::ALL
55 .iter()
56 .map(|p| (*p, p.gains().to_vec()))
57 .collect())
58}
59
60#[tauri::command]
61#[specta::specta]
62pub async fn player_get_audio_settings(
63 player: State<'_, PlayerStateWrapper>,
64) -> Result<AudioSettings, String> {
65 let controller = player.0.lock().await;
66 Ok(controller.audio_settings())
67}
68
69#[tauri::command]
70#[specta::specta]
71pub async fn player_set_video_settings(
72 video_settings: State<'_, VideoSettingsWrapper>,
73 player: State<'_, PlayerStateWrapper>,
74 db: State<'_, DatabaseWrapper>,
75 settings: VideoSettings,
76) -> Result<VideoSettings, String> {
77 let validated = settings.with_countdown_clamped();
78 {
79 let mut current = video_settings.0.lock().map_err(|e| e.to_string())?;
80 *current = validated.clone();
81 } crate::repository::online::set_streaming_quality(validated.streaming_quality);
87 persist_streaming_quality(&db, validated.streaming_quality).await;
88
89 let controller = player.0.lock().await;
91 controller.set_autoplay_settings(AutoplaySettings {
92 enabled: validated.auto_play_next_episode,
93 countdown_seconds: validated.auto_play_countdown_seconds,
94 max_episodes: validated.auto_play_max_episodes,
95 });
96
97 Ok(validated)
98}
99
100#[tauri::command]
109#[specta::specta]
110pub async fn player_get_streaming_qualities(
111) -> Result<Vec<(StreamingQuality, String, String)>, String> {
112 Ok(StreamingQuality::ALL
113 .iter()
114 .map(|q| (*q, q.label().to_string(), q.detail().to_string()))
115 .collect())
116}
117
118async fn persist_streaming_quality(db: &State<'_, DatabaseWrapper>, quality: StreamingQuality) {
124 let db_service = {
125 let database = db.0.lock_safe();
126 Arc::new(database.service())
127 };
128
129 let encoded = match serde_json::to_string(&quality) {
130 Ok(value) => value,
131 Err(e) => {
132 warn!("[VideoSettings] Failed to encode streaming quality: {}", e);
133 return;
134 }
135 };
136
137 let query = Query::with_params(
138 "INSERT OR REPLACE INTO app_settings (key, value, updated_at)
139 VALUES (?, ?, CURRENT_TIMESTAMP)",
140 vec![
141 QueryParam::String(STREAMING_QUALITY_KEY.to_string()),
142 QueryParam::String(encoded),
143 ],
144 );
145
146 if let Err(e) = db_service.execute(query).await {
147 warn!("[VideoSettings] Failed to persist streaming quality: {}", e);
148 }
149}
150
151pub async fn restore_streaming_quality(app: &tauri::AppHandle) {
160 let db_service = {
161 let Some(db) = app.try_state::<DatabaseWrapper>() else {
162 warn!("[VideoSettings] No database available; streaming quality stays uncapped");
163 return;
164 };
165 let database = db.0.lock_safe();
166 Arc::new(database.service())
167 };
168
169 let query = Query::with_params(
170 "SELECT value FROM app_settings WHERE key = ?",
171 vec![QueryParam::String(STREAMING_QUALITY_KEY.to_string())],
172 );
173
174 let stored: Option<String> = match db_service.query_optional(query, |row| row.get(0)).await {
175 Ok(value) => value,
176 Err(e) => {
177 warn!("[VideoSettings] Failed to read streaming quality: {}", e);
178 return;
179 }
180 };
181
182 let Some(stored) = stored else { return };
183 let quality: StreamingQuality = match serde_json::from_str(&stored) {
184 Ok(quality) => quality,
185 Err(e) => {
186 warn!(
187 "[VideoSettings] Ignoring unrecognised persisted streaming quality {:?}: {}",
188 stored, e
189 );
190 return;
191 }
192 };
193
194 crate::repository::online::set_streaming_quality(quality);
195 if let Some(video_settings) = app.try_state::<VideoSettingsWrapper>() {
196 video_settings.0.lock_safe().streaming_quality = quality;
197 }
198 info!(
199 "[VideoSettings] Restored streaming quality cap: {}",
200 quality.label()
201 );
202}
203
204#[tauri::command]
205#[specta::specta]
206pub async fn player_get_video_settings(
207 video_settings: State<'_, VideoSettingsWrapper>,
208) -> Result<VideoSettings, String> {
209 let current = video_settings.0.lock().map_err(|e| e.to_string())?;
210 Ok(current.clone())
211}