use serde::{Deserialize, Serialize}; // --- Auth --- #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct UserInfo { pub id: i32, pub username: String, pub role: String, } #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct SetupRequired { pub required: bool, } // --- Library entities --- #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct Artist { pub id: i32, pub name: String, pub musicbrainz_id: Option, } #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct ArtistListItem { pub id: i32, pub name: String, pub musicbrainz_id: Option, pub total_watched: usize, pub total_owned: usize, pub total_items: usize, } #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct FullAlbumInfo { pub mbid: String, pub title: String, pub release_type: Option, pub date: Option, pub track_count: u32, pub local_album_id: Option, pub watched_tracks: u32, pub downloaded_tracks: u32, pub owned_tracks: u32, pub total_local_tracks: u32, pub status: String, } #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct FullArtistDetail { pub artist: Artist, pub albums: Vec, pub artist_status: String, #[serde(default)] pub total_available_tracks: u32, #[serde(default)] pub total_watched_tracks: u32, #[serde(default)] pub total_owned_tracks: u32, #[serde(default)] pub enriched: bool, #[serde(default)] pub artist_info: Option, #[serde(default)] pub artist_photo: Option, #[serde(default)] pub artist_bio: Option, #[serde(default)] pub artist_banner: Option, } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct ArtistInfoFe { pub name: String, #[serde(default)] pub disambiguation: Option, #[serde(default)] pub country: Option, #[serde(default)] pub artist_type: Option, #[serde(default)] pub begin_year: Option, #[serde(default)] pub urls: Vec, } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct ArtistUrlFe { pub url: String, pub link_type: String, } #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct LyricsResult { pub found: bool, pub lyrics: Option, pub synced_lyrics: Option, } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct Track { pub id: i32, pub file_path: String, pub title: Option, pub artist: Option, pub album: Option, pub track_number: Option, pub year: Option, pub genre: Option, pub codec: Option, } /// Album detail from MusicBrainz (the primary album view). #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct MbAlbumDetail { pub mbid: String, pub tracks: Vec, } #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct MbAlbumTrack { pub recording_mbid: String, pub title: String, pub track_number: Option, pub disc_number: Option, pub duration_ms: Option, pub status: Option, } // --- Search results --- #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct ArtistResult { pub id: String, pub name: String, pub disambiguation: Option, pub country: Option, pub artist_type: Option, pub score: u8, } #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct AlbumResult { pub id: String, pub title: String, pub artist: String, pub artist_id: Option, pub year: Option, pub track_count: Option, pub score: u8, } #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct TrackResult { pub id: String, pub title: String, pub artist: String, pub artist_id: Option, pub album: Option, pub score: u8, } // --- YouTube Auth --- #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct YtAuthStatus { pub authenticated: bool, pub cookie_age_hours: Option, pub cookie_count: Option, pub refresh_enabled: bool, pub login_session_active: bool, pub vnc_url: Option, #[serde(default)] pub ytdlp_version: Option, #[serde(default)] pub ytdlp_latest: Option, #[serde(default)] pub ytdlp_update_available: bool, #[serde(default)] pub lastfm_api_key_set: bool, #[serde(default)] pub fanart_api_key_set: bool, } // --- Downloads --- #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct DownloadItem { pub id: i32, pub query: String, pub status: String, pub source_url: Option, pub error_message: Option, pub retry_count: i32, } // --- Tasks --- #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct TaskProgress { pub current: u64, pub total: u64, pub message: String, } #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct TaskInfo { pub id: String, pub task_type: String, pub status: String, pub progress: Option, pub result: Option, } #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct TaskRef { pub task_id: String, } #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct PipelineRef { pub task_ids: Vec, } // --- Status --- #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct TaggingStatus { pub needs_tagging: usize, #[serde(default)] pub items: Vec, } #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct Status { pub library: LibrarySummary, pub queue: QueueStatus, #[serde(default)] pub tagging: Option, pub tasks: Vec, } #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct LibrarySummary { pub total_items: u64, pub wanted: u64, pub available: u64, pub downloaded: u64, pub owned: u64, } #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct QueueStatus { pub pending: usize, pub downloading: usize, #[serde(default)] pub failed: usize, #[serde(default)] pub items: Vec, } // --- API responses --- #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct AddSummary { pub tracks_added: u64, pub tracks_already_owned: u64, pub errors: u64, } #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct SyncStats { pub found: u64, pub enqueued: u64, pub skipped: u64, } // --- Config --- #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct AppConfig { pub library_path: String, pub database_url: String, pub download_path: String, pub organization_format: String, #[serde(default)] pub allowed_secondary_types: Vec, #[serde(default)] pub web: WebConfigFe, #[serde(default)] pub tagging: TaggingConfigFe, #[serde(default)] pub download: DownloadConfigFe, #[serde(default)] pub indexing: IndexingConfigFe, #[serde(default)] pub metadata: MetadataConfigFe, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)] pub struct WebConfigFe { #[serde(default)] pub port: u16, #[serde(default)] pub bind: String, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)] pub struct TaggingConfigFe { #[serde(default)] pub auto_tag: bool, #[serde(default)] pub write_tags: bool, #[serde(default)] pub confidence: f64, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)] pub struct DownloadConfigFe { #[serde(default)] pub format: String, #[serde(default)] pub search_source: String, #[serde(default)] pub cookies_path: Option, #[serde(default)] pub rate_limit: u32, #[serde(default)] pub rate_limit_auth: u32, #[serde(default)] pub cookie_refresh_enabled: bool, #[serde(default = "default_cookie_refresh_hours")] pub cookie_refresh_hours: u32, #[serde(default = "default_vnc_port")] pub vnc_port: u16, } fn default_cookie_refresh_hours() -> u32 { 6 } fn default_vnc_port() -> u16 { 6080 } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)] pub struct IndexingConfigFe { #[serde(default)] pub concurrency: usize, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct MetadataConfigFe { #[serde(default = "default_metadata_source")] pub metadata_source: String, #[serde(default = "default_artist_image_source")] pub artist_image_source: String, #[serde(default = "default_artist_bio_source")] pub artist_bio_source: String, #[serde(default = "default_lyrics_source")] pub lyrics_source: String, #[serde(default = "default_cover_art_source")] pub cover_art_source: String, } impl Default for MetadataConfigFe { fn default() -> Self { Self { metadata_source: default_metadata_source(), artist_image_source: default_artist_image_source(), artist_bio_source: default_artist_bio_source(), lyrics_source: default_lyrics_source(), cover_art_source: default_cover_art_source(), } } } fn default_metadata_source() -> String { "musicbrainz".into() } fn default_artist_image_source() -> String { "wikipedia".into() } fn default_artist_bio_source() -> String { "wikipedia".into() } fn default_lyrics_source() -> String { "lrclib".into() } fn default_cover_art_source() -> String { "coverartarchive".into() }