Workstream E (backend): wire tauri-specta — annotate commands, derive Type, generate-ready Builder
- Add #[specta::specta] to all 201 #[tauri::command] functions. - Derive specta::Type on all IPC DTOs (repository/types, settings, player/storage/ download command DTOs, player enums, jellyfin SessionInfo/NowPlayingItem/PlayState, ThumbnailCacheStats, DownloadInfo, CacheConfig, etc.). - Replace tauri::generate_handler! with a tauri_specta::Builder + collect_commands! in lib.rs (exports bindings.ts in debug builds). Two contract changes required by specta constraints (frontend migration follows): - specta caps command arity at 10 args: download_item_and_start / download_item / download_video now take a single request struct (params bundled, body unchanged via destructuring). - specta can't parse split serde rename_all: SessionInfo/NowPlayingItem/PlayState switched to rename_all = "PascalCase" (Jellyfin deserialization preserved; these now serialize PascalCase to the frontend). cargo check --lib is clean (0 errors). Frontend migration to bindings.ts is the next step.
This commit is contained in:
parent
55f1b85f12
commit
ada3ed64ab
@ -10,7 +10,7 @@ use crate::connectivity::ConnectivityMonitor;
|
|||||||
pub use session_verifier::SessionVerifier;
|
pub use session_verifier::SessionVerifier;
|
||||||
|
|
||||||
/// Server information returned from Jellyfin
|
/// Server information returned from Jellyfin
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ServerInfo {
|
pub struct ServerInfo {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@ -21,7 +21,7 @@ pub struct ServerInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// User information
|
/// User information
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
@ -31,7 +31,7 @@ pub struct User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Authentication result
|
/// Authentication result
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct AuthResult {
|
pub struct AuthResult {
|
||||||
pub user: User,
|
pub user: User,
|
||||||
@ -40,7 +40,7 @@ pub struct AuthResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Active session for restoration
|
/// Active session for restoration
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Session {
|
pub struct Session {
|
||||||
pub user_id: String,
|
pub user_id: String,
|
||||||
@ -55,7 +55,7 @@ pub struct Session {
|
|||||||
|
|
||||||
// Jellyfin API response types (PascalCase from server)
|
// Jellyfin API response types (PascalCase from server)
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(specta::Type, Debug, Deserialize)]
|
||||||
#[serde(rename_all = "PascalCase")]
|
#[serde(rename_all = "PascalCase")]
|
||||||
struct PublicSystemInfo {
|
struct PublicSystemInfo {
|
||||||
server_name: String,
|
server_name: String,
|
||||||
@ -63,7 +63,7 @@ struct PublicSystemInfo {
|
|||||||
id: String,
|
id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(specta::Type, Debug, Deserialize)]
|
||||||
#[serde(rename_all = "PascalCase")]
|
#[serde(rename_all = "PascalCase")]
|
||||||
struct AuthenticateByNameResponse {
|
struct AuthenticateByNameResponse {
|
||||||
user: JellyfinUser,
|
user: JellyfinUser,
|
||||||
@ -71,7 +71,7 @@ struct AuthenticateByNameResponse {
|
|||||||
server_id: String,
|
server_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(specta::Type, Debug, Deserialize)]
|
||||||
#[serde(rename_all = "PascalCase")]
|
#[serde(rename_all = "PascalCase")]
|
||||||
struct JellyfinUser {
|
struct JellyfinUser {
|
||||||
id: String,
|
id: String,
|
||||||
|
|||||||
@ -12,6 +12,7 @@ pub struct SessionVerifierWrapper(pub Arc<tokio::sync::Mutex<Option<SessionVerif
|
|||||||
/// Initialize the auth manager (call on app startup)
|
/// Initialize the auth manager (call on app startup)
|
||||||
/// Restores session from storage if available
|
/// Restores session from storage if available
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn auth_initialize(
|
pub async fn auth_initialize(
|
||||||
auth_manager: State<'_, AuthManagerWrapper>,
|
auth_manager: State<'_, AuthManagerWrapper>,
|
||||||
database: State<'_, crate::commands::DatabaseWrapper>,
|
database: State<'_, crate::commands::DatabaseWrapper>,
|
||||||
@ -61,6 +62,7 @@ pub async fn auth_initialize(
|
|||||||
|
|
||||||
/// Connect to a Jellyfin server and get server info
|
/// Connect to a Jellyfin server and get server info
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn auth_connect_to_server(
|
pub async fn auth_connect_to_server(
|
||||||
server_url: String,
|
server_url: String,
|
||||||
auth_manager: State<'_, AuthManagerWrapper>,
|
auth_manager: State<'_, AuthManagerWrapper>,
|
||||||
@ -70,6 +72,7 @@ pub async fn auth_connect_to_server(
|
|||||||
|
|
||||||
/// Login with username and password
|
/// Login with username and password
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn auth_login(
|
pub async fn auth_login(
|
||||||
server_url: String,
|
server_url: String,
|
||||||
username: String,
|
username: String,
|
||||||
@ -100,6 +103,7 @@ pub async fn auth_login(
|
|||||||
|
|
||||||
/// Verify current session
|
/// Verify current session
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn auth_verify_session(
|
pub async fn auth_verify_session(
|
||||||
server_url: String,
|
server_url: String,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
@ -118,6 +122,7 @@ pub async fn auth_verify_session(
|
|||||||
|
|
||||||
/// Logout (clear session and call Jellyfin logout endpoint)
|
/// Logout (clear session and call Jellyfin logout endpoint)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn auth_logout(
|
pub async fn auth_logout(
|
||||||
server_url: String,
|
server_url: String,
|
||||||
access_token: String,
|
access_token: String,
|
||||||
@ -143,6 +148,7 @@ pub async fn auth_logout(
|
|||||||
|
|
||||||
/// Get current session
|
/// Get current session
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn auth_get_session(
|
pub async fn auth_get_session(
|
||||||
auth_manager: State<'_, AuthManagerWrapper>,
|
auth_manager: State<'_, AuthManagerWrapper>,
|
||||||
) -> Result<Option<Session>, String> {
|
) -> Result<Option<Session>, String> {
|
||||||
@ -151,6 +157,7 @@ pub async fn auth_get_session(
|
|||||||
|
|
||||||
/// Set current session (for restoration from storage)
|
/// Set current session (for restoration from storage)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn auth_set_session(
|
pub async fn auth_set_session(
|
||||||
session: Option<Session>,
|
session: Option<Session>,
|
||||||
auth_manager: State<'_, AuthManagerWrapper>,
|
auth_manager: State<'_, AuthManagerWrapper>,
|
||||||
@ -170,6 +177,7 @@ pub async fn auth_set_session(
|
|||||||
|
|
||||||
/// Start background session verification
|
/// Start background session verification
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn auth_start_verification(
|
pub async fn auth_start_verification(
|
||||||
device_id: String,
|
device_id: String,
|
||||||
app_handle: tauri::AppHandle,
|
app_handle: tauri::AppHandle,
|
||||||
@ -198,6 +206,7 @@ pub async fn auth_start_verification(
|
|||||||
|
|
||||||
/// Stop background session verification
|
/// Stop background session verification
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn auth_stop_verification(
|
pub async fn auth_stop_verification(
|
||||||
session_verifier: State<'_, SessionVerifierWrapper>,
|
session_verifier: State<'_, SessionVerifierWrapper>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
@ -212,6 +221,7 @@ pub async fn auth_stop_verification(
|
|||||||
|
|
||||||
/// Re-authenticate with password (when session expired)
|
/// Re-authenticate with password (when session expired)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn auth_reauthenticate(
|
pub async fn auth_reauthenticate(
|
||||||
password: String,
|
password: String,
|
||||||
device_id: String,
|
device_id: String,
|
||||||
|
|||||||
@ -7,6 +7,7 @@ pub struct ConnectivityMonitorWrapper(pub Arc<tokio::sync::Mutex<ConnectivityMon
|
|||||||
|
|
||||||
/// Check if the server is currently reachable
|
/// Check if the server is currently reachable
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn connectivity_check_server(
|
pub async fn connectivity_check_server(
|
||||||
state: State<'_, ConnectivityMonitorWrapper>,
|
state: State<'_, ConnectivityMonitorWrapper>,
|
||||||
) -> Result<bool, String> {
|
) -> Result<bool, String> {
|
||||||
@ -16,6 +17,7 @@ pub async fn connectivity_check_server(
|
|||||||
|
|
||||||
/// Set the server URL and trigger an immediate check
|
/// Set the server URL and trigger an immediate check
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn connectivity_set_server_url(
|
pub async fn connectivity_set_server_url(
|
||||||
url: String,
|
url: String,
|
||||||
state: State<'_, ConnectivityMonitorWrapper>,
|
state: State<'_, ConnectivityMonitorWrapper>,
|
||||||
@ -27,6 +29,7 @@ pub async fn connectivity_set_server_url(
|
|||||||
|
|
||||||
/// Get the current connectivity status
|
/// Get the current connectivity status
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn connectivity_get_status(
|
pub async fn connectivity_get_status(
|
||||||
state: State<'_, ConnectivityMonitorWrapper>,
|
state: State<'_, ConnectivityMonitorWrapper>,
|
||||||
) -> Result<ConnectivityStatus, String> {
|
) -> Result<ConnectivityStatus, String> {
|
||||||
@ -36,6 +39,7 @@ pub async fn connectivity_get_status(
|
|||||||
|
|
||||||
/// Start monitoring connectivity with adaptive polling
|
/// Start monitoring connectivity with adaptive polling
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn connectivity_start_monitoring(
|
pub async fn connectivity_start_monitoring(
|
||||||
state: State<'_, ConnectivityMonitorWrapper>,
|
state: State<'_, ConnectivityMonitorWrapper>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
@ -46,6 +50,7 @@ pub async fn connectivity_start_monitoring(
|
|||||||
|
|
||||||
/// Stop monitoring connectivity
|
/// Stop monitoring connectivity
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn connectivity_stop_monitoring(
|
pub async fn connectivity_stop_monitoring(
|
||||||
state: State<'_, ConnectivityMonitorWrapper>,
|
state: State<'_, ConnectivityMonitorWrapper>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
@ -56,6 +61,7 @@ pub async fn connectivity_stop_monitoring(
|
|||||||
|
|
||||||
/// Mark the server as reachable (called after successful API calls)
|
/// Mark the server as reachable (called after successful API calls)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn connectivity_mark_reachable(
|
pub async fn connectivity_mark_reachable(
|
||||||
state: State<'_, ConnectivityMonitorWrapper>,
|
state: State<'_, ConnectivityMonitorWrapper>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
@ -66,6 +72,7 @@ pub async fn connectivity_mark_reachable(
|
|||||||
|
|
||||||
/// Mark the server as unreachable (called after failed API calls)
|
/// Mark the server as unreachable (called after failed API calls)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn connectivity_mark_unreachable(
|
pub async fn connectivity_mark_unreachable(
|
||||||
error: Option<String>,
|
error: Option<String>,
|
||||||
state: State<'_, ConnectivityMonitorWrapper>,
|
state: State<'_, ConnectivityMonitorWrapper>,
|
||||||
|
|||||||
@ -16,6 +16,7 @@ use crate::utils::conversions::{
|
|||||||
/// # Returns
|
/// # Returns
|
||||||
/// Formatted string like "3:45" or "12:09"
|
/// Formatted string like "3:45" or "12:09"
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub fn format_time_seconds(seconds: f64) -> String {
|
pub fn format_time_seconds(seconds: f64) -> String {
|
||||||
format_time(seconds)
|
format_time(seconds)
|
||||||
}
|
}
|
||||||
@ -32,6 +33,7 @@ pub fn format_time_seconds(seconds: f64) -> String {
|
|||||||
/// # Returns
|
/// # Returns
|
||||||
/// Formatted string like "1:23:45" or "3:45"
|
/// Formatted string like "1:23:45" or "3:45"
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub fn format_time_seconds_long(seconds: f64) -> String {
|
pub fn format_time_seconds_long(seconds: f64) -> String {
|
||||||
format_time_long(seconds)
|
format_time_long(seconds)
|
||||||
}
|
}
|
||||||
@ -44,6 +46,7 @@ pub fn format_time_seconds_long(seconds: f64) -> String {
|
|||||||
/// # Returns
|
/// # Returns
|
||||||
/// Time in seconds
|
/// Time in seconds
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub fn convert_ticks_to_seconds(ticks: i64) -> f64 {
|
pub fn convert_ticks_to_seconds(ticks: i64) -> f64 {
|
||||||
ticks_to_seconds(ticks)
|
ticks_to_seconds(ticks)
|
||||||
}
|
}
|
||||||
@ -57,6 +60,7 @@ pub fn convert_ticks_to_seconds(ticks: i64) -> f64 {
|
|||||||
/// # Returns
|
/// # Returns
|
||||||
/// Progress as percentage (0.0 to 100.0)
|
/// Progress as percentage (0.0 to 100.0)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub fn calc_progress(position: f64, duration: f64) -> f64 {
|
pub fn calc_progress(position: f64, duration: f64) -> f64 {
|
||||||
calculate_progress(position, duration)
|
calculate_progress(position, duration)
|
||||||
}
|
}
|
||||||
@ -69,6 +73,7 @@ pub fn calc_progress(position: f64, duration: f64) -> f64 {
|
|||||||
/// # Returns
|
/// # Returns
|
||||||
/// Normalized volume (0.0 to 1.0)
|
/// Normalized volume (0.0 to 1.0)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub fn convert_percent_to_volume(percent: f64) -> f64 {
|
pub fn convert_percent_to_volume(percent: f64) -> f64 {
|
||||||
percent_to_volume(percent)
|
percent_to_volume(percent)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,6 +23,7 @@ use crate::storage::db_service::{DatabaseService, Query, QueryParam};
|
|||||||
///
|
///
|
||||||
/// TRACES: UR-009 | DR-011
|
/// TRACES: UR-009 | DR-011
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn device_get_id(db: State<'_, DatabaseWrapper>) -> Result<String, String> {
|
pub async fn device_get_id(db: State<'_, DatabaseWrapper>) -> Result<String, String> {
|
||||||
let db_service = {
|
let db_service = {
|
||||||
let database = db.0.lock().map_err(|e| e.to_string())?;
|
let database = db.0.lock().map_err(|e| e.to_string())?;
|
||||||
@ -79,6 +80,7 @@ pub async fn device_get_id(db: State<'_, DatabaseWrapper>) -> Result<String, Str
|
|||||||
///
|
///
|
||||||
/// TRACES: UR-009 | DR-011
|
/// TRACES: UR-009 | DR-011
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn device_set_id(device_id: String, db: State<'_, DatabaseWrapper>) -> Result<(), String> {
|
pub async fn device_set_id(device_id: String, db: State<'_, DatabaseWrapper>) -> Result<(), String> {
|
||||||
let db_service = {
|
let db_service = {
|
||||||
let database = db.0.lock().map_err(|e| e.to_string())?;
|
let database = db.0.lock().map_err(|e| e.to_string())?;
|
||||||
|
|||||||
@ -22,7 +22,7 @@ pub struct DownloadManagerWrapper(pub Mutex<DownloadManager>);
|
|||||||
|
|
||||||
/// Download statistics computed server-side
|
/// Download statistics computed server-side
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(specta::Type, Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct DownloadStats {
|
pub struct DownloadStats {
|
||||||
pub total: usize,
|
pub total: usize,
|
||||||
@ -35,7 +35,7 @@ pub struct DownloadStats {
|
|||||||
|
|
||||||
/// Enhanced response with pre-computed stats
|
/// Enhanced response with pre-computed stats
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(specta::Type, Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct DownloadsResponse {
|
pub struct DownloadsResponse {
|
||||||
pub downloads: Vec<DownloadInfo>,
|
pub downloads: Vec<DownloadInfo>,
|
||||||
@ -52,22 +52,66 @@ fn sanitize_filename(name: &str) -> String {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request payload for download_item_and_start (bundled to stay within specta's
|
||||||
|
/// 10-argument command limit).
|
||||||
|
#[derive(Debug, specta::Type, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct DownloadItemAndStartRequest {
|
||||||
|
pub item_id: String,
|
||||||
|
pub user_id: String,
|
||||||
|
pub stream_url: String,
|
||||||
|
pub target_dir: String,
|
||||||
|
pub item_name: Option<String>,
|
||||||
|
pub artist_name: Option<String>,
|
||||||
|
pub album_name: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Request payload for download_item.
|
||||||
|
#[derive(Debug, specta::Type, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct DownloadItemRequest {
|
||||||
|
pub item_id: String,
|
||||||
|
pub user_id: String,
|
||||||
|
pub file_path: String,
|
||||||
|
pub mime_type: Option<String>,
|
||||||
|
pub priority: Option<i32>,
|
||||||
|
pub item_name: Option<String>,
|
||||||
|
pub artist_name: Option<String>,
|
||||||
|
pub album_name: Option<String>,
|
||||||
|
pub expected_size: Option<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Request payload for download_video.
|
||||||
|
#[derive(Debug, specta::Type, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct DownloadVideoRequest {
|
||||||
|
pub item_id: String,
|
||||||
|
pub user_id: String,
|
||||||
|
pub file_path: String,
|
||||||
|
pub mime_type: Option<String>,
|
||||||
|
pub priority: Option<i32>,
|
||||||
|
pub item_name: Option<String>,
|
||||||
|
pub quality_preset: Option<String>,
|
||||||
|
pub series_name: Option<String>,
|
||||||
|
pub season_name: Option<String>,
|
||||||
|
pub episode_number: Option<i32>,
|
||||||
|
pub season_number: Option<i32>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Queue and start a download in a single atomic operation
|
/// Queue and start a download in a single atomic operation
|
||||||
/// This simplifies the frontend flow by combining multiple steps
|
/// This simplifies the frontend flow by combining multiple steps
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn download_item_and_start(
|
pub async fn download_item_and_start(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
smart_cache: State<'_, SmartCacheWrapper>,
|
smart_cache: State<'_, SmartCacheWrapper>,
|
||||||
download_manager: State<'_, DownloadManagerWrapper>,
|
download_manager: State<'_, DownloadManagerWrapper>,
|
||||||
app: tauri::AppHandle,
|
app: tauri::AppHandle,
|
||||||
item_id: String,
|
request: DownloadItemAndStartRequest,
|
||||||
user_id: String,
|
|
||||||
stream_url: String,
|
|
||||||
target_dir: String,
|
|
||||||
item_name: Option<String>,
|
|
||||||
artist_name: Option<String>,
|
|
||||||
album_name: Option<String>,
|
|
||||||
) -> Result<i64, String> {
|
) -> Result<i64, String> {
|
||||||
|
let DownloadItemAndStartRequest {
|
||||||
|
item_id, user_id, stream_url, target_dir, item_name, artist_name, album_name,
|
||||||
|
} = request;
|
||||||
// Sanitize filename
|
// Sanitize filename
|
||||||
let safe_name = sanitize_filename(item_name.as_deref().unwrap_or(&item_id));
|
let safe_name = sanitize_filename(item_name.as_deref().unwrap_or(&item_id));
|
||||||
let file_path = format!("downloads/{}.mp3", safe_name);
|
let file_path = format!("downloads/{}.mp3", safe_name);
|
||||||
@ -76,15 +120,17 @@ pub async fn download_item_and_start(
|
|||||||
let download_id = download_item(
|
let download_id = download_item(
|
||||||
db.clone(),
|
db.clone(),
|
||||||
smart_cache.clone(),
|
smart_cache.clone(),
|
||||||
|
DownloadItemRequest {
|
||||||
item_id,
|
item_id,
|
||||||
user_id,
|
user_id,
|
||||||
file_path,
|
file_path,
|
||||||
None, // mime_type
|
mime_type: None,
|
||||||
None, // priority
|
priority: None,
|
||||||
item_name,
|
item_name,
|
||||||
artist_name,
|
artist_name,
|
||||||
album_name,
|
album_name,
|
||||||
None, // expected_size
|
expected_size: None,
|
||||||
|
},
|
||||||
).await?;
|
).await?;
|
||||||
|
|
||||||
// Start the download immediately
|
// Start the download immediately
|
||||||
@ -102,19 +148,15 @@ pub async fn download_item_and_start(
|
|||||||
|
|
||||||
/// Queue a media item for download
|
/// Queue a media item for download
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn download_item(
|
pub async fn download_item(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
smart_cache: State<'_, SmartCacheWrapper>,
|
smart_cache: State<'_, SmartCacheWrapper>,
|
||||||
item_id: String,
|
request: DownloadItemRequest,
|
||||||
user_id: String,
|
|
||||||
file_path: String,
|
|
||||||
mime_type: Option<String>,
|
|
||||||
priority: Option<i32>,
|
|
||||||
item_name: Option<String>,
|
|
||||||
artist_name: Option<String>,
|
|
||||||
album_name: Option<String>,
|
|
||||||
expected_size: Option<i64>,
|
|
||||||
) -> Result<i64, String> {
|
) -> Result<i64, String> {
|
||||||
|
let DownloadItemRequest {
|
||||||
|
item_id, user_id, file_path, mime_type, priority, item_name, artist_name, album_name, expected_size,
|
||||||
|
} = request;
|
||||||
let db_service = {
|
let db_service = {
|
||||||
let database = db.0.lock().map_err(|e| e.to_string())?;
|
let database = db.0.lock().map_err(|e| e.to_string())?;
|
||||||
Arc::new(database.service())
|
Arc::new(database.service())
|
||||||
@ -196,6 +238,7 @@ pub async fn download_item(
|
|||||||
|
|
||||||
/// Queue an entire album for download
|
/// Queue an entire album for download
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn download_album(
|
pub async fn download_album(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
album_id: String,
|
album_id: String,
|
||||||
@ -267,21 +310,15 @@ pub async fn download_album(
|
|||||||
|
|
||||||
/// Queue a video item (movie or episode) for download with quality preset
|
/// Queue a video item (movie or episode) for download with quality preset
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn download_video(
|
pub async fn download_video(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
item_id: String,
|
request: DownloadVideoRequest,
|
||||||
user_id: String,
|
|
||||||
file_path: String,
|
|
||||||
mime_type: Option<String>,
|
|
||||||
priority: Option<i32>,
|
|
||||||
item_name: Option<String>,
|
|
||||||
quality_preset: Option<String>,
|
|
||||||
// Video-specific metadata
|
|
||||||
series_name: Option<String>,
|
|
||||||
season_name: Option<String>,
|
|
||||||
episode_number: Option<i32>,
|
|
||||||
season_number: Option<i32>,
|
|
||||||
) -> Result<i64, String> {
|
) -> Result<i64, String> {
|
||||||
|
let DownloadVideoRequest {
|
||||||
|
item_id, user_id, file_path, mime_type, priority, item_name, quality_preset,
|
||||||
|
series_name, season_name, episode_number, season_number,
|
||||||
|
} = request;
|
||||||
let db_service = {
|
let db_service = {
|
||||||
let database = db.0.lock().map_err(|e| e.to_string())?;
|
let database = db.0.lock().map_err(|e| e.to_string())?;
|
||||||
Arc::new(database.service())
|
Arc::new(database.service())
|
||||||
@ -338,6 +375,7 @@ pub async fn download_video(
|
|||||||
|
|
||||||
/// Queue all episodes of a series for download
|
/// Queue all episodes of a series for download
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn download_series(
|
pub async fn download_series(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
series_id: String,
|
series_id: String,
|
||||||
@ -438,6 +476,7 @@ pub async fn download_series(
|
|||||||
|
|
||||||
/// Queue all episodes of a specific season for download
|
/// Queue all episodes of a specific season for download
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn download_season(
|
pub async fn download_season(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
season_id: String,
|
season_id: String,
|
||||||
@ -558,6 +597,7 @@ fn compute_download_stats(downloads: &[DownloadInfo]) -> DownloadStats {
|
|||||||
|
|
||||||
/// Get all downloads for a user, optionally filtered by status
|
/// Get all downloads for a user, optionally filtered by status
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn get_downloads(
|
pub async fn get_downloads(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
@ -632,6 +672,7 @@ pub async fn get_downloads(
|
|||||||
|
|
||||||
/// Pause a download
|
/// Pause a download
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn pause_download(db: State<'_, DatabaseWrapper>, download_id: i64) -> Result<(), String> {
|
pub async fn pause_download(db: State<'_, DatabaseWrapper>, download_id: i64) -> Result<(), String> {
|
||||||
let db_service = {
|
let db_service = {
|
||||||
let database = db.0.lock().map_err(|e| e.to_string())?;
|
let database = db.0.lock().map_err(|e| e.to_string())?;
|
||||||
@ -649,6 +690,7 @@ pub async fn pause_download(db: State<'_, DatabaseWrapper>, download_id: i64) ->
|
|||||||
|
|
||||||
/// Resume a paused download
|
/// Resume a paused download
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn resume_download(db: State<'_, DatabaseWrapper>, download_id: i64) -> Result<(), String> {
|
pub async fn resume_download(db: State<'_, DatabaseWrapper>, download_id: i64) -> Result<(), String> {
|
||||||
let db_service = {
|
let db_service = {
|
||||||
let database = db.0.lock().map_err(|e| e.to_string())?;
|
let database = db.0.lock().map_err(|e| e.to_string())?;
|
||||||
@ -666,6 +708,7 @@ pub async fn resume_download(db: State<'_, DatabaseWrapper>, download_id: i64) -
|
|||||||
|
|
||||||
/// Cancel a download
|
/// Cancel a download
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn cancel_download(
|
pub async fn cancel_download(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
download_manager: State<'_, DownloadManagerWrapper>,
|
download_manager: State<'_, DownloadManagerWrapper>,
|
||||||
@ -714,6 +757,7 @@ pub async fn cancel_download(
|
|||||||
|
|
||||||
/// Mark a download as completed
|
/// Mark a download as completed
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn mark_download_completed(
|
pub async fn mark_download_completed(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
download_id: i64,
|
download_id: i64,
|
||||||
@ -742,6 +786,7 @@ pub async fn mark_download_completed(
|
|||||||
|
|
||||||
/// Mark a download as failed
|
/// Mark a download as failed
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn mark_download_failed(
|
pub async fn mark_download_failed(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
download_id: i64,
|
download_id: i64,
|
||||||
@ -764,6 +809,7 @@ pub async fn mark_download_failed(
|
|||||||
/// Start downloading a file immediately
|
/// Start downloading a file immediately
|
||||||
/// This command actually downloads the file using the worker
|
/// This command actually downloads the file using the worker
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn start_download(
|
pub async fn start_download(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
download_manager: State<'_, DownloadManagerWrapper>,
|
download_manager: State<'_, DownloadManagerWrapper>,
|
||||||
@ -981,6 +1027,7 @@ pub async fn start_download(
|
|||||||
|
|
||||||
/// Delete a completed download
|
/// Delete a completed download
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn delete_download(db: State<'_, DatabaseWrapper>, download_id: i64) -> Result<(), String> {
|
pub async fn delete_download(db: State<'_, DatabaseWrapper>, download_id: i64) -> Result<(), String> {
|
||||||
let db_service = {
|
let db_service = {
|
||||||
let database = db.0.lock().map_err(|e| e.to_string())?;
|
let database = db.0.lock().map_err(|e| e.to_string())?;
|
||||||
@ -1048,7 +1095,7 @@ fn map_download_row(row: &rusqlite::Row) -> rusqlite::Result<DownloadInfo> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Storage statistics for downloads
|
/// Storage statistics for downloads
|
||||||
#[derive(Debug, Clone, serde::Serialize)]
|
#[derive(specta::Type, Debug, Clone, serde::Serialize)]
|
||||||
pub struct StorageStats {
|
pub struct StorageStats {
|
||||||
pub total_bytes: i64,
|
pub total_bytes: i64,
|
||||||
pub total_items: i64,
|
pub total_items: i64,
|
||||||
@ -1056,7 +1103,7 @@ pub struct StorageStats {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Storage info for a single album
|
/// Storage info for a single album
|
||||||
#[derive(Debug, Clone, serde::Serialize)]
|
#[derive(specta::Type, Debug, Clone, serde::Serialize)]
|
||||||
pub struct AlbumStorageInfo {
|
pub struct AlbumStorageInfo {
|
||||||
pub album_id: String,
|
pub album_id: String,
|
||||||
pub album_name: String,
|
pub album_name: String,
|
||||||
@ -1067,6 +1114,7 @@ pub struct AlbumStorageInfo {
|
|||||||
|
|
||||||
/// Get storage statistics for downloads
|
/// Get storage statistics for downloads
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn get_download_storage_stats(
|
pub async fn get_download_storage_stats(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
@ -1127,6 +1175,7 @@ pub async fn get_download_storage_stats(
|
|||||||
|
|
||||||
/// Delete all downloads for a user
|
/// Delete all downloads for a user
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn delete_all_downloads(db: State<'_, DatabaseWrapper>, user_id: String) -> Result<i64, String> {
|
pub async fn delete_all_downloads(db: State<'_, DatabaseWrapper>, user_id: String) -> Result<i64, String> {
|
||||||
let db_service = {
|
let db_service = {
|
||||||
let database = db.0.lock().map_err(|e| e.to_string())?;
|
let database = db.0.lock().map_err(|e| e.to_string())?;
|
||||||
@ -1166,6 +1215,7 @@ pub async fn delete_all_downloads(db: State<'_, DatabaseWrapper>, user_id: Strin
|
|||||||
|
|
||||||
/// Clear all stale pending/failed/paused downloads
|
/// Clear all stale pending/failed/paused downloads
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn clear_stale_downloads(
|
pub async fn clear_stale_downloads(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
@ -1208,6 +1258,7 @@ pub async fn clear_stale_downloads(
|
|||||||
|
|
||||||
/// Delete all downloads for a specific album
|
/// Delete all downloads for a specific album
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn delete_album_downloads(
|
pub async fn delete_album_downloads(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
album_id: String,
|
album_id: String,
|
||||||
@ -1252,7 +1303,7 @@ pub async fn delete_album_downloads(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Download manager statistics
|
/// Download manager statistics
|
||||||
#[derive(Debug, Clone, serde::Serialize)]
|
#[derive(specta::Type, Debug, Clone, serde::Serialize)]
|
||||||
pub struct DownloadManagerStats {
|
pub struct DownloadManagerStats {
|
||||||
pub max_concurrent: usize,
|
pub max_concurrent: usize,
|
||||||
pub active_count: usize,
|
pub active_count: usize,
|
||||||
@ -1261,6 +1312,7 @@ pub struct DownloadManagerStats {
|
|||||||
|
|
||||||
/// Get download manager statistics
|
/// Get download manager statistics
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn get_download_manager_stats(
|
pub async fn get_download_manager_stats(
|
||||||
download_manager: State<'_, DownloadManagerWrapper>,
|
download_manager: State<'_, DownloadManagerWrapper>,
|
||||||
) -> Result<DownloadManagerStats, String> {
|
) -> Result<DownloadManagerStats, String> {
|
||||||
@ -1278,6 +1330,7 @@ pub async fn get_download_manager_stats(
|
|||||||
|
|
||||||
/// Set the maximum concurrent downloads
|
/// Set the maximum concurrent downloads
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn set_max_concurrent_downloads(
|
pub async fn set_max_concurrent_downloads(
|
||||||
download_manager: State<'_, DownloadManagerWrapper>,
|
download_manager: State<'_, DownloadManagerWrapper>,
|
||||||
max: usize,
|
max: usize,
|
||||||
|
|||||||
@ -8,6 +8,7 @@ use crate::storage::db_service::{DatabaseService, Query, QueryParam};
|
|||||||
|
|
||||||
/// Pin an item's metadata (protects from cache clear)
|
/// Pin an item's metadata (protects from cache clear)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn pin_item(db: State<'_, DatabaseWrapper>, item_id: String) -> Result<(), String> {
|
pub async fn pin_item(db: State<'_, DatabaseWrapper>, item_id: String) -> Result<(), String> {
|
||||||
let db_service = {
|
let db_service = {
|
||||||
let database = db.0.lock().map_err(|e| e.to_string())?;
|
let database = db.0.lock().map_err(|e| e.to_string())?;
|
||||||
@ -25,6 +26,7 @@ pub async fn pin_item(db: State<'_, DatabaseWrapper>, item_id: String) -> Result
|
|||||||
|
|
||||||
/// Unpin an item's metadata
|
/// Unpin an item's metadata
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn unpin_item(db: State<'_, DatabaseWrapper>, item_id: String) -> Result<(), String> {
|
pub async fn unpin_item(db: State<'_, DatabaseWrapper>, item_id: String) -> Result<(), String> {
|
||||||
let db_service = {
|
let db_service = {
|
||||||
let database = db.0.lock().map_err(|e| e.to_string())?;
|
let database = db.0.lock().map_err(|e| e.to_string())?;
|
||||||
@ -42,6 +44,7 @@ pub async fn unpin_item(db: State<'_, DatabaseWrapper>, item_id: String) -> Resu
|
|||||||
|
|
||||||
/// Check if an item is pinned
|
/// Check if an item is pinned
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn is_item_pinned(db: State<'_, DatabaseWrapper>, item_id: String) -> Result<bool, String> {
|
pub async fn is_item_pinned(db: State<'_, DatabaseWrapper>, item_id: String) -> Result<bool, String> {
|
||||||
let db_service = {
|
let db_service = {
|
||||||
let database = db.0.lock().map_err(|e| e.to_string())?;
|
let database = db.0.lock().map_err(|e| e.to_string())?;
|
||||||
|
|||||||
@ -8,7 +8,7 @@ use crate::commands::{DatabaseWrapper, SmartCacheWrapper};
|
|||||||
use crate::storage::db_service::{DatabaseService, Query, QueryParam};
|
use crate::storage::db_service::{DatabaseService, Query, QueryParam};
|
||||||
|
|
||||||
/// SmartCache statistics
|
/// SmartCache statistics
|
||||||
#[derive(Debug, Clone, serde::Serialize)]
|
#[derive(specta::Type, Debug, Clone, serde::Serialize)]
|
||||||
pub struct SmartCacheStats {
|
pub struct SmartCacheStats {
|
||||||
pub total_size: u64,
|
pub total_size: u64,
|
||||||
pub storage_limit: u64,
|
pub storage_limit: u64,
|
||||||
@ -19,6 +19,7 @@ pub struct SmartCacheStats {
|
|||||||
|
|
||||||
/// Get SmartCache statistics
|
/// Get SmartCache statistics
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn get_smart_cache_stats(
|
pub async fn get_smart_cache_stats(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
smart_cache: State<'_, SmartCacheWrapper>,
|
smart_cache: State<'_, SmartCacheWrapper>,
|
||||||
@ -67,6 +68,7 @@ pub async fn get_smart_cache_stats(
|
|||||||
|
|
||||||
/// Update SmartCache configuration
|
/// Update SmartCache configuration
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn update_smart_cache_config(
|
pub async fn update_smart_cache_config(
|
||||||
smart_cache: State<'_, SmartCacheWrapper>,
|
smart_cache: State<'_, SmartCacheWrapper>,
|
||||||
config: crate::download::cache::CacheConfig,
|
config: crate::download::cache::CacheConfig,
|
||||||
@ -79,6 +81,7 @@ pub async fn update_smart_cache_config(
|
|||||||
|
|
||||||
/// Get SmartCache configuration
|
/// Get SmartCache configuration
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn get_smart_cache_config(
|
pub async fn get_smart_cache_config(
|
||||||
smart_cache: State<'_, SmartCacheWrapper>,
|
smart_cache: State<'_, SmartCacheWrapper>,
|
||||||
) -> Result<crate::download::cache::CacheConfig, String> {
|
) -> Result<crate::download::cache::CacheConfig, String> {
|
||||||
@ -89,7 +92,7 @@ pub async fn get_smart_cache_config(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Album recommendation info
|
/// Album recommendation info
|
||||||
#[derive(Debug, Clone, serde::Serialize)]
|
#[derive(specta::Type, Debug, Clone, serde::Serialize)]
|
||||||
pub struct AlbumRecommendation {
|
pub struct AlbumRecommendation {
|
||||||
pub album_id: String,
|
pub album_id: String,
|
||||||
pub album_name: String,
|
pub album_name: String,
|
||||||
@ -99,7 +102,7 @@ pub struct AlbumRecommendation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Album affinity status info
|
/// Album affinity status info
|
||||||
#[derive(Debug, Clone, serde::Serialize)]
|
#[derive(specta::Type, Debug, Clone, serde::Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct AlbumAffinityStatus {
|
pub struct AlbumAffinityStatus {
|
||||||
pub album_id: String,
|
pub album_id: String,
|
||||||
@ -110,6 +113,7 @@ pub struct AlbumAffinityStatus {
|
|||||||
|
|
||||||
/// Get album recommendations based on play history
|
/// Get album recommendations based on play history
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn get_album_recommendations(
|
pub async fn get_album_recommendations(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
smart_cache: State<'_, SmartCacheWrapper>,
|
smart_cache: State<'_, SmartCacheWrapper>,
|
||||||
@ -189,6 +193,7 @@ pub async fn get_album_recommendations(
|
|||||||
/// Get album affinity status for all tracked albums
|
/// Get album affinity status for all tracked albums
|
||||||
/// This shows the SmartCache's internal play history and threshold status
|
/// This shows the SmartCache's internal play history and threshold status
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub fn get_album_affinity_status(
|
pub fn get_album_affinity_status(
|
||||||
smart_cache: State<'_, SmartCacheWrapper>,
|
smart_cache: State<'_, SmartCacheWrapper>,
|
||||||
) -> Result<Vec<AlbumAffinityStatus>, String> {
|
) -> Result<Vec<AlbumAffinityStatus>, String> {
|
||||||
|
|||||||
@ -7,7 +7,7 @@ use tauri::State;
|
|||||||
use super::DatabaseWrapper;
|
use super::DatabaseWrapper;
|
||||||
use crate::storage::db_service::{DatabaseService, Query, QueryParam};
|
use crate::storage::db_service::{DatabaseService, Query, QueryParam};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct OfflineItem {
|
pub struct OfflineItem {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
@ -22,6 +22,7 @@ pub struct OfflineItem {
|
|||||||
|
|
||||||
/// Check if an item is available offline
|
/// Check if an item is available offline
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn offline_is_available(
|
pub async fn offline_is_available(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
item_id: String,
|
item_id: String,
|
||||||
@ -46,6 +47,7 @@ pub async fn offline_is_available(
|
|||||||
|
|
||||||
/// Get all offline items for a user
|
/// Get all offline items for a user
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn offline_get_items(
|
pub async fn offline_get_items(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
@ -84,6 +86,7 @@ pub async fn offline_get_items(
|
|||||||
|
|
||||||
/// Search offline items
|
/// Search offline items
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn offline_search(
|
pub async fn offline_search(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
|
|||||||
@ -8,6 +8,7 @@ pub struct PlaybackModeManagerWrapper(pub Arc<PlaybackModeManager>);
|
|||||||
|
|
||||||
/// Get the current playback mode
|
/// Get the current playback mode
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub fn playback_mode_get_current(
|
pub fn playback_mode_get_current(
|
||||||
manager: State<'_, PlaybackModeManagerWrapper>,
|
manager: State<'_, PlaybackModeManagerWrapper>,
|
||||||
) -> Result<PlaybackMode, String> {
|
) -> Result<PlaybackMode, String> {
|
||||||
@ -16,6 +17,7 @@ pub fn playback_mode_get_current(
|
|||||||
|
|
||||||
/// Set the playback mode (internal/testing use)
|
/// Set the playback mode (internal/testing use)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub fn playback_mode_set(
|
pub fn playback_mode_set(
|
||||||
manager: State<'_, PlaybackModeManagerWrapper>,
|
manager: State<'_, PlaybackModeManagerWrapper>,
|
||||||
mode: PlaybackMode,
|
mode: PlaybackMode,
|
||||||
@ -26,6 +28,7 @@ pub fn playback_mode_set(
|
|||||||
|
|
||||||
/// Check if currently transferring between playback modes
|
/// Check if currently transferring between playback modes
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub fn playback_mode_is_transferring(
|
pub fn playback_mode_is_transferring(
|
||||||
manager: State<'_, PlaybackModeManagerWrapper>,
|
manager: State<'_, PlaybackModeManagerWrapper>,
|
||||||
) -> Result<bool, String> {
|
) -> Result<bool, String> {
|
||||||
@ -34,6 +37,7 @@ pub fn playback_mode_is_transferring(
|
|||||||
|
|
||||||
/// Transfer playback from local device to a remote Jellyfin session
|
/// Transfer playback from local device to a remote Jellyfin session
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn playback_mode_transfer_to_remote(
|
pub async fn playback_mode_transfer_to_remote(
|
||||||
manager: State<'_, PlaybackModeManagerWrapper>,
|
manager: State<'_, PlaybackModeManagerWrapper>,
|
||||||
session_id: String,
|
session_id: String,
|
||||||
@ -51,6 +55,7 @@ pub async fn playback_mode_transfer_to_remote(
|
|||||||
/// - current_item_id: The Jellyfin item ID currently playing on remote
|
/// - current_item_id: The Jellyfin item ID currently playing on remote
|
||||||
/// - position_ticks: Current playback position in ticks (10,000 ticks = 1ms)
|
/// - position_ticks: Current playback position in ticks (10,000 ticks = 1ms)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn playback_mode_transfer_to_local(
|
pub async fn playback_mode_transfer_to_local(
|
||||||
manager: State<'_, PlaybackModeManagerWrapper>,
|
manager: State<'_, PlaybackModeManagerWrapper>,
|
||||||
current_item_id: String,
|
current_item_id: String,
|
||||||
@ -69,6 +74,7 @@ pub async fn playback_mode_transfer_to_local(
|
|||||||
|
|
||||||
/// Get remote session status (for polling position/duration)
|
/// Get remote session status (for polling position/duration)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn playback_mode_get_remote_status(
|
pub async fn playback_mode_get_remote_status(
|
||||||
manager: State<'_, PlaybackModeManagerWrapper>,
|
manager: State<'_, PlaybackModeManagerWrapper>,
|
||||||
player: State<'_, crate::commands::PlayerStateWrapper>,
|
player: State<'_, crate::commands::PlayerStateWrapper>,
|
||||||
@ -119,7 +125,7 @@ pub async fn playback_mode_get_remote_status(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Remote session status for UI updates
|
/// Remote session status for UI updates
|
||||||
#[derive(serde::Serialize)]
|
#[derive(specta::Type, serde::Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RemoteSessionStatus {
|
pub struct RemoteSessionStatus {
|
||||||
pub position: f64,
|
pub position: f64,
|
||||||
|
|||||||
@ -24,6 +24,7 @@ pub struct PlaybackReporterWrapper(pub Arc<TokioMutex<Option<PlaybackReporter>>>
|
|||||||
|
|
||||||
/// Initialize playback reporter (called after login)
|
/// Initialize playback reporter (called after login)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn playback_reporter_init(
|
pub async fn playback_reporter_init(
|
||||||
reporter_wrapper: State<'_, PlaybackReporterWrapper>,
|
reporter_wrapper: State<'_, PlaybackReporterWrapper>,
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
@ -66,6 +67,7 @@ pub async fn playback_reporter_init(
|
|||||||
|
|
||||||
/// Destroy playback reporter (called on logout)
|
/// Destroy playback reporter (called on logout)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn playback_reporter_destroy(
|
pub async fn playback_reporter_destroy(
|
||||||
reporter_wrapper: State<'_, PlaybackReporterWrapper>,
|
reporter_wrapper: State<'_, PlaybackReporterWrapper>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
@ -76,6 +78,7 @@ pub async fn playback_reporter_destroy(
|
|||||||
|
|
||||||
/// Report playback start
|
/// Report playback start
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn playback_report_start(
|
pub async fn playback_report_start(
|
||||||
reporter: State<'_, PlaybackReporterWrapper>,
|
reporter: State<'_, PlaybackReporterWrapper>,
|
||||||
connectivity: State<'_, ConnectivityMonitorWrapper>,
|
connectivity: State<'_, ConnectivityMonitorWrapper>,
|
||||||
@ -110,6 +113,7 @@ pub async fn playback_report_start(
|
|||||||
|
|
||||||
/// Report playback progress
|
/// Report playback progress
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn playback_report_progress(
|
pub async fn playback_report_progress(
|
||||||
reporter: State<'_, PlaybackReporterWrapper>,
|
reporter: State<'_, PlaybackReporterWrapper>,
|
||||||
connectivity: State<'_, ConnectivityMonitorWrapper>,
|
connectivity: State<'_, ConnectivityMonitorWrapper>,
|
||||||
@ -138,6 +142,7 @@ pub async fn playback_report_progress(
|
|||||||
|
|
||||||
/// Report playback stopped
|
/// Report playback stopped
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn playback_report_stopped(
|
pub async fn playback_report_stopped(
|
||||||
reporter: State<'_, PlaybackReporterWrapper>,
|
reporter: State<'_, PlaybackReporterWrapper>,
|
||||||
connectivity: State<'_, ConnectivityMonitorWrapper>,
|
connectivity: State<'_, ConnectivityMonitorWrapper>,
|
||||||
@ -164,6 +169,7 @@ pub async fn playback_report_stopped(
|
|||||||
|
|
||||||
/// Mark item as played
|
/// Mark item as played
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn playback_mark_played(
|
pub async fn playback_mark_played(
|
||||||
reporter: State<'_, PlaybackReporterWrapper>,
|
reporter: State<'_, PlaybackReporterWrapper>,
|
||||||
connectivity: State<'_, ConnectivityMonitorWrapper>,
|
connectivity: State<'_, ConnectivityMonitorWrapper>,
|
||||||
|
|||||||
@ -56,7 +56,7 @@ pub struct MediaSessionManagerWrapper(pub Mutex<MediaSessionManager>);
|
|||||||
pub struct VideoSettingsWrapper(pub Mutex<VideoSettings>);
|
pub struct VideoSettingsWrapper(pub Mutex<VideoSettings>);
|
||||||
|
|
||||||
/// Response for player state queries
|
/// Response for player state queries
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(specta::Type, Debug, Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct PlayerStatus {
|
pub struct PlayerStatus {
|
||||||
pub state: PlayerState,
|
pub state: PlayerState,
|
||||||
@ -82,7 +82,7 @@ pub struct PlayerStatus {
|
|||||||
|
|
||||||
/// Lightweight media item for merged playback state
|
/// Lightweight media item for merged playback state
|
||||||
/// Converts from both local MediaItem and remote NowPlayingItem
|
/// Converts from both local MediaItem and remote NowPlayingItem
|
||||||
#[derive(Debug, Serialize, Clone)]
|
#[derive(specta::Type, Debug, Serialize, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct MergedMediaItem {
|
pub struct MergedMediaItem {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
@ -134,7 +134,7 @@ impl From<&crate::jellyfin::client::NowPlayingItem> for MergedMediaItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Response for queue queries
|
/// Response for queue queries
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(specta::Type, Debug, Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct QueueStatus {
|
pub struct QueueStatus {
|
||||||
pub items: Vec<MediaItem>,
|
pub items: Vec<MediaItem>,
|
||||||
@ -146,7 +146,7 @@ pub struct QueueStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Backend type for video playback
|
/// Backend type for video playback
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(specta::Type, Debug, Serialize)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum VideoBackend {
|
pub enum VideoBackend {
|
||||||
/// Native backend (ExoPlayer on Android, libmpv on Linux)
|
/// Native backend (ExoPlayer on Android, libmpv on Linux)
|
||||||
@ -159,7 +159,7 @@ pub enum VideoBackend {
|
|||||||
///
|
///
|
||||||
/// Simplified to video playback only. Audio playback uses player_play_tracks
|
/// Simplified to video playback only. Audio playback uses player_play_tracks
|
||||||
/// to avoid Tauri Android serialization issues with complex objects.
|
/// to avoid Tauri Android serialization issues with complex objects.
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(specta::Type, Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct PlayItemRequest {
|
pub struct PlayItemRequest {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
@ -172,7 +172,7 @@ pub struct PlayItemRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Queue context for remote transfer - what type of queue is this?
|
/// Queue context for remote transfer - what type of queue is this?
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(specta::Type, Debug, Deserialize)]
|
||||||
#[serde(tag = "type", rename_all = "lowercase")]
|
#[serde(tag = "type", rename_all = "lowercase")]
|
||||||
pub enum PlayQueueContext {
|
pub enum PlayQueueContext {
|
||||||
/// Playing from a specific album
|
/// Playing from a specific album
|
||||||
@ -194,7 +194,7 @@ pub enum PlayQueueContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Request to play a queue of items
|
/// Request to play a queue of items
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(specta::Type, Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct PlayQueueRequest {
|
pub struct PlayQueueRequest {
|
||||||
pub items: Vec<PlayItemRequest>,
|
pub items: Vec<PlayItemRequest>,
|
||||||
@ -207,7 +207,7 @@ pub struct PlayQueueRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Request to play a track from an album (backend fetches all tracks)
|
/// Request to play a track from an album (backend fetches all tracks)
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(specta::Type, Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct PlayAlbumTrackRequest {
|
pub struct PlayAlbumTrackRequest {
|
||||||
pub album_id: String,
|
pub album_id: String,
|
||||||
@ -217,7 +217,7 @@ pub struct PlayAlbumTrackRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Request to play tracks by ID (backend fetches metadata)
|
/// Request to play tracks by ID (backend fetches metadata)
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(specta::Type, Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct PlayTracksRequest {
|
pub struct PlayTracksRequest {
|
||||||
pub track_ids: Vec<String>,
|
pub track_ids: Vec<String>,
|
||||||
@ -227,7 +227,7 @@ pub struct PlayTracksRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Context information for track playback
|
/// Context information for track playback
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(specta::Type, Debug, Deserialize)]
|
||||||
#[serde(tag = "type", rename_all = "lowercase")]
|
#[serde(tag = "type", rename_all = "lowercase")]
|
||||||
pub enum PlayTracksContext {
|
pub enum PlayTracksContext {
|
||||||
Playlist {
|
Playlist {
|
||||||
@ -249,7 +249,7 @@ pub enum PlayTracksContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Response for video seek operations
|
/// Response for video seek operations
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(specta::Type, Debug, Serialize)]
|
||||||
#[serde(tag = "strategy", rename_all = "camelCase")]
|
#[serde(tag = "strategy", rename_all = "camelCase")]
|
||||||
pub enum VideoSeekResponse {
|
pub enum VideoSeekResponse {
|
||||||
/// Use native seeking (HLS or direct stream)
|
/// Use native seeking (HLS or direct stream)
|
||||||
@ -267,7 +267,7 @@ pub enum VideoSeekResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Response for audio track switching operations
|
/// Response for audio track switching operations
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(specta::Type, Debug, Serialize)]
|
||||||
#[serde(tag = "strategy", rename_all = "camelCase")]
|
#[serde(tag = "strategy", rename_all = "camelCase")]
|
||||||
pub enum AudioTrackSwitchResponse {
|
pub enum AudioTrackSwitchResponse {
|
||||||
/// Native backend handled it (Android ExoPlayer)
|
/// Native backend handled it (Android ExoPlayer)
|
||||||
@ -384,6 +384,7 @@ pub(super) async fn check_for_local_download(
|
|||||||
/// @req: UR-005 - Control media playback (play operation)
|
/// @req: UR-005 - Control media playback (play operation)
|
||||||
/// @req: DR-009 - Audio player UI
|
/// @req: DR-009 - Audio player UI
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_play_item(
|
pub async fn player_play_item(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
session: State<'_, MediaSessionManagerWrapper>,
|
session: State<'_, MediaSessionManagerWrapper>,
|
||||||
@ -435,6 +436,7 @@ pub async fn player_play_item(
|
|||||||
/// @req: UR-015 - View and manage current audio queue
|
/// @req: UR-015 - View and manage current audio queue
|
||||||
/// @req: DR-005 - Queue manager with shuffle, repeat, history
|
/// @req: DR-005 - Queue manager with shuffle, repeat, history
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_play_queue(
|
pub async fn player_play_queue(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
session: State<'_, MediaSessionManagerWrapper>,
|
session: State<'_, MediaSessionManagerWrapper>,
|
||||||
@ -511,6 +513,7 @@ pub async fn player_play_queue(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_play(
|
pub async fn player_play(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
playback_mode: State<'_, super::playback_mode::PlaybackModeManagerWrapper>,
|
playback_mode: State<'_, super::playback_mode::PlaybackModeManagerWrapper>,
|
||||||
@ -538,6 +541,7 @@ pub async fn player_play(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_pause(
|
pub async fn player_pause(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
playback_mode: State<'_, super::playback_mode::PlaybackModeManagerWrapper>,
|
playback_mode: State<'_, super::playback_mode::PlaybackModeManagerWrapper>,
|
||||||
@ -565,6 +569,7 @@ pub async fn player_pause(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_toggle(
|
pub async fn player_toggle(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
playback_mode: State<'_, super::playback_mode::PlaybackModeManagerWrapper>,
|
playback_mode: State<'_, super::playback_mode::PlaybackModeManagerWrapper>,
|
||||||
@ -592,6 +597,7 @@ pub async fn player_toggle(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_stop(
|
pub async fn player_stop(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
session: State<'_, MediaSessionManagerWrapper>,
|
session: State<'_, MediaSessionManagerWrapper>,
|
||||||
@ -651,6 +657,7 @@ pub async fn player_stop(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_next(
|
pub async fn player_next(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
session: State<'_, MediaSessionManagerWrapper>,
|
session: State<'_, MediaSessionManagerWrapper>,
|
||||||
@ -703,6 +710,7 @@ pub async fn player_next(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_previous(
|
pub async fn player_previous(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
session: State<'_, MediaSessionManagerWrapper>,
|
session: State<'_, MediaSessionManagerWrapper>,
|
||||||
@ -753,6 +761,7 @@ pub async fn player_previous(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_seek(
|
pub async fn player_seek(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
playback_mode: State<'_, super::playback_mode::PlaybackModeManagerWrapper>,
|
playback_mode: State<'_, super::playback_mode::PlaybackModeManagerWrapper>,
|
||||||
@ -792,6 +801,7 @@ pub async fn player_seek(
|
|||||||
/// For native (non-HTML5) backends, this command handles the entire stream reload
|
/// For native (non-HTML5) backends, this command handles the entire stream reload
|
||||||
/// internally. For HTML5 backends, it returns the new URL for the frontend to handle.
|
/// internally. For HTML5 backends, it returns the new URL for the frontend to handle.
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_seek_video(
|
pub async fn player_seek_video(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
repository_manager: State<'_, super::repository::RepositoryManagerWrapper>,
|
repository_manager: State<'_, super::repository::RepositoryManagerWrapper>,
|
||||||
@ -929,6 +939,7 @@ pub async fn player_seek_video(
|
|||||||
/// Switch audio track - handles both HTML5 (stream reload) and native (direct switch)
|
/// Switch audio track - handles both HTML5 (stream reload) and native (direct switch)
|
||||||
/// Note: Frontend should handle saving series preferences after this command succeeds
|
/// Note: Frontend should handle saving series preferences after this command succeeds
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_switch_audio_track(
|
pub async fn player_switch_audio_track(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
repository_manager: State<'_, super::repository::RepositoryManagerWrapper>,
|
repository_manager: State<'_, super::repository::RepositoryManagerWrapper>,
|
||||||
@ -984,6 +995,7 @@ pub async fn player_switch_audio_track(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_set_audio_track(
|
pub async fn player_set_audio_track(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
stream_index: i32,
|
stream_index: i32,
|
||||||
@ -994,6 +1006,7 @@ pub async fn player_set_audio_track(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_set_subtitle_track(
|
pub async fn player_set_subtitle_track(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
stream_index: Option<i32>,
|
stream_index: Option<i32>,
|
||||||
@ -1004,6 +1017,7 @@ pub async fn player_set_subtitle_track(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_set_volume(
|
pub async fn player_set_volume(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
playback_mode: State<'_, super::playback_mode::PlaybackModeManagerWrapper>,
|
playback_mode: State<'_, super::playback_mode::PlaybackModeManagerWrapper>,
|
||||||
@ -1034,6 +1048,7 @@ pub async fn player_set_volume(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_toggle_mute(
|
pub async fn player_toggle_mute(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
playback_mode: State<'_, super::playback_mode::PlaybackModeManagerWrapper>,
|
playback_mode: State<'_, super::playback_mode::PlaybackModeManagerWrapper>,
|
||||||
@ -1062,6 +1077,7 @@ pub async fn player_toggle_mute(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_toggle_shuffle(
|
pub async fn player_toggle_shuffle(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
) -> Result<QueueStatus, String> {
|
) -> Result<QueueStatus, String> {
|
||||||
@ -1072,6 +1088,7 @@ pub async fn player_toggle_shuffle(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_cycle_repeat(player: State<'_, PlayerStateWrapper>) -> Result<QueueStatus, String> {
|
pub async fn player_cycle_repeat(player: State<'_, PlayerStateWrapper>) -> Result<QueueStatus, String> {
|
||||||
let controller = player.0.lock().await;
|
let controller = player.0.lock().await;
|
||||||
controller.cycle_repeat();
|
controller.cycle_repeat();
|
||||||
@ -1080,6 +1097,7 @@ pub async fn player_cycle_repeat(player: State<'_, PlayerStateWrapper>) -> Resul
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_get_status(
|
pub async fn player_get_status(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
playback_mode: State<'_, super::playback_mode::PlaybackModeManagerWrapper>,
|
playback_mode: State<'_, super::playback_mode::PlaybackModeManagerWrapper>,
|
||||||
@ -1165,6 +1183,7 @@ pub async fn player_get_status(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_get_queue(player: State<'_, PlayerStateWrapper>) -> Result<QueueStatus, String> {
|
pub async fn player_get_queue(player: State<'_, PlayerStateWrapper>) -> Result<QueueStatus, String> {
|
||||||
let controller = player.0.lock().await;
|
let controller = player.0.lock().await;
|
||||||
Ok(get_queue_status(&controller))
|
Ok(get_queue_status(&controller))
|
||||||
@ -1216,6 +1235,7 @@ pub(super) fn get_queue_status(controller: &PlayerController) -> QueueStatus {
|
|||||||
|
|
||||||
/// Play a track from an album - backend fetches all album tracks and builds queue
|
/// Play a track from an album - backend fetches all album tracks and builds queue
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_play_album_track(
|
pub async fn player_play_album_track(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
session: State<'_, MediaSessionManagerWrapper>,
|
session: State<'_, MediaSessionManagerWrapper>,
|
||||||
@ -1383,6 +1403,7 @@ pub async fn player_play_album_track(
|
|||||||
|
|
||||||
/// Play tracks by ID - backend fetches all metadata
|
/// Play tracks by ID - backend fetches all metadata
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_play_tracks(
|
pub async fn player_play_tracks(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
session: State<'_, MediaSessionManagerWrapper>,
|
session: State<'_, MediaSessionManagerWrapper>,
|
||||||
@ -1521,7 +1542,7 @@ pub async fn player_play_tracks(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Response for preload operation
|
/// Response for preload operation
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(specta::Type, Debug, Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct PreloadResult {
|
pub struct PreloadResult {
|
||||||
/// Number of tracks queued for preload
|
/// Number of tracks queued for preload
|
||||||
@ -1535,6 +1556,7 @@ pub struct PreloadResult {
|
|||||||
/// Preload upcoming tracks from the queue
|
/// Preload upcoming tracks from the queue
|
||||||
/// This queues background downloads for the next N tracks that aren't already downloaded
|
/// This queues background downloads for the next N tracks that aren't already downloaded
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_preload_upcoming(
|
pub async fn player_preload_upcoming(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
@ -1671,6 +1693,7 @@ fn sanitize_filename(name: &str) -> String {
|
|||||||
|
|
||||||
/// Update SmartCache configuration
|
/// Update SmartCache configuration
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_set_cache_config(
|
pub async fn player_set_cache_config(
|
||||||
smart_cache: State<'_, SmartCacheWrapper>,
|
smart_cache: State<'_, SmartCacheWrapper>,
|
||||||
config: CacheConfig,
|
config: CacheConfig,
|
||||||
@ -1682,6 +1705,7 @@ pub async fn player_set_cache_config(
|
|||||||
|
|
||||||
/// Get current SmartCache configuration
|
/// Get current SmartCache configuration
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_get_cache_config(
|
pub async fn player_get_cache_config(
|
||||||
smart_cache: State<'_, SmartCacheWrapper>,
|
smart_cache: State<'_, SmartCacheWrapper>,
|
||||||
) -> Result<CacheConfig, String> {
|
) -> Result<CacheConfig, String> {
|
||||||
@ -1691,6 +1715,7 @@ pub async fn player_get_cache_config(
|
|||||||
|
|
||||||
/// Configure Jellyfin API client for automatic playback reporting
|
/// Configure Jellyfin API client for automatic playback reporting
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_configure_jellyfin(
|
pub async fn player_configure_jellyfin(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
server_url: String,
|
server_url: String,
|
||||||
@ -1717,6 +1742,7 @@ pub async fn player_configure_jellyfin(
|
|||||||
|
|
||||||
/// Disable Jellyfin automatic playback reporting
|
/// Disable Jellyfin automatic playback reporting
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_disable_jellyfin(
|
pub async fn player_disable_jellyfin(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
|
|||||||
@ -16,7 +16,7 @@ use crate::repository::types::{ImageOptions, ImageType};
|
|||||||
use crate::repository::MediaRepository;
|
use crate::repository::MediaRepository;
|
||||||
|
|
||||||
/// Request to add items to queue
|
/// Request to add items to queue
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(specta::Type, Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct AddToQueueRequest {
|
pub struct AddToQueueRequest {
|
||||||
pub items: Vec<PlayItemRequest>,
|
pub items: Vec<PlayItemRequest>,
|
||||||
@ -24,7 +24,7 @@ pub struct AddToQueueRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Request to add a track by ID - backend fetches metadata
|
/// Request to add a track by ID - backend fetches metadata
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(specta::Type, Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct AddTrackByIdRequest {
|
pub struct AddTrackByIdRequest {
|
||||||
pub track_id: String,
|
pub track_id: String,
|
||||||
@ -32,7 +32,7 @@ pub struct AddTrackByIdRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Request to add multiple tracks by IDs - backend fetches metadata
|
/// Request to add multiple tracks by IDs - backend fetches metadata
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(specta::Type, Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct AddTracksByIdsRequest {
|
pub struct AddTracksByIdsRequest {
|
||||||
pub track_ids: Vec<String>,
|
pub track_ids: Vec<String>,
|
||||||
@ -40,6 +40,7 @@ pub struct AddTracksByIdsRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_add_to_queue(
|
pub async fn player_add_to_queue(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
@ -81,6 +82,7 @@ pub async fn player_add_to_queue(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_remove_from_queue(
|
pub async fn player_remove_from_queue(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
index: usize,
|
index: usize,
|
||||||
@ -107,6 +109,7 @@ pub async fn player_remove_from_queue(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_move_in_queue(
|
pub async fn player_move_in_queue(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
from_index: usize,
|
from_index: usize,
|
||||||
@ -137,6 +140,7 @@ pub async fn player_move_in_queue(
|
|||||||
|
|
||||||
/// Add a track to queue by ID - backend fetches metadata and constructs URLs
|
/// Add a track to queue by ID - backend fetches metadata and constructs URLs
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_add_track_by_id(
|
pub async fn player_add_track_by_id(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
@ -236,6 +240,7 @@ pub async fn player_add_track_by_id(
|
|||||||
|
|
||||||
/// Add multiple tracks to queue by IDs - backend fetches metadata and constructs URLs
|
/// Add multiple tracks to queue by IDs - backend fetches metadata and constructs URLs
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_add_tracks_by_ids(
|
pub async fn player_add_tracks_by_ids(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
@ -339,6 +344,7 @@ pub async fn player_add_tracks_by_ids(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_skip_to(
|
pub async fn player_skip_to(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
index: usize,
|
index: usize,
|
||||||
|
|||||||
@ -9,6 +9,7 @@ use super::PlayerStateWrapper;
|
|||||||
|
|
||||||
/// Play items on a remote Jellyfin session (casting)
|
/// Play items on a remote Jellyfin session (casting)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn remote_play_on_session(
|
pub async fn remote_play_on_session(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
session_id: String,
|
session_id: String,
|
||||||
@ -36,6 +37,7 @@ pub async fn remote_play_on_session(
|
|||||||
|
|
||||||
/// Send a playback command to a remote session
|
/// Send a playback command to a remote session
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn remote_send_command(
|
pub async fn remote_send_command(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
session_id: String,
|
session_id: String,
|
||||||
@ -59,6 +61,7 @@ pub async fn remote_send_command(
|
|||||||
|
|
||||||
/// Seek on a remote session
|
/// Seek on a remote session
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn remote_session_seek(
|
pub async fn remote_session_seek(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
session_id: String,
|
session_id: String,
|
||||||
@ -82,6 +85,7 @@ pub async fn remote_session_seek(
|
|||||||
|
|
||||||
/// Set volume on a remote session
|
/// Set volume on a remote session
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn remote_session_set_volume(
|
pub async fn remote_session_set_volume(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
session_id: String,
|
session_id: String,
|
||||||
@ -105,6 +109,7 @@ pub async fn remote_session_set_volume(
|
|||||||
|
|
||||||
/// Toggle mute on a remote session
|
/// Toggle mute on a remote session
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn remote_session_toggle_mute(
|
pub async fn remote_session_toggle_mute(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
session_id: String,
|
session_id: String,
|
||||||
|
|||||||
@ -10,6 +10,7 @@ use crate::player::PlayerStatusEvent;
|
|||||||
|
|
||||||
/// Get the current media session state
|
/// Get the current media session state
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_get_session(
|
pub async fn player_get_session(
|
||||||
session: State<'_, MediaSessionManagerWrapper>,
|
session: State<'_, MediaSessionManagerWrapper>,
|
||||||
) -> Result<crate::player::session::MediaSessionType, String> {
|
) -> Result<crate::player::session::MediaSessionType, String> {
|
||||||
@ -19,6 +20,7 @@ pub async fn player_get_session(
|
|||||||
|
|
||||||
/// Dismiss the current media session (returns to Idle)
|
/// Dismiss the current media session (returns to Idle)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_dismiss_session(
|
pub async fn player_dismiss_session(
|
||||||
session: State<'_, MediaSessionManagerWrapper>,
|
session: State<'_, MediaSessionManagerWrapper>,
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
|
|||||||
@ -7,6 +7,7 @@ use crate::player::AutoplaySettings;
|
|||||||
use crate::settings::{AudioSettings, VideoSettings};
|
use crate::settings::{AudioSettings, VideoSettings};
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_set_audio_settings(
|
pub async fn player_set_audio_settings(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
settings: AudioSettings,
|
settings: AudioSettings,
|
||||||
@ -19,6 +20,7 @@ pub async fn player_set_audio_settings(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_get_audio_settings(
|
pub async fn player_get_audio_settings(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
) -> Result<AudioSettings, String> {
|
) -> Result<AudioSettings, String> {
|
||||||
@ -27,6 +29,7 @@ pub async fn player_get_audio_settings(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_set_video_settings(
|
pub async fn player_set_video_settings(
|
||||||
video_settings: State<'_, VideoSettingsWrapper>,
|
video_settings: State<'_, VideoSettingsWrapper>,
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
@ -50,6 +53,7 @@ pub async fn player_set_video_settings(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_get_video_settings(
|
pub async fn player_get_video_settings(
|
||||||
video_settings: State<'_, VideoSettingsWrapper>,
|
video_settings: State<'_, VideoSettingsWrapper>,
|
||||||
) -> Result<VideoSettings, String> {
|
) -> Result<VideoSettings, String> {
|
||||||
|
|||||||
@ -17,6 +17,7 @@ use crate::storage::db_service::{DatabaseService, Query, QueryParam};
|
|||||||
|
|
||||||
/// Set sleep timer mode
|
/// Set sleep timer mode
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_set_sleep_timer(
|
pub async fn player_set_sleep_timer(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
mode: SleepTimerMode,
|
mode: SleepTimerMode,
|
||||||
@ -28,6 +29,7 @@ pub async fn player_set_sleep_timer(
|
|||||||
|
|
||||||
/// Cancel sleep timer
|
/// Cancel sleep timer
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_cancel_sleep_timer(
|
pub async fn player_cancel_sleep_timer(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
) -> Result<SleepTimerState, String> {
|
) -> Result<SleepTimerState, String> {
|
||||||
@ -38,6 +40,7 @@ pub async fn player_cancel_sleep_timer(
|
|||||||
|
|
||||||
/// Get current sleep timer state
|
/// Get current sleep timer state
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_get_sleep_timer(
|
pub async fn player_get_sleep_timer(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
) -> Result<SleepTimerState, String> {
|
) -> Result<SleepTimerState, String> {
|
||||||
@ -49,6 +52,7 @@ pub async fn player_get_sleep_timer(
|
|||||||
|
|
||||||
/// Get autoplay settings
|
/// Get autoplay settings
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_get_autoplay_settings(
|
pub async fn player_get_autoplay_settings(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
) -> Result<AutoplaySettings, String> {
|
) -> Result<AutoplaySettings, String> {
|
||||||
@ -58,6 +62,7 @@ pub async fn player_get_autoplay_settings(
|
|||||||
|
|
||||||
/// Set autoplay settings and persist to database
|
/// Set autoplay settings and persist to database
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_set_autoplay_settings(
|
pub async fn player_set_autoplay_settings(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
@ -101,6 +106,7 @@ pub async fn player_set_autoplay_settings(
|
|||||||
|
|
||||||
/// Cancel active autoplay countdown
|
/// Cancel active autoplay countdown
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_cancel_autoplay_countdown(
|
pub async fn player_cancel_autoplay_countdown(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
@ -111,6 +117,7 @@ pub async fn player_cancel_autoplay_countdown(
|
|||||||
|
|
||||||
/// Play next episode (user confirmed from popup)
|
/// Play next episode (user confirmed from popup)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_play_next_episode(
|
pub async fn player_play_next_episode(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
@ -131,6 +138,7 @@ pub async fn player_play_next_episode(
|
|||||||
/// - Frontend when audio track ends via backend event - no itemId/repositoryHandle needed
|
/// - Frontend when audio track ends via backend event - no itemId/repositoryHandle needed
|
||||||
/// - Android JNI callback also triggers this logic directly
|
/// - Android JNI callback also triggers this logic directly
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn player_on_playback_ended(
|
pub async fn player_on_playback_ended(
|
||||||
player: State<'_, PlayerStateWrapper>,
|
player: State<'_, PlayerStateWrapper>,
|
||||||
repository_manager: State<'_, crate::commands::repository::RepositoryManagerWrapper>,
|
repository_manager: State<'_, crate::commands::repository::RepositoryManagerWrapper>,
|
||||||
|
|||||||
@ -11,6 +11,7 @@ use super::repository::RepositoryManagerWrapper;
|
|||||||
|
|
||||||
/// Create a new playlist
|
/// Create a new playlist
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn playlist_create(
|
pub async fn playlist_create(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -27,6 +28,7 @@ pub async fn playlist_create(
|
|||||||
|
|
||||||
/// Delete a playlist
|
/// Delete a playlist
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn playlist_delete(
|
pub async fn playlist_delete(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -41,6 +43,7 @@ pub async fn playlist_delete(
|
|||||||
|
|
||||||
/// Rename a playlist
|
/// Rename a playlist
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn playlist_rename(
|
pub async fn playlist_rename(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -56,6 +59,7 @@ pub async fn playlist_rename(
|
|||||||
|
|
||||||
/// Get playlist items with PlaylistItemId
|
/// Get playlist items with PlaylistItemId
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn playlist_get_items(
|
pub async fn playlist_get_items(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -70,6 +74,7 @@ pub async fn playlist_get_items(
|
|||||||
|
|
||||||
/// Add items to a playlist
|
/// Add items to a playlist
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn playlist_add_items(
|
pub async fn playlist_add_items(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -85,6 +90,7 @@ pub async fn playlist_add_items(
|
|||||||
|
|
||||||
/// Remove items from a playlist (uses PlaylistItemId entry IDs, NOT media item IDs)
|
/// Remove items from a playlist (uses PlaylistItemId entry IDs, NOT media item IDs)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn playlist_remove_items(
|
pub async fn playlist_remove_items(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -100,6 +106,7 @@ pub async fn playlist_remove_items(
|
|||||||
|
|
||||||
/// Move a playlist item to a new position
|
/// Move a playlist item to a new position
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn playlist_move_item(
|
pub async fn playlist_move_item(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
|
|||||||
@ -48,6 +48,7 @@ pub struct RepositoryManagerWrapper(pub RepositoryManager);
|
|||||||
/// Create a new repository instance
|
/// Create a new repository instance
|
||||||
/// Returns a handle (UUID) for accessing the repository
|
/// Returns a handle (UUID) for accessing the repository
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_create(
|
pub async fn repository_create(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
db: State<'_, crate::commands::storage::DatabaseWrapper>,
|
db: State<'_, crate::commands::storage::DatabaseWrapper>,
|
||||||
@ -108,6 +109,7 @@ pub async fn repository_create(
|
|||||||
|
|
||||||
/// Destroy a repository instance
|
/// Destroy a repository instance
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_destroy(
|
pub async fn repository_destroy(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -118,6 +120,7 @@ pub async fn repository_destroy(
|
|||||||
|
|
||||||
/// Get libraries
|
/// Get libraries
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_get_libraries(
|
pub async fn repository_get_libraries(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -138,6 +141,7 @@ pub async fn repository_get_libraries(
|
|||||||
|
|
||||||
/// Get items in a container (library, folder, album, etc.)
|
/// Get items in a container (library, folder, album, etc.)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_get_items(
|
pub async fn repository_get_items(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -152,6 +156,7 @@ pub async fn repository_get_items(
|
|||||||
|
|
||||||
/// Get a single item by ID
|
/// Get a single item by ID
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_get_item(
|
pub async fn repository_get_item(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -165,6 +170,7 @@ pub async fn repository_get_item(
|
|||||||
|
|
||||||
/// Get latest items in a library
|
/// Get latest items in a library
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_get_latest_items(
|
pub async fn repository_get_latest_items(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -179,6 +185,7 @@ pub async fn repository_get_latest_items(
|
|||||||
|
|
||||||
/// Get resume items (continue watching/listening)
|
/// Get resume items (continue watching/listening)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_get_resume_items(
|
pub async fn repository_get_resume_items(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -201,6 +208,7 @@ pub async fn repository_get_resume_items(
|
|||||||
|
|
||||||
/// Get next up episodes
|
/// Get next up episodes
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_get_next_up_episodes(
|
pub async fn repository_get_next_up_episodes(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -215,6 +223,7 @@ pub async fn repository_get_next_up_episodes(
|
|||||||
|
|
||||||
/// Get recently played audio
|
/// Get recently played audio
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_get_recently_played_audio(
|
pub async fn repository_get_recently_played_audio(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -228,6 +237,7 @@ pub async fn repository_get_recently_played_audio(
|
|||||||
|
|
||||||
/// Get resume movies
|
/// Get resume movies
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_get_resume_movies(
|
pub async fn repository_get_resume_movies(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -241,6 +251,7 @@ pub async fn repository_get_resume_movies(
|
|||||||
|
|
||||||
/// Get genres for a library
|
/// Get genres for a library
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_get_genres(
|
pub async fn repository_get_genres(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -254,6 +265,7 @@ pub async fn repository_get_genres(
|
|||||||
|
|
||||||
/// Search for items
|
/// Search for items
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_search(
|
pub async fn repository_search(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -268,6 +280,7 @@ pub async fn repository_search(
|
|||||||
|
|
||||||
/// Get playback info for an item
|
/// Get playback info for an item
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_get_playback_info(
|
pub async fn repository_get_playback_info(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -281,6 +294,7 @@ pub async fn repository_get_playback_info(
|
|||||||
|
|
||||||
/// Get video stream URL with optional seeking support
|
/// Get video stream URL with optional seeking support
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_get_video_stream_url(
|
pub async fn repository_get_video_stream_url(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -303,6 +317,7 @@ pub async fn repository_get_video_stream_url(
|
|||||||
|
|
||||||
/// Get audio stream URL for a track
|
/// Get audio stream URL for a track
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_get_audio_stream_url(
|
pub async fn repository_get_audio_stream_url(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -317,6 +332,7 @@ pub async fn repository_get_audio_stream_url(
|
|||||||
|
|
||||||
/// Report playback start
|
/// Report playback start
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_report_playback_start(
|
pub async fn repository_report_playback_start(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -331,6 +347,7 @@ pub async fn repository_report_playback_start(
|
|||||||
|
|
||||||
/// Report playback progress
|
/// Report playback progress
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_report_playback_progress(
|
pub async fn repository_report_playback_progress(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -345,6 +362,7 @@ pub async fn repository_report_playback_progress(
|
|||||||
|
|
||||||
/// Report playback stopped
|
/// Report playback stopped
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_report_playback_stopped(
|
pub async fn repository_report_playback_stopped(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -359,6 +377,7 @@ pub async fn repository_report_playback_stopped(
|
|||||||
|
|
||||||
/// Get image URL for an item
|
/// Get image URL for an item
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub fn repository_get_image_url(
|
pub fn repository_get_image_url(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -372,6 +391,7 @@ pub fn repository_get_image_url(
|
|||||||
|
|
||||||
/// Get subtitle URL for a media item
|
/// Get subtitle URL for a media item
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn repository_get_subtitle_url(
|
pub fn repository_get_subtitle_url(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
@ -387,6 +407,7 @@ pub fn repository_get_subtitle_url(
|
|||||||
|
|
||||||
/// Get video download URL with quality preset
|
/// Get video download URL with quality preset
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn repository_get_video_download_url(
|
pub fn repository_get_video_download_url(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
@ -401,6 +422,7 @@ pub fn repository_get_video_download_url(
|
|||||||
|
|
||||||
/// Mark an item as favorite
|
/// Mark an item as favorite
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_mark_favorite(
|
pub async fn repository_mark_favorite(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -414,6 +436,7 @@ pub async fn repository_mark_favorite(
|
|||||||
|
|
||||||
/// Unmark an item as favorite
|
/// Unmark an item as favorite
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_unmark_favorite(
|
pub async fn repository_unmark_favorite(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -427,6 +450,7 @@ pub async fn repository_unmark_favorite(
|
|||||||
|
|
||||||
/// Get person details
|
/// Get person details
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_get_person(
|
pub async fn repository_get_person(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -440,6 +464,7 @@ pub async fn repository_get_person(
|
|||||||
|
|
||||||
/// Get items by person (actor, director, etc.)
|
/// Get items by person (actor, director, etc.)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_get_items_by_person(
|
pub async fn repository_get_items_by_person(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -454,6 +479,7 @@ pub async fn repository_get_items_by_person(
|
|||||||
|
|
||||||
/// Get similar/related items for a media item
|
/// Get similar/related items for a media item
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn repository_get_similar_items(
|
pub async fn repository_get_similar_items(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
|
|||||||
@ -10,6 +10,7 @@ pub struct SessionPollerWrapper(pub Arc<SessionPollerManager>);
|
|||||||
|
|
||||||
/// Set polling frequency hint based on UI state
|
/// Set polling frequency hint based on UI state
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub fn sessions_set_polling_hint(
|
pub fn sessions_set_polling_hint(
|
||||||
poller: State<'_, SessionPollerWrapper>,
|
poller: State<'_, SessionPollerWrapper>,
|
||||||
hint: String,
|
hint: String,
|
||||||
@ -27,6 +28,7 @@ pub fn sessions_set_polling_hint(
|
|||||||
|
|
||||||
/// Manually trigger a session poll (for refresh button)
|
/// Manually trigger a session poll (for refresh button)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn sessions_poll_now(
|
pub async fn sessions_poll_now(
|
||||||
poller: State<'_, SessionPollerWrapper>,
|
poller: State<'_, SessionPollerWrapper>,
|
||||||
) -> Result<Vec<SessionInfo>, String> {
|
) -> Result<Vec<SessionInfo>, String> {
|
||||||
|
|||||||
@ -32,7 +32,7 @@ pub struct CredentialStoreWrapper(pub Mutex<CredentialStore>);
|
|||||||
pub struct ThumbnailCacheWrapper(pub Arc<ThumbnailCache>);
|
pub struct ThumbnailCacheWrapper(pub Arc<ThumbnailCache>);
|
||||||
|
|
||||||
/// Server info returned to frontend
|
/// Server info returned to frontend
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ServerInfo {
|
pub struct ServerInfo {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@ -41,7 +41,7 @@ pub struct ServerInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// User info returned to frontend
|
/// User info returned to frontend
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct UserInfo {
|
pub struct UserInfo {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
@ -51,7 +51,7 @@ pub struct UserInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Active session info (for session restoration)
|
/// Active session info (for session restoration)
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ActiveSession {
|
pub struct ActiveSession {
|
||||||
pub user_id: String,
|
pub user_id: String,
|
||||||
@ -63,7 +63,7 @@ pub struct ActiveSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Security status info
|
/// Security status info
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct SecurityStatus {
|
pub struct SecurityStatus {
|
||||||
pub using_keyring: bool,
|
pub using_keyring: bool,
|
||||||
@ -72,6 +72,7 @@ pub struct SecurityStatus {
|
|||||||
|
|
||||||
/// Initialize the database and run migrations
|
/// Initialize the database and run migrations
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub fn storage_init(db: State<DatabaseWrapper>) -> Result<String, String> {
|
pub fn storage_init(db: State<DatabaseWrapper>) -> Result<String, String> {
|
||||||
let database = db.0.lock().map_err(|e| e.to_string())?;
|
let database = db.0.lock().map_err(|e| e.to_string())?;
|
||||||
Ok(database.path().to_string_lossy().to_string())
|
Ok(database.path().to_string_lossy().to_string())
|
||||||
@ -79,6 +80,7 @@ pub fn storage_init(db: State<DatabaseWrapper>) -> Result<String, String> {
|
|||||||
|
|
||||||
/// Get storage directory path (parent directory of the database file)
|
/// Get storage directory path (parent directory of the database file)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub fn storage_get_path(db: State<DatabaseWrapper>) -> Result<String, String> {
|
pub fn storage_get_path(db: State<DatabaseWrapper>) -> Result<String, String> {
|
||||||
let database = db.0.lock().map_err(|e| e.to_string())?;
|
let database = db.0.lock().map_err(|e| e.to_string())?;
|
||||||
let db_path = database.path();
|
let db_path = database.path();
|
||||||
@ -92,6 +94,7 @@ pub fn storage_get_path(db: State<DatabaseWrapper>) -> Result<String, String> {
|
|||||||
|
|
||||||
/// Get database file size in bytes
|
/// Get database file size in bytes
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub fn storage_get_size(db: State<DatabaseWrapper>) -> Result<Option<u64>, String> {
|
pub fn storage_get_size(db: State<DatabaseWrapper>) -> Result<Option<u64>, String> {
|
||||||
let database = db.0.lock().map_err(|e| e.to_string())?;
|
let database = db.0.lock().map_err(|e| e.to_string())?;
|
||||||
Ok(database.file_size())
|
Ok(database.file_size())
|
||||||
@ -99,6 +102,7 @@ pub fn storage_get_size(db: State<DatabaseWrapper>) -> Result<Option<u64>, Strin
|
|||||||
|
|
||||||
/// Get security status (keyring vs encrypted file fallback)
|
/// Get security status (keyring vs encrypted file fallback)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub fn storage_get_security_status(
|
pub fn storage_get_security_status(
|
||||||
creds: State<CredentialStoreWrapper>,
|
creds: State<CredentialStoreWrapper>,
|
||||||
) -> Result<SecurityStatus, String> {
|
) -> Result<SecurityStatus, String> {
|
||||||
@ -117,6 +121,7 @@ pub fn storage_get_security_status(
|
|||||||
/// Save a server connection
|
/// Save a server connection
|
||||||
/// Uses INSERT ... ON CONFLICT to avoid triggering CASCADE DELETE on users
|
/// Uses INSERT ... ON CONFLICT to avoid triggering CASCADE DELETE on users
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_save_server(
|
pub async fn storage_save_server(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
id: String,
|
id: String,
|
||||||
@ -154,6 +159,7 @@ pub async fn storage_save_server(
|
|||||||
|
|
||||||
/// Get all saved servers
|
/// Get all saved servers
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_get_servers(db: State<'_, DatabaseWrapper>) -> Result<Vec<ServerInfo>, String> {
|
pub async fn storage_get_servers(db: State<'_, DatabaseWrapper>) -> Result<Vec<ServerInfo>, String> {
|
||||||
let db_service = {
|
let db_service = {
|
||||||
let database = db.0.lock().map_err(|e| e.to_string())?;
|
let database = db.0.lock().map_err(|e| e.to_string())?;
|
||||||
@ -179,6 +185,7 @@ pub async fn storage_get_servers(db: State<'_, DatabaseWrapper>) -> Result<Vec<S
|
|||||||
|
|
||||||
/// Delete a server and all associated data
|
/// Delete a server and all associated data
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_delete_server(
|
pub async fn storage_delete_server(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
creds: State<'_, CredentialStoreWrapper>,
|
creds: State<'_, CredentialStoreWrapper>,
|
||||||
@ -221,6 +228,7 @@ pub async fn storage_delete_server(
|
|||||||
|
|
||||||
/// Save a user account (token stored in secure storage, not database)
|
/// Save a user account (token stored in secure storage, not database)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_save_user(
|
pub async fn storage_save_user(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
creds: State<'_, CredentialStoreWrapper>,
|
creds: State<'_, CredentialStoreWrapper>,
|
||||||
@ -298,6 +306,7 @@ pub async fn storage_save_user(
|
|||||||
|
|
||||||
/// Get users for a server
|
/// Get users for a server
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_get_users(
|
pub async fn storage_get_users(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
server_id: String,
|
server_id: String,
|
||||||
@ -330,6 +339,7 @@ pub async fn storage_get_users(
|
|||||||
|
|
||||||
/// Set a user as active (and deactivate all other users globally)
|
/// Set a user as active (and deactivate all other users globally)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_set_active_user(
|
pub async fn storage_set_active_user(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
@ -378,6 +388,7 @@ pub async fn storage_set_active_user(
|
|||||||
|
|
||||||
/// Get the active user for a server
|
/// Get the active user for a server
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_get_active_user(
|
pub async fn storage_get_active_user(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
server_id: String,
|
server_id: String,
|
||||||
@ -408,6 +419,7 @@ pub async fn storage_get_active_user(
|
|||||||
|
|
||||||
/// Get the active session (user + server + token) for session restoration
|
/// Get the active session (user + server + token) for session restoration
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_get_active_session(
|
pub async fn storage_get_active_session(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
creds: State<'_, CredentialStoreWrapper>,
|
creds: State<'_, CredentialStoreWrapper>,
|
||||||
@ -483,6 +495,7 @@ pub async fn storage_get_active_session(
|
|||||||
|
|
||||||
/// Get user's access token from secure storage
|
/// Get user's access token from secure storage
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub fn storage_get_access_token(
|
pub fn storage_get_access_token(
|
||||||
creds: State<CredentialStoreWrapper>,
|
creds: State<CredentialStoreWrapper>,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
@ -497,6 +510,7 @@ pub fn storage_get_access_token(
|
|||||||
|
|
||||||
/// Delete a user account and their token from secure storage
|
/// Delete a user account and their token from secure storage
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_delete_user(
|
pub async fn storage_delete_user(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
creds: State<'_, CredentialStoreWrapper>,
|
creds: State<'_, CredentialStoreWrapper>,
|
||||||
@ -529,7 +543,7 @@ pub async fn storage_delete_user(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Playback progress info
|
/// Playback progress info
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct PlaybackProgress {
|
pub struct PlaybackProgress {
|
||||||
pub item_id: String,
|
pub item_id: String,
|
||||||
@ -542,6 +556,7 @@ pub struct PlaybackProgress {
|
|||||||
/// Update playback progress in local database
|
/// Update playback progress in local database
|
||||||
/// This stores the progress locally for offline access and "continue watching"
|
/// This stores the progress locally for offline access and "continue watching"
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_update_playback_progress(
|
pub async fn storage_update_playback_progress(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
@ -593,6 +608,7 @@ pub async fn storage_update_playback_progress(
|
|||||||
/// Update playback progress with context in local database
|
/// Update playback progress with context in local database
|
||||||
/// This stores the progress along with playback context (container vs single)
|
/// This stores the progress along with playback context (container vs single)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_update_playback_context(
|
pub async fn storage_update_playback_context(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
@ -642,6 +658,7 @@ pub async fn storage_update_playback_context(
|
|||||||
|
|
||||||
/// Mark item as played in local database
|
/// Mark item as played in local database
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_mark_played(
|
pub async fn storage_mark_played(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
smart_cache: State<'_, SmartCacheWrapper>,
|
smart_cache: State<'_, SmartCacheWrapper>,
|
||||||
@ -772,6 +789,7 @@ pub async fn storage_mark_played(
|
|||||||
|
|
||||||
/// Get playback progress for an item
|
/// Get playback progress for an item
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_get_playback_progress(
|
pub async fn storage_get_playback_progress(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
@ -804,6 +822,7 @@ pub async fn storage_get_playback_progress(
|
|||||||
|
|
||||||
/// Mark pending sync as completed for an item
|
/// Mark pending sync as completed for an item
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_mark_synced(
|
pub async fn storage_mark_synced(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
@ -828,6 +847,7 @@ pub async fn storage_mark_synced(
|
|||||||
/// Toggle favorite status for an item in local database
|
/// Toggle favorite status for an item in local database
|
||||||
/// This updates the is_favorite field and marks it for sync to Jellyfin
|
/// This updates the is_favorite field and marks it for sync to Jellyfin
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_toggle_favorite(
|
pub async fn storage_toggle_favorite(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
@ -873,7 +893,7 @@ pub async fn storage_toggle_favorite(
|
|||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
/// Cached library info returned to frontend
|
/// Cached library info returned to frontend
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct CachedLibrary {
|
pub struct CachedLibrary {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
@ -884,7 +904,7 @@ pub struct CachedLibrary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Cached media item returned to frontend
|
/// Cached media item returned to frontend
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct CachedItem {
|
pub struct CachedItem {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
@ -915,6 +935,7 @@ pub struct CachedItem {
|
|||||||
|
|
||||||
/// Get cached libraries for a server
|
/// Get cached libraries for a server
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_get_libraries(
|
pub async fn storage_get_libraries(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
server_id: String,
|
server_id: String,
|
||||||
@ -977,6 +998,7 @@ fn row_to_cached_item(row: &rusqlite::Row) -> rusqlite::Result<CachedItem> {
|
|||||||
|
|
||||||
/// Get cached items with optional filtering
|
/// Get cached items with optional filtering
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_get_items(
|
pub async fn storage_get_items(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
server_id: String,
|
server_id: String,
|
||||||
@ -1043,6 +1065,7 @@ pub async fn storage_get_items(
|
|||||||
|
|
||||||
/// Get a single cached item by ID
|
/// Get a single cached item by ID
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_get_item(
|
pub async fn storage_get_item(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
item_id: String,
|
item_id: String,
|
||||||
@ -1070,6 +1093,7 @@ pub async fn storage_get_item(
|
|||||||
|
|
||||||
/// Search cached items using FTS
|
/// Search cached items using FTS
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_search_items(
|
pub async fn storage_search_items(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
server_id: String,
|
server_id: String,
|
||||||
@ -1111,6 +1135,7 @@ pub async fn storage_search_items(
|
|||||||
|
|
||||||
/// Save a library to the cache
|
/// Save a library to the cache
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_save_library(
|
pub async fn storage_save_library(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
id: String,
|
id: String,
|
||||||
@ -1144,6 +1169,7 @@ pub async fn storage_save_library(
|
|||||||
|
|
||||||
/// Save an item to the cache
|
/// Save an item to the cache
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_save_item(
|
pub async fn storage_save_item(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
item: CachedItem,
|
item: CachedItem,
|
||||||
@ -1207,6 +1233,7 @@ pub async fn storage_save_item(
|
|||||||
|
|
||||||
/// Get count of pending sync operations for a user
|
/// Get count of pending sync operations for a user
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_get_pending_sync_count(
|
pub async fn storage_get_pending_sync_count(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
|
|||||||
@ -9,7 +9,7 @@ use crate::storage::db_service::{DatabaseService, Query, QueryParam};
|
|||||||
|
|
||||||
|
|
||||||
/// Cached person info returned to frontend
|
/// Cached person info returned to frontend
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct CachedPerson {
|
pub struct CachedPerson {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
@ -22,7 +22,7 @@ pub struct CachedPerson {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Item-person association for caching
|
/// Item-person association for caching
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct CachedItemPerson {
|
pub struct CachedItemPerson {
|
||||||
pub item_id: String,
|
pub item_id: String,
|
||||||
@ -35,6 +35,7 @@ pub struct CachedItemPerson {
|
|||||||
|
|
||||||
/// Save a person to the cache
|
/// Save a person to the cache
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_save_person(
|
pub async fn storage_save_person(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
person: CachedPerson,
|
person: CachedPerson,
|
||||||
@ -66,6 +67,7 @@ pub async fn storage_save_person(
|
|||||||
|
|
||||||
/// Get a cached person by ID
|
/// Get a cached person by ID
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_get_person(
|
pub async fn storage_get_person(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
person_id: String,
|
person_id: String,
|
||||||
@ -101,6 +103,7 @@ pub async fn storage_get_person(
|
|||||||
|
|
||||||
/// Save item-person associations (batch)
|
/// Save item-person associations (batch)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_save_item_people(
|
pub async fn storage_save_item_people(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
associations: Vec<CachedItemPerson>,
|
associations: Vec<CachedItemPerson>,
|
||||||
@ -139,6 +142,7 @@ pub async fn storage_save_item_people(
|
|||||||
|
|
||||||
/// Get people for an item (with person details joined)
|
/// Get people for an item (with person details joined)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_get_item_people(
|
pub async fn storage_get_item_people(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
item_id: String,
|
item_id: String,
|
||||||
|
|||||||
@ -9,7 +9,7 @@ use crate::storage::db_service::{DatabaseService, Query, QueryParam};
|
|||||||
|
|
||||||
|
|
||||||
/// Audio track preference for a series
|
/// Audio track preference for a series
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct SeriesAudioPreference {
|
pub struct SeriesAudioPreference {
|
||||||
pub series_id: String,
|
pub series_id: String,
|
||||||
@ -20,6 +20,7 @@ pub struct SeriesAudioPreference {
|
|||||||
|
|
||||||
/// Save user's preferred audio track for a series
|
/// Save user's preferred audio track for a series
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_save_series_audio_preference(
|
pub async fn storage_save_series_audio_preference(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
@ -59,6 +60,7 @@ pub async fn storage_save_series_audio_preference(
|
|||||||
|
|
||||||
/// Get user's preferred audio track for a series
|
/// Get user's preferred audio track for a series
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn storage_get_series_audio_preference(
|
pub async fn storage_get_series_audio_preference(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
|
|||||||
@ -15,6 +15,7 @@ use crate::thumbnail::{ThumbnailCacheStats, ThumbnailWorker};
|
|||||||
/// Get cached thumbnail path, returns None if not cached
|
/// Get cached thumbnail path, returns None if not cached
|
||||||
/// Also updates last_accessed timestamp for LRU tracking
|
/// Also updates last_accessed timestamp for LRU tracking
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn thumbnail_get_cached(
|
pub async fn thumbnail_get_cached(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
thumbnail_cache: State<'_, ThumbnailCacheWrapper>,
|
thumbnail_cache: State<'_, ThumbnailCacheWrapper>,
|
||||||
@ -38,6 +39,7 @@ pub async fn thumbnail_get_cached(
|
|||||||
/// Download and save a thumbnail to cache
|
/// Download and save a thumbnail to cache
|
||||||
/// Returns the local file path on success
|
/// Returns the local file path on success
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn thumbnail_save(
|
pub async fn thumbnail_save(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
thumbnail_cache: State<'_, ThumbnailCacheWrapper>,
|
thumbnail_cache: State<'_, ThumbnailCacheWrapper>,
|
||||||
@ -65,6 +67,7 @@ pub async fn thumbnail_save(
|
|||||||
|
|
||||||
/// Get thumbnail cache statistics
|
/// Get thumbnail cache statistics
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn thumbnail_get_stats(
|
pub async fn thumbnail_get_stats(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
thumbnail_cache: State<'_, ThumbnailCacheWrapper>,
|
thumbnail_cache: State<'_, ThumbnailCacheWrapper>,
|
||||||
@ -87,6 +90,7 @@ pub async fn thumbnail_get_stats(
|
|||||||
|
|
||||||
/// Set thumbnail cache storage limit in bytes
|
/// Set thumbnail cache storage limit in bytes
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn thumbnail_set_limit(
|
pub async fn thumbnail_set_limit(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
thumbnail_cache: State<'_, ThumbnailCacheWrapper>,
|
thumbnail_cache: State<'_, ThumbnailCacheWrapper>,
|
||||||
@ -102,6 +106,7 @@ pub async fn thumbnail_set_limit(
|
|||||||
|
|
||||||
/// Clear all cached thumbnails
|
/// Clear all cached thumbnails
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn thumbnail_clear_cache(
|
pub async fn thumbnail_clear_cache(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
thumbnail_cache: State<'_, ThumbnailCacheWrapper>,
|
thumbnail_cache: State<'_, ThumbnailCacheWrapper>,
|
||||||
@ -116,6 +121,7 @@ pub async fn thumbnail_clear_cache(
|
|||||||
|
|
||||||
/// Delete cached thumbnails for a specific item
|
/// Delete cached thumbnails for a specific item
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn thumbnail_delete_item(
|
pub async fn thumbnail_delete_item(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
thumbnail_cache: State<'_, ThumbnailCacheWrapper>,
|
thumbnail_cache: State<'_, ThumbnailCacheWrapper>,
|
||||||
@ -149,7 +155,7 @@ fn image_semaphore() -> &'static Semaphore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Request to get an image URL (with caching)
|
/// Request to get an image URL (with caching)
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(specta::Type, Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct GetImageRequest {
|
pub struct GetImageRequest {
|
||||||
pub item_id: String,
|
pub item_id: String,
|
||||||
@ -165,6 +171,7 @@ pub struct GetImageRequest {
|
|||||||
/// Get image as base64 data URL, caching if not already cached
|
/// Get image as base64 data URL, caching if not already cached
|
||||||
/// This extends the thumbnail system to serve all images through Rust with automatic caching
|
/// This extends the thumbnail system to serve all images through Rust with automatic caching
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn image_get_url(
|
pub async fn image_get_url(
|
||||||
repository_manager: State<'_, RepositoryManagerWrapper>,
|
repository_manager: State<'_, RepositoryManagerWrapper>,
|
||||||
thumbnail_cache: State<'_, ThumbnailCacheWrapper>,
|
thumbnail_cache: State<'_, ThumbnailCacheWrapper>,
|
||||||
|
|||||||
@ -12,7 +12,7 @@ use super::storage::DatabaseWrapper;
|
|||||||
use crate::storage::db_service::{DatabaseService, Query, QueryParam};
|
use crate::storage::db_service::{DatabaseService, Query, QueryParam};
|
||||||
|
|
||||||
/// Sync queue item returned to frontend
|
/// Sync queue item returned to frontend
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct SyncQueueItem {
|
pub struct SyncQueueItem {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
@ -28,6 +28,7 @@ pub struct SyncQueueItem {
|
|||||||
|
|
||||||
/// Queue a mutation for sync to server
|
/// Queue a mutation for sync to server
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn sync_queue_mutation(
|
pub async fn sync_queue_mutation(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
@ -59,6 +60,7 @@ pub async fn sync_queue_mutation(
|
|||||||
|
|
||||||
/// Get all pending sync operations for a user
|
/// Get all pending sync operations for a user
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn sync_get_pending(
|
pub async fn sync_get_pending(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
@ -107,6 +109,7 @@ pub async fn sync_get_pending(
|
|||||||
|
|
||||||
/// Mark a sync operation as in progress
|
/// Mark a sync operation as in progress
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn sync_mark_processing(
|
pub async fn sync_mark_processing(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
id: i64,
|
id: i64,
|
||||||
@ -127,6 +130,7 @@ pub async fn sync_mark_processing(
|
|||||||
|
|
||||||
/// Mark a sync operation as completed
|
/// Mark a sync operation as completed
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn sync_mark_completed(
|
pub async fn sync_mark_completed(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
id: i64,
|
id: i64,
|
||||||
@ -147,6 +151,7 @@ pub async fn sync_mark_completed(
|
|||||||
|
|
||||||
/// Mark a sync operation as failed with error message
|
/// Mark a sync operation as failed with error message
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn sync_mark_failed(
|
pub async fn sync_mark_failed(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
id: i64,
|
id: i64,
|
||||||
@ -173,6 +178,7 @@ pub async fn sync_mark_failed(
|
|||||||
|
|
||||||
/// Get count of pending sync operations for a user
|
/// Get count of pending sync operations for a user
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn sync_get_pending_count(
|
pub async fn sync_get_pending_count(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
@ -195,6 +201,7 @@ pub async fn sync_get_pending_count(
|
|||||||
|
|
||||||
/// Delete completed sync operations older than specified days
|
/// Delete completed sync operations older than specified days
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn sync_cleanup_completed(
|
pub async fn sync_cleanup_completed(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
days_old: i32,
|
days_old: i32,
|
||||||
@ -217,6 +224,7 @@ pub async fn sync_cleanup_completed(
|
|||||||
|
|
||||||
/// Delete all sync operations for a user (used during logout)
|
/// Delete all sync operations for a user (used during logout)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
pub async fn sync_clear_user(
|
pub async fn sync_clear_user(
|
||||||
db: State<'_, DatabaseWrapper>,
|
db: State<'_, DatabaseWrapper>,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
|
|||||||
@ -12,7 +12,7 @@ const AUTO_CHECK_INTERVAL_MS: u64 = 30000; // 30 seconds when online
|
|||||||
const RETRY_CHECK_INTERVAL_MS: u64 = 5000; // 5 seconds when offline
|
const RETRY_CHECK_INTERVAL_MS: u64 = 5000; // 5 seconds when offline
|
||||||
|
|
||||||
/// Connectivity status
|
/// Connectivity status
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ConnectivityStatus {
|
pub struct ConnectivityStatus {
|
||||||
/// Whether the Jellyfin server is reachable
|
/// Whether the Jellyfin server is reachable
|
||||||
@ -39,7 +39,7 @@ impl Default for ConnectivityStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Connectivity change event emitted to frontend
|
/// Connectivity change event emitted to frontend
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
struct ConnectivityChangeEvent {
|
struct ConnectivityChangeEvent {
|
||||||
is_reachable: bool,
|
is_reachable: bool,
|
||||||
|
|||||||
@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::storage::db_service::{DatabaseService, Query, QueryParam};
|
use crate::storage::db_service::{DatabaseService, Query, QueryParam};
|
||||||
|
|
||||||
/// Smart caching configuration
|
/// Smart caching configuration
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct CacheConfig {
|
pub struct CacheConfig {
|
||||||
/// Enable queue pre-caching
|
/// Enable queue pre-caching
|
||||||
|
|||||||
@ -77,7 +77,7 @@ impl DownloadManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Information about a download
|
/// Information about a download
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(specta::Type, Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct DownloadInfo {
|
pub struct DownloadInfo {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
|
|||||||
@ -381,8 +381,8 @@ fn default_true() -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Session information from Jellyfin
|
/// Session information from Jellyfin
|
||||||
#[derive(Debug, Clone, Deserialize, serde::Serialize)]
|
#[derive(specta::Type, Debug, Clone, Deserialize, serde::Serialize)]
|
||||||
#[serde(rename_all(deserialize = "PascalCase", serialize = "camelCase"))]
|
#[serde(rename_all = "PascalCase")]
|
||||||
pub struct SessionInfo {
|
pub struct SessionInfo {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub id: Option<String>,
|
pub id: Option<String>,
|
||||||
@ -414,8 +414,8 @@ pub struct SessionInfo {
|
|||||||
pub supported_commands: Option<Vec<String>>,
|
pub supported_commands: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, serde::Serialize)]
|
#[derive(specta::Type, Debug, Clone, Deserialize, serde::Serialize)]
|
||||||
#[serde(rename_all(deserialize = "PascalCase", serialize = "camelCase"))]
|
#[serde(rename_all = "PascalCase")]
|
||||||
pub struct NowPlayingItem {
|
pub struct NowPlayingItem {
|
||||||
pub id: Option<String>,
|
pub id: Option<String>,
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
@ -431,8 +431,8 @@ pub struct NowPlayingItem {
|
|||||||
pub item_type: Option<String>,
|
pub item_type: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, serde::Serialize)]
|
#[derive(specta::Type, Debug, Clone, Deserialize, serde::Serialize)]
|
||||||
#[serde(rename_all(deserialize = "PascalCase", serialize = "camelCase"))]
|
#[serde(rename_all = "PascalCase")]
|
||||||
pub struct PlayState {
|
pub struct PlayState {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub position_ticks: Option<i64>,
|
pub position_ticks: Option<i64>,
|
||||||
|
|||||||
@ -17,6 +17,7 @@ pub mod utils;
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use tokio::sync::Mutex as TokioMutex;
|
use tokio::sync::Mutex as TokioMutex;
|
||||||
use tauri::{Emitter, Manager};
|
use tauri::{Emitter, Manager};
|
||||||
|
use tauri_specta::Builder;
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
use log::warn;
|
use log::warn;
|
||||||
@ -353,6 +354,240 @@ pub fn run() {
|
|||||||
.filter_level(log::LevelFilter::Info)
|
.filter_level(log::LevelFilter::Info)
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
|
let builder = Builder::<tauri::Wry>::new()
|
||||||
|
.commands(tauri_specta::collect_commands![
|
||||||
|
// Player commands
|
||||||
|
player_play_item,
|
||||||
|
player_play_queue,
|
||||||
|
player_play_album_track,
|
||||||
|
player_play_tracks,
|
||||||
|
player_play,
|
||||||
|
player_pause,
|
||||||
|
player_toggle,
|
||||||
|
player_stop,
|
||||||
|
player_next,
|
||||||
|
player_previous,
|
||||||
|
player_seek,
|
||||||
|
player_seek_video,
|
||||||
|
player_set_volume,
|
||||||
|
player_toggle_mute,
|
||||||
|
player_set_audio_track,
|
||||||
|
player_switch_audio_track,
|
||||||
|
player_set_subtitle_track,
|
||||||
|
player_toggle_shuffle,
|
||||||
|
player_cycle_repeat,
|
||||||
|
player_get_status,
|
||||||
|
player_get_queue,
|
||||||
|
player_add_to_queue,
|
||||||
|
player_add_track_by_id,
|
||||||
|
player_add_tracks_by_ids,
|
||||||
|
player_remove_from_queue,
|
||||||
|
player_move_in_queue,
|
||||||
|
player_skip_to,
|
||||||
|
player_set_audio_settings,
|
||||||
|
player_get_audio_settings,
|
||||||
|
player_set_video_settings,
|
||||||
|
player_get_video_settings,
|
||||||
|
// Sleep timer and autoplay commands
|
||||||
|
player_set_sleep_timer,
|
||||||
|
player_cancel_sleep_timer,
|
||||||
|
player_get_sleep_timer,
|
||||||
|
player_get_autoplay_settings,
|
||||||
|
player_set_autoplay_settings,
|
||||||
|
player_cancel_autoplay_countdown,
|
||||||
|
player_play_next_episode,
|
||||||
|
player_on_playback_ended,
|
||||||
|
// Preload commands
|
||||||
|
player_preload_upcoming,
|
||||||
|
player_set_cache_config,
|
||||||
|
player_get_cache_config,
|
||||||
|
// Jellyfin reporting commands
|
||||||
|
player_configure_jellyfin,
|
||||||
|
player_disable_jellyfin,
|
||||||
|
// Session management commands
|
||||||
|
player_get_session,
|
||||||
|
player_dismiss_session,
|
||||||
|
// Remote session control commands
|
||||||
|
remote_play_on_session,
|
||||||
|
remote_send_command,
|
||||||
|
remote_session_seek,
|
||||||
|
remote_session_set_volume,
|
||||||
|
remote_session_toggle_mute,
|
||||||
|
// Session polling commands
|
||||||
|
sessions_set_polling_hint,
|
||||||
|
sessions_poll_now,
|
||||||
|
// Playback mode commands
|
||||||
|
playback_mode_get_current,
|
||||||
|
playback_mode_set,
|
||||||
|
playback_mode_is_transferring,
|
||||||
|
playback_mode_transfer_to_remote,
|
||||||
|
playback_mode_get_remote_status,
|
||||||
|
playback_mode_transfer_to_local,
|
||||||
|
// Playback reporting commands
|
||||||
|
playback_reporter_init,
|
||||||
|
playback_reporter_destroy,
|
||||||
|
playback_report_start,
|
||||||
|
playback_report_progress,
|
||||||
|
playback_report_stopped,
|
||||||
|
playback_mark_played,
|
||||||
|
// Auth commands
|
||||||
|
auth_initialize,
|
||||||
|
auth_connect_to_server,
|
||||||
|
auth_login,
|
||||||
|
auth_verify_session,
|
||||||
|
auth_logout,
|
||||||
|
auth_get_session,
|
||||||
|
auth_set_session,
|
||||||
|
auth_start_verification,
|
||||||
|
auth_stop_verification,
|
||||||
|
auth_reauthenticate,
|
||||||
|
// Device commands
|
||||||
|
device_get_id,
|
||||||
|
device_set_id,
|
||||||
|
// Connectivity commands
|
||||||
|
connectivity_check_server,
|
||||||
|
connectivity_set_server_url,
|
||||||
|
connectivity_get_status,
|
||||||
|
connectivity_start_monitoring,
|
||||||
|
connectivity_stop_monitoring,
|
||||||
|
connectivity_mark_reachable,
|
||||||
|
connectivity_mark_unreachable,
|
||||||
|
// Storage commands
|
||||||
|
storage_init,
|
||||||
|
storage_get_path,
|
||||||
|
storage_get_size,
|
||||||
|
storage_get_security_status,
|
||||||
|
storage_save_server,
|
||||||
|
storage_get_servers,
|
||||||
|
storage_delete_server,
|
||||||
|
storage_save_user,
|
||||||
|
storage_get_users,
|
||||||
|
storage_set_active_user,
|
||||||
|
storage_get_active_user,
|
||||||
|
storage_get_active_session,
|
||||||
|
storage_get_access_token,
|
||||||
|
storage_delete_user,
|
||||||
|
// Playback progress commands
|
||||||
|
storage_update_playback_progress,
|
||||||
|
storage_update_playback_context,
|
||||||
|
storage_mark_played,
|
||||||
|
storage_get_playback_progress,
|
||||||
|
storage_mark_synced,
|
||||||
|
storage_toggle_favorite,
|
||||||
|
// Download commands
|
||||||
|
download_item,
|
||||||
|
download_item_and_start,
|
||||||
|
download_album,
|
||||||
|
download_video,
|
||||||
|
download_series,
|
||||||
|
download_season,
|
||||||
|
get_downloads,
|
||||||
|
pause_download,
|
||||||
|
resume_download,
|
||||||
|
cancel_download,
|
||||||
|
delete_download,
|
||||||
|
delete_all_downloads,
|
||||||
|
delete_album_downloads,
|
||||||
|
clear_stale_downloads,
|
||||||
|
get_download_storage_stats,
|
||||||
|
mark_download_completed,
|
||||||
|
mark_download_failed,
|
||||||
|
start_download,
|
||||||
|
get_download_manager_stats,
|
||||||
|
set_max_concurrent_downloads,
|
||||||
|
get_smart_cache_stats,
|
||||||
|
update_smart_cache_config,
|
||||||
|
get_smart_cache_config,
|
||||||
|
get_album_recommendations,
|
||||||
|
get_album_affinity_status,
|
||||||
|
// Pinning commands
|
||||||
|
pin_item,
|
||||||
|
unpin_item,
|
||||||
|
is_item_pinned,
|
||||||
|
// Offline commands
|
||||||
|
offline_is_available,
|
||||||
|
offline_get_items,
|
||||||
|
offline_search,
|
||||||
|
// Offline cache commands
|
||||||
|
storage_get_libraries,
|
||||||
|
storage_get_items,
|
||||||
|
storage_get_item,
|
||||||
|
storage_search_items,
|
||||||
|
storage_save_library,
|
||||||
|
storage_save_item,
|
||||||
|
storage_get_pending_sync_count,
|
||||||
|
// Sync queue commands
|
||||||
|
sync_queue_mutation,
|
||||||
|
sync_get_pending,
|
||||||
|
sync_mark_processing,
|
||||||
|
sync_mark_completed,
|
||||||
|
sync_mark_failed,
|
||||||
|
sync_get_pending_count,
|
||||||
|
sync_cleanup_completed,
|
||||||
|
sync_clear_user,
|
||||||
|
// Thumbnail cache and image commands
|
||||||
|
thumbnail_get_cached,
|
||||||
|
thumbnail_save,
|
||||||
|
thumbnail_get_stats,
|
||||||
|
thumbnail_set_limit,
|
||||||
|
thumbnail_clear_cache,
|
||||||
|
thumbnail_delete_item,
|
||||||
|
image_get_url,
|
||||||
|
// People cache commands
|
||||||
|
storage_save_person,
|
||||||
|
storage_get_person,
|
||||||
|
storage_save_item_people,
|
||||||
|
storage_get_item_people,
|
||||||
|
// Series audio preferences
|
||||||
|
storage_save_series_audio_preference,
|
||||||
|
storage_get_series_audio_preference,
|
||||||
|
// Repository commands
|
||||||
|
repository_create,
|
||||||
|
repository_destroy,
|
||||||
|
repository_get_libraries,
|
||||||
|
repository_get_items,
|
||||||
|
repository_get_item,
|
||||||
|
repository_get_latest_items,
|
||||||
|
repository_get_resume_items,
|
||||||
|
repository_get_next_up_episodes,
|
||||||
|
repository_get_recently_played_audio,
|
||||||
|
repository_get_resume_movies,
|
||||||
|
repository_get_genres,
|
||||||
|
repository_search,
|
||||||
|
repository_get_playback_info,
|
||||||
|
repository_get_video_stream_url,
|
||||||
|
repository_get_audio_stream_url,
|
||||||
|
repository_report_playback_start,
|
||||||
|
repository_report_playback_progress,
|
||||||
|
repository_report_playback_stopped,
|
||||||
|
repository_get_image_url,
|
||||||
|
repository_mark_favorite,
|
||||||
|
repository_unmark_favorite,
|
||||||
|
repository_get_person,
|
||||||
|
repository_get_items_by_person,
|
||||||
|
repository_get_similar_items,
|
||||||
|
// Playlist commands
|
||||||
|
playlist_create,
|
||||||
|
playlist_delete,
|
||||||
|
playlist_rename,
|
||||||
|
playlist_get_items,
|
||||||
|
playlist_add_items,
|
||||||
|
playlist_remove_items,
|
||||||
|
playlist_move_item,
|
||||||
|
// Conversion commands
|
||||||
|
format_time_seconds,
|
||||||
|
format_time_seconds_long,
|
||||||
|
convert_ticks_to_seconds,
|
||||||
|
calc_progress,
|
||||||
|
convert_percent_to_volume,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Export TypeScript bindings (types + typed invoke wrappers) in dev builds.
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
builder
|
||||||
|
.export(specta_typescript::Typescript::default(), "../src/lib/api/bindings.ts")
|
||||||
|
.expect("Failed to export typescript bindings");
|
||||||
|
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.plugin(tauri_plugin_opener::init())
|
.plugin(tauri_plugin_opener::init())
|
||||||
.plugin(tauri_plugin_os::init())
|
.plugin(tauri_plugin_os::init())
|
||||||
@ -596,232 +831,7 @@ pub fn run() {
|
|||||||
info!("[INIT] Application setup completed successfully");
|
info!("[INIT] Application setup completed successfully");
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(builder.invoke_handler())
|
||||||
// Player commands
|
|
||||||
player_play_item,
|
|
||||||
player_play_queue,
|
|
||||||
player_play_album_track,
|
|
||||||
player_play_tracks,
|
|
||||||
player_play,
|
|
||||||
player_pause,
|
|
||||||
player_toggle,
|
|
||||||
player_stop,
|
|
||||||
player_next,
|
|
||||||
player_previous,
|
|
||||||
player_seek,
|
|
||||||
player_seek_video,
|
|
||||||
player_set_volume,
|
|
||||||
player_toggle_mute,
|
|
||||||
player_set_audio_track,
|
|
||||||
player_switch_audio_track,
|
|
||||||
player_set_subtitle_track,
|
|
||||||
player_toggle_shuffle,
|
|
||||||
player_cycle_repeat,
|
|
||||||
player_get_status,
|
|
||||||
player_get_queue,
|
|
||||||
player_add_to_queue,
|
|
||||||
player_add_track_by_id,
|
|
||||||
player_add_tracks_by_ids,
|
|
||||||
player_remove_from_queue,
|
|
||||||
player_move_in_queue,
|
|
||||||
player_skip_to,
|
|
||||||
player_set_audio_settings,
|
|
||||||
player_get_audio_settings,
|
|
||||||
player_set_video_settings,
|
|
||||||
player_get_video_settings,
|
|
||||||
// Sleep timer and autoplay commands
|
|
||||||
player_set_sleep_timer,
|
|
||||||
player_cancel_sleep_timer,
|
|
||||||
player_get_sleep_timer,
|
|
||||||
player_get_autoplay_settings,
|
|
||||||
player_set_autoplay_settings,
|
|
||||||
player_cancel_autoplay_countdown,
|
|
||||||
player_play_next_episode,
|
|
||||||
player_on_playback_ended,
|
|
||||||
// Preload commands
|
|
||||||
player_preload_upcoming,
|
|
||||||
player_set_cache_config,
|
|
||||||
player_get_cache_config,
|
|
||||||
// Jellyfin reporting commands
|
|
||||||
player_configure_jellyfin,
|
|
||||||
player_disable_jellyfin,
|
|
||||||
// Session management commands
|
|
||||||
player_get_session,
|
|
||||||
player_dismiss_session,
|
|
||||||
// Remote session control commands
|
|
||||||
remote_play_on_session,
|
|
||||||
remote_send_command,
|
|
||||||
remote_session_seek,
|
|
||||||
remote_session_set_volume,
|
|
||||||
remote_session_toggle_mute,
|
|
||||||
// Session polling commands
|
|
||||||
sessions_set_polling_hint,
|
|
||||||
sessions_poll_now,
|
|
||||||
// Playback mode commands
|
|
||||||
playback_mode_get_current,
|
|
||||||
playback_mode_set,
|
|
||||||
playback_mode_is_transferring,
|
|
||||||
playback_mode_transfer_to_remote,
|
|
||||||
playback_mode_get_remote_status,
|
|
||||||
playback_mode_transfer_to_local,
|
|
||||||
// Playback reporting commands
|
|
||||||
playback_reporter_init,
|
|
||||||
playback_reporter_destroy,
|
|
||||||
playback_report_start,
|
|
||||||
playback_report_progress,
|
|
||||||
playback_report_stopped,
|
|
||||||
playback_mark_played,
|
|
||||||
// Auth commands
|
|
||||||
auth_initialize,
|
|
||||||
auth_connect_to_server,
|
|
||||||
auth_login,
|
|
||||||
auth_verify_session,
|
|
||||||
auth_logout,
|
|
||||||
auth_get_session,
|
|
||||||
auth_set_session,
|
|
||||||
auth_start_verification,
|
|
||||||
auth_stop_verification,
|
|
||||||
auth_reauthenticate,
|
|
||||||
// Device commands
|
|
||||||
device_get_id,
|
|
||||||
device_set_id,
|
|
||||||
// Connectivity commands
|
|
||||||
connectivity_check_server,
|
|
||||||
connectivity_set_server_url,
|
|
||||||
connectivity_get_status,
|
|
||||||
connectivity_start_monitoring,
|
|
||||||
connectivity_stop_monitoring,
|
|
||||||
connectivity_mark_reachable,
|
|
||||||
connectivity_mark_unreachable,
|
|
||||||
// Storage commands
|
|
||||||
storage_init,
|
|
||||||
storage_get_path,
|
|
||||||
storage_get_size,
|
|
||||||
storage_get_security_status,
|
|
||||||
storage_save_server,
|
|
||||||
storage_get_servers,
|
|
||||||
storage_delete_server,
|
|
||||||
storage_save_user,
|
|
||||||
storage_get_users,
|
|
||||||
storage_set_active_user,
|
|
||||||
storage_get_active_user,
|
|
||||||
storage_get_active_session,
|
|
||||||
storage_get_access_token,
|
|
||||||
storage_delete_user,
|
|
||||||
// Playback progress commands
|
|
||||||
storage_update_playback_progress,
|
|
||||||
storage_update_playback_context,
|
|
||||||
storage_mark_played,
|
|
||||||
storage_get_playback_progress,
|
|
||||||
storage_mark_synced,
|
|
||||||
storage_toggle_favorite,
|
|
||||||
// Download commands
|
|
||||||
download_item,
|
|
||||||
download_item_and_start,
|
|
||||||
download_album,
|
|
||||||
download_video,
|
|
||||||
download_series,
|
|
||||||
download_season,
|
|
||||||
get_downloads,
|
|
||||||
pause_download,
|
|
||||||
resume_download,
|
|
||||||
cancel_download,
|
|
||||||
delete_download,
|
|
||||||
delete_all_downloads,
|
|
||||||
delete_album_downloads,
|
|
||||||
clear_stale_downloads,
|
|
||||||
get_download_storage_stats,
|
|
||||||
mark_download_completed,
|
|
||||||
mark_download_failed,
|
|
||||||
start_download,
|
|
||||||
get_download_manager_stats,
|
|
||||||
set_max_concurrent_downloads,
|
|
||||||
get_smart_cache_stats,
|
|
||||||
update_smart_cache_config,
|
|
||||||
get_smart_cache_config,
|
|
||||||
get_album_recommendations,
|
|
||||||
get_album_affinity_status,
|
|
||||||
// Pinning commands
|
|
||||||
pin_item,
|
|
||||||
unpin_item,
|
|
||||||
is_item_pinned,
|
|
||||||
// Offline commands
|
|
||||||
offline_is_available,
|
|
||||||
offline_get_items,
|
|
||||||
offline_search,
|
|
||||||
// Offline cache commands
|
|
||||||
storage_get_libraries,
|
|
||||||
storage_get_items,
|
|
||||||
storage_get_item,
|
|
||||||
storage_search_items,
|
|
||||||
storage_save_library,
|
|
||||||
storage_save_item,
|
|
||||||
storage_get_pending_sync_count,
|
|
||||||
// Sync queue commands
|
|
||||||
sync_queue_mutation,
|
|
||||||
sync_get_pending,
|
|
||||||
sync_mark_processing,
|
|
||||||
sync_mark_completed,
|
|
||||||
sync_mark_failed,
|
|
||||||
sync_get_pending_count,
|
|
||||||
sync_cleanup_completed,
|
|
||||||
sync_clear_user,
|
|
||||||
// Thumbnail cache and image commands
|
|
||||||
thumbnail_get_cached,
|
|
||||||
thumbnail_save,
|
|
||||||
thumbnail_get_stats,
|
|
||||||
thumbnail_set_limit,
|
|
||||||
thumbnail_clear_cache,
|
|
||||||
thumbnail_delete_item,
|
|
||||||
image_get_url,
|
|
||||||
// People cache commands
|
|
||||||
storage_save_person,
|
|
||||||
storage_get_person,
|
|
||||||
storage_save_item_people,
|
|
||||||
storage_get_item_people,
|
|
||||||
// Series audio preferences
|
|
||||||
storage_save_series_audio_preference,
|
|
||||||
storage_get_series_audio_preference,
|
|
||||||
// Repository commands
|
|
||||||
repository_create,
|
|
||||||
repository_destroy,
|
|
||||||
repository_get_libraries,
|
|
||||||
repository_get_items,
|
|
||||||
repository_get_item,
|
|
||||||
repository_get_latest_items,
|
|
||||||
repository_get_resume_items,
|
|
||||||
repository_get_next_up_episodes,
|
|
||||||
repository_get_recently_played_audio,
|
|
||||||
repository_get_resume_movies,
|
|
||||||
repository_get_genres,
|
|
||||||
repository_search,
|
|
||||||
repository_get_playback_info,
|
|
||||||
repository_get_video_stream_url,
|
|
||||||
repository_get_audio_stream_url,
|
|
||||||
repository_report_playback_start,
|
|
||||||
repository_report_playback_progress,
|
|
||||||
repository_report_playback_stopped,
|
|
||||||
repository_get_image_url,
|
|
||||||
repository_mark_favorite,
|
|
||||||
repository_unmark_favorite,
|
|
||||||
repository_get_person,
|
|
||||||
repository_get_items_by_person,
|
|
||||||
repository_get_similar_items,
|
|
||||||
// Playlist commands
|
|
||||||
playlist_create,
|
|
||||||
playlist_delete,
|
|
||||||
playlist_rename,
|
|
||||||
playlist_get_items,
|
|
||||||
playlist_add_items,
|
|
||||||
playlist_remove_items,
|
|
||||||
playlist_move_item,
|
|
||||||
// Conversion commands
|
|
||||||
format_time_seconds,
|
|
||||||
format_time_seconds_long,
|
|
||||||
convert_ticks_to_seconds,
|
|
||||||
calc_progress,
|
|
||||||
convert_percent_to_volume,
|
|
||||||
])
|
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
.expect("error while running tauri application");
|
.expect("error while running tauri application");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ use crate::jellyfin::JellyfinClient;
|
|||||||
use crate::player::{PlayerController, QueueContext};
|
use crate::player::{PlayerController, QueueContext};
|
||||||
|
|
||||||
/// Playback mode - local device, remote session, or idle
|
/// Playback mode - local device, remote session, or idle
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
#[serde(tag = "type", rename_all = "lowercase")]
|
#[serde(tag = "type", rename_all = "lowercase")]
|
||||||
pub enum PlaybackMode {
|
pub enum PlaybackMode {
|
||||||
Local,
|
Local,
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::repository::types::MediaItem;
|
use crate::repository::types::MediaItem;
|
||||||
|
|
||||||
/// Autoplay decision result - determines what happens after playback ends
|
/// Autoplay decision result - determines what happens after playback ends
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize)]
|
||||||
#[serde(tag = "action", rename_all = "camelCase")]
|
#[serde(tag = "action", rename_all = "camelCase")]
|
||||||
pub enum AutoplayDecision {
|
pub enum AutoplayDecision {
|
||||||
/// Stop playback (no next item or timer expired)
|
/// Stop playback (no next item or timer expired)
|
||||||
@ -21,7 +21,7 @@ pub enum AutoplayDecision {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Autoplay settings (controls next episode behavior)
|
/// Autoplay settings (controls next episode behavior)
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct AutoplaySettings {
|
pub struct AutoplaySettings {
|
||||||
/// Whether autoplay is enabled for next episodes
|
/// Whether autoplay is enabled for next episodes
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use std::path::PathBuf;
|
|||||||
|
|
||||||
/// Context for the current queue - where did the queue items come from?
|
/// Context for the current queue - where did the queue items come from?
|
||||||
/// This is used for remote playback transfer to send album/playlist context.
|
/// This is used for remote playback transfer to send album/playlist context.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||||
#[serde(tag = "type", rename_all = "lowercase")]
|
#[serde(tag = "type", rename_all = "lowercase")]
|
||||||
pub enum QueueContext {
|
pub enum QueueContext {
|
||||||
/// Playing from a specific album
|
/// Playing from a specific album
|
||||||
@ -23,7 +23,7 @@ pub enum QueueContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a subtitle track
|
/// Represents a subtitle track
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct SubtitleTrack {
|
pub struct SubtitleTrack {
|
||||||
/// Stream index in the media source
|
/// Stream index in the media source
|
||||||
pub index: i32,
|
pub index: i32,
|
||||||
@ -40,7 +40,7 @@ pub struct SubtitleTrack {
|
|||||||
/// Represents a media item that can be played
|
/// Represents a media item that can be played
|
||||||
///
|
///
|
||||||
/// TRACES: UR-003, UR-004 | DR-002
|
/// TRACES: UR-003, UR-004 | DR-002
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct MediaItem {
|
pub struct MediaItem {
|
||||||
/// Unique identifier
|
/// Unique identifier
|
||||||
@ -106,7 +106,7 @@ pub struct MediaItem {
|
|||||||
pub server_id: Option<String>,
|
pub server_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum MediaType {
|
pub enum MediaType {
|
||||||
Audio,
|
Audio,
|
||||||
@ -114,7 +114,7 @@ pub enum MediaType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// TRACES: UR-002, UR-003, UR-004, UR-011 | DR-003
|
/// TRACES: UR-002, UR-003, UR-004, UR-011 | DR-003
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
#[serde(tag = "type", rename_all = "lowercase")]
|
#[serde(tag = "type", rename_all = "lowercase")]
|
||||||
pub enum MediaSource {
|
pub enum MediaSource {
|
||||||
/// Streaming from Jellyfin server
|
/// Streaming from Jellyfin server
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use super::media::{MediaItem, MediaSource, QueueContext};
|
|||||||
/// Repeat mode for the queue
|
/// Repeat mode for the queue
|
||||||
///
|
///
|
||||||
/// TRACES: UR-005 | DR-005
|
/// TRACES: UR-005 | DR-005
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
#[derive(specta::Type, Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum RepeatMode {
|
pub enum RepeatMode {
|
||||||
#[default]
|
#[default]
|
||||||
@ -18,7 +18,7 @@ pub enum RepeatMode {
|
|||||||
/// Queue manager for playlist functionality
|
/// Queue manager for playlist functionality
|
||||||
///
|
///
|
||||||
/// TRACES: UR-005, UR-015 | DR-005, DR-020
|
/// TRACES: UR-005, UR-015 | DR-005, DR-020
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct QueueManager {
|
pub struct QueueManager {
|
||||||
/// All items in the queue
|
/// All items in the queue
|
||||||
items: Vec<MediaItem>,
|
items: Vec<MediaItem>,
|
||||||
|
|||||||
@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use super::media::MediaItem;
|
use super::media::MediaItem;
|
||||||
|
|
||||||
/// Media session type tracking the high-level playback context
|
/// Media session type tracking the high-level playback context
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
#[serde(tag = "type", rename_all = "snake_case")]
|
#[serde(tag = "type", rename_all = "snake_case")]
|
||||||
pub enum MediaSessionType {
|
pub enum MediaSessionType {
|
||||||
/// No active session - browsing library
|
/// No active session - browsing library
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
/// Sleep timer mode - determines when playback should stop
|
/// Sleep timer mode - determines when playback should stop
|
||||||
/// TRACES: UR-026 | DR-029
|
/// TRACES: UR-026 | DR-029
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
#[serde(tag = "kind", rename_all = "camelCase")]
|
#[serde(tag = "kind", rename_all = "camelCase")]
|
||||||
pub enum SleepTimerMode {
|
pub enum SleepTimerMode {
|
||||||
/// Timer is off
|
/// Timer is off
|
||||||
@ -19,7 +19,7 @@ pub enum SleepTimerMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sleep timer state
|
/// Sleep timer state
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct SleepTimerState {
|
pub struct SleepTimerState {
|
||||||
pub mode: SleepTimerMode,
|
pub mode: SleepTimerMode,
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use super::media::MediaItem;
|
|||||||
/// Tracks why playback ended to determine autoplay behavior
|
/// Tracks why playback ended to determine autoplay behavior
|
||||||
///
|
///
|
||||||
/// TRACES: UR-005 | DR-001
|
/// TRACES: UR-005 | DR-001
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum EndReason {
|
pub enum EndReason {
|
||||||
/// Track played to completion (natural end) - trigger autoplay
|
/// Track played to completion (natural end) - trigger autoplay
|
||||||
@ -23,7 +23,7 @@ pub enum EndReason {
|
|||||||
/// Player state machine (6 states: Idle, Loading, Playing, Paused, Seeking, Error)
|
/// Player state machine (6 states: Idle, Loading, Playing, Paused, Seeking, Error)
|
||||||
///
|
///
|
||||||
/// TRACES: UR-005 | DR-001
|
/// TRACES: UR-005 | DR-001
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
#[serde(tag = "kind", rename_all = "lowercase")]
|
#[serde(tag = "kind", rename_all = "lowercase")]
|
||||||
pub enum PlayerState {
|
pub enum PlayerState {
|
||||||
#[default]
|
#[default]
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Error types for repository operations
|
/// Error types for repository operations
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(tag = "type", rename_all = "lowercase")]
|
#[serde(tag = "type", rename_all = "lowercase")]
|
||||||
pub enum RepoError {
|
pub enum RepoError {
|
||||||
Network { message: String },
|
Network { message: String },
|
||||||
@ -28,7 +28,7 @@ impl std::fmt::Display for RepoError {
|
|||||||
impl std::error::Error for RepoError {}
|
impl std::error::Error for RepoError {}
|
||||||
|
|
||||||
/// Library (media collection)
|
/// Library (media collection)
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Library {
|
pub struct Library {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
@ -39,7 +39,7 @@ pub struct Library {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// User-specific data for an item (playback state, favorites, etc.)
|
/// User-specific data for an item (playback state, favorites, etc.)
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct UserData {
|
pub struct UserData {
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
@ -59,7 +59,7 @@ pub struct UserData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Artist item with ID and name (for clickable artist links)
|
/// Artist item with ID and name (for clickable artist links)
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
#[serde(rename_all = "PascalCase")]
|
#[serde(rename_all = "PascalCase")]
|
||||||
pub struct ArtistItem {
|
pub struct ArtistItem {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
@ -67,7 +67,7 @@ pub struct ArtistItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Person (cast/crew member) - for movies, series, and episodes
|
/// Person (cast/crew member) - for movies, series, and episodes
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Person {
|
pub struct Person {
|
||||||
/// Deserializes from API's "Id" field (PascalCase), serializes as "id" (camelCase to frontend)
|
/// Deserializes from API's "Id" field (PascalCase), serializes as "id" (camelCase to frontend)
|
||||||
@ -95,7 +95,7 @@ pub struct Person {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Media item
|
/// Media item
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct MediaItem {
|
pub struct MediaItem {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
@ -158,7 +158,7 @@ pub struct MediaItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Media stream information (audio, video, subtitle tracks)
|
/// Media stream information (audio, video, subtitle tracks)
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct MediaStream {
|
pub struct MediaStream {
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
@ -175,7 +175,7 @@ pub struct MediaStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Media source information
|
/// Media source information
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct MediaSource {
|
pub struct MediaSource {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
@ -194,7 +194,7 @@ pub struct MediaSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Search result with pagination
|
/// Search result with pagination
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct SearchResult {
|
pub struct SearchResult {
|
||||||
pub items: Vec<MediaItem>,
|
pub items: Vec<MediaItem>,
|
||||||
@ -202,7 +202,7 @@ pub struct SearchResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Options for querying items
|
/// Options for querying items
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct GetItemsOptions {
|
pub struct GetItemsOptions {
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
@ -224,7 +224,7 @@ pub struct GetItemsOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Options for search queries
|
/// Options for search queries
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct SearchOptions {
|
pub struct SearchOptions {
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
@ -236,7 +236,7 @@ pub struct SearchOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Playback information
|
/// Playback information
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct PlaybackInfo {
|
pub struct PlaybackInfo {
|
||||||
pub media_source_id: String,
|
pub media_source_id: String,
|
||||||
@ -247,7 +247,7 @@ pub struct PlaybackInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Genre
|
/// Genre
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Genre {
|
pub struct Genre {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
@ -255,7 +255,7 @@ pub struct Genre {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Image type
|
/// Image type
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum ImageType {
|
pub enum ImageType {
|
||||||
Primary,
|
Primary,
|
||||||
Backdrop,
|
Backdrop,
|
||||||
@ -277,7 +277,7 @@ impl ImageType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Image options
|
/// Image options
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ImageOptions {
|
pub struct ImageOptions {
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
@ -335,7 +335,7 @@ impl MeaningfulContent for PlaybackInfo {
|
|||||||
/// needed for remove/reorder operations (distinct from the media item's ID)
|
/// needed for remove/reorder operations (distinct from the media item's ID)
|
||||||
///
|
///
|
||||||
/// @req: UR-014 - Make and edit playlists of music that sync back to Jellyfin
|
/// @req: UR-014 - Make and edit playlists of music that sync back to Jellyfin
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct PlaylistEntry {
|
pub struct PlaylistEntry {
|
||||||
/// The playlist-scoped entry ID (Jellyfin's PlaylistItemId)
|
/// The playlist-scoped entry ID (Jellyfin's PlaylistItemId)
|
||||||
@ -348,7 +348,7 @@ pub struct PlaylistEntry {
|
|||||||
/// Result of creating a playlist
|
/// Result of creating a playlist
|
||||||
///
|
///
|
||||||
/// @req: JA-019 - Get/create/update playlists
|
/// @req: JA-019 - Get/create/update playlists
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct PlaylistCreatedResult {
|
pub struct PlaylistCreatedResult {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Volume normalization levels matching Spotify's presets
|
/// Volume normalization levels matching Spotify's presets
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Default)]
|
#[derive(specta::Type, Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Default)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum VolumeLevel {
|
pub enum VolumeLevel {
|
||||||
/// Louder output (-11 LUFS)
|
/// Louder output (-11 LUFS)
|
||||||
@ -27,7 +27,7 @@ impl VolumeLevel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Audio playback settings
|
/// Audio playback settings
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct AudioSettings {
|
pub struct AudioSettings {
|
||||||
/// Crossfade duration in seconds (0 = disabled, max 12)
|
/// Crossfade duration in seconds (0 = disabled, max 12)
|
||||||
@ -60,7 +60,7 @@ impl AudioSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Video playback settings
|
/// Video playback settings
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct VideoSettings {
|
pub struct VideoSettings {
|
||||||
/// Enable auto-play of next episode (with countdown)
|
/// Enable auto-play of next episode (with countdown)
|
||||||
|
|||||||
@ -13,7 +13,7 @@ pub use cache::{CacheConfig, ThumbnailCache};
|
|||||||
pub use worker::ThumbnailWorker;
|
pub use worker::ThumbnailWorker;
|
||||||
|
|
||||||
/// Statistics about the thumbnail cache
|
/// Statistics about the thumbnail cache
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(specta::Type, Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ThumbnailCacheStats {
|
pub struct ThumbnailCacheStats {
|
||||||
pub total_size_bytes: u64,
|
pub total_size_bytes: u64,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user