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:
2026-07-22 21:52:07 +02:00
parent 4e6ab017d4
commit 3fbf6afdbc
72 changed files with 6728 additions and 2338 deletions
+33 -12
View File
@@ -6,8 +6,8 @@
use log::debug;
use tauri::State;
use crate::repository::{MediaRepository, types::*};
use super::repository::RepositoryManagerWrapper;
use crate::repository::{types::*, MediaRepository};
/// Create a new playlist
#[tauri::command]
@@ -21,7 +21,8 @@ pub async fn playlist_create(
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)
repo.as_ref()
.create_playlist(&name, &ids)
.await
.map_err(|e| format!("{:?}", e))
}
@@ -36,7 +37,8 @@ pub async fn playlist_delete(
) -> 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)
repo.as_ref()
.delete_playlist(&playlist_id)
.await
.map_err(|e| format!("{:?}", e))
}
@@ -50,9 +52,13 @@ pub async fn playlist_rename(
playlist_id: String,
name: String,
) -> Result<(), String> {
debug!("[PLAYLIST] rename called: id={}, name={}", playlist_id, name);
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)
repo.as_ref()
.rename_playlist(&playlist_id, &name)
.await
.map_err(|e| format!("{:?}", e))
}
@@ -67,7 +73,8 @@ pub async fn playlist_get_items(
) -> 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)
repo.as_ref()
.get_playlist_items(&playlist_id)
.await
.map_err(|e| format!("{:?}", e))
}
@@ -81,9 +88,14 @@ pub async fn playlist_add_items(
playlist_id: String,
item_ids: Vec<String>,
) -> Result<(), String> {
debug!("[PLAYLIST] add_items called: id={}, count={}", playlist_id, item_ids.len());
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)
repo.as_ref()
.add_to_playlist(&playlist_id, &item_ids)
.await
.map_err(|e| format!("{:?}", e))
}
@@ -97,9 +109,14 @@ pub async fn playlist_remove_items(
playlist_id: String,
entry_ids: Vec<String>,
) -> Result<(), String> {
debug!("[PLAYLIST] remove_items called: id={}, count={}", playlist_id, entry_ids.len());
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)
repo.as_ref()
.remove_from_playlist(&playlist_id, &entry_ids)
.await
.map_err(|e| format!("{:?}", e))
}
@@ -114,9 +131,13 @@ pub async fn playlist_move_item(
item_id: String,
new_index: u32,
) -> Result<(), String> {
debug!("[PLAYLIST] move_item called: playlist={}, item={}, index={}", playlist_id, item_id, new_index);
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)
repo.as_ref()
.move_playlist_item(&playlist_id, &item_id, new_index)
.await
.map_err(|e| format!("{:?}", e))
}