From 2ecd4cb6af6c0fd27ea069dc4583af0dea2d6b7a Mon Sep 17 00:00:00 2001 From: Wojciech Kozlowski Date: Thu, 2 Jan 2025 15:50:55 +0100 Subject: [PATCH] Add a library identifier to disambiguate clashes in the library (#238) Part 1 of #231 Reviewed-on: https://git.thenineworlds.net/wojtek/musichoard/pulls/238 --- .gitattributes | 1 + src/core/collection/album.rs | 50 ++++++---- src/core/collection/artist.rs | 106 ++++++++++++++++++--- src/core/collection/merge.rs | 16 +--- src/core/interface/library/mod.rs | 22 ++++- src/core/interface/library/testmod.rs | 27 +++++- src/core/musichoard/library.rs | 5 +- src/core/testmod.rs | 2 +- src/external/database/json/testmod.rs | 22 ++--- src/external/database/serde/common.rs | 10 +- src/external/database/serde/deserialize.rs | 27 ++++-- src/external/database/serde/serialize.rs | 22 ++++- src/external/library/beets/mod.rs | 37 ++++--- src/external/library/beets/testmod.rs | 44 ++++----- src/external/musicbrainz/api/lookup.rs | 7 +- src/testmod/full.rs | 10 ++ src/testmod/library.rs | 10 ++ src/tui/testmod.rs | 2 +- src/tui/ui/display.rs | 21 +++- src/tui/ui/info_state.rs | 6 +- tests/files/database/database.json | 2 +- tests/library/testmod.rs | 85 ++++++++++++++++- tests/testlib.rs | 13 ++- 23 files changed, 434 insertions(+), 113 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..b1f76c8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ + src/external/** linguist-vendored=false diff --git a/src/core/collection/album.rs b/src/core/collection/album.rs index 6356692..da49982 100644 --- a/src/core/collection/album.rs +++ b/src/core/collection/album.rs @@ -4,7 +4,7 @@ use std::{ }; use crate::core::collection::{ - merge::{Merge, MergeSorted, WithId}, + merge::{Merge, MergeSorted}, musicbrainz::{MbAlbumRef, MbRefOption}, track::{Track, TrackFormat}, }; @@ -33,18 +33,34 @@ pub struct AlbumInfo { pub secondary_types: Vec, } -impl WithId for Album { - type Id = AlbumId; - - fn id(&self) -> &Self::Id { - &self.meta.id - } -} - /// The album identifier. #[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)] pub struct AlbumId { pub title: String, + pub lib_id: AlbumLibId, +} + +impl AlbumId { + pub fn compatible(&self, other: &AlbumId) -> bool { + let titles_compatible = self.title == other.title; + let lib_id_compatible = + self.lib_id.is_none() || other.lib_id.is_none() || (self.lib_id == other.lib_id); + titles_compatible && lib_id_compatible + } +} + +/// Unique library identifier. +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)] +pub enum AlbumLibId { + Value(u32), + Singleton, + None, +} + +impl AlbumLibId { + pub fn is_none(&self) -> bool { + matches!(self, AlbumLibId::None) + } } // There are crates for handling dates, but we don't need much complexity beyond year-month-day. @@ -252,9 +268,8 @@ impl Ord for AlbumMeta { impl Merge for AlbumMeta { fn merge_in_place(&mut self, other: Self) { - assert_eq!(self.id, other.id); + assert!(self.id.compatible(&other.id)); self.seq = std::cmp::max(self.seq, other.seq); - self.info.merge_in_place(other.info); } } @@ -283,7 +298,10 @@ impl AsRef for AlbumId { impl AlbumId { pub fn new>(name: S) -> AlbumId { - AlbumId { title: name.into() } + AlbumId { + title: name.into(), + lib_id: AlbumLibId::None, + } } } @@ -315,15 +333,11 @@ mod tests { fn same_date_seq_cmp() { let date: AlbumDate = (2024, 3, 2).into(); - let album_id_1 = AlbumId { - title: String::from("album z"), - }; + let album_id_1 = AlbumId::new("album z"); let mut album_1 = Album::new(album_id_1).with_date(date.clone()); album_1.meta.set_seq(AlbumSeq(1)); - let album_id_2 = AlbumId { - title: String::from("album a"), - }; + let album_id_2 = AlbumId::new("album a"); let mut album_2 = Album::new(album_id_2).with_date(date.clone()); album_2.meta.set_seq(AlbumSeq(2)); diff --git a/src/core/collection/artist.rs b/src/core/collection/artist.rs index 730ef87..8851470 100644 --- a/src/core/collection/artist.rs +++ b/src/core/collection/artist.rs @@ -1,12 +1,11 @@ use std::{ collections::HashMap, fmt::{self, Debug, Display}, - mem, }; use crate::core::collection::{ - album::Album, - merge::{Merge, MergeCollections, WithId}, + album::{Album, AlbumLibId}, + merge::{Merge, MergeId}, musicbrainz::{MbArtistRef, MbRefOption}, }; @@ -32,7 +31,7 @@ pub struct ArtistInfo { pub properties: HashMap>, } -impl WithId for Artist { +impl MergeId for Artist { type Id = ArtistId; fn id(&self) -> &Self::Id { @@ -54,6 +53,56 @@ impl Artist { albums: vec![], } } + + fn merge_album_by_lib_id( + primary_albums: &mut [Album], + mut secondary_album: Album, + ) -> Option { + let id_opt = secondary_album.meta.id.lib_id; + if let id @ AlbumLibId::Value(_) | id @ AlbumLibId::Singleton = id_opt { + let mut iter = primary_albums.iter_mut(); + if let Some(ref mut primary_album) = iter.find(|a| a.meta.id.lib_id == id) { + primary_album.merge_in_place(secondary_album); + return None; + } + secondary_album.meta.id.lib_id = AlbumLibId::None; + } + Some(secondary_album) + } + + fn merge_albums_by_lib_id( + primary_albums: &mut [Album], + secondary_albums: Vec, + ) -> HashMap> { + let mut secondary_without_id = HashMap::>::new(); + for secondary_album in secondary_albums.into_iter() { + let unmerged = Artist::merge_album_by_lib_id(primary_albums, secondary_album); + if let Some(secondary_album) = unmerged { + secondary_without_id + .entry(secondary_album.meta.id.title.clone()) + .or_default() + .push(secondary_album); + } + } + secondary_without_id + } + + fn merge_albums_by_title( + primary_albums: &mut Vec, + secondary_without_id: HashMap>, + ) { + for (title, mut secondary_albums) in secondary_without_id.into_iter() { + let mut iter = primary_albums.iter_mut(); + match iter.find(|album| album.meta.id.title == title) { + Some(ref mut primary_album) => { + // We do not support merging multiple DB albums with same title yet. + assert_eq!(secondary_albums.len(), 1); + primary_album.merge_in_place(secondary_albums.pop().unwrap()) + } + None => primary_albums.append(&mut secondary_albums), + } + } + } } impl PartialOrd for Artist { @@ -71,8 +120,10 @@ impl Ord for Artist { impl Merge for Artist { fn merge_in_place(&mut self, other: Self) { self.meta.merge_in_place(other.meta); - let albums = mem::take(&mut self.albums); - self.albums = MergeCollections::merge_iter(albums, other.albums); + + let other_without_id = Artist::merge_albums_by_lib_id(&mut self.albums, other.albums); + Artist::merge_albums_by_title(&mut self.albums, other_without_id); + self.albums.sort_unstable(); } } @@ -410,6 +461,12 @@ mod tests { assert!(info.properties.is_empty()); } + fn reset_lib_id(albums: &mut [Album]) { + for album in albums.iter_mut() { + album.meta.id.lib_id = AlbumLibId::None; + } + } + #[test] fn merge_artist_no_overlap() { let left = FULL_COLLECTION[0].to_owned(); @@ -424,13 +481,25 @@ mod tests { .info .properties .merge(right.clone().meta.info.properties); - expected.albums.append(&mut right.albums.clone()); + + // If an album in the secondary (right) collection has a lib id but there is no match in the + // primary (left) collection then it is removed. + let mut right_albums_without_lib_id = right.albums.clone(); + reset_lib_id(&mut right_albums_without_lib_id); + expected.albums.extend(right_albums_without_lib_id); expected.albums.sort_unstable(); let merged = left.clone().merge(right.clone()); assert_eq!(expected, merged); - // Non-overlapping merge should be commutative. + // Non-overlapping merge should be commutative. Except for lib id which will be erased from + // the albums in the secondary collection. + expected.albums = right.albums.clone(); + let mut left_albums_without_lib_id = left.albums.clone(); + reset_lib_id(&mut left_albums_without_lib_id); + expected.albums.extend(left_albums_without_lib_id); + expected.albums.sort_unstable(); + let merged = right.clone().merge(left.clone()); assert_eq!(expected, merged); } @@ -440,8 +509,20 @@ mod tests { let mut left = FULL_COLLECTION[0].to_owned(); let mut right = FULL_COLLECTION[1].to_owned(); right.meta.id = left.meta.id.clone(); + + // The right collection needs more albums than we modify to make sure some do not overlap. + assert!(right.albums.len() > 2); + + // This album will have a lib_id and will match based on lib_id. left.albums.push(right.albums[0].clone()); - left.albums.sort_unstable(); + + // This album will not have a lib_id and will match based on title. + left.albums.push(right.albums[1].clone()); + right.albums[1].meta.id.lib_id = AlbumLibId::None; + + // Albums on right without a match on the left will lose their lib id. + let mut newly_added = right.albums[2..].to_vec(); + reset_lib_id(&mut newly_added); let mut expected = left.clone(); expected.meta.info.properties = expected @@ -449,9 +530,12 @@ mod tests { .info .properties .merge(right.clone().meta.info.properties); - expected.albums.append(&mut right.albums.clone()); + expected.albums.extend(newly_added); expected.albums.sort_unstable(); - expected.albums.dedup(); + + // Albums are expected to be sorted. + left.albums.sort_unstable(); + right.albums.sort_unstable(); let merged = left.clone().merge(right); assert_eq!(expected, merged); diff --git a/src/core/collection/merge.rs b/src/core/collection/merge.rs index 2173801..42d833a 100644 --- a/src/core/collection/merge.rs +++ b/src/core/collection/merge.rs @@ -23,8 +23,8 @@ impl Merge for Vec { } impl Merge for HashMap> { - fn merge_in_place(&mut self, mut other: Self) { - for (other_key, other_value) in other.drain() { + fn merge_in_place(&mut self, other: Self) { + for (other_key, other_value) in other.into_iter() { if let Some(ref mut value) = self.get_mut(&other_key) { value.merge_in_place(other_value) } else { @@ -80,7 +80,7 @@ where } } -pub trait WithId { +pub trait MergeId { type Id; fn id(&self) -> &Self::Id; @@ -95,17 +95,9 @@ pub struct MergeCollections { impl MergeCollections where ID: Eq + Hash + Clone, - T: WithId + Merge + Ord, + T: MergeId + Merge + Ord, IT: IntoIterator, { - pub fn merge_iter(primary: IT, secondary: IT) -> Vec { - let primary = primary - .into_iter() - .map(|item| (item.id().clone(), item)) - .collect(); - Self::merge(primary, secondary) - } - pub fn merge(mut primary: HashMap, secondary: IT) -> Vec { for secondary_item in secondary { if let Some(ref mut primary_item) = primary.get_mut(secondary_item.id()) { diff --git a/src/core/interface/library/mod.rs b/src/core/interface/library/mod.rs index 76609bc..0cdce85 100644 --- a/src/core/interface/library/mod.rs +++ b/src/core/interface/library/mod.rs @@ -1,11 +1,16 @@ //! Module for interacting with the music library. -use std::{collections::HashSet, fmt, num::ParseIntError, str::Utf8Error}; +use std::{ + collections::HashSet, + fmt, + num::ParseIntError, + str::{ParseBoolError, Utf8Error}, +}; #[cfg(test)] use mockall::automock; -use crate::core::collection::track::TrackFormat; +use crate::{collection::album::AlbumLibId, core::collection::track::TrackFormat}; /// Trait for interacting with the music library. #[cfg_attr(test, automock)] @@ -32,6 +37,7 @@ pub struct Item { pub album_month: u8, pub album_day: u8, pub album_title: String, + pub album_lib_id: AlbumLibId, pub track_number: u32, pub track_title: String, pub track_artist: Vec, @@ -90,6 +96,8 @@ pub enum Error { Io(String), /// The library received invalid data. Invalid(String), + /// The library failed to parse a boolean. + ParseBool(String), /// The library failed to parse an integer. ParseInt(String), /// The library failed to parse a UTF-8 string. @@ -102,6 +110,7 @@ impl fmt::Display for Error { Self::Executor(ref s) => write!(f, "the library's executor failed: {s}"), Self::Io(ref s) => write!(f, "the library experienced an I/O error: {s}"), Self::Invalid(ref s) => write!(f, "the library received invalid data: {s}"), + Self::ParseBool(ref s) => write!(f, "the library failed to parse a boolean: {s}"), Self::ParseInt(ref s) => write!(f, "the library failed to parse an integer: {s}"), Self::Utf8(ref s) => write!(f, "the library failed to parse a UTF-8 string: {s}"), } @@ -114,6 +123,12 @@ impl From for Error { } } +impl From for Error { + fn from(err: ParseBoolError) -> Error { + Error::ParseBool(err.to_string()) + } +} + impl From for Error { fn from(err: ParseIntError) -> Error { Error::ParseInt(err.to_string()) @@ -162,6 +177,7 @@ mod tests { let exe_err = Error::Executor(String::from("Executor")); let io_err: Error = io::Error::new(io::ErrorKind::Interrupted, "Interrupted").into(); let inv_err = Error::Invalid(String::from("Invalid")); + let bool_err: Error = "f".parse::().unwrap_err().into(); let int_err: Error = "five".parse::().unwrap_err().into(); #[allow(invalid_from_utf8)] let utf_err: Error = std::str::from_utf8(b"\xe2\x28\xa1").unwrap_err().into(); @@ -169,12 +185,14 @@ mod tests { assert!(!exe_err.to_string().is_empty()); assert!(!io_err.to_string().is_empty()); assert!(!inv_err.to_string().is_empty()); + assert!(!bool_err.to_string().is_empty()); assert!(!int_err.to_string().is_empty()); assert!(!utf_err.to_string().is_empty()); assert!(!format!("{:?}", exe_err).is_empty()); assert!(!format!("{:?}", io_err).is_empty()); assert!(!format!("{:?}", inv_err).is_empty()); + assert!(!format!("{:?}", bool_err).is_empty()); assert!(!format!("{:?}", int_err).is_empty()); assert!(!format!("{:?}", utf_err).is_empty()); } diff --git a/src/core/interface/library/testmod.rs b/src/core/interface/library/testmod.rs index 6afc5b9..43408b6 100644 --- a/src/core/interface/library/testmod.rs +++ b/src/core/interface/library/testmod.rs @@ -1,6 +1,9 @@ use once_cell::sync::Lazy; -use crate::core::{collection::track::TrackFormat, interface::library::Item}; +use crate::{ + collection::album::AlbumLibId, + core::{collection::track::TrackFormat, interface::library::Item}, +}; pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { vec![ @@ -11,6 +14,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("album_title a.a"), + album_lib_id: AlbumLibId::Value(1), track_number: 1, track_title: String::from("track a.a.1"), track_artist: vec![String::from("artist a.a.1")], @@ -24,6 +28,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("album_title a.a"), + album_lib_id: AlbumLibId::Value(1), track_number: 2, track_title: String::from("track a.a.2"), track_artist: vec![ @@ -40,6 +45,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("album_title a.a"), + album_lib_id: AlbumLibId::Value(1), track_number: 3, track_title: String::from("track a.a.3"), track_artist: vec![String::from("artist a.a.3")], @@ -53,6 +59,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("album_title a.a"), + album_lib_id: AlbumLibId::Value(1), track_number: 4, track_title: String::from("track a.a.4"), track_artist: vec![String::from("artist a.a.4")], @@ -66,6 +73,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 4, album_day: 0, album_title: String::from("album_title a.b"), + album_lib_id: AlbumLibId::Value(2), track_number: 1, track_title: String::from("track a.b.1"), track_artist: vec![String::from("artist a.b.1")], @@ -79,6 +87,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 4, album_day: 0, album_title: String::from("album_title a.b"), + album_lib_id: AlbumLibId::Value(2), track_number: 2, track_title: String::from("track a.b.2"), track_artist: vec![String::from("artist a.b.2")], @@ -92,6 +101,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 6, album_day: 6, album_title: String::from("album_title b.a"), + album_lib_id: AlbumLibId::Value(3), track_number: 1, track_title: String::from("track b.a.1"), track_artist: vec![String::from("artist b.a.1")], @@ -105,6 +115,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 6, album_day: 6, album_title: String::from("album_title b.a"), + album_lib_id: AlbumLibId::Value(3), track_number: 2, track_title: String::from("track b.a.2"), track_artist: vec![ @@ -121,6 +132,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("album_title b.b"), + album_lib_id: AlbumLibId::Value(4), track_number: 1, track_title: String::from("track b.b.1"), track_artist: vec![String::from("artist b.b.1")], @@ -134,6 +146,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("album_title b.b"), + album_lib_id: AlbumLibId::Value(4), track_number: 2, track_title: String::from("track b.b.2"), track_artist: vec![ @@ -150,6 +163,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("album_title b.c"), + album_lib_id: AlbumLibId::Value(5), track_number: 1, track_title: String::from("track b.c.1"), track_artist: vec![String::from("artist b.c.1")], @@ -163,6 +177,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("album_title b.c"), + album_lib_id: AlbumLibId::Value(5), track_number: 2, track_title: String::from("track b.c.2"), track_artist: vec![ @@ -179,6 +194,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("album_title b.d"), + album_lib_id: AlbumLibId::Value(6), track_number: 1, track_title: String::from("track b.d.1"), track_artist: vec![String::from("artist b.d.1")], @@ -192,6 +208,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("album_title b.d"), + album_lib_id: AlbumLibId::Value(6), track_number: 2, track_title: String::from("track b.d.2"), track_artist: vec![ @@ -208,6 +225,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("album_title c.a"), + album_lib_id: AlbumLibId::Value(7), track_number: 1, track_title: String::from("track c.a.1"), track_artist: vec![String::from("artist c.a.1")], @@ -221,6 +239,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("album_title c.a"), + album_lib_id: AlbumLibId::Value(7), track_number: 2, track_title: String::from("track c.a.2"), track_artist: vec![ @@ -237,6 +256,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("album_title c.b"), + album_lib_id: AlbumLibId::Value(8), track_number: 1, track_title: String::from("track c.b.1"), track_artist: vec![String::from("artist c.b.1")], @@ -250,6 +270,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("album_title c.b"), + album_lib_id: AlbumLibId::Value(8), track_number: 2, track_title: String::from("track c.b.2"), track_artist: vec![ @@ -266,6 +287,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("album_title d.a"), + album_lib_id: AlbumLibId::Value(9), track_number: 1, track_title: String::from("track d.a.1"), track_artist: vec![String::from("artist d.a.1")], @@ -279,6 +301,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("album_title d.a"), + album_lib_id: AlbumLibId::Value(9), track_number: 2, track_title: String::from("track d.a.2"), track_artist: vec![ @@ -295,6 +318,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("album_title d.b"), + album_lib_id: AlbumLibId::Value(10), track_number: 1, track_title: String::from("track d.b.1"), track_artist: vec![String::from("artist d.b.1")], @@ -308,6 +332,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("album_title d.b"), + album_lib_id: AlbumLibId::Value(10), track_number: 2, track_title: String::from("track d.b.2"), track_artist: vec![ diff --git a/src/core/musichoard/library.rs b/src/core/musichoard/library.rs index 5272b6d..09fa249 100644 --- a/src/core/musichoard/library.rs +++ b/src/core/musichoard/library.rs @@ -56,6 +56,7 @@ impl MusicHoard { let album_id = AlbumId { title: item.album_title, + lib_id: item.album_lib_id, }; let album_date = AlbumDate { @@ -230,7 +231,7 @@ mod tests { } #[test] - fn rescan_library_album_id_clash() { + fn rescan_library_different_artist_album_title_clash() { let mut library = MockILibrary::new(); let mut expected = LIBRARY_COLLECTION.to_owned(); @@ -245,7 +246,7 @@ mod tests { item.album_title = clashed_album_id.title.clone(); } - expected[0].albums[0].meta.id = clashed_album_id.clone(); + expected[0].albums[0].meta.id.title = clashed_album_id.title.clone(); let library_input = Query::new(); let library_result = Ok(items); diff --git a/src/core/testmod.rs b/src/core/testmod.rs index 32dab21..2ef6236 100644 --- a/src/core/testmod.rs +++ b/src/core/testmod.rs @@ -2,7 +2,7 @@ use once_cell::sync::Lazy; use std::collections::HashMap; use crate::core::collection::{ - album::{Album, AlbumId, AlbumInfo, AlbumMeta, AlbumPrimaryType, AlbumSeq}, + album::{Album, AlbumId, AlbumInfo, AlbumLibId, AlbumMeta, AlbumPrimaryType, AlbumSeq}, artist::{Artist, ArtistId, ArtistInfo, ArtistMeta}, musicbrainz::{MbAlbumRef, MbArtistRef, MbRefOption}, track::{Track, TrackFormat, TrackId, TrackNum, TrackQuality}, diff --git a/src/external/database/json/testmod.rs b/src/external/database/json/testmod.rs index d7b1255..0f2f602 100644 --- a/src/external/database/json/testmod.rs +++ b/src/external/database/json/testmod.rs @@ -1,5 +1,5 @@ pub static DATABASE_JSON: &str = "{\ - \"V20240924\":\ + \"V20250101\":\ [\ {\ \"name\":\"Album_Artist ‘A’\",\ @@ -11,12 +11,12 @@ pub static DATABASE_JSON: &str = "{\ },\ \"albums\":[\ {\ - \"title\":\"album_title a.a\",\"seq\":1,\ + \"title\":\"album_title a.a\",\"lib_id\":{\"Value\":1},\"seq\":1,\ \"musicbrainz\":{\"Some\":\"00000000-0000-0000-0000-000000000000\"},\ \"primary_type\":\"Album\",\"secondary_types\":[]\ },\ {\ - \"title\":\"album_title a.b\",\"seq\":1,\"musicbrainz\":\"None\",\ + \"title\":\"album_title a.b\",\"lib_id\":{\"Value\":2},\"seq\":1,\"musicbrainz\":\"None\",\ \"primary_type\":\"Album\",\"secondary_types\":[]\ }\ ]\ @@ -35,21 +35,21 @@ pub static DATABASE_JSON: &str = "{\ },\ \"albums\":[\ {\ - \"title\":\"album_title b.a\",\"seq\":1,\"musicbrainz\":\"None\",\ + \"title\":\"album_title b.a\",\"lib_id\":{\"Value\":3},\"seq\":1,\"musicbrainz\":\"None\",\ \"primary_type\":\"Album\",\"secondary_types\":[]\ },\ {\ - \"title\":\"album_title b.b\",\"seq\":3,\ + \"title\":\"album_title b.b\",\"lib_id\":{\"Value\":4},\"seq\":3,\ \"musicbrainz\":{\"Some\":\"11111111-1111-1111-1111-111111111111\"},\ \"primary_type\":\"Album\",\"secondary_types\":[]\ },\ {\ - \"title\":\"album_title b.c\",\"seq\":2,\ + \"title\":\"album_title b.c\",\"lib_id\":{\"Value\":5},\"seq\":2,\ \"musicbrainz\":{\"Some\":\"11111111-1111-1111-1111-111111111112\"},\ \"primary_type\":\"Album\",\"secondary_types\":[]\ },\ {\ - \"title\":\"album_title b.d\",\"seq\":4,\"musicbrainz\":\"None\",\ + \"title\":\"album_title b.d\",\"lib_id\":{\"Value\":6},\"seq\":4,\"musicbrainz\":\"None\",\ \"primary_type\":\"Album\",\"secondary_types\":[]\ }\ ]\ @@ -61,11 +61,11 @@ pub static DATABASE_JSON: &str = "{\ \"properties\":{},\ \"albums\":[\ {\ - \"title\":\"album_title c.a\",\"seq\":0,\"musicbrainz\":\"None\",\ + \"title\":\"album_title c.a\",\"lib_id\":{\"Value\":7},\"seq\":0,\"musicbrainz\":\"None\",\ \"primary_type\":\"Album\",\"secondary_types\":[]\ },\ {\ - \"title\":\"album_title c.b\",\"seq\":0,\"musicbrainz\":\"None\",\ + \"title\":\"album_title c.b\",\"lib_id\":{\"Value\":8},\"seq\":0,\"musicbrainz\":\"None\",\ \"primary_type\":\"Album\",\"secondary_types\":[]\ }\ ]\ @@ -77,11 +77,11 @@ pub static DATABASE_JSON: &str = "{\ \"properties\":{},\ \"albums\":[\ {\ - \"title\":\"album_title d.a\",\"seq\":0,\"musicbrainz\":\"None\",\ + \"title\":\"album_title d.a\",\"lib_id\":{\"Value\":9},\"seq\":0,\"musicbrainz\":\"None\",\ \"primary_type\":\"Album\",\"secondary_types\":[]\ },\ {\ - \"title\":\"album_title d.b\",\"seq\":0,\"musicbrainz\":\"None\",\ + \"title\":\"album_title d.b\",\"lib_id\":{\"Value\":10},\"seq\":0,\"musicbrainz\":\"None\",\ \"primary_type\":\"Album\",\"secondary_types\":[]\ }\ ]\ diff --git a/src/external/database/serde/common.rs b/src/external/database/serde/common.rs index fb10599..ff75896 100644 --- a/src/external/database/serde/common.rs +++ b/src/external/database/serde/common.rs @@ -2,9 +2,17 @@ use serde::{Deserialize, Serialize}; use crate::{ collection::musicbrainz::MbRefOption, - core::collection::album::{AlbumPrimaryType, AlbumSecondaryType}, + core::collection::album::{AlbumLibId, AlbumPrimaryType, AlbumSecondaryType}, }; +#[derive(Debug, Deserialize, Serialize)] +#[serde(remote = "AlbumLibId")] +pub enum AlbumLibIdDef { + Value(u32), + Singleton, + None, +} + #[derive(Debug, Deserialize, Serialize)] #[serde(remote = "MbRefOption")] pub enum MbRefOptionDef { diff --git a/src/external/database/serde/deserialize.rs b/src/external/database/serde/deserialize.rs index e0ad951..5cddf35 100644 --- a/src/external/database/serde/deserialize.rs +++ b/src/external/database/serde/deserialize.rs @@ -4,7 +4,7 @@ use serde::{de::Visitor, Deserialize, Deserializer}; use crate::{ collection::{ - album::{AlbumInfo, AlbumMeta}, + album::{AlbumInfo, AlbumLibId, AlbumMeta}, artist::{ArtistInfo, ArtistMeta}, musicbrainz::{MbAlbumRef, MbArtistRef, MbRefOption, Mbid}, }, @@ -13,20 +13,20 @@ use crate::{ artist::{Artist, ArtistId}, Collection, Error as CollectionError, }, - external::database::serde::common::{SerdeAlbumPrimaryType, SerdeAlbumSecondaryType}, + external::database::serde::common::{ + AlbumLibIdDef, MbRefOptionDef, SerdeAlbumPrimaryType, SerdeAlbumSecondaryType, + }, }; -use super::common::MbRefOptionDef; - #[derive(Debug, Deserialize)] pub enum DeserializeDatabase { - V20240924(Vec), + V20250101(Vec), } impl From for Collection { fn from(database: DeserializeDatabase) -> Self { match database { - DeserializeDatabase::V20240924(collection) => { + DeserializeDatabase::V20250101(collection) => { collection.into_iter().map(Into::into).collect() } } @@ -45,12 +45,22 @@ pub struct DeserializeArtist { #[derive(Debug, Deserialize)] pub struct DeserializeAlbum { title: String, + lib_id: DeserializeAlbumLibId, seq: u8, musicbrainz: DeserializeMbRefOption, primary_type: Option, secondary_types: Vec, } +#[derive(Debug, Deserialize)] +pub struct DeserializeAlbumLibId(#[serde(with = "AlbumLibIdDef")] AlbumLibId); + +impl From for AlbumLibId { + fn from(value: DeserializeAlbumLibId) -> Self { + value.0 + } +} + #[derive(Debug, Deserialize)] pub struct DeserializeMbRefOption(#[serde(with = "MbRefOptionDef")] MbRefOption); @@ -129,7 +139,10 @@ impl From for Album { fn from(album: DeserializeAlbum) -> Self { Album { meta: AlbumMeta { - id: AlbumId { title: album.title }, + id: AlbumId { + title: album.title, + lib_id: album.lib_id.into(), + }, date: AlbumDate::default(), seq: AlbumSeq(album.seq), info: AlbumInfo { diff --git a/src/external/database/serde/serialize.rs b/src/external/database/serde/serialize.rs index bc50ce3..4ffd96b 100644 --- a/src/external/database/serde/serialize.rs +++ b/src/external/database/serde/serialize.rs @@ -3,21 +3,24 @@ use std::collections::BTreeMap; use serde::Serialize; use crate::{ - collection::musicbrainz::{MbRefOption, Mbid}, + collection::{ + album::AlbumLibId, + musicbrainz::{MbRefOption, Mbid}, + }, core::collection::{album::Album, artist::Artist, musicbrainz::IMusicBrainzRef, Collection}, external::database::serde::common::{ - MbRefOptionDef, SerdeAlbumPrimaryType, SerdeAlbumSecondaryType, + AlbumLibIdDef, MbRefOptionDef, SerdeAlbumPrimaryType, SerdeAlbumSecondaryType, }, }; #[derive(Debug, Serialize)] pub enum SerializeDatabase<'a> { - V20240924(Vec>), + V20250101(Vec>), } impl<'a> From<&'a Collection> for SerializeDatabase<'a> { fn from(collection: &'a Collection) -> Self { - SerializeDatabase::V20240924(collection.iter().map(Into::into).collect()) + SerializeDatabase::V20250101(collection.iter().map(Into::into).collect()) } } @@ -33,12 +36,22 @@ pub struct SerializeArtist<'a> { #[derive(Debug, Serialize)] pub struct SerializeAlbum<'a> { title: &'a str, + lib_id: SerializeAlbumLibId, seq: u8, musicbrainz: SerializeMbRefOption<'a>, primary_type: Option, secondary_types: Vec, } +#[derive(Debug, Serialize)] +pub struct SerializeAlbumLibId(#[serde(with = "AlbumLibIdDef")] AlbumLibId); + +impl From for SerializeAlbumLibId { + fn from(value: AlbumLibId) -> Self { + SerializeAlbumLibId(value) + } +} + #[derive(Debug, Serialize)] pub struct SerializeMbRefOption<'a>( #[serde(with = "MbRefOptionDef")] MbRefOption>, @@ -90,6 +103,7 @@ impl<'a> From<&'a Album> for SerializeAlbum<'a> { fn from(album: &'a Album) -> Self { SerializeAlbum { title: &album.meta.id.title, + lib_id: album.meta.id.lib_id.into(), seq: album.meta.seq.0, musicbrainz: (&album.meta.info.musicbrainz).into(), primary_type: album.meta.info.primary_type.map(Into::into), diff --git a/src/external/library/beets/mod.rs b/src/external/library/beets/mod.rs index e157029..e72bf56 100644 --- a/src/external/library/beets/mod.rs +++ b/src/external/library/beets/mod.rs @@ -6,9 +6,12 @@ pub mod executor; #[cfg(test)] use mockall::automock; -use crate::core::{ - collection::track::TrackFormat, - interface::library::{Error, Field, ILibrary, Item, Query}, +use crate::{ + collection::album::AlbumLibId, + core::{ + collection::track::TrackFormat, + interface::library::{Error, Field, ILibrary, Item, Query}, + }, }; macro_rules! list_format_separator { @@ -31,8 +34,12 @@ const LIST_FORMAT_ARG: &str = concat!( list_format_separator!(), "$day", list_format_separator!(), + "$singleton", + list_format_separator!(), "$album", list_format_separator!(), + "$album_id", + list_format_separator!(), "$track", list_format_separator!(), "$title", @@ -144,7 +151,7 @@ impl BeetsLibrary { } let split: Vec<&str> = line.split(LIST_FORMAT_SEPARATOR).collect(); - if split.len() != 11 { + if split.len() != 13 { return Err(Error::Invalid(line.to_string())); } @@ -156,15 +163,20 @@ impl BeetsLibrary { let album_year = split[2].parse::()?; let album_month = split[3].parse::()?; let album_day = split[4].parse::()?; - let album_title = split[5].to_string(); - let track_number = split[6].parse::()?; - let track_title = split[7].to_string(); - let track_artist = split[8].split("; ").map(|s| s.to_owned()).collect(); - let track_format = match str_to_format(split[9].to_string().as_str()) { + let singleton = split[5].to_lowercase().parse::()?; + let album_title = split[6].to_string(); + let album_lib_id = match singleton { + true => AlbumLibId::Singleton, + false => AlbumLibId::Value(split[7].parse::()?), + }; + let track_number = split[8].parse::()?; + let track_title = split[9].to_string(); + let track_artist = split[10].split("; ").map(|s| s.to_owned()).collect(); + let track_format = match str_to_format(split[11].to_string().as_str()) { Some(format) => format, None => return Err(Error::Invalid(line.to_string())), }; - let track_bitrate = split[10].trim_end_matches("kbps").parse::()?; + let track_bitrate = split[12].trim_end_matches("kbps").parse::()?; items.push(Item { album_artist, @@ -173,6 +185,7 @@ impl BeetsLibrary { album_month, album_day, album_title, + album_lib_id, track_number, track_title, track_artist, @@ -358,8 +371,8 @@ mod tests { .split(LIST_FORMAT_SEPARATOR) .map(|s| s.to_owned()) .collect::>(); - invalid_string[9].clear(); - invalid_string[9].push_str("invalid format"); + invalid_string[11].clear(); + invalid_string[11].push_str("invalid format"); let invalid_string = invalid_string.join(LIST_FORMAT_SEPARATOR); output[2] = invalid_string.clone(); let result = Ok(output); diff --git a/src/external/library/beets/testmod.rs b/src/external/library/beets/testmod.rs index b0fc10a..e75f1f4 100644 --- a/src/external/library/beets/testmod.rs +++ b/src/external/library/beets/testmod.rs @@ -4,112 +4,112 @@ pub static LIBRARY_BEETS: Lazy> = Lazy::new(|| -> Vec { vec![ String::from( "Album_Artist ‘A’ -*^- -*^- \ - 1998 -*^- 00 -*^- 00 -*^- album_title a.a -*^- \ + 1998 -*^- 00 -*^- 00 -*^- False -*^- album_title a.a -*^- 1 -*^- \ 1 -*^- track a.a.1 -*^- artist a.a.1 -*^- FLAC -*^- 992", ), String::from( "Album_Artist ‘A’ -*^- -*^- \ - 1998 -*^- 00 -*^- 00 -*^- album_title a.a -*^- \ + 1998 -*^- 00 -*^- 00 -*^- False -*^- album_title a.a -*^- 1 -*^- \ 2 -*^- track a.a.2 -*^- artist a.a.2.1; artist a.a.2.2 -*^- MP3 -*^- 320", ), String::from( "Album_Artist ‘A’ -*^- -*^- \ - 1998 -*^- 00 -*^- 00 -*^- album_title a.a -*^- \ + 1998 -*^- 00 -*^- 00 -*^- False -*^- album_title a.a -*^- 1 -*^- \ 3 -*^- track a.a.3 -*^- artist a.a.3 -*^- FLAC -*^- 1061", ), String::from( "Album_Artist ‘A’ -*^- -*^- \ - 1998 -*^- 00 -*^- 00 -*^- album_title a.a -*^- \ + 1998 -*^- 00 -*^- 00 -*^- False -*^- album_title a.a -*^- 1 -*^- \ 4 -*^- track a.a.4 -*^- artist a.a.4 -*^- FLAC -*^- 1042", ), String::from( "Album_Artist ‘A’ -*^- -*^- \ - 2015 -*^- 04 -*^- 00 -*^- album_title a.b -*^- \ + 2015 -*^- 04 -*^- 00 -*^- False -*^- album_title a.b -*^- 2 -*^- \ 1 -*^- track a.b.1 -*^- artist a.b.1 -*^- FLAC -*^- 1004", ), String::from( "Album_Artist ‘A’ -*^- -*^- \ - 2015 -*^- 04 -*^- 00 -*^- album_title a.b -*^- \ + 2015 -*^- 04 -*^- 00 -*^- False -*^- album_title a.b -*^- 2 -*^- \ 2 -*^- track a.b.2 -*^- artist a.b.2 -*^- FLAC -*^- 1077", ), String::from( "Album_Artist ‘B’ -*^- -*^- \ - 2003 -*^- 06 -*^- 06 -*^- album_title b.a -*^- \ + 2003 -*^- 06 -*^- 06 -*^- False -*^- album_title b.a -*^- 3 -*^- \ 1 -*^- track b.a.1 -*^- artist b.a.1 -*^- MP3 -*^- 190", ), String::from( "Album_Artist ‘B’ -*^- -*^- \ - 2003 -*^- 06 -*^- 06 -*^- album_title b.a -*^- \ + 2003 -*^- 06 -*^- 06 -*^- False -*^- album_title b.a -*^- 3 -*^- \ 2 -*^- track b.a.2 -*^- artist b.a.2.1; artist b.a.2.2 -*^- MP3 -*^- 120", ), String::from( "Album_Artist ‘B’ -*^- -*^- \ - 2008 -*^- 00 -*^- 00 -*^- album_title b.b -*^- \ + 2008 -*^- 00 -*^- 00 -*^- False -*^- album_title b.b -*^- 4 -*^- \ 1 -*^- track b.b.1 -*^- artist b.b.1 -*^- FLAC -*^- 1077", ), String::from( "Album_Artist ‘B’ -*^- -*^- \ - 2008 -*^- 00 -*^- 00 -*^- album_title b.b -*^- \ + 2008 -*^- 00 -*^- 00 -*^- False -*^- album_title b.b -*^- 4 -*^- \ 2 -*^- track b.b.2 -*^- artist b.b.2.1; artist b.b.2.2 -*^- MP3 -*^- 320", ), String::from( "Album_Artist ‘B’ -*^- -*^- \ - 2009 -*^- 00 -*^- 00 -*^- album_title b.c -*^- \ + 2009 -*^- 00 -*^- 00 -*^- False -*^- album_title b.c -*^- 5 -*^- \ 1 -*^- track b.c.1 -*^- artist b.c.1 -*^- MP3 -*^- 190", ), String::from( "Album_Artist ‘B’ -*^- -*^- \ - 2009 -*^- 00 -*^- 00 -*^- album_title b.c -*^- \ + 2009 -*^- 00 -*^- 00 -*^- False -*^- album_title b.c -*^- 5 -*^- \ 2 -*^- track b.c.2 -*^- artist b.c.2.1; artist b.c.2.2 -*^- MP3 -*^- 120", ), String::from( "Album_Artist ‘B’ -*^- -*^- \ - 2015 -*^- 00 -*^- 00 -*^- album_title b.d -*^- \ + 2015 -*^- 00 -*^- 00 -*^- False -*^- album_title b.d -*^- 6 -*^- \ 1 -*^- track b.d.1 -*^- artist b.d.1 -*^- MP3 -*^- 190", ), String::from( "Album_Artist ‘B’ -*^- -*^- \ - 2015 -*^- 00 -*^- 00 -*^- album_title b.d -*^- \ + 2015 -*^- 00 -*^- 00 -*^- False -*^- album_title b.d -*^- 6 -*^- \ 2 -*^- track b.d.2 -*^- artist b.d.2.1; artist b.d.2.2 -*^- MP3 -*^- 120", ), String::from( "The Album_Artist ‘C’ -*^- Album_Artist ‘C’, The -*^- \ - 1985 -*^- 00 -*^- 00 -*^- album_title c.a -*^- \ + 1985 -*^- 00 -*^- 00 -*^- False -*^- album_title c.a -*^- 7 -*^- \ 1 -*^- track c.a.1 -*^- artist c.a.1 -*^- MP3 -*^- 320", ), String::from( "The Album_Artist ‘C’ -*^- Album_Artist ‘C’, The -*^- \ - 1985 -*^- 00 -*^- 00 -*^- album_title c.a -*^- \ + 1985 -*^- 00 -*^- 00 -*^- False -*^- album_title c.a -*^- 7 -*^- \ 2 -*^- track c.a.2 -*^- artist c.a.2.1; artist c.a.2.2 -*^- MP3 -*^- 120", ), String::from( "The Album_Artist ‘C’ -*^- Album_Artist ‘C’, The -*^- \ - 2018 -*^- 00 -*^- 00 -*^- album_title c.b -*^- \ + 2018 -*^- 00 -*^- 00 -*^- False -*^- album_title c.b -*^- 8 -*^- \ 1 -*^- track c.b.1 -*^- artist c.b.1 -*^- FLAC -*^- 1041", ), String::from( "The Album_Artist ‘C’ -*^- Album_Artist ‘C’, The -*^- \ - 2018 -*^- 00 -*^- 00 -*^- album_title c.b -*^- \ + 2018 -*^- 00 -*^- 00 -*^- False -*^- album_title c.b -*^- 8 -*^- \ 2 -*^- track c.b.2 -*^- artist c.b.2.1; artist c.b.2.2 -*^- FLAC -*^- 756", ), String::from( "Album_Artist ‘D’ -*^- -*^- \ - 1995 -*^- 00 -*^- 00 -*^- album_title d.a -*^- \ + 1995 -*^- 00 -*^- 00 -*^- False -*^- album_title d.a -*^- 9 -*^- \ 1 -*^- track d.a.1 -*^- artist d.a.1 -*^- MP3 -*^- 120", ), String::from( "Album_Artist ‘D’ -*^- -*^- \ - 1995 -*^- 00 -*^- 00 -*^- album_title d.a -*^- \ + 1995 -*^- 00 -*^- 00 -*^- False -*^- album_title d.a -*^- 9 -*^- \ 2 -*^- track d.a.2 -*^- artist d.a.2.1; artist d.a.2.2 -*^- MP3 -*^- 120", ), String::from( "Album_Artist ‘D’ -*^- -*^- \ - 2028 -*^- 00 -*^- 00 -*^- album_title d.b -*^- \ + 2028 -*^- 00 -*^- 00 -*^- False -*^- album_title d.b -*^- 10 -*^- \ 1 -*^- track d.b.1 -*^- artist d.b.1 -*^- FLAC -*^- 841", ), String::from( "Album_Artist ‘D’ -*^- -*^- \ - 2028 -*^- 00 -*^- 00 -*^- album_title d.b -*^- \ + 2028 -*^- 00 -*^- 00 -*^- False -*^- album_title d.b -*^- 10 -*^- \ 2 -*^- track d.b.2 -*^- artist d.b.2.1; artist d.b.2.2 -*^- FLAC -*^- 756", ), ] diff --git a/src/external/musicbrainz/api/lookup.rs b/src/external/musicbrainz/api/lookup.rs index 82197d5..140eded 100644 --- a/src/external/musicbrainz/api/lookup.rs +++ b/src/external/musicbrainz/api/lookup.rs @@ -4,13 +4,14 @@ use url::form_urlencoded; use crate::{ collection::musicbrainz::Mbid, external::musicbrainz::{ - api::{Error, MusicBrainzClient, MB_BASE_URL}, + api::{ + Error, MbArtistMeta, MbReleaseGroupMeta, MusicBrainzClient, SerdeMbArtistMeta, + SerdeMbReleaseGroupMeta, MB_BASE_URL, + }, IMusicBrainzHttp, }, }; -use super::{MbArtistMeta, MbReleaseGroupMeta, SerdeMbArtistMeta, SerdeMbReleaseGroupMeta}; - impl MusicBrainzClient { pub fn lookup_artist( &mut self, diff --git a/src/testmod/full.rs b/src/testmod/full.rs index ea0f159..87e1cbc 100644 --- a/src/testmod/full.rs +++ b/src/testmod/full.rs @@ -28,6 +28,7 @@ macro_rules! full_collection { meta: AlbumMeta { id: AlbumId { title: "album_title a.a".to_string(), + lib_id: AlbumLibId::Value(1), }, date: 1998.into(), seq: AlbumSeq(1), @@ -93,6 +94,7 @@ macro_rules! full_collection { meta: AlbumMeta { id: AlbumId { title: "album_title a.b".to_string(), + lib_id: AlbumLibId::Value(2), }, date: (2015, 4).into(), seq: AlbumSeq(1), @@ -160,6 +162,7 @@ macro_rules! full_collection { meta: AlbumMeta { id: AlbumId { title: "album_title b.a".to_string(), + lib_id: AlbumLibId::Value(3), }, date: (2003, 6, 6).into(), seq: AlbumSeq(1), @@ -201,6 +204,7 @@ macro_rules! full_collection { meta: AlbumMeta { id: AlbumId { title: "album_title b.b".to_string(), + lib_id: AlbumLibId::Value(4), }, date: 2008.into(), seq: AlbumSeq(3), @@ -244,6 +248,7 @@ macro_rules! full_collection { meta: AlbumMeta { id: AlbumId { title: "album_title b.c".to_string(), + lib_id: AlbumLibId::Value(5), }, date: 2009.into(), seq: AlbumSeq(2), @@ -287,6 +292,7 @@ macro_rules! full_collection { meta: AlbumMeta { id: AlbumId { title: "album_title b.d".to_string(), + lib_id: AlbumLibId::Value(6), }, date: 2015.into(), seq: AlbumSeq(4), @@ -342,6 +348,7 @@ macro_rules! full_collection { meta: AlbumMeta { id: AlbumId { title: "album_title c.a".to_string(), + lib_id: AlbumLibId::Value(7), }, date: 1985.into(), seq: AlbumSeq(0), @@ -383,6 +390,7 @@ macro_rules! full_collection { meta: AlbumMeta { id: AlbumId { title: "album_title c.b".to_string(), + lib_id: AlbumLibId::Value(8), }, date: 2018.into(), seq: AlbumSeq(0), @@ -438,6 +446,7 @@ macro_rules! full_collection { meta: AlbumMeta { id: AlbumId { title: "album_title d.a".to_string(), + lib_id: AlbumLibId::Value(9), }, date: 1995.into(), seq: AlbumSeq(0), @@ -479,6 +488,7 @@ macro_rules! full_collection { meta: AlbumMeta { id: AlbumId { title: "album_title d.b".to_string(), + lib_id: AlbumLibId::Value(10), }, date: 2028.into(), seq: AlbumSeq(0), diff --git a/src/testmod/library.rs b/src/testmod/library.rs index 1024f23..a50b16c 100644 --- a/src/testmod/library.rs +++ b/src/testmod/library.rs @@ -18,6 +18,7 @@ macro_rules! library_collection { meta: AlbumMeta { id: AlbumId { title: "album_title a.a".to_string(), + lib_id: AlbumLibId::Value(1), }, date: 1998.into(), seq: AlbumSeq(0), @@ -77,6 +78,7 @@ macro_rules! library_collection { meta: AlbumMeta { id: AlbumId { title: "album_title a.b".to_string(), + lib_id: AlbumLibId::Value(2), }, date: (2015, 4).into(), seq: AlbumSeq(0), @@ -125,6 +127,7 @@ macro_rules! library_collection { meta: AlbumMeta { id: AlbumId { title: "album_title b.a".to_string(), + lib_id: AlbumLibId::Value(3), }, date: (2003, 6, 6).into(), seq: AlbumSeq(0), @@ -162,6 +165,7 @@ macro_rules! library_collection { meta: AlbumMeta { id: AlbumId { title: "album_title b.b".to_string(), + lib_id: AlbumLibId::Value(4), }, date: 2008.into(), seq: AlbumSeq(0), @@ -199,6 +203,7 @@ macro_rules! library_collection { meta: AlbumMeta { id: AlbumId { title: "album_title b.c".to_string(), + lib_id: AlbumLibId::Value(5), }, date: 2009.into(), seq: AlbumSeq(0), @@ -236,6 +241,7 @@ macro_rules! library_collection { meta: AlbumMeta { id: AlbumId { title: "album_title b.d".to_string(), + lib_id: AlbumLibId::Value(6), }, date: 2015.into(), seq: AlbumSeq(0), @@ -287,6 +293,7 @@ macro_rules! library_collection { meta: AlbumMeta { id: AlbumId { title: "album_title c.a".to_string(), + lib_id: AlbumLibId::Value(7), }, date: 1985.into(), seq: AlbumSeq(0), @@ -324,6 +331,7 @@ macro_rules! library_collection { meta: AlbumMeta { id: AlbumId { title: "album_title c.b".to_string(), + lib_id: AlbumLibId::Value(8), }, date: 2018.into(), seq: AlbumSeq(0), @@ -375,6 +383,7 @@ macro_rules! library_collection { meta: AlbumMeta { id: AlbumId { title: "album_title d.a".to_string(), + lib_id: AlbumLibId::Value(9), }, date: 1995.into(), seq: AlbumSeq(0), @@ -412,6 +421,7 @@ macro_rules! library_collection { meta: AlbumMeta { id: AlbumId { title: "album_title d.b".to_string(), + lib_id: AlbumLibId::Value(10), }, date: 2028.into(), seq: AlbumSeq(0), diff --git a/src/tui/testmod.rs b/src/tui/testmod.rs index 5b7ddc2..6624bac 100644 --- a/src/tui/testmod.rs +++ b/src/tui/testmod.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use musichoard::collection::{ - album::{Album, AlbumId, AlbumInfo, AlbumMeta, AlbumPrimaryType, AlbumSeq}, + album::{Album, AlbumId, AlbumInfo, AlbumLibId, AlbumMeta, AlbumPrimaryType, AlbumSeq}, artist::{Artist, ArtistId, ArtistInfo, ArtistMeta}, musicbrainz::{MbAlbumRef, MbArtistRef, MbRefOption}, track::{Track, TrackFormat, TrackId, TrackNum, TrackQuality}, diff --git a/src/tui/ui/display.rs b/src/tui/ui/display.rs index 0210688..68c2281 100644 --- a/src/tui/ui/display.rs +++ b/src/tui/ui/display.rs @@ -1,6 +1,7 @@ use musichoard::collection::{ album::{ - AlbumDate, AlbumId, AlbumMeta, AlbumPrimaryType, AlbumSecondaryType, AlbumSeq, AlbumStatus, + AlbumDate, AlbumId, AlbumLibId, AlbumMeta, AlbumPrimaryType, AlbumSecondaryType, AlbumSeq, + AlbumStatus, }, artist::ArtistMeta, musicbrainz::{IMusicBrainzRef, MbRefOption}, @@ -20,6 +21,14 @@ impl UiDisplay { } } + pub fn display_album_lib_id(lib_id: &AlbumLibId) -> String { + match lib_id { + AlbumLibId::Value(val) => val.to_string(), + AlbumLibId::Singleton => "Singleton".to_string(), + AlbumLibId::None => "None".to_string(), + } + } + pub fn display_album_date(date: &AlbumDate) -> String { match date.year { Some(year) => match date.month { @@ -196,6 +205,16 @@ mod tests { ); } + #[test] + fn display_album_lib_id() { + assert_eq!(UiDisplay::display_album_lib_id(&AlbumLibId::Value(5)), "5"); + assert_eq!( + UiDisplay::display_album_lib_id(&AlbumLibId::Singleton), + "Singleton" + ); + assert_eq!(UiDisplay::display_album_lib_id(&AlbumLibId::None), "None"); + } + #[test] fn display_date() { let date: AlbumDate = 1990.into(); diff --git a/src/tui/ui/info_state.rs b/src/tui/ui/info_state.rs index 684b914..4a99c0a 100644 --- a/src/tui/ui/info_state.rs +++ b/src/tui/ui/info_state.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use musichoard::collection::{album::Album, artist::Artist}; use ratatui::widgets::{ListState, Paragraph}; -use super::display::UiDisplay; +use crate::tui::ui::display::UiDisplay; struct InfoOverlay; @@ -101,8 +101,12 @@ impl<'a> AlbumOverlay<'a> { let properties = Paragraph::new(format!( "Album: {}\n\n{item_indent}\ + Library ID: {}\n{item_indent}\ MusicBrainz: {}", album.map(|a| a.meta.id.title.as_str()).unwrap_or(""), + album + .map(|a| UiDisplay::display_album_lib_id(&a.meta.id.lib_id)) + .unwrap_or_default(), album .map(|a| UiDisplay::display_mb_ref_option_as_url(&a.meta.info.musicbrainz)) .unwrap_or_default(), diff --git a/tests/files/database/database.json b/tests/files/database/database.json index 401d0d0..93fb18a 100644 --- a/tests/files/database/database.json +++ b/tests/files/database/database.json @@ -1 +1 @@ -{"V20240924":[{"name":"Аркона","sort":"Arkona","musicbrainz":{"Some":"baad262d-55ef-427a-83c7-f7530964f212"},"properties":{"Bandcamp":["https://arkonamoscow.bandcamp.com/"],"MusicButler":["https://www.musicbutler.io/artist-page/283448581"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/arkona/download-streaming-albums"]},"albums":[{"title":"Slovo","seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":[]}]},{"name":"Eluveitie","sort":null,"musicbrainz":{"Some":"8000598a-5edb-401c-8e6d-36b167feaf38"},"properties":{"MusicButler":["https://www.musicbutler.io/artist-page/269358403"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/eluveitie/download-streaming-albums"]},"albums":[{"title":"Vên [re‐recorded]","seq":0,"musicbrainz":"None","primary_type":"Ep","secondary_types":[]},{"title":"Slania","seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":[]}]},{"name":"Frontside","sort":null,"musicbrainz":{"Some":"3a901353-fccd-4afd-ad01-9c03f451b490"},"properties":{"MusicButler":["https://www.musicbutler.io/artist-page/826588800"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/frontside/download-streaming-albums"]},"albums":[{"title":"…nasze jest królestwo, potęga i chwała na wieki…","seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":[]}]},{"name":"Heaven’s Basement","sort":"Heaven’s Basement","musicbrainz":{"Some":"c2c4d56a-d599-4a18-bd2f-ae644e2198cc"},"properties":{"MusicButler":["https://www.musicbutler.io/artist-page/291158685"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/heaven-s-basement/download-streaming-albums"]},"albums":[{"title":"Paper Plague","seq":0,"musicbrainz":"None","primary_type":null,"secondary_types":[]},{"title":"Unbreakable","seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":[]}]},{"name":"Metallica","sort":null,"musicbrainz":{"Some":"65f4f0c5-ef9e-490c-aee3-909e7ae6b2ab"},"properties":{"MusicButler":["https://www.musicbutler.io/artist-page/3996865"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/metallica/download-streaming-albums"]},"albums":[{"title":"Ride the Lightning","seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":[]},{"title":"S&M","seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":["Live"]}]}]} \ No newline at end of file +{"V20250101":[{"name":"Аркона","sort":"Arkona","musicbrainz":{"Some":"baad262d-55ef-427a-83c7-f7530964f212"},"properties":{"Bandcamp":["https://arkonamoscow.bandcamp.com/"],"MusicButler":["https://www.musicbutler.io/artist-page/283448581"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/arkona/download-streaming-albums"]},"albums":[{"title":"Slovo","lib_id":{"Value":7},"seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":[]}]},{"name":"Eluveitie","sort":null,"musicbrainz":{"Some":"8000598a-5edb-401c-8e6d-36b167feaf38"},"properties":{"MusicButler":["https://www.musicbutler.io/artist-page/269358403"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/eluveitie/download-streaming-albums"]},"albums":[{"title":"Vên [re‐recorded]","lib_id":{"Value":1},"seq":0,"musicbrainz":"None","primary_type":"Ep","secondary_types":[]},{"title":"Slania","lib_id":{"Value":2},"seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":[]}]},{"name":"Frontside","sort":null,"musicbrainz":{"Some":"3a901353-fccd-4afd-ad01-9c03f451b490"},"properties":{"MusicButler":["https://www.musicbutler.io/artist-page/826588800"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/frontside/download-streaming-albums"]},"albums":[{"title":"…nasze jest królestwo, potęga i chwała na wieki…","lib_id":{"Value":3},"seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":[]}]},{"name":"Heaven’s Basement","sort":"Heaven’s Basement","musicbrainz":{"Some":"c2c4d56a-d599-4a18-bd2f-ae644e2198cc"},"properties":{"MusicButler":["https://www.musicbutler.io/artist-page/291158685"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/heaven-s-basement/download-streaming-albums"]},"albums":[{"title":"Paper Plague","lib_id":"Singleton","seq":0,"musicbrainz":"None","primary_type":null,"secondary_types":[]},{"title":"Unbreakable","lib_id":{"Value":4},"seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":[]}]},{"name":"Metallica","sort":null,"musicbrainz":{"Some":"65f4f0c5-ef9e-490c-aee3-909e7ae6b2ab"},"properties":{"MusicButler":["https://www.musicbutler.io/artist-page/3996865"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/metallica/download-streaming-albums"]},"albums":[{"title":"Ride the Lightning","lib_id":{"Value":5},"seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":[]},{"title":"S&M","lib_id":{"Value":6},"seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":["Live"]}]}]} \ No newline at end of file diff --git a/tests/library/testmod.rs b/tests/library/testmod.rs index ba62508..9889663 100644 --- a/tests/library/testmod.rs +++ b/tests/library/testmod.rs @@ -1,6 +1,9 @@ use once_cell::sync::Lazy; -use musichoard::{collection::track::TrackFormat, interface::library::Item}; +use musichoard::{ + collection::{album::AlbumLibId, track::TrackFormat}, + interface::library::Item, +}; pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { vec![ @@ -11,6 +14,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slovo"), + album_lib_id: AlbumLibId::Value(7), track_number: 1, track_title: String::from("Az’"), track_artist: vec![String::from("Аркона")], @@ -24,6 +28,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slovo"), + album_lib_id: AlbumLibId::Value(7), track_number: 2, track_title: String::from("Arkaim"), track_artist: vec![String::from("Аркона")], @@ -37,6 +42,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slovo"), + album_lib_id: AlbumLibId::Value(7), track_number: 3, track_title: String::from("Bol’no mne"), track_artist: vec![String::from("Аркона")], @@ -50,6 +56,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slovo"), + album_lib_id: AlbumLibId::Value(7), track_number: 4, track_title: String::from("Leshiy"), track_artist: vec![String::from("Аркона")], @@ -63,6 +70,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slovo"), + album_lib_id: AlbumLibId::Value(7), track_number: 5, track_title: String::from("Zakliatie"), track_artist: vec![String::from("Аркона")], @@ -76,6 +84,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slovo"), + album_lib_id: AlbumLibId::Value(7), track_number: 6, track_title: String::from("Predok"), track_artist: vec![String::from("Аркона")], @@ -89,6 +98,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slovo"), + album_lib_id: AlbumLibId::Value(7), track_number: 7, track_title: String::from("Nikogda"), track_artist: vec![String::from("Аркона")], @@ -102,6 +112,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slovo"), + album_lib_id: AlbumLibId::Value(7), track_number: 8, track_title: String::from("Tam za tumanami"), track_artist: vec![String::from("Аркона")], @@ -115,6 +126,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slovo"), + album_lib_id: AlbumLibId::Value(7), track_number: 9, track_title: String::from("Potomok"), track_artist: vec![String::from("Аркона")], @@ -128,6 +140,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slovo"), + album_lib_id: AlbumLibId::Value(7), track_number: 10, track_title: String::from("Slovo"), track_artist: vec![String::from("Аркона")], @@ -141,6 +154,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slovo"), + album_lib_id: AlbumLibId::Value(7), track_number: 11, track_title: String::from("Odna"), track_artist: vec![String::from("Аркона")], @@ -154,6 +168,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slovo"), + album_lib_id: AlbumLibId::Value(7), track_number: 12, track_title: String::from("Vo moiom sadochke…"), track_artist: vec![String::from("Аркона")], @@ -167,6 +182,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slovo"), + album_lib_id: AlbumLibId::Value(7), track_number: 13, track_title: String::from("Stenka na stenku"), track_artist: vec![String::from("Аркона")], @@ -180,6 +196,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slovo"), + album_lib_id: AlbumLibId::Value(7), track_number: 14, track_title: String::from("Zimushka"), track_artist: vec![String::from("Аркона")], @@ -193,6 +210,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Vên [re‐recorded]"), + album_lib_id: AlbumLibId::Value(1), track_number: 1, track_title: String::from("Verja Urit an Bitus"), track_artist: vec![String::from("Eluveitie")], @@ -206,6 +224,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Vên [re‐recorded]"), + album_lib_id: AlbumLibId::Value(1), track_number: 2, track_title: String::from("Uis Elveti"), track_artist: vec![String::from("Eluveitie")], @@ -219,6 +238,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Vên [re‐recorded]"), + album_lib_id: AlbumLibId::Value(1), track_number: 3, track_title: String::from("Ôrô"), track_artist: vec![String::from("Eluveitie")], @@ -232,6 +252,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Vên [re‐recorded]"), + album_lib_id: AlbumLibId::Value(1), track_number: 4, track_title: String::from("Lament"), track_artist: vec![String::from("Eluveitie")], @@ -245,6 +266,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Vên [re‐recorded]"), + album_lib_id: AlbumLibId::Value(1), track_number: 5, track_title: String::from("Druid"), track_artist: vec![String::from("Eluveitie")], @@ -258,6 +280,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Vên [re‐recorded]"), + album_lib_id: AlbumLibId::Value(1), track_number: 6, track_title: String::from("Jêzaïg"), track_artist: vec![String::from("Eluveitie")], @@ -271,6 +294,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slania"), + album_lib_id: AlbumLibId::Value(2), track_number: 1, track_title: String::from("Samon"), track_artist: vec![String::from("Eluveitie")], @@ -284,6 +308,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slania"), + album_lib_id: AlbumLibId::Value(2), track_number: 2, track_title: String::from("Primordial Breath"), track_artist: vec![String::from("Eluveitie")], @@ -297,6 +322,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slania"), + album_lib_id: AlbumLibId::Value(2), track_number: 3, track_title: String::from("Inis Mona"), track_artist: vec![String::from("Eluveitie")], @@ -310,6 +336,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slania"), + album_lib_id: AlbumLibId::Value(2), track_number: 4, track_title: String::from("Gray Sublime Archon"), track_artist: vec![String::from("Eluveitie")], @@ -323,6 +350,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slania"), + album_lib_id: AlbumLibId::Value(2), track_number: 5, track_title: String::from("Anagantios"), track_artist: vec![String::from("Eluveitie")], @@ -336,6 +364,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slania"), + album_lib_id: AlbumLibId::Value(2), track_number: 6, track_title: String::from("Bloodstained Ground"), track_artist: vec![String::from("Eluveitie")], @@ -349,6 +378,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slania"), + album_lib_id: AlbumLibId::Value(2), track_number: 7, track_title: String::from("The Somber Lay"), track_artist: vec![String::from("Eluveitie")], @@ -362,6 +392,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slania"), + album_lib_id: AlbumLibId::Value(2), track_number: 8, track_title: String::from("Slanias Song"), track_artist: vec![String::from("Eluveitie")], @@ -375,6 +406,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slania"), + album_lib_id: AlbumLibId::Value(2), track_number: 9, track_title: String::from("Giamonios"), track_artist: vec![String::from("Eluveitie")], @@ -388,6 +420,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slania"), + album_lib_id: AlbumLibId::Value(2), track_number: 10, track_title: String::from("Tarvos"), track_artist: vec![String::from("Eluveitie")], @@ -401,6 +434,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slania"), + album_lib_id: AlbumLibId::Value(2), track_number: 11, track_title: String::from("Calling the Rain"), track_artist: vec![String::from("Eluveitie")], @@ -414,6 +448,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Slania"), + album_lib_id: AlbumLibId::Value(2), track_number: 12, track_title: String::from("Elembivos"), track_artist: vec![String::from("Eluveitie")], @@ -427,6 +462,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("…nasze jest królestwo, potęga i chwała na wieki…"), + album_lib_id: AlbumLibId::Value(3), track_number: 1, track_title: String::from("Intro = Chaos"), track_artist: vec![String::from("Frontside")], @@ -440,6 +476,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("…nasze jest królestwo, potęga i chwała na wieki…"), + album_lib_id: AlbumLibId::Value(3), track_number: 2, track_title: String::from("Modlitwa"), track_artist: vec![String::from("Frontside")], @@ -453,6 +490,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("…nasze jest królestwo, potęga i chwała na wieki…"), + album_lib_id: AlbumLibId::Value(3), track_number: 3, track_title: String::from("Długa droga z piekła"), track_artist: vec![String::from("Frontside")], @@ -466,6 +504,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("…nasze jest królestwo, potęga i chwała na wieki…"), + album_lib_id: AlbumLibId::Value(3), track_number: 4, track_title: String::from("Synowie ognia"), track_artist: vec![String::from("Frontside")], @@ -479,6 +518,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("…nasze jest królestwo, potęga i chwała na wieki…"), + album_lib_id: AlbumLibId::Value(3), track_number: 5, track_title: String::from("1902"), track_artist: vec![String::from("Frontside")], @@ -492,6 +532,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("…nasze jest królestwo, potęga i chwała na wieki…"), + album_lib_id: AlbumLibId::Value(3), track_number: 6, track_title: String::from("Krew za krew"), track_artist: vec![String::from("Frontside")], @@ -505,6 +546,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("…nasze jest królestwo, potęga i chwała na wieki…"), + album_lib_id: AlbumLibId::Value(3), track_number: 7, track_title: String::from("Kulminacja"), track_artist: vec![String::from("Frontside")], @@ -518,6 +560,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("…nasze jest królestwo, potęga i chwała na wieki…"), + album_lib_id: AlbumLibId::Value(3), track_number: 8, track_title: String::from("Judasz"), track_artist: vec![String::from("Frontside")], @@ -531,6 +574,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("…nasze jest królestwo, potęga i chwała na wieki…"), + album_lib_id: AlbumLibId::Value(3), track_number: 9, track_title: String::from("Więzy"), track_artist: vec![String::from("Frontside")], @@ -544,6 +588,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("…nasze jest królestwo, potęga i chwała na wieki…"), + album_lib_id: AlbumLibId::Value(3), track_number: 10, track_title: String::from("Zagubione dusze"), track_artist: vec![String::from("Frontside")], @@ -557,6 +602,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("…nasze jest królestwo, potęga i chwała na wieki…"), + album_lib_id: AlbumLibId::Value(3), track_number: 11, track_title: String::from("Linia życia"), track_artist: vec![String::from("Frontside")], @@ -570,6 +616,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Paper Plague"), + album_lib_id: AlbumLibId::Singleton, track_number: 0, track_title: String::from("Paper Plague"), track_artist: vec![String::from("Heaven’s Basement")], @@ -583,6 +630,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Unbreakable"), + album_lib_id: AlbumLibId::Value(4), track_number: 1, track_title: String::from("Unbreakable"), track_artist: vec![String::from("Heaven’s Basement")], @@ -596,6 +644,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Unbreakable"), + album_lib_id: AlbumLibId::Value(4), track_number: 2, track_title: String::from("Guilt Trips and Sins"), track_artist: vec![String::from("Heaven’s Basement")], @@ -609,6 +658,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Unbreakable"), + album_lib_id: AlbumLibId::Value(4), track_number: 3, track_title: String::from("The Long Goodbye"), track_artist: vec![String::from("Heaven’s Basement")], @@ -622,6 +672,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Unbreakable"), + album_lib_id: AlbumLibId::Value(4), track_number: 4, track_title: String::from("Close Encounters"), track_artist: vec![String::from("Heaven’s Basement")], @@ -635,6 +686,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Unbreakable"), + album_lib_id: AlbumLibId::Value(4), track_number: 5, track_title: String::from("Paranoia"), track_artist: vec![String::from("Heaven’s Basement")], @@ -648,6 +700,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Unbreakable"), + album_lib_id: AlbumLibId::Value(4), track_number: 6, track_title: String::from("Let Me Out of Here"), track_artist: vec![String::from("Heaven’s Basement")], @@ -661,6 +714,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Unbreakable"), + album_lib_id: AlbumLibId::Value(4), track_number: 7, track_title: String::from("Leeches"), track_artist: vec![String::from("Heaven’s Basement")], @@ -674,6 +728,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Ride the Lightning"), + album_lib_id: AlbumLibId::Value(5), track_number: 1, track_title: String::from("Fight Fire with Fire"), track_artist: vec![String::from("Metallica")], @@ -687,6 +742,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Ride the Lightning"), + album_lib_id: AlbumLibId::Value(5), track_number: 2, track_title: String::from("Ride the Lightning"), track_artist: vec![String::from("Metallica")], @@ -700,6 +756,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Ride the Lightning"), + album_lib_id: AlbumLibId::Value(5), track_number: 3, track_title: String::from("For Whom the Bell Tolls"), track_artist: vec![String::from("Metallica")], @@ -713,6 +770,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Ride the Lightning"), + album_lib_id: AlbumLibId::Value(5), track_number: 4, track_title: String::from("Fade to Black"), track_artist: vec![String::from("Metallica")], @@ -726,6 +784,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Ride the Lightning"), + album_lib_id: AlbumLibId::Value(5), track_number: 5, track_title: String::from("Trapped under Ice"), track_artist: vec![String::from("Metallica")], @@ -739,6 +798,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Ride the Lightning"), + album_lib_id: AlbumLibId::Value(5), track_number: 6, track_title: String::from("Escape"), track_artist: vec![String::from("Metallica")], @@ -752,6 +812,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Ride the Lightning"), + album_lib_id: AlbumLibId::Value(5), track_number: 7, track_title: String::from("Creeping Death"), track_artist: vec![String::from("Metallica")], @@ -765,6 +826,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("Ride the Lightning"), + album_lib_id: AlbumLibId::Value(5), track_number: 8, track_title: String::from("The Call of Ktulu"), track_artist: vec![String::from("Metallica")], @@ -778,6 +840,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("S&M"), + album_lib_id: AlbumLibId::Value(6), track_number: 1, track_title: String::from("The Ecstasy of Gold"), track_artist: vec![String::from("Metallica")], @@ -791,6 +854,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("S&M"), + album_lib_id: AlbumLibId::Value(6), track_number: 2, track_title: String::from("The Call of Ktulu"), track_artist: vec![String::from("Metallica")], @@ -804,6 +868,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("S&M"), + album_lib_id: AlbumLibId::Value(6), track_number: 3, track_title: String::from("Master of Puppets"), track_artist: vec![String::from("Metallica")], @@ -817,6 +882,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("S&M"), + album_lib_id: AlbumLibId::Value(6), track_number: 4, track_title: String::from("Of Wolf and Man"), track_artist: vec![String::from("Metallica")], @@ -830,6 +896,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("S&M"), + album_lib_id: AlbumLibId::Value(6), track_number: 5, track_title: String::from("The Thing That Should Not Be"), track_artist: vec![String::from("Metallica")], @@ -843,6 +910,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("S&M"), + album_lib_id: AlbumLibId::Value(6), track_number: 6, track_title: String::from("Fuel"), track_artist: vec![String::from("Metallica")], @@ -856,6 +924,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("S&M"), + album_lib_id: AlbumLibId::Value(6), track_number: 7, track_title: String::from("The Memory Remains"), track_artist: vec![String::from("Metallica")], @@ -869,6 +938,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("S&M"), + album_lib_id: AlbumLibId::Value(6), track_number: 8, track_title: String::from("No Leaf Clover"), track_artist: vec![String::from("Metallica")], @@ -882,6 +952,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("S&M"), + album_lib_id: AlbumLibId::Value(6), track_number: 9, track_title: String::from("Hero of the Day"), track_artist: vec![String::from("Metallica")], @@ -895,6 +966,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("S&M"), + album_lib_id: AlbumLibId::Value(6), track_number: 10, track_title: String::from("Devil’s Dance"), track_artist: vec![String::from("Metallica")], @@ -908,6 +980,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("S&M"), + album_lib_id: AlbumLibId::Value(6), track_number: 11, track_title: String::from("Bleeding Me"), track_artist: vec![String::from("Metallica")], @@ -921,6 +994,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("S&M"), + album_lib_id: AlbumLibId::Value(6), track_number: 12, track_title: String::from("Nothing Else Matters"), track_artist: vec![String::from("Metallica")], @@ -934,6 +1008,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("S&M"), + album_lib_id: AlbumLibId::Value(6), track_number: 13, track_title: String::from("Until It Sleeps"), track_artist: vec![String::from("Metallica")], @@ -947,6 +1022,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("S&M"), + album_lib_id: AlbumLibId::Value(6), track_number: 14, track_title: String::from("For Whom the Bell Tolls"), track_artist: vec![String::from("Metallica")], @@ -960,6 +1036,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("S&M"), + album_lib_id: AlbumLibId::Value(6), track_number: 15, track_title: String::from("−Human"), track_artist: vec![String::from("Metallica")], @@ -973,6 +1050,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("S&M"), + album_lib_id: AlbumLibId::Value(6), track_number: 16, track_title: String::from("Wherever I May Roam"), track_artist: vec![String::from("Metallica")], @@ -986,6 +1064,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("S&M"), + album_lib_id: AlbumLibId::Value(6), track_number: 17, track_title: String::from("Outlaw Torn"), track_artist: vec![String::from("Metallica")], @@ -999,6 +1078,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("S&M"), + album_lib_id: AlbumLibId::Value(6), track_number: 18, track_title: String::from("Sad but True"), track_artist: vec![String::from("Metallica")], @@ -1012,6 +1092,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("S&M"), + album_lib_id: AlbumLibId::Value(6), track_number: 19, track_title: String::from("One"), track_artist: vec![String::from("Metallica")], @@ -1025,6 +1106,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("S&M"), + album_lib_id: AlbumLibId::Value(6), track_number: 20, track_title: String::from("Enter Sandman"), track_artist: vec![String::from("Metallica")], @@ -1038,6 +1120,7 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { album_month: 0, album_day: 0, album_title: String::from("S&M"), + album_lib_id: AlbumLibId::Value(6), track_number: 21, track_title: String::from("Battery"), track_artist: vec![String::from("Metallica")], diff --git a/tests/testlib.rs b/tests/testlib.rs index e0cd704..072b325 100644 --- a/tests/testlib.rs +++ b/tests/testlib.rs @@ -2,7 +2,10 @@ use once_cell::sync::Lazy; use std::collections::HashMap; use musichoard::collection::{ - album::{Album, AlbumId, AlbumInfo, AlbumMeta, AlbumPrimaryType, AlbumSecondaryType, AlbumSeq}, + album::{ + Album, AlbumId, AlbumInfo, AlbumLibId, AlbumMeta, AlbumPrimaryType, AlbumSecondaryType, + AlbumSeq, + }, artist::{Artist, ArtistId, ArtistInfo, ArtistMeta}, musicbrainz::{MbArtistRef, MbRefOption}, track::{Track, TrackFormat, TrackId, TrackNum, TrackQuality}, @@ -38,6 +41,7 @@ pub static COLLECTION: Lazy> = Lazy::new(|| -> Collection { meta: AlbumMeta { id: AlbumId { title: String::from("Slovo"), + lib_id: AlbumLibId::Value(7), }, date: 2011.into(), seq: AlbumSeq(0), @@ -230,6 +234,7 @@ pub static COLLECTION: Lazy> = Lazy::new(|| -> Collection { meta: AlbumMeta { id: AlbumId { title: String::from("Vên [re‐recorded]"), + lib_id: AlbumLibId::Value(1), }, date: 2004.into(), seq: AlbumSeq(0), @@ -312,6 +317,7 @@ pub static COLLECTION: Lazy> = Lazy::new(|| -> Collection { meta: AlbumMeta { id: AlbumId { title: String::from("Slania"), + lib_id: AlbumLibId::Value(2), }, date: 2008.into(), seq: AlbumSeq(0), @@ -482,6 +488,7 @@ pub static COLLECTION: Lazy> = Lazy::new(|| -> Collection { meta: AlbumMeta { id: AlbumId { title: String::from("…nasze jest królestwo, potęga i chwała na wieki…"), + lib_id: AlbumLibId::Value(3), }, date: 2001.into(), seq: AlbumSeq(0), @@ -640,6 +647,7 @@ pub static COLLECTION: Lazy> = Lazy::new(|| -> Collection { meta: AlbumMeta { id: AlbumId { title: String::from("Paper Plague"), + lib_id: AlbumLibId::Singleton, }, date: 2011.into(), seq: AlbumSeq(0), @@ -662,6 +670,7 @@ pub static COLLECTION: Lazy> = Lazy::new(|| -> Collection { meta: AlbumMeta { id: AlbumId { title: String::from("Unbreakable"), + lib_id: AlbumLibId::Value(4), }, date: 2011.into(), seq: AlbumSeq(0), @@ -777,6 +786,7 @@ pub static COLLECTION: Lazy> = Lazy::new(|| -> Collection { meta: AlbumMeta { id: AlbumId { title: String::from("Ride the Lightning"), + lib_id: AlbumLibId::Value(5), }, date: 1984.into(), seq: AlbumSeq(0), @@ -881,6 +891,7 @@ pub static COLLECTION: Lazy> = Lazy::new(|| -> Collection { meta: AlbumMeta { id: AlbumId { title: String::from("S&M"), + lib_id: AlbumLibId::Value(6), }, date: 1999.into(), seq: AlbumSeq(0),