refactor(library): move state types out of commands.rs
Relocates LibraryState (struct + impl), CleanupResult, BackfillReport, LibraryAlbumMetadataUpdateRequest, and LibraryAlbumTrackMetadataUpdate from library/commands.rs to a new library/state.rs module. These types are consumed by commands_v2/library.rs, commands_v2/legacy_compat.rs, commands_v2/mixtapes.rs, commands_v2/link_resolver.rs, cast/commands.rs, and session_lifecycle.rs. The existing pub use re-exports in library/mod.rs are updated to source from state, and commands.rs re-exports them in turn so historical crate::library::commands::* paths (still used by commands_v2/legacy_compat.rs, which is out of scope for this task) continue to compile. This unblocks future deletion of library/commands.rs once the remaining #[tauri::command] definitions there are inlined into their commands_v2 callers (separate task). No serde shape changes; struct fields, derives and serde attributes are preserved verbatim, so the JSON the frontend receives is identical. cc
This commit is contained in:
3 files changed
+101
-73
No files matched your search
@@ -1,45 +1,26 @@
|
||||
//! Tauri commands for local library
|
||||
|
||||
use serde::Deserialize;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::Ordering;
|
||||
use tauri::{Emitter, State};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::discogs::DiscogsClient;
|
||||
use crate::library::{
|
||||
cue_to_tracks, get_artwork_cache_dir, thumbnails, ArtistImageInfo, CueParser, LibraryDatabase,
|
||||
LibraryFolder, LibraryScanner, LibraryStats, LocalAlbum, LocalArtist, LocalTrack,
|
||||
MetadataExtractor, ScanError, ScanProgress, ScanStatus,
|
||||
cue_to_tracks, get_artwork_cache_dir, thumbnails, ArtistImageInfo, CueParser, LibraryFolder,
|
||||
LibraryScanner, LibraryStats, LocalAlbum, LocalArtist, LocalTrack, MetadataExtractor,
|
||||
ScanError, ScanProgress, ScanStatus,
|
||||
};
|
||||
use crate::network::{is_network_path, MountKind, NetworkFs};
|
||||
|
||||
/// Library state shared across commands
|
||||
pub struct LibraryState {
|
||||
pub db: Arc<Mutex<Option<LibraryDatabase>>>,
|
||||
pub scan_progress: Arc<Mutex<ScanProgress>>,
|
||||
pub scan_cancel: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl LibraryState {
|
||||
pub async fn init_at(&self, base_dir: &std::path::Path) -> Result<(), String> {
|
||||
std::fs::create_dir_all(base_dir)
|
||||
.map_err(|e| format!("Failed to create directory: {}", e))?;
|
||||
let db_path = base_dir.join("library.db");
|
||||
let db = LibraryDatabase::open(&db_path).map_err(|e| e.to_string())?;
|
||||
let mut guard = self.db.lock().await;
|
||||
*guard = Some(db);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn teardown(&self) {
|
||||
let mut guard = self.db.lock().await;
|
||||
*guard = None;
|
||||
}
|
||||
}
|
||||
// Shared state types and DTOs live in `super::state`; re-export them from
|
||||
// this module so historical `crate::library::commands::*` paths used by
|
||||
// `commands_v2/legacy_compat.rs` continue to compile.
|
||||
pub use super::state::{
|
||||
BackfillReport, CleanupResult, LibraryAlbumMetadataUpdateRequest,
|
||||
LibraryAlbumTrackMetadataUpdate, LibraryState,
|
||||
};
|
||||
|
||||
fn normalize_library_path(path: &Path) -> PathBuf {
|
||||
fs::canonicalize(path).unwrap_or_else(|_| path.to_path_buf())
|
||||
@@ -124,14 +105,6 @@ pub async fn library_remove_folder(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Result of cleanup operation
|
||||
#[derive(Debug, Clone, serde::Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CleanupResult {
|
||||
pub checked: usize,
|
||||
pub removed: usize,
|
||||
}
|
||||
|
||||
/// Clean up tracks whose files no longer exist on disk
|
||||
#[tauri::command]
|
||||
pub async fn library_cleanup_missing_files(
|
||||
@@ -2074,29 +2047,6 @@ pub async fn library_set_album_hidden(
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LibraryAlbumTrackMetadataUpdate {
|
||||
pub id: i64,
|
||||
pub file_path: String,
|
||||
pub cue_start_secs: Option<f64>,
|
||||
pub title: String,
|
||||
pub disc_number: Option<u32>,
|
||||
pub track_number: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LibraryAlbumMetadataUpdateRequest {
|
||||
pub album_group_key: String,
|
||||
pub album_title: String,
|
||||
pub album_artist: String,
|
||||
pub year: Option<u32>,
|
||||
pub genre: Option<String>,
|
||||
pub catalog_number: Option<String>,
|
||||
pub tracks: Vec<LibraryAlbumTrackMetadataUpdate>,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn library_update_album_metadata_impl(
|
||||
request: LibraryAlbumMetadataUpdateRequest,
|
||||
@@ -2503,15 +2453,6 @@ pub async fn library_get_hidden_albums(
|
||||
|
||||
// === Qobuz Downloads Integration ===
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
pub struct BackfillReport {
|
||||
pub total_downloads: usize,
|
||||
pub added_tracks: usize,
|
||||
pub repaired_tracks: usize,
|
||||
pub skipped_tracks: usize,
|
||||
pub failed_tracks: Vec<String>,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn library_backfill_downloads(
|
||||
state: State<'_, LibraryState>,
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
// Tauri-specific modules (stay here)
|
||||
pub mod commands;
|
||||
pub mod remote_metadata;
|
||||
pub mod state;
|
||||
|
||||
// Re-export everything from qbz-library
|
||||
pub use qbz_library::{
|
||||
@@ -79,8 +80,11 @@ pub mod thumbnails {
|
||||
};
|
||||
}
|
||||
|
||||
// Re-export commands::LibraryState for compatibility
|
||||
pub use commands::LibraryState;
|
||||
// State and DTO types live in `state`; re-export for compatibility.
|
||||
pub use state::{
|
||||
BackfillReport, CleanupResult, LibraryAlbumMetadataUpdateRequest,
|
||||
LibraryAlbumTrackMetadataUpdate, LibraryState,
|
||||
};
|
||||
pub use commands::{
|
||||
library_add_folder, library_cleanup_missing_files, library_clear_impl,
|
||||
library_fetch_missing_artwork, library_get_album_tracks, library_get_artists,
|
||||
@@ -90,7 +94,7 @@ pub use commands::{
|
||||
library_scan_folder_impl, library_scan_impl, library_search, library_stop_scan_impl,
|
||||
library_update_album_metadata_impl, library_write_album_metadata_to_files_impl,
|
||||
playlist_get_custom_order, playlist_get_tracks_with_local_copies, playlist_has_custom_order,
|
||||
update_playlist_folder, CleanupResult, LibraryAlbumMetadataUpdateRequest,
|
||||
update_playlist_folder,
|
||||
};
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
//! Shared state and DTO types for the library module.
|
||||
//!
|
||||
//! These types were originally defined in `library/commands.rs` alongside
|
||||
//! their owning Tauri commands. They are relocated here so the type
|
||||
//! surface remains available after the legacy `#[tauri::command]`
|
||||
//! definitions in `commands.rs` are eventually removed.
|
||||
//!
|
||||
//! Consumers (`commands_v2`, `session_lifecycle`, `cast/commands.rs`,
|
||||
//! `offline_cache/commands.rs`, etc.) reach these via the existing
|
||||
//! re-exports in `library/mod.rs`. `commands.rs` itself re-exports the
|
||||
//! whole module so any historical `crate::library::commands::*` paths
|
||||
//! continue to compile.
|
||||
|
||||
use serde::Deserialize;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::library::{LibraryDatabase, ScanProgress};
|
||||
|
||||
/// Library state shared across commands
|
||||
pub struct LibraryState {
|
||||
pub db: Arc<Mutex<Option<LibraryDatabase>>>,
|
||||
pub scan_progress: Arc<Mutex<ScanProgress>>,
|
||||
pub scan_cancel: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl LibraryState {
|
||||
pub async fn init_at(&self, base_dir: &std::path::Path) -> Result<(), String> {
|
||||
std::fs::create_dir_all(base_dir)
|
||||
.map_err(|e| format!("Failed to create directory: {}", e))?;
|
||||
let db_path = base_dir.join("library.db");
|
||||
let db = LibraryDatabase::open(&db_path).map_err(|e| e.to_string())?;
|
||||
let mut guard = self.db.lock().await;
|
||||
*guard = Some(db);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn teardown(&self) {
|
||||
let mut guard = self.db.lock().await;
|
||||
*guard = None;
|
||||
}
|
||||
}
|
||||
|
||||
/// Result of cleanup operation
|
||||
#[derive(Debug, Clone, serde::Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CleanupResult {
|
||||
pub checked: usize,
|
||||
pub removed: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LibraryAlbumTrackMetadataUpdate {
|
||||
pub id: i64,
|
||||
pub file_path: String,
|
||||
pub cue_start_secs: Option<f64>,
|
||||
pub title: String,
|
||||
pub disc_number: Option<u32>,
|
||||
pub track_number: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LibraryAlbumMetadataUpdateRequest {
|
||||
pub album_group_key: String,
|
||||
pub album_title: String,
|
||||
pub album_artist: String,
|
||||
pub year: Option<u32>,
|
||||
pub genre: Option<String>,
|
||||
pub catalog_number: Option<String>,
|
||||
pub tracks: Vec<LibraryAlbumTrackMetadataUpdate>,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
pub struct BackfillReport {
|
||||
pub total_downloads: usize,
|
||||
pub added_tracks: usize,
|
||||
pub repaired_tracks: usize,
|
||||
pub skipped_tracks: usize,
|
||||
pub failed_tracks: Vec<String>,
|
||||
}
|
||||
Reference in new issue
Block a user