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:
vicrodh committed 2026-04-26 17:12:47 -06:00
1 parent aecdd4f5c8
commit e0dc464a65
3 files changed
+101 -73

No files matched your search

+11 -70
View File
@@ -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>,
+7 -3
View File
@@ -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;
+83
View File
@@ -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>,
}