From 8ddad497bfefe9f2c33d35cc22e44c9503b2d64b Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Sat, 20 Jun 2026 16:25:43 +0200 Subject: [PATCH] Workstream C: convert commands/player to a folder module, extract remote-session commands - Move commands/player.rs to commands/player/mod.rs (folder module). - Extract the 5 self-contained remote-session control commands (remote_play_on_session/send_command/session_seek/set_volume/toggle_mute) into commands/player/remote.rs, re-exported via `pub use remote::*` so the command names remain at commands::player::* and the invoke_handler is unchanged. No behavior change; establishes the submodule split pattern for the oversized command file. --- .../src/commands/{player.rs => player/mod.rs} | 123 +---------------- src-tauri/src/commands/player/remote.rs | 126 ++++++++++++++++++ 2 files changed, 131 insertions(+), 118 deletions(-) rename src-tauri/src/commands/{player.rs => player/mod.rs} (95%) create mode 100644 src-tauri/src/commands/player/remote.rs diff --git a/src-tauri/src/commands/player.rs b/src-tauri/src/commands/player/mod.rs similarity index 95% rename from src-tauri/src/commands/player.rs rename to src-tauri/src/commands/player/mod.rs index 8fe8546..87f78b2 100644 --- a/src-tauri/src/commands/player.rs +++ b/src-tauri/src/commands/player/mod.rs @@ -1,5 +1,10 @@ //! TRACES: UR-003, UR-004, UR-005, UR-010, UR-020, UR-021 | JA-022, JA-023, JA-024, JA-025, JA-026 | DR-001 +// Remote Jellyfin session control commands (casting) live in their own submodule +// and are re-exported so the command names remain at `commands::player::*`. +mod remote; +pub use remote::*; + use crate::utils::lock::MutexSafe; use log::{debug, error, info, warn}; use serde::{Deserialize, Serialize}; @@ -2111,124 +2116,6 @@ pub async fn player_disable_jellyfin( Ok(()) } -/// Play items on a remote Jellyfin session (casting) -#[tauri::command] -pub async fn remote_play_on_session( - player: State<'_, PlayerStateWrapper>, - session_id: String, - item_ids: Vec, - start_index: usize, -) -> Result<(), String> { - log::info!("[RemoteSession] Playing {} items on session {} (start index: {})", item_ids.len(), session_id, start_index); - log::info!("[RemoteSession] Item IDs: {:?}", item_ids); - - let client_opt = { - let controller = player.0.lock().await; - controller.jellyfin_client().lock().map_err(|e| e.to_string())?.clone() - }; - - if let Some(client) = client_opt { - log::info!("[RemoteSession] Jellyfin client IS configured, calling play_on_session"); - client.play_on_session(session_id, item_ids, start_index, None).await?; - log::info!("[RemoteSession] Successfully started playback on remote session"); - Ok(()) - } else { - log::error!("[RemoteSession] Jellyfin client is NOT configured! User needs to log out/in or restart app"); - Err("Jellyfin client not configured - please restart the app or log out and log back in".to_string()) - } -} - -/// Send a playback command to a remote session -#[tauri::command] -pub async fn remote_send_command( - player: State<'_, PlayerStateWrapper>, - session_id: String, - command: String, -) -> Result<(), String> { - log::info!("[RemoteSession] Sending command '{}' to session {}", command, session_id); - - let client_opt = { - let controller = player.0.lock().await; - controller.jellyfin_client().lock().map_err(|e| e.to_string())?.clone() - }; - - if let Some(client) = client_opt { - client.send_session_command(session_id, &command).await?; - log::info!("[RemoteSession] Command sent successfully"); - Ok(()) - } else { - Err("Jellyfin client not configured".to_string()) - } -} - -/// Seek on a remote session -#[tauri::command] -pub async fn remote_session_seek( - player: State<'_, PlayerStateWrapper>, - session_id: String, - position_ticks: i64, -) -> Result<(), String> { - log::info!("[RemoteSession] Seeking to {} ticks on session {}", position_ticks, session_id); - - let client_opt = { - let controller = player.0.lock().await; - controller.jellyfin_client().lock().map_err(|e| e.to_string())?.clone() - }; - - if let Some(client) = client_opt { - client.session_seek(session_id, position_ticks).await?; - log::info!("[RemoteSession] Seek successful"); - Ok(()) - } else { - Err("Jellyfin client not configured".to_string()) - } -} - -/// Set volume on a remote session -#[tauri::command] -pub async fn remote_session_set_volume( - player: State<'_, PlayerStateWrapper>, - session_id: String, - volume: i32, -) -> Result<(), String> { - log::info!("[RemoteSession] Setting volume to {} on session {}", volume, session_id); - - let client_opt = { - let controller = player.0.lock().await; - controller.jellyfin_client().lock().map_err(|e| e.to_string())?.clone() - }; - - if let Some(client) = client_opt { - client.session_set_volume(session_id, volume).await?; - log::info!("[RemoteSession] Volume set successfully"); - Ok(()) - } else { - Err("Jellyfin client not configured".to_string()) - } -} - -/// Toggle mute on a remote session -#[tauri::command] -pub async fn remote_session_toggle_mute( - player: State<'_, PlayerStateWrapper>, - session_id: String, -) -> Result<(), String> { - log::info!("[RemoteSession] Toggling mute on session {}", session_id); - - let client_opt = { - let controller = player.0.lock().await; - controller.jellyfin_client().lock().map_err(|e| e.to_string())?.clone() - }; - - if let Some(client) = client_opt { - client.session_toggle_mute(session_id).await?; - log::info!("[RemoteSession] Mute toggled successfully"); - Ok(()) - } else { - Err("Jellyfin client not configured".to_string()) - } -} - // ===== Sleep Timer Commands ===== /// Set sleep timer mode diff --git a/src-tauri/src/commands/player/remote.rs b/src-tauri/src/commands/player/remote.rs new file mode 100644 index 0000000..8d3bf68 --- /dev/null +++ b/src-tauri/src/commands/player/remote.rs @@ -0,0 +1,126 @@ +//! Remote Jellyfin session control commands (casting to another device). +//! +//! These thin command adapters forward control actions to the active Jellyfin +//! session via the player's configured `JellyfinClient`. + +use tauri::State; + +use super::PlayerStateWrapper; + +/// Play items on a remote Jellyfin session (casting) +#[tauri::command] +pub async fn remote_play_on_session( + player: State<'_, PlayerStateWrapper>, + session_id: String, + item_ids: Vec, + start_index: usize, +) -> Result<(), String> { + log::info!("[RemoteSession] Playing {} items on session {} (start index: {})", item_ids.len(), session_id, start_index); + log::info!("[RemoteSession] Item IDs: {:?}", item_ids); + + let client_opt = { + let controller = player.0.lock().await; + controller.jellyfin_client().lock().map_err(|e| e.to_string())?.clone() + }; + + if let Some(client) = client_opt { + log::info!("[RemoteSession] Jellyfin client IS configured, calling play_on_session"); + client.play_on_session(session_id, item_ids, start_index, None).await?; + log::info!("[RemoteSession] Successfully started playback on remote session"); + Ok(()) + } else { + log::error!("[RemoteSession] Jellyfin client is NOT configured! User needs to log out/in or restart app"); + Err("Jellyfin client not configured - please restart the app or log out and log back in".to_string()) + } +} + +/// Send a playback command to a remote session +#[tauri::command] +pub async fn remote_send_command( + player: State<'_, PlayerStateWrapper>, + session_id: String, + command: String, +) -> Result<(), String> { + log::info!("[RemoteSession] Sending command '{}' to session {}", command, session_id); + + let client_opt = { + let controller = player.0.lock().await; + controller.jellyfin_client().lock().map_err(|e| e.to_string())?.clone() + }; + + if let Some(client) = client_opt { + client.send_session_command(session_id, &command).await?; + log::info!("[RemoteSession] Command sent successfully"); + Ok(()) + } else { + Err("Jellyfin client not configured".to_string()) + } +} + +/// Seek on a remote session +#[tauri::command] +pub async fn remote_session_seek( + player: State<'_, PlayerStateWrapper>, + session_id: String, + position_ticks: i64, +) -> Result<(), String> { + log::info!("[RemoteSession] Seeking to {} ticks on session {}", position_ticks, session_id); + + let client_opt = { + let controller = player.0.lock().await; + controller.jellyfin_client().lock().map_err(|e| e.to_string())?.clone() + }; + + if let Some(client) = client_opt { + client.session_seek(session_id, position_ticks).await?; + log::info!("[RemoteSession] Seek successful"); + Ok(()) + } else { + Err("Jellyfin client not configured".to_string()) + } +} + +/// Set volume on a remote session +#[tauri::command] +pub async fn remote_session_set_volume( + player: State<'_, PlayerStateWrapper>, + session_id: String, + volume: i32, +) -> Result<(), String> { + log::info!("[RemoteSession] Setting volume to {} on session {}", volume, session_id); + + let client_opt = { + let controller = player.0.lock().await; + controller.jellyfin_client().lock().map_err(|e| e.to_string())?.clone() + }; + + if let Some(client) = client_opt { + client.session_set_volume(session_id, volume).await?; + log::info!("[RemoteSession] Volume set successfully"); + Ok(()) + } else { + Err("Jellyfin client not configured".to_string()) + } +} + +/// Toggle mute on a remote session +#[tauri::command] +pub async fn remote_session_toggle_mute( + player: State<'_, PlayerStateWrapper>, + session_id: String, +) -> Result<(), String> { + log::info!("[RemoteSession] Toggling mute on session {}", session_id); + + let client_opt = { + let controller = player.0.lock().await; + controller.jellyfin_client().lock().map_err(|e| e.to_string())?.clone() + }; + + if let Some(client) = client_opt { + client.session_toggle_mute(session_id).await?; + log::info!("[RemoteSession] Mute toggled successfully"); + Ok(()) + } else { + Err("Jellyfin client not configured".to_string()) + } +}