Background-audio handoff for video + repository/player refactor
Hand video playback off to a native audio-only stream when the app is backgrounded or locked, with no on-device video decode (UR-040). Adds player_enter/exit_background_audio commands, an audio-only stream URL for video items across the repository layer, and the frontend handoff state machine wired into VideoPlayer. Includes accompanying repository/offline/player refactoring and regenerates the traceability matrix.
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
//! Authentication and session-lifecycle commands.
|
||||
//!
|
||||
//! TRACES: UR-042 | IR-009, IR-014, JA-002 | DR-054
|
||||
|
||||
use std::sync::Arc;
|
||||
use tauri::State;
|
||||
|
||||
use crate::auth::{AuthManager, SessionVerifier, ServerInfo, AuthResult, Session};
|
||||
use crate::auth::{AuthManager, AuthResult, ServerInfo, Session, SessionVerifier};
|
||||
|
||||
/// Wrapper for AuthManager to manage in Tauri state
|
||||
pub struct AuthManagerWrapper(pub Arc<AuthManager>);
|
||||
@@ -27,17 +31,18 @@ pub async fn auth_initialize(
|
||||
log::info!("[AuthManager] Restoring session from storage...");
|
||||
|
||||
// Use the existing storage_get_active_session function
|
||||
let active_session = match crate::commands::storage::storage_get_active_session(database, credentials).await {
|
||||
Ok(Some(session)) => session,
|
||||
Ok(None) => {
|
||||
log::info!("[AuthManager] No active session in storage");
|
||||
return Ok(None);
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("[AuthManager] Failed to get active session: {}", e);
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
let active_session =
|
||||
match crate::commands::storage::storage_get_active_session(database, credentials).await {
|
||||
Ok(Some(session)) => session,
|
||||
Ok(None) => {
|
||||
log::info!("[AuthManager] No active session in storage");
|
||||
return Ok(None);
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("[AuthManager] Failed to get active session: {}", e);
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
||||
// Create session object from active session with normalized URL
|
||||
let normalized_url = crate::auth::AuthManager::normalize_url(&active_session.server_url)?;
|
||||
@@ -56,7 +61,11 @@ pub async fn auth_initialize(
|
||||
// Store in AuthManager
|
||||
auth_manager.0.set_session(Some(session.clone())).await;
|
||||
|
||||
log::info!("[AuthManager] Session restored for user: {} with normalized URL: {}", session.username, session.server_url);
|
||||
log::info!(
|
||||
"[AuthManager] Session restored for user: {} with normalized URL: {}",
|
||||
session.username,
|
||||
session.server_url
|
||||
);
|
||||
Ok(Some(session))
|
||||
}
|
||||
|
||||
@@ -80,7 +89,10 @@ pub async fn auth_login(
|
||||
device_id: String,
|
||||
auth_manager: State<'_, AuthManagerWrapper>,
|
||||
) -> Result<AuthResult, String> {
|
||||
let result = auth_manager.0.login(&server_url, &username, &password, &device_id).await?;
|
||||
let result = auth_manager
|
||||
.0
|
||||
.login(&server_url, &username, &password, &device_id)
|
||||
.await?;
|
||||
|
||||
// Create session from auth result with normalized URL
|
||||
let normalized_url = crate::auth::AuthManager::normalize_url(&server_url)?;
|
||||
@@ -111,7 +123,11 @@ pub async fn auth_verify_session(
|
||||
device_id: String,
|
||||
auth_manager: State<'_, AuthManagerWrapper>,
|
||||
) -> Result<bool, String> {
|
||||
match auth_manager.0.verify_session(&server_url, &user_id, &access_token, &device_id).await {
|
||||
match auth_manager
|
||||
.0
|
||||
.verify_session(&server_url, &user_id, &access_token, &device_id)
|
||||
.await
|
||||
{
|
||||
Ok(_) => Ok(true),
|
||||
Err(e) => {
|
||||
log::warn!("[AuthCommands] Session verification failed: {}", e);
|
||||
@@ -138,7 +154,10 @@ pub async fn auth_logout(
|
||||
drop(verifier_guard);
|
||||
|
||||
// Call Jellyfin logout endpoint
|
||||
auth_manager.0.logout(&server_url, &access_token, &device_id).await?;
|
||||
auth_manager
|
||||
.0
|
||||
.logout(&server_url, &access_token, &device_id)
|
||||
.await?;
|
||||
|
||||
// Clear session
|
||||
auth_manager.0.set_session(None).await;
|
||||
@@ -228,11 +247,22 @@ pub async fn auth_reauthenticate(
|
||||
auth_manager: State<'_, AuthManagerWrapper>,
|
||||
) -> Result<AuthResult, String> {
|
||||
// Get current session to extract server_url and username
|
||||
let session = auth_manager.0.get_session().await
|
||||
let session = auth_manager
|
||||
.0
|
||||
.get_session()
|
||||
.await
|
||||
.ok_or_else(|| "No active session to re-authenticate".to_string())?;
|
||||
|
||||
// Re-login with stored credentials
|
||||
let result = auth_manager.0.login(&session.server_url, &session.username, &password, &device_id).await?;
|
||||
let result = auth_manager
|
||||
.0
|
||||
.login(
|
||||
&session.server_url,
|
||||
&session.username,
|
||||
&password,
|
||||
&device_id,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Update session with new token
|
||||
let updated_session = Session {
|
||||
|
||||
Reference in New Issue
Block a user