Workstream C: convert commands/player to a folder module, extract remote-session commands
Some checks failed
🏗️ Build and Test JellyTau / Run Tests (push) Failing after 10m49s
🏗️ Build and Test JellyTau / Build Android APK (push) Has been skipped
Traceability Validation / Check Requirement Traces (push) Failing after 5s

- 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.
This commit is contained in:
Duncan Tourolle 2026-06-20 16:25:43 +02:00
parent 46b9d328ab
commit 8ddad497bf
2 changed files with 131 additions and 118 deletions

View File

@ -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<String>,
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

View File

@ -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<String>,
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())
}
}