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.
144 lines
4.0 KiB
Rust
144 lines
4.0 KiB
Rust
//! Tauri commands for playlist management
|
|
//! Uses handle-based system: UUID -> Arc<HybridRepository>
|
|
//!
|
|
//! TRACES: UR-014 | JA-019, JA-020
|
|
|
|
use log::debug;
|
|
use tauri::State;
|
|
|
|
use super::repository::RepositoryManagerWrapper;
|
|
use crate::repository::{types::*, MediaRepository};
|
|
|
|
/// Create a new playlist
|
|
#[tauri::command]
|
|
#[specta::specta]
|
|
pub async fn playlist_create(
|
|
manager: State<'_, RepositoryManagerWrapper>,
|
|
handle: String,
|
|
name: String,
|
|
item_ids: Option<Vec<String>>,
|
|
) -> Result<PlaylistCreatedResult, String> {
|
|
debug!("[PLAYLIST] create called: name={}", name);
|
|
let repo = manager.0.get(&handle).ok_or("Repository not found")?;
|
|
let ids = item_ids.unwrap_or_default();
|
|
repo.as_ref()
|
|
.create_playlist(&name, &ids)
|
|
.await
|
|
.map_err(|e| format!("{:?}", e))
|
|
}
|
|
|
|
/// Delete a playlist
|
|
#[tauri::command]
|
|
#[specta::specta]
|
|
pub async fn playlist_delete(
|
|
manager: State<'_, RepositoryManagerWrapper>,
|
|
handle: String,
|
|
playlist_id: String,
|
|
) -> Result<(), String> {
|
|
debug!("[PLAYLIST] delete called: id={}", playlist_id);
|
|
let repo = manager.0.get(&handle).ok_or("Repository not found")?;
|
|
repo.as_ref()
|
|
.delete_playlist(&playlist_id)
|
|
.await
|
|
.map_err(|e| format!("{:?}", e))
|
|
}
|
|
|
|
/// Rename a playlist
|
|
#[tauri::command]
|
|
#[specta::specta]
|
|
pub async fn playlist_rename(
|
|
manager: State<'_, RepositoryManagerWrapper>,
|
|
handle: String,
|
|
playlist_id: String,
|
|
name: String,
|
|
) -> Result<(), String> {
|
|
debug!(
|
|
"[PLAYLIST] rename called: id={}, name={}",
|
|
playlist_id, name
|
|
);
|
|
let repo = manager.0.get(&handle).ok_or("Repository not found")?;
|
|
repo.as_ref()
|
|
.rename_playlist(&playlist_id, &name)
|
|
.await
|
|
.map_err(|e| format!("{:?}", e))
|
|
}
|
|
|
|
/// Get playlist items with PlaylistItemId
|
|
#[tauri::command]
|
|
#[specta::specta]
|
|
pub async fn playlist_get_items(
|
|
manager: State<'_, RepositoryManagerWrapper>,
|
|
handle: String,
|
|
playlist_id: String,
|
|
) -> Result<Vec<PlaylistEntry>, String> {
|
|
debug!("[PLAYLIST] get_items called: id={}", playlist_id);
|
|
let repo = manager.0.get(&handle).ok_or("Repository not found")?;
|
|
repo.as_ref()
|
|
.get_playlist_items(&playlist_id)
|
|
.await
|
|
.map_err(|e| format!("{:?}", e))
|
|
}
|
|
|
|
/// Add items to a playlist
|
|
#[tauri::command]
|
|
#[specta::specta]
|
|
pub async fn playlist_add_items(
|
|
manager: State<'_, RepositoryManagerWrapper>,
|
|
handle: String,
|
|
playlist_id: String,
|
|
item_ids: Vec<String>,
|
|
) -> Result<(), String> {
|
|
debug!(
|
|
"[PLAYLIST] add_items called: id={}, count={}",
|
|
playlist_id,
|
|
item_ids.len()
|
|
);
|
|
let repo = manager.0.get(&handle).ok_or("Repository not found")?;
|
|
repo.as_ref()
|
|
.add_to_playlist(&playlist_id, &item_ids)
|
|
.await
|
|
.map_err(|e| format!("{:?}", e))
|
|
}
|
|
|
|
/// Remove items from a playlist (uses PlaylistItemId entry IDs, NOT media item IDs)
|
|
#[tauri::command]
|
|
#[specta::specta]
|
|
pub async fn playlist_remove_items(
|
|
manager: State<'_, RepositoryManagerWrapper>,
|
|
handle: String,
|
|
playlist_id: String,
|
|
entry_ids: Vec<String>,
|
|
) -> Result<(), String> {
|
|
debug!(
|
|
"[PLAYLIST] remove_items called: id={}, count={}",
|
|
playlist_id,
|
|
entry_ids.len()
|
|
);
|
|
let repo = manager.0.get(&handle).ok_or("Repository not found")?;
|
|
repo.as_ref()
|
|
.remove_from_playlist(&playlist_id, &entry_ids)
|
|
.await
|
|
.map_err(|e| format!("{:?}", e))
|
|
}
|
|
|
|
/// Move a playlist item to a new position
|
|
#[tauri::command]
|
|
#[specta::specta]
|
|
pub async fn playlist_move_item(
|
|
manager: State<'_, RepositoryManagerWrapper>,
|
|
handle: String,
|
|
playlist_id: String,
|
|
item_id: String,
|
|
new_index: u32,
|
|
) -> Result<(), String> {
|
|
debug!(
|
|
"[PLAYLIST] move_item called: playlist={}, item={}, index={}",
|
|
playlist_id, item_id, new_index
|
|
);
|
|
let repo = manager.0.get(&handle).ok_or("Repository not found")?;
|
|
repo.as_ref()
|
|
.move_playlist_item(&playlist_id, &item_id, new_index)
|
|
.await
|
|
.map_err(|e| format!("{:?}", e))
|
|
}
|