Make MBID part of the album identifier to disambiguate MB clashes (#240)
Part 2 of #231 Reviewed-on: #240
This commit is contained in:
parent
2ecd4cb6af
commit
dee8cbea4e
@ -26,9 +26,8 @@ pub struct AlbumMeta {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Album non-identifier metadata.
|
/// Album non-identifier metadata.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||||
pub struct AlbumInfo {
|
pub struct AlbumInfo {
|
||||||
pub musicbrainz: MbRefOption<MbAlbumRef>,
|
|
||||||
pub primary_type: Option<AlbumPrimaryType>,
|
pub primary_type: Option<AlbumPrimaryType>,
|
||||||
pub secondary_types: Vec<AlbumSecondaryType>,
|
pub secondary_types: Vec<AlbumSecondaryType>,
|
||||||
}
|
}
|
||||||
@ -38,15 +37,7 @@ pub struct AlbumInfo {
|
|||||||
pub struct AlbumId {
|
pub struct AlbumId {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub lib_id: AlbumLibId,
|
pub lib_id: AlbumLibId,
|
||||||
}
|
pub db_id: AlbumDbId,
|
||||||
|
|
||||||
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.
|
/// Unique library identifier.
|
||||||
@ -63,6 +54,9 @@ impl AlbumLibId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unique database identifier. Use MBID for this purpose.
|
||||||
|
pub type AlbumDbId = MbRefOption<MbAlbumRef>;
|
||||||
|
|
||||||
// There are crates for handling dates, but we don't need much complexity beyond year-month-day.
|
// There are crates for handling dates, but we don't need much complexity beyond year-month-day.
|
||||||
/// The album's release date.
|
/// The album's release date.
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
@ -221,6 +215,14 @@ impl AlbumMeta {
|
|||||||
(&self.date, &self.seq, &self.id)
|
(&self.date, &self.seq, &self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_db_id(&mut self, db_id: AlbumDbId) {
|
||||||
|
self.id.set_db_id(db_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_db_id(&mut self) {
|
||||||
|
self.id.clear_db_id();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_seq(&mut self, seq: AlbumSeq) {
|
pub fn set_seq(&mut self, seq: AlbumSeq) {
|
||||||
self.seq = seq;
|
self.seq = seq;
|
||||||
}
|
}
|
||||||
@ -230,24 +232,12 @@ impl AlbumMeta {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for AlbumInfo {
|
|
||||||
fn default() -> Self {
|
|
||||||
AlbumInfo {
|
|
||||||
musicbrainz: MbRefOption::None,
|
|
||||||
primary_type: None,
|
|
||||||
secondary_types: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AlbumInfo {
|
impl AlbumInfo {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
musicbrainz: MbRefOption<MbAlbumRef>,
|
|
||||||
primary_type: Option<AlbumPrimaryType>,
|
primary_type: Option<AlbumPrimaryType>,
|
||||||
secondary_types: Vec<AlbumSecondaryType>,
|
secondary_types: Vec<AlbumSecondaryType>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
AlbumInfo {
|
AlbumInfo {
|
||||||
musicbrainz,
|
|
||||||
primary_type,
|
primary_type,
|
||||||
secondary_types,
|
secondary_types,
|
||||||
}
|
}
|
||||||
@ -269,6 +259,7 @@ impl Ord for AlbumMeta {
|
|||||||
impl Merge for AlbumMeta {
|
impl Merge for AlbumMeta {
|
||||||
fn merge_in_place(&mut self, other: Self) {
|
fn merge_in_place(&mut self, other: Self) {
|
||||||
assert!(self.id.compatible(&other.id));
|
assert!(self.id.compatible(&other.id));
|
||||||
|
self.id.db_id = self.id.db_id.take().or(other.id.db_id);
|
||||||
self.seq = std::cmp::max(self.seq, other.seq);
|
self.seq = std::cmp::max(self.seq, other.seq);
|
||||||
self.info.merge_in_place(other.info);
|
self.info.merge_in_place(other.info);
|
||||||
}
|
}
|
||||||
@ -276,7 +267,6 @@ impl Merge for AlbumMeta {
|
|||||||
|
|
||||||
impl Merge for AlbumInfo {
|
impl Merge for AlbumInfo {
|
||||||
fn merge_in_place(&mut self, other: Self) {
|
fn merge_in_place(&mut self, other: Self) {
|
||||||
self.musicbrainz = self.musicbrainz.take().or(other.musicbrainz);
|
|
||||||
self.primary_type = self.primary_type.take().or(other.primary_type);
|
self.primary_type = self.primary_type.take().or(other.primary_type);
|
||||||
if self.secondary_types.is_empty() {
|
if self.secondary_types.is_empty() {
|
||||||
self.secondary_types = other.secondary_types;
|
self.secondary_types = other.secondary_types;
|
||||||
@ -301,8 +291,31 @@ impl AlbumId {
|
|||||||
AlbumId {
|
AlbumId {
|
||||||
title: name.into(),
|
title: name.into(),
|
||||||
lib_id: AlbumLibId::None,
|
lib_id: AlbumLibId::None,
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_db_id(mut self, db_id: AlbumDbId) -> Self {
|
||||||
|
self.db_id = db_id;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_db_id(&mut self, db_id: AlbumDbId) {
|
||||||
|
self.db_id = db_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_db_id(&mut self) {
|
||||||
|
self.db_id = AlbumDbId::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
let db_id_compatible =
|
||||||
|
self.db_id.is_none() || other.db_id.is_none() || (self.db_id == other.db_id);
|
||||||
|
titles_compatible && lib_id_compatible && db_id_compatible
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for AlbumId {
|
impl Display for AlbumId {
|
||||||
|
@ -7,7 +7,7 @@ use crate::core::collection::Error;
|
|||||||
|
|
||||||
const MB_DOMAIN: &str = "musicbrainz.org";
|
const MB_DOMAIN: &str = "musicbrainz.org";
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct Mbid(Uuid);
|
pub struct Mbid(Uuid);
|
||||||
|
|
||||||
impl Mbid {
|
impl Mbid {
|
||||||
@ -38,7 +38,7 @@ try_from_impl_for_mbid!(&str);
|
|||||||
try_from_impl_for_mbid!(&String);
|
try_from_impl_for_mbid!(&String);
|
||||||
try_from_impl_for_mbid!(String);
|
try_from_impl_for_mbid!(String);
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub enum MbRefOption<T> {
|
pub enum MbRefOption<T> {
|
||||||
Some(T),
|
Some(T),
|
||||||
CannotHaveMbid,
|
CannotHaveMbid,
|
||||||
@ -70,7 +70,7 @@ impl<T> MbRefOption<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
struct MusicBrainzRef {
|
struct MusicBrainzRef {
|
||||||
mbid: Mbid,
|
mbid: Mbid,
|
||||||
url: Url,
|
url: Url,
|
||||||
@ -82,10 +82,10 @@ pub trait IMusicBrainzRef {
|
|||||||
fn entity() -> &'static str;
|
fn entity() -> &'static str;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct MbArtistRef(MusicBrainzRef);
|
pub struct MbArtistRef(MusicBrainzRef);
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct MbAlbumRef(MusicBrainzRef);
|
pub struct MbAlbumRef(MusicBrainzRef);
|
||||||
|
|
||||||
macro_rules! impl_imusicbrainzref {
|
macro_rules! impl_imusicbrainzref {
|
||||||
|
@ -2,7 +2,7 @@ use std::mem;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
collection::{
|
collection::{
|
||||||
album::{AlbumInfo, AlbumMeta},
|
album::{AlbumDbId, AlbumInfo, AlbumMeta},
|
||||||
artist::ArtistInfo,
|
artist::ArtistInfo,
|
||||||
merge::Merge,
|
merge::Merge,
|
||||||
},
|
},
|
||||||
@ -72,6 +72,17 @@ pub trait IMusicHoardDatabase {
|
|||||||
album_id: AlbumIdRef,
|
album_id: AlbumIdRef,
|
||||||
) -> Result<(), Error>;
|
) -> Result<(), Error>;
|
||||||
|
|
||||||
|
fn set_album_db_id<ArtistIdRef: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
|
||||||
|
&mut self,
|
||||||
|
artist_id: ArtistIdRef,
|
||||||
|
album_id: AlbumIdRef,
|
||||||
|
db_id: AlbumDbId,
|
||||||
|
) -> Result<(), Error>;
|
||||||
|
fn clear_album_db_id<ArtistIdRef: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
|
||||||
|
&mut self,
|
||||||
|
artist_id: ArtistIdRef,
|
||||||
|
album_id: AlbumIdRef,
|
||||||
|
) -> Result<(), Error>;
|
||||||
fn set_album_seq<ArtistIdRef: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
|
fn set_album_seq<ArtistIdRef: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
artist_id: ArtistIdRef,
|
artist_id: ArtistIdRef,
|
||||||
@ -242,6 +253,33 @@ impl<Database: IDatabase, Library> IMusicHoardDatabase for MusicHoard<Database,
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_album_db_id<ArtistIdRef: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
|
||||||
|
&mut self,
|
||||||
|
artist_id: ArtistIdRef,
|
||||||
|
album_id: AlbumIdRef,
|
||||||
|
db_id: AlbumDbId,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.update_album_and(
|
||||||
|
artist_id.as_ref(),
|
||||||
|
album_id.as_ref(),
|
||||||
|
|album| album.meta.set_db_id(db_id),
|
||||||
|
|artist| artist.albums.sort_unstable(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_album_db_id<ArtistIdRef: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
|
||||||
|
&mut self,
|
||||||
|
artist_id: ArtistIdRef,
|
||||||
|
album_id: AlbumIdRef,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.update_album_and(
|
||||||
|
artist_id.as_ref(),
|
||||||
|
album_id.as_ref(),
|
||||||
|
|album| album.meta.clear_db_id(),
|
||||||
|
|artist| artist.albums.sort_unstable(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn set_album_seq<ArtistIdRef: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
|
fn set_album_seq<ArtistIdRef: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
artist_id: ArtistIdRef,
|
artist_id: ArtistIdRef,
|
||||||
@ -708,6 +746,61 @@ mod tests {
|
|||||||
assert_eq!(music_hoard.collection, collection);
|
assert_eq!(music_hoard.collection, collection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn set_clear_album_db_id() {
|
||||||
|
let mut database = MockIDatabase::new();
|
||||||
|
|
||||||
|
let artist_id = ArtistId::new("an artist");
|
||||||
|
let mut album_id = AlbumId::new("an album");
|
||||||
|
let album_id_2 = AlbumId::new("another album");
|
||||||
|
|
||||||
|
let mut database_result = vec![Artist::new(artist_id.clone())];
|
||||||
|
database_result[0].albums.push(Album::new(album_id.clone()));
|
||||||
|
|
||||||
|
database
|
||||||
|
.expect_load()
|
||||||
|
.times(1)
|
||||||
|
.return_once(|| Ok(database_result));
|
||||||
|
database.expect_save().times(2).returning(|_| Ok(()));
|
||||||
|
|
||||||
|
let mut music_hoard = MusicHoard::database(database).unwrap();
|
||||||
|
let album = &music_hoard.collection[0].albums[0];
|
||||||
|
assert_eq!(album.meta.id.db_id, AlbumDbId::None);
|
||||||
|
|
||||||
|
// Seting db_id on an album not belonging to the artist is an error.
|
||||||
|
assert!(music_hoard
|
||||||
|
.set_album_db_id(&artist_id, &album_id_2, AlbumDbId::CannotHaveMbid)
|
||||||
|
.is_err());
|
||||||
|
let album = &music_hoard.collection[0].albums[0];
|
||||||
|
assert_eq!(album.meta.id.db_id, AlbumDbId::None);
|
||||||
|
|
||||||
|
// Set db_id.
|
||||||
|
assert!(music_hoard
|
||||||
|
.set_album_db_id(&artist_id, &album_id, AlbumDbId::CannotHaveMbid)
|
||||||
|
.is_ok());
|
||||||
|
let album = &music_hoard.collection[0].albums[0];
|
||||||
|
assert_eq!(album.meta.id.db_id, AlbumDbId::CannotHaveMbid);
|
||||||
|
|
||||||
|
// Clearing db_id on an album that does not exist is an error.
|
||||||
|
assert!(music_hoard
|
||||||
|
.clear_album_db_id(&artist_id, &album_id_2)
|
||||||
|
.is_err());
|
||||||
|
|
||||||
|
// Clearing db_id from album without the db_id set is an error. Effectively the album does
|
||||||
|
// not exist.
|
||||||
|
assert!(music_hoard
|
||||||
|
.clear_album_db_id(&artist_id, &album_id)
|
||||||
|
.is_err());
|
||||||
|
let album = &music_hoard.collection[0].albums[0];
|
||||||
|
assert_eq!(album.meta.id.db_id, AlbumDbId::CannotHaveMbid);
|
||||||
|
|
||||||
|
// To clear the db_id we need the album_id to have the db_id to identify the correct album.
|
||||||
|
album_id.set_db_id(AlbumDbId::CannotHaveMbid);
|
||||||
|
assert!(music_hoard.clear_album_db_id(&artist_id, &album_id).is_ok());
|
||||||
|
let album = &music_hoard.collection[0].albums[0];
|
||||||
|
assert_eq!(album.meta.id.db_id, AlbumDbId::None);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn set_clear_album_seq() {
|
fn set_clear_album_seq() {
|
||||||
let mut database = MockIDatabase::new();
|
let mut database = MockIDatabase::new();
|
||||||
@ -767,12 +860,10 @@ mod tests {
|
|||||||
let mut music_hoard = MusicHoard::database(database).unwrap();
|
let mut music_hoard = MusicHoard::database(database).unwrap();
|
||||||
|
|
||||||
let meta = &music_hoard.collection[0].albums[0].meta;
|
let meta = &music_hoard.collection[0].albums[0].meta;
|
||||||
assert_eq!(meta.info.musicbrainz, MbRefOption::None);
|
|
||||||
assert_eq!(meta.info.primary_type, None);
|
assert_eq!(meta.info.primary_type, None);
|
||||||
assert_eq!(meta.info.secondary_types, Vec::new());
|
assert_eq!(meta.info.secondary_types, Vec::new());
|
||||||
|
|
||||||
let info = AlbumInfo::new(
|
let info = AlbumInfo::new(
|
||||||
MbRefOption::CannotHaveMbid,
|
|
||||||
Some(AlbumPrimaryType::Album),
|
Some(AlbumPrimaryType::Album),
|
||||||
vec![AlbumSecondaryType::Live],
|
vec![AlbumSecondaryType::Live],
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::core::{
|
use crate::{
|
||||||
|
collection::album::AlbumDbId,
|
||||||
|
core::{
|
||||||
collection::{
|
collection::{
|
||||||
album::{Album, AlbumDate, AlbumId},
|
album::{Album, AlbumDate, AlbumId},
|
||||||
artist::{Artist, ArtistId},
|
artist::{Artist, ArtistId},
|
||||||
@ -15,6 +17,7 @@ use crate::core::{
|
|||||||
base::IMusicHoardBasePrivate, database::IMusicHoardDatabasePrivate, Error, MusicHoard,
|
base::IMusicHoardBasePrivate, database::IMusicHoardDatabasePrivate, Error, MusicHoard,
|
||||||
NoDatabase,
|
NoDatabase,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait IMusicHoardLibrary {
|
pub trait IMusicHoardLibrary {
|
||||||
@ -57,6 +60,7 @@ impl<Database, Library: ILibrary> MusicHoard<Database, Library> {
|
|||||||
let album_id = AlbumId {
|
let album_id = AlbumId {
|
||||||
title: item.album_title,
|
title: item.album_title,
|
||||||
lib_id: item.album_lib_id,
|
lib_id: item.album_lib_id,
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let album_date = AlbumDate {
|
let album_date = AlbumDate {
|
||||||
|
@ -2,7 +2,9 @@ use once_cell::sync::Lazy;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::core::collection::{
|
use crate::core::collection::{
|
||||||
album::{Album, AlbumId, AlbumInfo, AlbumLibId, AlbumMeta, AlbumPrimaryType, AlbumSeq},
|
album::{
|
||||||
|
Album, AlbumDbId, AlbumId, AlbumInfo, AlbumLibId, AlbumMeta, AlbumPrimaryType, AlbumSeq,
|
||||||
|
},
|
||||||
artist::{Artist, ArtistId, ArtistInfo, ArtistMeta},
|
artist::{Artist, ArtistId, ArtistInfo, ArtistMeta},
|
||||||
musicbrainz::{MbAlbumRef, MbArtistRef, MbRefOption},
|
musicbrainz::{MbAlbumRef, MbArtistRef, MbRefOption},
|
||||||
track::{Track, TrackFormat, TrackId, TrackNum, TrackQuality},
|
track::{Track, TrackFormat, TrackId, TrackNum, TrackQuality},
|
||||||
|
@ -142,11 +142,11 @@ impl From<DeserializeAlbum> for Album {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: album.title,
|
title: album.title,
|
||||||
lib_id: album.lib_id.into(),
|
lib_id: album.lib_id.into(),
|
||||||
|
db_id: album.musicbrainz.into(),
|
||||||
},
|
},
|
||||||
date: AlbumDate::default(),
|
date: AlbumDate::default(),
|
||||||
seq: AlbumSeq(album.seq),
|
seq: AlbumSeq(album.seq),
|
||||||
info: AlbumInfo {
|
info: AlbumInfo {
|
||||||
musicbrainz: album.musicbrainz.into(),
|
|
||||||
primary_type: album.primary_type.map(Into::into),
|
primary_type: album.primary_type.map(Into::into),
|
||||||
secondary_types: album.secondary_types.into_iter().map(Into::into).collect(),
|
secondary_types: album.secondary_types.into_iter().map(Into::into).collect(),
|
||||||
},
|
},
|
||||||
|
@ -105,7 +105,7 @@ impl<'a> From<&'a Album> for SerializeAlbum<'a> {
|
|||||||
title: &album.meta.id.title,
|
title: &album.meta.id.title,
|
||||||
lib_id: album.meta.id.lib_id.into(),
|
lib_id: album.meta.id.lib_id.into(),
|
||||||
seq: album.meta.seq.0,
|
seq: album.meta.seq.0,
|
||||||
musicbrainz: (&album.meta.info.musicbrainz).into(),
|
musicbrainz: (&album.meta.id.db_id).into(),
|
||||||
primary_type: album.meta.info.primary_type.map(Into::into),
|
primary_type: album.meta.info.primary_type.map(Into::into),
|
||||||
secondary_types: album
|
secondary_types: album
|
||||||
.meta
|
.meta
|
||||||
|
@ -29,13 +29,13 @@ macro_rules! full_collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: "album_title a.a".to_string(),
|
title: "album_title a.a".to_string(),
|
||||||
lib_id: AlbumLibId::Value(1),
|
lib_id: AlbumLibId::Value(1),
|
||||||
|
db_id: AlbumDbId::Some(MbAlbumRef::from_url_str(
|
||||||
|
"https://musicbrainz.org/release-group/00000000-0000-0000-0000-000000000000"
|
||||||
|
).unwrap()),
|
||||||
},
|
},
|
||||||
date: 1998.into(),
|
date: 1998.into(),
|
||||||
seq: AlbumSeq(1),
|
seq: AlbumSeq(1),
|
||||||
info: AlbumInfo {
|
info: AlbumInfo {
|
||||||
musicbrainz: MbRefOption::Some(MbAlbumRef::from_url_str(
|
|
||||||
"https://musicbrainz.org/release-group/00000000-0000-0000-0000-000000000000"
|
|
||||||
).unwrap()),
|
|
||||||
primary_type: Some(AlbumPrimaryType::Album),
|
primary_type: Some(AlbumPrimaryType::Album),
|
||||||
secondary_types: vec![],
|
secondary_types: vec![],
|
||||||
},
|
},
|
||||||
@ -95,11 +95,11 @@ macro_rules! full_collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: "album_title a.b".to_string(),
|
title: "album_title a.b".to_string(),
|
||||||
lib_id: AlbumLibId::Value(2),
|
lib_id: AlbumLibId::Value(2),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: (2015, 4).into(),
|
date: (2015, 4).into(),
|
||||||
seq: AlbumSeq(1),
|
seq: AlbumSeq(1),
|
||||||
info: AlbumInfo {
|
info: AlbumInfo {
|
||||||
musicbrainz: MbRefOption::None,
|
|
||||||
primary_type: Some(AlbumPrimaryType::Album),
|
primary_type: Some(AlbumPrimaryType::Album),
|
||||||
secondary_types: vec![],
|
secondary_types: vec![],
|
||||||
},
|
},
|
||||||
@ -163,11 +163,11 @@ macro_rules! full_collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: "album_title b.a".to_string(),
|
title: "album_title b.a".to_string(),
|
||||||
lib_id: AlbumLibId::Value(3),
|
lib_id: AlbumLibId::Value(3),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: (2003, 6, 6).into(),
|
date: (2003, 6, 6).into(),
|
||||||
seq: AlbumSeq(1),
|
seq: AlbumSeq(1),
|
||||||
info: AlbumInfo {
|
info: AlbumInfo {
|
||||||
musicbrainz: MbRefOption::None,
|
|
||||||
primary_type: Some(AlbumPrimaryType::Album),
|
primary_type: Some(AlbumPrimaryType::Album),
|
||||||
secondary_types: vec![],
|
secondary_types: vec![],
|
||||||
},
|
},
|
||||||
@ -205,13 +205,13 @@ macro_rules! full_collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: "album_title b.b".to_string(),
|
title: "album_title b.b".to_string(),
|
||||||
lib_id: AlbumLibId::Value(4),
|
lib_id: AlbumLibId::Value(4),
|
||||||
|
db_id: AlbumDbId::Some(MbAlbumRef::from_url_str(
|
||||||
|
"https://musicbrainz.org/release-group/11111111-1111-1111-1111-111111111111"
|
||||||
|
).unwrap()),
|
||||||
},
|
},
|
||||||
date: 2008.into(),
|
date: 2008.into(),
|
||||||
seq: AlbumSeq(3),
|
seq: AlbumSeq(3),
|
||||||
info: AlbumInfo {
|
info: AlbumInfo {
|
||||||
musicbrainz: MbRefOption::Some(MbAlbumRef::from_url_str(
|
|
||||||
"https://musicbrainz.org/release-group/11111111-1111-1111-1111-111111111111"
|
|
||||||
).unwrap()),
|
|
||||||
primary_type: Some(AlbumPrimaryType::Album),
|
primary_type: Some(AlbumPrimaryType::Album),
|
||||||
secondary_types: vec![],
|
secondary_types: vec![],
|
||||||
},
|
},
|
||||||
@ -249,13 +249,13 @@ macro_rules! full_collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: "album_title b.c".to_string(),
|
title: "album_title b.c".to_string(),
|
||||||
lib_id: AlbumLibId::Value(5),
|
lib_id: AlbumLibId::Value(5),
|
||||||
|
db_id: AlbumDbId::Some(MbAlbumRef::from_url_str(
|
||||||
|
"https://musicbrainz.org/release-group/11111111-1111-1111-1111-111111111112"
|
||||||
|
).unwrap()),
|
||||||
},
|
},
|
||||||
date: 2009.into(),
|
date: 2009.into(),
|
||||||
seq: AlbumSeq(2),
|
seq: AlbumSeq(2),
|
||||||
info: AlbumInfo {
|
info: AlbumInfo {
|
||||||
musicbrainz: MbRefOption::Some(MbAlbumRef::from_url_str(
|
|
||||||
"https://musicbrainz.org/release-group/11111111-1111-1111-1111-111111111112"
|
|
||||||
).unwrap()),
|
|
||||||
primary_type: Some(AlbumPrimaryType::Album),
|
primary_type: Some(AlbumPrimaryType::Album),
|
||||||
secondary_types: vec![],
|
secondary_types: vec![],
|
||||||
},
|
},
|
||||||
@ -293,11 +293,11 @@ macro_rules! full_collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: "album_title b.d".to_string(),
|
title: "album_title b.d".to_string(),
|
||||||
lib_id: AlbumLibId::Value(6),
|
lib_id: AlbumLibId::Value(6),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: 2015.into(),
|
date: 2015.into(),
|
||||||
seq: AlbumSeq(4),
|
seq: AlbumSeq(4),
|
||||||
info: AlbumInfo {
|
info: AlbumInfo {
|
||||||
musicbrainz: MbRefOption::None,
|
|
||||||
primary_type: Some(AlbumPrimaryType::Album),
|
primary_type: Some(AlbumPrimaryType::Album),
|
||||||
secondary_types: vec![],
|
secondary_types: vec![],
|
||||||
},
|
},
|
||||||
@ -349,11 +349,11 @@ macro_rules! full_collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: "album_title c.a".to_string(),
|
title: "album_title c.a".to_string(),
|
||||||
lib_id: AlbumLibId::Value(7),
|
lib_id: AlbumLibId::Value(7),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: 1985.into(),
|
date: 1985.into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
info: AlbumInfo {
|
info: AlbumInfo {
|
||||||
musicbrainz: MbRefOption::None,
|
|
||||||
primary_type: Some(AlbumPrimaryType::Album),
|
primary_type: Some(AlbumPrimaryType::Album),
|
||||||
secondary_types: vec![],
|
secondary_types: vec![],
|
||||||
},
|
},
|
||||||
@ -391,11 +391,11 @@ macro_rules! full_collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: "album_title c.b".to_string(),
|
title: "album_title c.b".to_string(),
|
||||||
lib_id: AlbumLibId::Value(8),
|
lib_id: AlbumLibId::Value(8),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: 2018.into(),
|
date: 2018.into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
info: AlbumInfo {
|
info: AlbumInfo {
|
||||||
musicbrainz: MbRefOption::None,
|
|
||||||
primary_type: Some(AlbumPrimaryType::Album),
|
primary_type: Some(AlbumPrimaryType::Album),
|
||||||
secondary_types: vec![],
|
secondary_types: vec![],
|
||||||
},
|
},
|
||||||
@ -447,11 +447,11 @@ macro_rules! full_collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: "album_title d.a".to_string(),
|
title: "album_title d.a".to_string(),
|
||||||
lib_id: AlbumLibId::Value(9),
|
lib_id: AlbumLibId::Value(9),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: 1995.into(),
|
date: 1995.into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
info: AlbumInfo {
|
info: AlbumInfo {
|
||||||
musicbrainz: MbRefOption::None,
|
|
||||||
primary_type: Some(AlbumPrimaryType::Album),
|
primary_type: Some(AlbumPrimaryType::Album),
|
||||||
secondary_types: vec![],
|
secondary_types: vec![],
|
||||||
},
|
},
|
||||||
@ -489,11 +489,11 @@ macro_rules! full_collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: "album_title d.b".to_string(),
|
title: "album_title d.b".to_string(),
|
||||||
lib_id: AlbumLibId::Value(10),
|
lib_id: AlbumLibId::Value(10),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: 2028.into(),
|
date: 2028.into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
info: AlbumInfo {
|
info: AlbumInfo {
|
||||||
musicbrainz: MbRefOption::None,
|
|
||||||
primary_type: Some(AlbumPrimaryType::Album),
|
primary_type: Some(AlbumPrimaryType::Album),
|
||||||
secondary_types: vec![],
|
secondary_types: vec![],
|
||||||
},
|
},
|
||||||
|
@ -19,6 +19,7 @@ macro_rules! library_collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: "album_title a.a".to_string(),
|
title: "album_title a.a".to_string(),
|
||||||
lib_id: AlbumLibId::Value(1),
|
lib_id: AlbumLibId::Value(1),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: 1998.into(),
|
date: 1998.into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
@ -79,6 +80,7 @@ macro_rules! library_collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: "album_title a.b".to_string(),
|
title: "album_title a.b".to_string(),
|
||||||
lib_id: AlbumLibId::Value(2),
|
lib_id: AlbumLibId::Value(2),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: (2015, 4).into(),
|
date: (2015, 4).into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
@ -128,6 +130,7 @@ macro_rules! library_collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: "album_title b.a".to_string(),
|
title: "album_title b.a".to_string(),
|
||||||
lib_id: AlbumLibId::Value(3),
|
lib_id: AlbumLibId::Value(3),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: (2003, 6, 6).into(),
|
date: (2003, 6, 6).into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
@ -166,6 +169,7 @@ macro_rules! library_collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: "album_title b.b".to_string(),
|
title: "album_title b.b".to_string(),
|
||||||
lib_id: AlbumLibId::Value(4),
|
lib_id: AlbumLibId::Value(4),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: 2008.into(),
|
date: 2008.into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
@ -204,6 +208,7 @@ macro_rules! library_collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: "album_title b.c".to_string(),
|
title: "album_title b.c".to_string(),
|
||||||
lib_id: AlbumLibId::Value(5),
|
lib_id: AlbumLibId::Value(5),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: 2009.into(),
|
date: 2009.into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
@ -242,6 +247,7 @@ macro_rules! library_collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: "album_title b.d".to_string(),
|
title: "album_title b.d".to_string(),
|
||||||
lib_id: AlbumLibId::Value(6),
|
lib_id: AlbumLibId::Value(6),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: 2015.into(),
|
date: 2015.into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
@ -294,6 +300,7 @@ macro_rules! library_collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: "album_title c.a".to_string(),
|
title: "album_title c.a".to_string(),
|
||||||
lib_id: AlbumLibId::Value(7),
|
lib_id: AlbumLibId::Value(7),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: 1985.into(),
|
date: 1985.into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
@ -332,6 +339,7 @@ macro_rules! library_collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: "album_title c.b".to_string(),
|
title: "album_title c.b".to_string(),
|
||||||
lib_id: AlbumLibId::Value(8),
|
lib_id: AlbumLibId::Value(8),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: 2018.into(),
|
date: 2018.into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
@ -384,6 +392,7 @@ macro_rules! library_collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: "album_title d.a".to_string(),
|
title: "album_title d.a".to_string(),
|
||||||
lib_id: AlbumLibId::Value(9),
|
lib_id: AlbumLibId::Value(9),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: 1995.into(),
|
date: 1995.into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
@ -422,6 +431,7 @@ macro_rules! library_collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: "album_title d.b".to_string(),
|
title: "album_title d.b".to_string(),
|
||||||
lib_id: AlbumLibId::Value(10),
|
lib_id: AlbumLibId::Value(10),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: 2028.into(),
|
date: 2028.into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
|
@ -213,7 +213,7 @@ impl AppMachine<FetchState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn album_match(old: &AlbumMeta, new: &AlbumMeta) -> bool {
|
fn album_match(old: &AlbumMeta, new: &AlbumMeta) -> bool {
|
||||||
old.info.musicbrainz.is_some() && (old.info.musicbrainz == new.info.musicbrainz)
|
old.id.db_id.is_some() && (old.id.db_id == new.id.db_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn app_lookup_artist(
|
pub fn app_lookup_artist(
|
||||||
@ -287,7 +287,7 @@ impl AppMachine<FetchState> {
|
|||||||
let arid = arid.mbid();
|
let arid = arid.mbid();
|
||||||
albums
|
albums
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|album| album.meta.info.musicbrainz.is_none())
|
.filter(|album| album.meta.id.db_id.is_none())
|
||||||
.map(|album| {
|
.map(|album| {
|
||||||
MbParams::search_release_group(artist.clone(), arid.clone(), album.meta.clone())
|
MbParams::search_release_group(artist.clone(), arid.clone(), album.meta.clone())
|
||||||
})
|
})
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
||||||
use musichoard::collection::{
|
use musichoard::collection::{
|
||||||
album::{AlbumInfo, AlbumMeta},
|
album::{AlbumDbId, AlbumInfo, AlbumMeta},
|
||||||
artist::{ArtistInfo, ArtistMeta},
|
artist::{ArtistInfo, ArtistMeta},
|
||||||
musicbrainz::{MbRefOption, Mbid},
|
musicbrainz::{MbRefOption, Mbid},
|
||||||
};
|
};
|
||||||
@ -12,6 +12,11 @@ use crate::tui::app::{
|
|||||||
MatchOption, MatchStatePublic, WidgetState,
|
MatchOption, MatchStatePublic, WidgetState,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AlbumInfoTuple {
|
||||||
|
db_id: AlbumDbId,
|
||||||
|
info: AlbumInfo,
|
||||||
|
}
|
||||||
|
|
||||||
trait GetInfoMeta {
|
trait GetInfoMeta {
|
||||||
type InfoType;
|
type InfoType;
|
||||||
}
|
}
|
||||||
@ -19,7 +24,7 @@ impl GetInfoMeta for ArtistMeta {
|
|||||||
type InfoType = ArtistInfo;
|
type InfoType = ArtistInfo;
|
||||||
}
|
}
|
||||||
impl GetInfoMeta for AlbumMeta {
|
impl GetInfoMeta for AlbumMeta {
|
||||||
type InfoType = AlbumInfo;
|
type InfoType = AlbumInfoTuple;
|
||||||
}
|
}
|
||||||
|
|
||||||
trait GetInfo {
|
trait GetInfo {
|
||||||
@ -47,16 +52,20 @@ impl GetInfo for MatchOption<ArtistMeta> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl GetInfo for MatchOption<AlbumMeta> {
|
impl GetInfo for MatchOption<AlbumMeta> {
|
||||||
type InfoType = AlbumInfo;
|
type InfoType = AlbumInfoTuple;
|
||||||
|
|
||||||
fn get_info(&self) -> InfoOption<Self::InfoType> {
|
fn get_info(&self) -> InfoOption<Self::InfoType> {
|
||||||
|
let db_id;
|
||||||
let mut info = AlbumInfo::default();
|
let mut info = AlbumInfo::default();
|
||||||
match self {
|
match self {
|
||||||
MatchOption::Some(option) => info = option.entity.info.clone(),
|
MatchOption::Some(option) => {
|
||||||
MatchOption::CannotHaveMbid => info.musicbrainz = MbRefOption::CannotHaveMbid,
|
db_id = option.entity.id.db_id.clone();
|
||||||
|
info = option.entity.info.clone();
|
||||||
|
}
|
||||||
|
MatchOption::CannotHaveMbid => db_id = AlbumDbId::CannotHaveMbid,
|
||||||
MatchOption::ManualInputMbid => return InfoOption::NeedInput,
|
MatchOption::ManualInputMbid => return InfoOption::NeedInput,
|
||||||
}
|
}
|
||||||
InfoOption::Info(info)
|
InfoOption::Info(AlbumInfoTuple { db_id, info })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,9 +241,11 @@ impl IAppInteractMatch for AppMachine<MatchState> {
|
|||||||
InfoOption::NeedInput => return self.get_input(),
|
InfoOption::NeedInput => return self.get_input(),
|
||||||
},
|
},
|
||||||
EntityMatches::Album(ref mut matches) => match matches.list.extract_info(index) {
|
EntityMatches::Album(ref mut matches) => match matches.list.extract_info(index) {
|
||||||
InfoOption::Info(info) => {
|
InfoOption::Info(tuple) => mh
|
||||||
mh.merge_album_info(&matches.artist, &matches.matching, info)
|
.merge_album_info(&matches.artist, &matches.matching, tuple.info)
|
||||||
}
|
.and_then(|()| {
|
||||||
|
mh.set_album_db_id(&matches.artist, &matches.matching, tuple.db_id)
|
||||||
|
}),
|
||||||
InfoOption::NeedInput => return self.get_input(),
|
InfoOption::NeedInput => return self.get_input(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -255,7 +266,10 @@ impl IAppInteractMatch for AppMachine<MatchState> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use std::{collections::VecDeque, sync::mpsc};
|
use std::{collections::VecDeque, sync::mpsc};
|
||||||
|
|
||||||
use mockall::predicate::{self, eq};
|
use mockall::{
|
||||||
|
predicate::{self, eq},
|
||||||
|
Sequence,
|
||||||
|
};
|
||||||
use musichoard::collection::{
|
use musichoard::collection::{
|
||||||
album::{AlbumDate, AlbumId, AlbumInfo, AlbumMeta, AlbumPrimaryType, AlbumSecondaryType},
|
album::{AlbumDate, AlbumId, AlbumInfo, AlbumMeta, AlbumPrimaryType, AlbumSecondaryType},
|
||||||
artist::{ArtistId, ArtistMeta},
|
artist::{ArtistId, ArtistMeta},
|
||||||
@ -315,14 +329,13 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn album_id() -> AlbumId {
|
fn album_id() -> AlbumId {
|
||||||
AlbumId::new("Album")
|
AlbumId::new("Album").with_db_id(MbRefOption::Some(mbid().into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn album_meta(id: AlbumId) -> AlbumMeta {
|
fn album_meta(id: AlbumId) -> AlbumMeta {
|
||||||
AlbumMeta::new(id)
|
AlbumMeta::new(id)
|
||||||
.with_date(AlbumDate::new(Some(1990), Some(5), None))
|
.with_date(AlbumDate::new(Some(1990), Some(5), None))
|
||||||
.with_info(AlbumInfo::new(
|
.with_info(AlbumInfo::new(
|
||||||
MbRefOption::Some(mbid().into()),
|
|
||||||
Some(AlbumPrimaryType::Album),
|
Some(AlbumPrimaryType::Album),
|
||||||
vec![AlbumSecondaryType::Live, AlbumSecondaryType::Compilation],
|
vec![AlbumSecondaryType::Live, AlbumSecondaryType::Compilation],
|
||||||
))
|
))
|
||||||
@ -330,7 +343,7 @@ mod tests {
|
|||||||
|
|
||||||
fn album_match() -> EntityMatches {
|
fn album_match() -> EntityMatches {
|
||||||
let artist_id = ArtistId::new("Artist");
|
let artist_id = ArtistId::new("Artist");
|
||||||
let album_id = album_id();
|
let mut album_id = album_id();
|
||||||
let album_meta = album_meta(album_id.clone());
|
let album_meta = album_meta(album_id.clone());
|
||||||
|
|
||||||
let album_1 = album_meta.clone();
|
let album_1 = album_meta.clone();
|
||||||
@ -341,14 +354,17 @@ mod tests {
|
|||||||
album_2.info.secondary_types.pop();
|
album_2.info.secondary_types.pop();
|
||||||
let album_match_2 = Entity::with_score(album_2, 100);
|
let album_match_2 = Entity::with_score(album_2, 100);
|
||||||
|
|
||||||
|
album_id.clear_db_id();
|
||||||
let list = vec![album_match_1.clone(), album_match_2.clone()];
|
let list = vec![album_match_1.clone(), album_match_2.clone()];
|
||||||
EntityMatches::album_search(artist_id, album_id, list)
|
EntityMatches::album_search(artist_id, album_id, list)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn album_lookup() -> EntityMatches {
|
fn album_lookup() -> EntityMatches {
|
||||||
let artist_id = ArtistId::new("Artist");
|
let artist_id = ArtistId::new("Artist");
|
||||||
let album_id = album_id();
|
let mut album_id = album_id();
|
||||||
let album_meta = album_meta(album_id.clone());
|
let album_meta = album_meta(album_id.clone());
|
||||||
|
|
||||||
|
album_id.clear_db_id();
|
||||||
let lookup = Entity::new(album_meta.clone());
|
let lookup = Entity::new(album_meta.clone());
|
||||||
EntityMatches::album_lookup(artist_id, album_id, lookup)
|
EntityMatches::album_lookup(artist_id, album_id, lookup)
|
||||||
}
|
}
|
||||||
@ -393,14 +409,21 @@ mod tests {
|
|||||||
match matches_info {
|
match matches_info {
|
||||||
EntityMatches::Album(_) => {
|
EntityMatches::Album(_) => {
|
||||||
let album_id = AlbumId::new("Album");
|
let album_id = AlbumId::new("Album");
|
||||||
let info = AlbumInfo {
|
let db_id = MbRefOption::CannotHaveMbid;
|
||||||
musicbrainz: MbRefOption::CannotHaveMbid,
|
let info = AlbumInfo::default();
|
||||||
..Default::default()
|
|
||||||
};
|
let mut seq = Sequence::new();
|
||||||
music_hoard
|
music_hoard
|
||||||
.expect_merge_album_info()
|
.expect_merge_album_info()
|
||||||
.with(eq(artist_id.clone()), eq(album_id.clone()), eq(info))
|
.with(eq(artist_id.clone()), eq(album_id.clone()), eq(info))
|
||||||
.times(1)
|
.times(1)
|
||||||
|
.in_sequence(&mut seq)
|
||||||
|
.return_once(|_, _, _| Ok(()));
|
||||||
|
music_hoard
|
||||||
|
.expect_set_album_db_id()
|
||||||
|
.with(eq(artist_id.clone()), eq(album_id.clone()), eq(db_id))
|
||||||
|
.times(1)
|
||||||
|
.in_sequence(&mut seq)
|
||||||
.return_once(|_, _, _| Ok(()));
|
.return_once(|_, _, _| Ok(()));
|
||||||
}
|
}
|
||||||
EntityMatches::Artist(_) => {
|
EntityMatches::Artist(_) => {
|
||||||
@ -515,11 +538,24 @@ mod tests {
|
|||||||
match matches_info {
|
match matches_info {
|
||||||
EntityMatches::Artist(_) => panic!(),
|
EntityMatches::Artist(_) => panic!(),
|
||||||
EntityMatches::Album(matches) => {
|
EntityMatches::Album(matches) => {
|
||||||
let meta = album_meta(album_id());
|
let mut album_id = album_id();
|
||||||
|
let meta = album_meta(album_id.clone());
|
||||||
|
let db_id = album_id.db_id.clone();
|
||||||
|
album_id.clear_db_id();
|
||||||
|
let artist = matches.artist.clone();
|
||||||
|
|
||||||
|
let mut seq = Sequence::new();
|
||||||
music_hoard
|
music_hoard
|
||||||
.expect_merge_album_info()
|
.expect_merge_album_info()
|
||||||
.with(eq(matches.artist), eq(meta.id), eq(meta.info))
|
.with(eq(artist.clone()), eq(album_id.clone()), eq(meta.info))
|
||||||
.times(1)
|
.times(1)
|
||||||
|
.in_sequence(&mut seq)
|
||||||
|
.return_once(|_, _, _| Ok(()));
|
||||||
|
music_hoard
|
||||||
|
.expect_set_album_db_id()
|
||||||
|
.with(eq(artist.clone()), eq(album_id.clone()), eq(db_id))
|
||||||
|
.times(1)
|
||||||
|
.in_sequence(&mut seq)
|
||||||
.return_once(|_, _, _| Ok(()));
|
.return_once(|_, _, _| Ok(()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
src/tui/lib/external/musicbrainz/api/mod.rs
vendored
9
src/tui/lib/external/musicbrainz/api/mod.rs
vendored
@ -4,7 +4,7 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use musichoard::{
|
use musichoard::{
|
||||||
collection::{
|
collection::{
|
||||||
album::{AlbumDate, AlbumInfo, AlbumMeta, AlbumSeq},
|
album::{AlbumDate, AlbumDbId, AlbumId, AlbumInfo, AlbumLibId, AlbumMeta, AlbumSeq},
|
||||||
artist::{ArtistInfo, ArtistMeta},
|
artist::{ArtistInfo, ArtistMeta},
|
||||||
musicbrainz::{MbRefOption, Mbid},
|
musicbrainz::{MbRefOption, Mbid},
|
||||||
},
|
},
|
||||||
@ -128,11 +128,14 @@ fn from_mb_artist_meta(meta: MbArtistMeta) -> (ArtistMeta, Option<String>) {
|
|||||||
|
|
||||||
fn from_mb_release_group_meta(meta: MbReleaseGroupMeta) -> AlbumMeta {
|
fn from_mb_release_group_meta(meta: MbReleaseGroupMeta) -> AlbumMeta {
|
||||||
AlbumMeta {
|
AlbumMeta {
|
||||||
id: meta.title.into(),
|
id: AlbumId {
|
||||||
|
title: meta.title,
|
||||||
|
lib_id: AlbumLibId::None,
|
||||||
|
db_id: AlbumDbId::Some(meta.id.into()),
|
||||||
|
},
|
||||||
date: meta.first_release_date,
|
date: meta.first_release_date,
|
||||||
seq: AlbumSeq::default(),
|
seq: AlbumSeq::default(),
|
||||||
info: AlbumInfo {
|
info: AlbumInfo {
|
||||||
musicbrainz: MbRefOption::Some(meta.id.into()),
|
|
||||||
primary_type: meta.primary_type,
|
primary_type: meta.primary_type,
|
||||||
secondary_types: meta.secondary_types.unwrap_or_default(),
|
secondary_types: meta.secondary_types.unwrap_or_default(),
|
||||||
},
|
},
|
||||||
|
@ -3,7 +3,7 @@ pub mod interface;
|
|||||||
|
|
||||||
use musichoard::{
|
use musichoard::{
|
||||||
collection::{
|
collection::{
|
||||||
album::{AlbumId, AlbumInfo, AlbumMeta},
|
album::{AlbumDbId, AlbumId, AlbumInfo, AlbumMeta},
|
||||||
artist::{ArtistId, ArtistInfo},
|
artist::{ArtistId, ArtistInfo},
|
||||||
Collection,
|
Collection,
|
||||||
},
|
},
|
||||||
@ -31,6 +31,12 @@ pub trait IMusicHoard {
|
|||||||
id: &ArtistId,
|
id: &ArtistId,
|
||||||
info: ArtistInfo,
|
info: ArtistInfo,
|
||||||
) -> Result<(), musichoard::Error>;
|
) -> Result<(), musichoard::Error>;
|
||||||
|
fn set_album_db_id(
|
||||||
|
&mut self,
|
||||||
|
artist_id: &ArtistId,
|
||||||
|
album_id: &AlbumId,
|
||||||
|
db_id: AlbumDbId,
|
||||||
|
) -> Result<(), musichoard::Error>;
|
||||||
fn merge_album_info(
|
fn merge_album_info(
|
||||||
&mut self,
|
&mut self,
|
||||||
artist_id: &ArtistId,
|
artist_id: &ArtistId,
|
||||||
@ -69,6 +75,15 @@ impl<Database: IDatabase, Library: ILibrary> IMusicHoard for MusicHoard<Database
|
|||||||
<Self as IMusicHoardDatabase>::merge_artist_info(self, id, info)
|
<Self as IMusicHoardDatabase>::merge_artist_info(self, id, info)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_album_db_id(
|
||||||
|
&mut self,
|
||||||
|
artist_id: &ArtistId,
|
||||||
|
album_id: &AlbumId,
|
||||||
|
db_id: AlbumDbId,
|
||||||
|
) -> Result<(), musichoard::Error> {
|
||||||
|
<Self as IMusicHoardDatabase>::set_album_db_id(self, artist_id, album_id, db_id)
|
||||||
|
}
|
||||||
|
|
||||||
fn merge_album_info(
|
fn merge_album_info(
|
||||||
&mut self,
|
&mut self,
|
||||||
artist_id: &ArtistId,
|
artist_id: &ArtistId,
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use musichoard::collection::{
|
use musichoard::collection::{
|
||||||
album::{Album, AlbumId, AlbumInfo, AlbumLibId, AlbumMeta, AlbumPrimaryType, AlbumSeq},
|
album::{
|
||||||
|
Album, AlbumDbId, AlbumId, AlbumInfo, AlbumLibId, AlbumMeta, AlbumPrimaryType, AlbumSeq,
|
||||||
|
},
|
||||||
artist::{Artist, ArtistId, ArtistInfo, ArtistMeta},
|
artist::{Artist, ArtistId, ArtistInfo, ArtistMeta},
|
||||||
musicbrainz::{MbAlbumRef, MbArtistRef, MbRefOption},
|
musicbrainz::{MbAlbumRef, MbArtistRef, MbRefOption},
|
||||||
track::{Track, TrackFormat, TrackId, TrackNum, TrackQuality},
|
track::{Track, TrackFormat, TrackId, TrackNum, TrackQuality},
|
||||||
|
@ -108,7 +108,7 @@ impl<'a> AlbumOverlay<'a> {
|
|||||||
.map(|a| UiDisplay::display_album_lib_id(&a.meta.id.lib_id))
|
.map(|a| UiDisplay::display_album_lib_id(&a.meta.id.lib_id))
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
album
|
album
|
||||||
.map(|a| UiDisplay::display_mb_ref_option_as_url(&a.meta.info.musicbrainz))
|
.map(|a| UiDisplay::display_mb_ref_option_as_url(&a.meta.id.db_id))
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -201,7 +201,6 @@ mod tests {
|
|||||||
use musichoard::collection::{
|
use musichoard::collection::{
|
||||||
album::{AlbumDate, AlbumId, AlbumInfo, AlbumMeta, AlbumPrimaryType, AlbumSecondaryType},
|
album::{AlbumDate, AlbumId, AlbumInfo, AlbumMeta, AlbumPrimaryType, AlbumSecondaryType},
|
||||||
artist::{Artist, ArtistId, ArtistMeta},
|
artist::{Artist, ArtistId, ArtistMeta},
|
||||||
musicbrainz::MbRefOption,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::tui::{
|
use crate::tui::{
|
||||||
@ -362,7 +361,6 @@ mod tests {
|
|||||||
AlbumMeta::new(id)
|
AlbumMeta::new(id)
|
||||||
.with_date(AlbumDate::new(Some(1990), Some(5), None))
|
.with_date(AlbumDate::new(Some(1990), Some(5), None))
|
||||||
.with_info(AlbumInfo::new(
|
.with_info(AlbumInfo::new(
|
||||||
MbRefOption::None,
|
|
||||||
Some(AlbumPrimaryType::Album),
|
Some(AlbumPrimaryType::Album),
|
||||||
vec![AlbumSecondaryType::Live, AlbumSecondaryType::Compilation],
|
vec![AlbumSecondaryType::Live, AlbumSecondaryType::Compilation],
|
||||||
))
|
))
|
||||||
|
@ -3,8 +3,8 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use musichoard::collection::{
|
use musichoard::collection::{
|
||||||
album::{
|
album::{
|
||||||
Album, AlbumId, AlbumInfo, AlbumLibId, AlbumMeta, AlbumPrimaryType, AlbumSecondaryType,
|
Album, AlbumDbId, AlbumId, AlbumInfo, AlbumLibId, AlbumMeta, AlbumPrimaryType,
|
||||||
AlbumSeq,
|
AlbumSecondaryType, AlbumSeq,
|
||||||
},
|
},
|
||||||
artist::{Artist, ArtistId, ArtistInfo, ArtistMeta},
|
artist::{Artist, ArtistId, ArtistInfo, ArtistMeta},
|
||||||
musicbrainz::{MbArtistRef, MbRefOption},
|
musicbrainz::{MbArtistRef, MbRefOption},
|
||||||
@ -42,11 +42,11 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: String::from("Slovo"),
|
title: String::from("Slovo"),
|
||||||
lib_id: AlbumLibId::Value(7),
|
lib_id: AlbumLibId::Value(7),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: 2011.into(),
|
date: 2011.into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
info: AlbumInfo {
|
info: AlbumInfo {
|
||||||
musicbrainz: MbRefOption::None,
|
|
||||||
primary_type: Some(AlbumPrimaryType::Album),
|
primary_type: Some(AlbumPrimaryType::Album),
|
||||||
secondary_types: vec![],
|
secondary_types: vec![],
|
||||||
},
|
},
|
||||||
@ -235,11 +235,11 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: String::from("Vên [re‐recorded]"),
|
title: String::from("Vên [re‐recorded]"),
|
||||||
lib_id: AlbumLibId::Value(1),
|
lib_id: AlbumLibId::Value(1),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: 2004.into(),
|
date: 2004.into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
info: AlbumInfo {
|
info: AlbumInfo {
|
||||||
musicbrainz: MbRefOption::None,
|
|
||||||
primary_type: Some(AlbumPrimaryType::Ep),
|
primary_type: Some(AlbumPrimaryType::Ep),
|
||||||
secondary_types: vec![],
|
secondary_types: vec![],
|
||||||
},
|
},
|
||||||
@ -318,11 +318,11 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: String::from("Slania"),
|
title: String::from("Slania"),
|
||||||
lib_id: AlbumLibId::Value(2),
|
lib_id: AlbumLibId::Value(2),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: 2008.into(),
|
date: 2008.into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
info: AlbumInfo {
|
info: AlbumInfo {
|
||||||
musicbrainz: MbRefOption::None,
|
|
||||||
primary_type: Some(AlbumPrimaryType::Album),
|
primary_type: Some(AlbumPrimaryType::Album),
|
||||||
secondary_types: vec![],
|
secondary_types: vec![],
|
||||||
},
|
},
|
||||||
@ -489,11 +489,11 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: String::from("…nasze jest królestwo, potęga i chwała na wieki…"),
|
title: String::from("…nasze jest królestwo, potęga i chwała na wieki…"),
|
||||||
lib_id: AlbumLibId::Value(3),
|
lib_id: AlbumLibId::Value(3),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: 2001.into(),
|
date: 2001.into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
info: AlbumInfo {
|
info: AlbumInfo {
|
||||||
musicbrainz: MbRefOption::None,
|
|
||||||
primary_type: Some(AlbumPrimaryType::Album),
|
primary_type: Some(AlbumPrimaryType::Album),
|
||||||
secondary_types: vec![],
|
secondary_types: vec![],
|
||||||
},
|
},
|
||||||
@ -648,6 +648,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: String::from("Paper Plague"),
|
title: String::from("Paper Plague"),
|
||||||
lib_id: AlbumLibId::Singleton,
|
lib_id: AlbumLibId::Singleton,
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: 2011.into(),
|
date: 2011.into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
@ -671,11 +672,11 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: String::from("Unbreakable"),
|
title: String::from("Unbreakable"),
|
||||||
lib_id: AlbumLibId::Value(4),
|
lib_id: AlbumLibId::Value(4),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: 2011.into(),
|
date: 2011.into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
info: AlbumInfo {
|
info: AlbumInfo {
|
||||||
musicbrainz: MbRefOption::None,
|
|
||||||
primary_type: Some(AlbumPrimaryType::Album),
|
primary_type: Some(AlbumPrimaryType::Album),
|
||||||
secondary_types: vec![],
|
secondary_types: vec![],
|
||||||
},
|
},
|
||||||
@ -787,11 +788,11 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: String::from("Ride the Lightning"),
|
title: String::from("Ride the Lightning"),
|
||||||
lib_id: AlbumLibId::Value(5),
|
lib_id: AlbumLibId::Value(5),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: 1984.into(),
|
date: 1984.into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
info: AlbumInfo {
|
info: AlbumInfo {
|
||||||
musicbrainz: MbRefOption::None,
|
|
||||||
primary_type: Some(AlbumPrimaryType::Album),
|
primary_type: Some(AlbumPrimaryType::Album),
|
||||||
secondary_types: vec![],
|
secondary_types: vec![],
|
||||||
},
|
},
|
||||||
@ -892,11 +893,11 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
|||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
title: String::from("S&M"),
|
title: String::from("S&M"),
|
||||||
lib_id: AlbumLibId::Value(6),
|
lib_id: AlbumLibId::Value(6),
|
||||||
|
db_id: AlbumDbId::None,
|
||||||
},
|
},
|
||||||
date: 1999.into(),
|
date: 1999.into(),
|
||||||
seq: AlbumSeq(0),
|
seq: AlbumSeq(0),
|
||||||
info: AlbumInfo {
|
info: AlbumInfo {
|
||||||
musicbrainz: MbRefOption::None,
|
|
||||||
primary_type: Some(AlbumPrimaryType::Album),
|
primary_type: Some(AlbumPrimaryType::Album),
|
||||||
secondary_types: vec![AlbumSecondaryType::Live],
|
secondary_types: vec![AlbumSecondaryType::Live],
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user