jellytau/src-tauri/src/commands/playback_mode.rs

130 lines
4.2 KiB
Rust

use std::sync::Arc;
use tauri::State;
use crate::playback_mode::{PlaybackMode, PlaybackModeManager};
/// Wrapper for PlaybackModeManager to manage in Tauri state
pub struct PlaybackModeManagerWrapper(pub Arc<PlaybackModeManager>);
/// Get the current playback mode
#[tauri::command]
pub fn playback_mode_get_current(
manager: State<'_, PlaybackModeManagerWrapper>,
) -> Result<PlaybackMode, String> {
Ok(manager.0.get_mode())
}
/// Set the playback mode (internal/testing use)
#[tauri::command]
pub fn playback_mode_set(
manager: State<'_, PlaybackModeManagerWrapper>,
mode: PlaybackMode,
) -> Result<(), String> {
manager.0.set_mode(mode);
Ok(())
}
/// Check if currently transferring between playback modes
#[tauri::command]
pub fn playback_mode_is_transferring(
manager: State<'_, PlaybackModeManagerWrapper>,
) -> Result<bool, String> {
Ok(manager.0.is_transferring())
}
/// Transfer playback from local device to a remote Jellyfin session
#[tauri::command]
pub async fn playback_mode_transfer_to_remote(
manager: State<'_, PlaybackModeManagerWrapper>,
session_id: String,
) -> Result<(), String> {
log::info!(
"[PlaybackModeCommands] Transferring to remote session: {}",
session_id
);
manager.0.transfer_to_remote(session_id).await
}
/// Transfer playback from remote session back to local device
///
/// Parameters:
/// - current_item_id: The Jellyfin item ID currently playing on remote
/// - position_ticks: Current playback position in ticks (10,000 ticks = 1ms)
#[tauri::command]
pub async fn playback_mode_transfer_to_local(
manager: State<'_, PlaybackModeManagerWrapper>,
current_item_id: String,
position_ticks: i64,
) -> Result<(), String> {
log::info!(
"[PlaybackModeCommands] Transferring to local: item_id={}, position={}",
current_item_id,
position_ticks
);
manager
.0
.transfer_to_local(current_item_id, position_ticks)
.await
}
/// Get remote session status (for polling position/duration)
#[tauri::command]
pub async fn playback_mode_get_remote_status(
manager: State<'_, PlaybackModeManagerWrapper>,
player: State<'_, crate::commands::PlayerStateWrapper>,
) -> Result<RemoteSessionStatus, String> {
let mode = manager.0.get_mode();
if let crate::playback_mode::PlaybackMode::Remote { session_id } = mode {
// Get Jellyfin client from player controller - clone before await
let client = {
let controller = player.0.lock().await;
let client_arc = controller.jellyfin_client();
let client_opt = client_arc.lock().map_err(|e| e.to_string())?;
client_opt.as_ref().ok_or("Jellyfin client not configured")?.clone()
};
// Get session info
match client.get_session(&session_id).await {
Ok(Some(session)) => {
let position_ticks = session.play_state.as_ref()
.and_then(|ps| ps.position_ticks)
.unwrap_or(0);
let duration_ticks = session.now_playing_item.as_ref()
.and_then(|item| item.run_time_ticks)
.unwrap_or(0);
let is_paused = session.play_state.as_ref()
.and_then(|ps| ps.is_paused)
.unwrap_or(true);
Ok(RemoteSessionStatus {
position: position_ticks as f64 / 10_000_000.0,
duration: if duration_ticks > 0 {
Some(duration_ticks as f64 / 10_000_000.0)
} else {
None
},
is_playing: !is_paused,
now_playing_item: session.now_playing_item.clone(),
})
}
Ok(None) => Err("Remote session not found".to_string()),
Err(e) => Err(format!("Failed to get session status: {}", e)),
}
} else {
Err("Not in remote playback mode".to_string())
}
}
/// Remote session status for UI updates
#[derive(serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RemoteSessionStatus {
pub position: f64,
pub duration: Option<f64>,
pub is_playing: bool,
pub now_playing_item: Option<crate::jellyfin::NowPlayingItem>,
}