Enable fetch to apply modifications to the database #221
@ -206,7 +206,7 @@ impl MusicBrainzCommand {
|
|||||||
fn handle(self, music_hoard: &mut MH, artist_name: &str) {
|
fn handle(self, music_hoard: &mut MH, artist_name: &str) {
|
||||||
match self {
|
match self {
|
||||||
MusicBrainzCommand::Set(musicbrainz_value) => music_hoard
|
MusicBrainzCommand::Set(musicbrainz_value) => music_hoard
|
||||||
.set_artist_musicbrainz(ArtistId::new(artist_name), musicbrainz_value.url)
|
.set_artist_musicbrainz_from_url(ArtistId::new(artist_name), musicbrainz_value.url)
|
||||||
.expect("failed to set MusicBrainz URL"),
|
.expect("failed to set MusicBrainz URL"),
|
||||||
MusicBrainzCommand::Clear => music_hoard
|
MusicBrainzCommand::Clear => music_hoard
|
||||||
.clear_artist_musicbrainz(ArtistId::new(artist_name))
|
.clear_artist_musicbrainz(ArtistId::new(artist_name))
|
||||||
|
@ -204,13 +204,29 @@ impl AlbumMeta {
|
|||||||
self.seq = AlbumSeq::default();
|
self.seq = AlbumSeq::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_musicbrainz_ref(&mut self, mbref: MbAlbumRef) {
|
pub fn set_musicbrainz_ref(&mut self, mbref: MbRefOption<MbAlbumRef>) {
|
||||||
self.musicbrainz.replace(mbref);
|
_ = mem::replace(&mut self.musicbrainz, mbref);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_musicbrainz_ref(&mut self) {
|
pub fn clear_musicbrainz_ref(&mut self) {
|
||||||
self.musicbrainz.take();
|
self.musicbrainz.take();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_primary_type(&mut self, primary_type: Option<AlbumPrimaryType>) {
|
||||||
|
_ = mem::replace(&mut self.primary_type, primary_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_primary_type(&mut self) {
|
||||||
|
self.primary_type.take();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_secondary_types(&mut self, secondary_types: Vec<AlbumSecondaryType>) {
|
||||||
|
self.secondary_types = secondary_types;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_secondary_types(&mut self) {
|
||||||
|
self.secondary_types.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for AlbumMeta {
|
impl PartialOrd for AlbumMeta {
|
||||||
@ -368,20 +384,20 @@ mod tests {
|
|||||||
assert_eq!(album.meta.musicbrainz, expected);
|
assert_eq!(album.meta.musicbrainz, expected);
|
||||||
|
|
||||||
// Setting a URL on an album.
|
// Setting a URL on an album.
|
||||||
album
|
album.meta.set_musicbrainz_ref(MbRefOption::Some(
|
||||||
.meta
|
MbAlbumRef::from_url_str(MUSICBRAINZ).unwrap(),
|
||||||
.set_musicbrainz_ref(MbAlbumRef::from_url_str(MUSICBRAINZ).unwrap());
|
));
|
||||||
expected.replace(MbAlbumRef::from_url_str(MUSICBRAINZ).unwrap());
|
expected.replace(MbAlbumRef::from_url_str(MUSICBRAINZ).unwrap());
|
||||||
assert_eq!(album.meta.musicbrainz, expected);
|
assert_eq!(album.meta.musicbrainz, expected);
|
||||||
|
|
||||||
album
|
album.meta.set_musicbrainz_ref(MbRefOption::Some(
|
||||||
.meta
|
MbAlbumRef::from_url_str(MUSICBRAINZ).unwrap(),
|
||||||
.set_musicbrainz_ref(MbAlbumRef::from_url_str(MUSICBRAINZ).unwrap());
|
));
|
||||||
assert_eq!(album.meta.musicbrainz, expected);
|
assert_eq!(album.meta.musicbrainz, expected);
|
||||||
|
|
||||||
album
|
album.meta.set_musicbrainz_ref(MbRefOption::Some(
|
||||||
.meta
|
MbAlbumRef::from_url_str(MUSICBRAINZ_2).unwrap(),
|
||||||
.set_musicbrainz_ref(MbAlbumRef::from_url_str(MUSICBRAINZ_2).unwrap());
|
));
|
||||||
expected.replace(MbAlbumRef::from_url_str(MUSICBRAINZ_2).unwrap());
|
expected.replace(MbAlbumRef::from_url_str(MUSICBRAINZ_2).unwrap());
|
||||||
assert_eq!(album.meta.musicbrainz, expected);
|
assert_eq!(album.meta.musicbrainz, expected);
|
||||||
|
|
||||||
|
@ -92,8 +92,8 @@ impl ArtistMeta {
|
|||||||
self.sort.take();
|
self.sort.take();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_musicbrainz_ref(&mut self, mbref: MbArtistRef) {
|
pub fn set_musicbrainz_ref(&mut self, mbref: MbRefOption<MbArtistRef>) {
|
||||||
self.musicbrainz.replace(mbref);
|
self.musicbrainz = mbref
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_musicbrainz_ref(&mut self) {
|
pub fn clear_musicbrainz_ref(&mut self) {
|
||||||
@ -259,20 +259,20 @@ mod tests {
|
|||||||
assert_eq!(artist.meta.musicbrainz, expected);
|
assert_eq!(artist.meta.musicbrainz, expected);
|
||||||
|
|
||||||
// Setting a URL on an artist.
|
// Setting a URL on an artist.
|
||||||
artist
|
artist.meta.set_musicbrainz_ref(MbRefOption::Some(
|
||||||
.meta
|
MbArtistRef::from_url_str(MUSICBRAINZ).unwrap(),
|
||||||
.set_musicbrainz_ref(MbArtistRef::from_url_str(MUSICBRAINZ).unwrap());
|
));
|
||||||
expected.replace(MbArtistRef::from_url_str(MUSICBRAINZ).unwrap());
|
expected.replace(MbArtistRef::from_url_str(MUSICBRAINZ).unwrap());
|
||||||
assert_eq!(artist.meta.musicbrainz, expected);
|
assert_eq!(artist.meta.musicbrainz, expected);
|
||||||
|
|
||||||
artist
|
artist.meta.set_musicbrainz_ref(MbRefOption::Some(
|
||||||
.meta
|
MbArtistRef::from_url_str(MUSICBRAINZ).unwrap(),
|
||||||
.set_musicbrainz_ref(MbArtistRef::from_url_str(MUSICBRAINZ).unwrap());
|
));
|
||||||
assert_eq!(artist.meta.musicbrainz, expected);
|
assert_eq!(artist.meta.musicbrainz, expected);
|
||||||
|
|
||||||
artist
|
artist.meta.set_musicbrainz_ref(MbRefOption::Some(
|
||||||
.meta
|
MbArtistRef::from_url_str(MUSICBRAINZ_2).unwrap(),
|
||||||
.set_musicbrainz_ref(MbArtistRef::from_url_str(MUSICBRAINZ_2).unwrap());
|
));
|
||||||
expected.replace(MbArtistRef::from_url_str(MUSICBRAINZ_2).unwrap());
|
expected.replace(MbArtistRef::from_url_str(MUSICBRAINZ_2).unwrap());
|
||||||
assert_eq!(artist.meta.musicbrainz, expected);
|
assert_eq!(artist.meta.musicbrainz, expected);
|
||||||
|
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
use crate::core::{
|
use crate::{
|
||||||
|
collection::{
|
||||||
|
album::{AlbumPrimaryType, AlbumSecondaryType},
|
||||||
|
musicbrainz::{MbAlbumRef, MbRefOption},
|
||||||
|
},
|
||||||
|
core::{
|
||||||
collection::{
|
collection::{
|
||||||
album::{Album, AlbumId, AlbumSeq},
|
album::{Album, AlbumId, AlbumSeq},
|
||||||
artist::{Artist, ArtistId},
|
artist::{Artist, ArtistId},
|
||||||
@ -7,6 +12,7 @@ use crate::core::{
|
|||||||
},
|
},
|
||||||
interface::database::IDatabase,
|
interface::database::IDatabase,
|
||||||
musichoard::{base::IMusicHoardBasePrivate, Error, MusicHoard, NoDatabase},
|
musichoard::{base::IMusicHoardBasePrivate, Error, MusicHoard, NoDatabase},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait IMusicHoardDatabase {
|
pub trait IMusicHoardDatabase {
|
||||||
@ -22,7 +28,12 @@ pub trait IMusicHoardDatabase {
|
|||||||
) -> Result<(), Error>;
|
) -> Result<(), Error>;
|
||||||
fn clear_artist_sort<Id: AsRef<ArtistId>>(&mut self, artist_id: Id) -> Result<(), Error>;
|
fn clear_artist_sort<Id: AsRef<ArtistId>>(&mut self, artist_id: Id) -> Result<(), Error>;
|
||||||
|
|
||||||
fn set_artist_musicbrainz<Id: AsRef<ArtistId>, S: AsRef<str>>(
|
fn set_artist_musicbrainz<Id: AsRef<ArtistId>>(
|
||||||
|
&mut self,
|
||||||
|
artist_id: Id,
|
||||||
|
mbid: MbRefOption<MbArtistRef>,
|
||||||
|
) -> Result<(), Error>;
|
||||||
|
fn set_artist_musicbrainz_from_url<Id: AsRef<ArtistId>, S: AsRef<str>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
artist_id: Id,
|
artist_id: Id,
|
||||||
url: S,
|
url: S,
|
||||||
@ -54,6 +65,17 @@ pub trait IMusicHoardDatabase {
|
|||||||
property: S,
|
property: S,
|
||||||
) -> Result<(), Error>;
|
) -> Result<(), Error>;
|
||||||
|
|
||||||
|
fn set_album_musicbrainz<Id: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
|
||||||
|
&mut self,
|
||||||
|
artist_id: Id,
|
||||||
|
album_id: AlbumIdRef,
|
||||||
|
mbid: MbRefOption<MbAlbumRef>,
|
||||||
|
) -> Result<(), Error>;
|
||||||
|
fn clear_album_musicbrainz<Id: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
|
||||||
|
&mut self,
|
||||||
|
artist_id: Id,
|
||||||
|
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,
|
||||||
@ -65,6 +87,28 @@ pub trait IMusicHoardDatabase {
|
|||||||
artist_id: ArtistIdRef,
|
artist_id: ArtistIdRef,
|
||||||
album_id: AlbumIdRef,
|
album_id: AlbumIdRef,
|
||||||
) -> Result<(), Error>;
|
) -> Result<(), Error>;
|
||||||
|
fn set_album_primary_type<Id: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
|
||||||
|
&mut self,
|
||||||
|
artist_id: Id,
|
||||||
|
album_id: AlbumIdRef,
|
||||||
|
primary_type: Option<AlbumPrimaryType>,
|
||||||
|
) -> Result<(), Error>;
|
||||||
|
fn clear_album_primary_type<Id: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
|
||||||
|
&mut self,
|
||||||
|
artist_id: Id,
|
||||||
|
album_id: AlbumIdRef,
|
||||||
|
) -> Result<(), Error>;
|
||||||
|
fn set_album_secondary_types<Id: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
|
||||||
|
&mut self,
|
||||||
|
artist_id: Id,
|
||||||
|
album_id: AlbumIdRef,
|
||||||
|
secondary_types: Vec<AlbumSecondaryType>,
|
||||||
|
) -> Result<(), Error>;
|
||||||
|
fn clear_album_secondary_types<Id: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
|
||||||
|
&mut self,
|
||||||
|
artist_id: Id,
|
||||||
|
album_id: AlbumIdRef,
|
||||||
|
) -> Result<(), Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Database: IDatabase, Library> IMusicHoardDatabase for MusicHoard<Database, Library> {
|
impl<Database: IDatabase, Library> IMusicHoardDatabase for MusicHoard<Database, Library> {
|
||||||
@ -120,14 +164,24 @@ impl<Database: IDatabase, Library> IMusicHoardDatabase for MusicHoard<Database,
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_artist_musicbrainz<Id: AsRef<ArtistId>, S: AsRef<str>>(
|
fn set_artist_musicbrainz<Id: AsRef<ArtistId>>(
|
||||||
|
&mut self,
|
||||||
|
artist_id: Id,
|
||||||
|
mbid: MbRefOption<MbArtistRef>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.update_artist(artist_id.as_ref(), |artist| {
|
||||||
|
artist.meta.set_musicbrainz_ref(mbid)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_artist_musicbrainz_from_url<Id: AsRef<ArtistId>, S: AsRef<str>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
artist_id: Id,
|
artist_id: Id,
|
||||||
url: S,
|
url: S,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mb = MbArtistRef::from_url_str(url)?;
|
let mb = MbArtistRef::from_url_str(url)?;
|
||||||
self.update_artist(artist_id.as_ref(), |artist| {
|
self.update_artist(artist_id.as_ref(), |artist| {
|
||||||
artist.meta.set_musicbrainz_ref(mb)
|
artist.meta.set_musicbrainz_ref(MbRefOption::Some(mb))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,6 +237,27 @@ impl<Database: IDatabase, Library> IMusicHoardDatabase for MusicHoard<Database,
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_album_musicbrainz<Id: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
|
||||||
|
&mut self,
|
||||||
|
artist_id: Id,
|
||||||
|
album_id: AlbumIdRef,
|
||||||
|
mbid: MbRefOption<MbAlbumRef>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.update_album(artist_id.as_ref(), album_id.as_ref(), |album| {
|
||||||
|
album.meta.set_musicbrainz_ref(mbid)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_album_musicbrainz<Id: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
|
||||||
|
&mut self,
|
||||||
|
artist_id: Id,
|
||||||
|
album_id: AlbumIdRef,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.update_album(artist_id.as_ref(), album_id.as_ref(), |album| {
|
||||||
|
album.meta.clear_musicbrainz_ref()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
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,
|
||||||
@ -194,7 +269,6 @@ impl<Database: IDatabase, Library> IMusicHoardDatabase for MusicHoard<Database,
|
|||||||
album_id.as_ref(),
|
album_id.as_ref(),
|
||||||
|album| album.meta.set_seq(AlbumSeq(seq)),
|
|album| album.meta.set_seq(AlbumSeq(seq)),
|
||||||
|artist| artist.albums.sort_unstable(),
|
|artist| artist.albums.sort_unstable(),
|
||||||
|_| {},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,9 +282,50 @@ impl<Database: IDatabase, Library> IMusicHoardDatabase for MusicHoard<Database,
|
|||||||
album_id.as_ref(),
|
album_id.as_ref(),
|
||||||
|album| album.meta.clear_seq(),
|
|album| album.meta.clear_seq(),
|
||||||
|artist| artist.albums.sort_unstable(),
|
|artist| artist.albums.sort_unstable(),
|
||||||
|_| {},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_album_primary_type<Id: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
|
||||||
|
&mut self,
|
||||||
|
artist_id: Id,
|
||||||
|
album_id: AlbumIdRef,
|
||||||
|
primary_type: Option<AlbumPrimaryType>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.update_album(artist_id.as_ref(), album_id.as_ref(), |album| {
|
||||||
|
album.meta.set_primary_type(primary_type)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_album_primary_type<Id: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
|
||||||
|
&mut self,
|
||||||
|
artist_id: Id,
|
||||||
|
album_id: AlbumIdRef,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.update_album(artist_id.as_ref(), album_id.as_ref(), |album| {
|
||||||
|
album.meta.clear_primary_type()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_album_secondary_types<Id: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
|
||||||
|
&mut self,
|
||||||
|
artist_id: Id,
|
||||||
|
album_id: AlbumIdRef,
|
||||||
|
secondary_types: Vec<AlbumSecondaryType>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.update_album(artist_id.as_ref(), album_id.as_ref(), |album| {
|
||||||
|
album.meta.set_secondary_types(secondary_types)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_album_secondary_types<Id: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
|
||||||
|
&mut self,
|
||||||
|
artist_id: Id,
|
||||||
|
album_id: AlbumIdRef,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.update_album(artist_id.as_ref(), album_id.as_ref(), |album| {
|
||||||
|
album.meta.clear_secondary_types()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait IMusicHoardDatabasePrivate {
|
pub trait IMusicHoardDatabasePrivate {
|
||||||
@ -272,24 +387,34 @@ impl<Database: IDatabase, Library> MusicHoard<Database, Library> {
|
|||||||
self.update_artist_and(artist_id, fn_artist, |_| {})
|
self.update_artist_and(artist_id, fn_artist, |_| {})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_album_and<FnAlbum, FnArtist, FnColl>(
|
fn update_album_and<FnAlbum, FnArtist>(
|
||||||
&mut self,
|
&mut self,
|
||||||
artist_id: &ArtistId,
|
artist_id: &ArtistId,
|
||||||
album_id: &AlbumId,
|
album_id: &AlbumId,
|
||||||
fn_album: FnAlbum,
|
fn_album: FnAlbum,
|
||||||
fn_artist: FnArtist,
|
fn_artist: FnArtist,
|
||||||
fn_coll: FnColl,
|
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
FnAlbum: FnOnce(&mut Album),
|
FnAlbum: FnOnce(&mut Album),
|
||||||
FnArtist: FnOnce(&mut Artist),
|
FnArtist: FnOnce(&mut Artist),
|
||||||
FnColl: FnOnce(&mut Collection),
|
|
||||||
{
|
{
|
||||||
let artist = Self::get_artist_mut_or_err(&mut self.pre_commit, artist_id)?;
|
let artist = Self::get_artist_mut_or_err(&mut self.pre_commit, artist_id)?;
|
||||||
let album = Self::get_album_mut_or_err(artist, album_id)?;
|
let album = Self::get_album_mut_or_err(artist, album_id)?;
|
||||||
fn_album(album);
|
fn_album(album);
|
||||||
fn_artist(artist);
|
fn_artist(artist);
|
||||||
self.update_collection(fn_coll)
|
self.update_collection(|_| {})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_album<FnAlbum>(
|
||||||
|
&mut self,
|
||||||
|
artist_id: &ArtistId,
|
||||||
|
album_id: &AlbumId,
|
||||||
|
fn_album: FnAlbum,
|
||||||
|
) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
FnAlbum: FnOnce(&mut Album),
|
||||||
|
{
|
||||||
|
self.update_album_and(artist_id, album_id, fn_album, |_| {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,7 +548,7 @@ mod tests {
|
|||||||
assert!(music_hoard.add_artist(artist_id.clone()).is_ok());
|
assert!(music_hoard.add_artist(artist_id.clone()).is_ok());
|
||||||
|
|
||||||
let actual_err = music_hoard
|
let actual_err = music_hoard
|
||||||
.set_artist_musicbrainz(&artist_id, MUSICBUTLER)
|
.set_artist_musicbrainz_from_url(&artist_id, MUSICBUTLER)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
let expected_err = Error::CollectionError(format!(
|
let expected_err = Error::CollectionError(format!(
|
||||||
"an error occurred when processing a URL: invalid artist MusicBrainz URL: {MUSICBUTLER}"
|
"an error occurred when processing a URL: invalid artist MusicBrainz URL: {MUSICBUTLER}"
|
||||||
@ -449,13 +574,13 @@ mod tests {
|
|||||||
|
|
||||||
// Setting a URL on an artist not in the collection is an error.
|
// Setting a URL on an artist not in the collection is an error.
|
||||||
assert!(music_hoard
|
assert!(music_hoard
|
||||||
.set_artist_musicbrainz(&artist_id_2, MUSICBRAINZ)
|
.set_artist_musicbrainz_from_url(&artist_id_2, MUSICBRAINZ)
|
||||||
.is_err());
|
.is_err());
|
||||||
assert_eq!(music_hoard.collection[0].meta.musicbrainz, expected);
|
assert_eq!(music_hoard.collection[0].meta.musicbrainz, expected);
|
||||||
|
|
||||||
// Setting a URL on an artist.
|
// Setting a URL on an artist.
|
||||||
assert!(music_hoard
|
assert!(music_hoard
|
||||||
.set_artist_musicbrainz(&artist_id, MUSICBRAINZ)
|
.set_artist_musicbrainz_from_url(&artist_id, MUSICBRAINZ)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
expected.replace(MbArtistRef::from_url_str(MUSICBRAINZ).unwrap());
|
expected.replace(MbArtistRef::from_url_str(MUSICBRAINZ).unwrap());
|
||||||
assert_eq!(music_hoard.collection[0].meta.musicbrainz, expected);
|
assert_eq!(music_hoard.collection[0].meta.musicbrainz, expected);
|
||||||
|
@ -73,7 +73,7 @@ impl IAppInteractBrowse for AppMachine<BrowseState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_musicbrainz(self) -> Self::APP {
|
fn fetch_musicbrainz(self) -> Self::APP {
|
||||||
AppMachine::app_fetch_new(self.inner)
|
AppMachine::app_fetch_first(self.inner)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ use std::{
|
|||||||
|
|
||||||
use musichoard::collection::{
|
use musichoard::collection::{
|
||||||
album::AlbumMeta,
|
album::AlbumMeta,
|
||||||
artist::{Artist, ArtistMeta},
|
artist::{Artist, ArtistId, ArtistMeta},
|
||||||
musicbrainz::{IMusicBrainzRef, MbRefOption, Mbid},
|
musicbrainz::{IMusicBrainzRef, MbRefOption, Mbid},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -46,12 +46,27 @@ impl FetchState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum FetchError {
|
||||||
|
NothingToFetch,
|
||||||
|
SubmitError(DaemonError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<DaemonError> for FetchError {
|
||||||
|
fn from(value: DaemonError) -> Self {
|
||||||
|
FetchError::SubmitError(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AppMachine<FetchState> {
|
impl AppMachine<FetchState> {
|
||||||
fn fetch_state(inner: AppInner, state: FetchState) -> Self {
|
fn fetch_state(inner: AppInner, state: FetchState) -> Self {
|
||||||
AppMachine::new(inner, state)
|
AppMachine::new(inner, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn app_fetch_new(inner: AppInner) -> App {
|
pub fn app_fetch_first(inner: AppInner) -> App {
|
||||||
|
Self::app_fetch_new(inner, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn app_fetch_new(inner: AppInner, first: bool) -> App {
|
||||||
let coll = inner.music_hoard.get_collection();
|
let coll = inner.music_hoard.get_collection();
|
||||||
let artist = match inner.selection.state_artist(coll) {
|
let artist = match inner.selection.state_artist(coll) {
|
||||||
Some(artist_state) => &coll[artist_state.index],
|
Some(artist_state) => &coll[artist_state.index],
|
||||||
@ -61,16 +76,38 @@ impl AppMachine<FetchState> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (fetch_tx, fetch_rx) = mpsc::channel::<MbApiResult>();
|
let (fetch_tx, fetch_rx) = mpsc::channel::<MbApiResult>();
|
||||||
if let Err(err) = Self::submit_fetch_job(&*inner.musicbrainz, fetch_tx, artist) {
|
|
||||||
return AppMachine::error_state(inner, err.to_string()).into();
|
|
||||||
}
|
|
||||||
|
|
||||||
let fetch = FetchState::new(fetch_rx);
|
let fetch = FetchState::new(fetch_rx);
|
||||||
AppMachine::app_fetch(inner, fetch, true)
|
match Self::submit_fetch_job(&*inner.musicbrainz, fetch_tx, artist) {
|
||||||
|
Ok(()) => AppMachine::fetch_state(inner, fetch).into(),
|
||||||
|
Err(FetchError::NothingToFetch) => {
|
||||||
|
if first {
|
||||||
|
AppMachine::match_state(inner, MatchState::new(None, fetch)).into()
|
||||||
|
} else {
|
||||||
|
AppMachine::browse_state(inner).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(FetchError::SubmitError(daemon_err)) => {
|
||||||
|
AppMachine::error_state(inner, daemon_err.to_string()).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn app_fetch_next(inner: AppInner, fetch: FetchState) -> App {
|
pub fn app_fetch_next(inner: AppInner, mut fetch: FetchState) -> App {
|
||||||
Self::app_fetch(inner, fetch, false)
|
match fetch.try_recv() {
|
||||||
|
Ok(fetch_result) => match fetch_result {
|
||||||
|
Ok(next_match) => {
|
||||||
|
let current = Some(next_match);
|
||||||
|
AppMachine::match_state(inner, MatchState::new(current, fetch)).into()
|
||||||
|
}
|
||||||
|
Err(fetch_err) => {
|
||||||
|
AppMachine::error_state(inner, format!("fetch failed: {fetch_err}")).into()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(recv_err) => match recv_err {
|
||||||
|
TryRecvError::Empty => AppMachine::fetch_state(inner, fetch).into(),
|
||||||
|
TryRecvError::Disconnected => Self::app_fetch_new(inner, false),
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn app_lookup_artist(
|
pub fn app_lookup_artist(
|
||||||
@ -86,10 +123,13 @@ impl AppMachine<FetchState> {
|
|||||||
pub fn app_lookup_album(
|
pub fn app_lookup_album(
|
||||||
inner: AppInner,
|
inner: AppInner,
|
||||||
fetch: FetchState,
|
fetch: FetchState,
|
||||||
|
artist_id: &ArtistId,
|
||||||
album: &AlbumMeta,
|
album: &AlbumMeta,
|
||||||
mbid: Mbid,
|
mbid: Mbid,
|
||||||
) -> App {
|
) -> App {
|
||||||
let f = Self::submit_lookup_release_group_job;
|
let f = |mb: &dyn IMbJobSender, rs, album, mbid| {
|
||||||
|
Self::submit_lookup_release_group_job(mb, rs, artist_id, album, mbid)
|
||||||
|
};
|
||||||
Self::app_lookup(f, inner, fetch, album, mbid)
|
Self::app_lookup(f, inner, fetch, album, mbid)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,48 +151,33 @@ impl AppMachine<FetchState> {
|
|||||||
Self::app_fetch_next(inner, fetch)
|
Self::app_fetch_next(inner, fetch)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn app_fetch(inner: AppInner, mut fetch: FetchState, first: bool) -> App {
|
|
||||||
match fetch.try_recv() {
|
|
||||||
Ok(fetch_result) => match fetch_result {
|
|
||||||
Ok(next_match) => {
|
|
||||||
let current = Some(next_match);
|
|
||||||
AppMachine::match_state(inner, MatchState::new(current, fetch)).into()
|
|
||||||
}
|
|
||||||
Err(fetch_err) => {
|
|
||||||
AppMachine::error_state(inner, format!("fetch failed: {fetch_err}")).into()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(recv_err) => match recv_err {
|
|
||||||
TryRecvError::Empty => AppMachine::fetch_state(inner, fetch).into(),
|
|
||||||
TryRecvError::Disconnected => {
|
|
||||||
if first {
|
|
||||||
AppMachine::match_state(inner, MatchState::new(None, fetch)).into()
|
|
||||||
} else {
|
|
||||||
AppMachine::browse_state(inner).into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn submit_fetch_job(
|
fn submit_fetch_job(
|
||||||
musicbrainz: &dyn IMbJobSender,
|
musicbrainz: &dyn IMbJobSender,
|
||||||
result_sender: ResultSender,
|
result_sender: ResultSender,
|
||||||
artist: &Artist,
|
artist: &Artist,
|
||||||
) -> Result<(), DaemonError> {
|
) -> Result<(), FetchError> {
|
||||||
let requests = match artist.meta.musicbrainz {
|
let requests = match artist.meta.musicbrainz {
|
||||||
MbRefOption::Some(ref arid) => {
|
MbRefOption::Some(ref arid) => {
|
||||||
let arid = arid.mbid();
|
let arid = arid.mbid();
|
||||||
let albums = artist.albums.iter();
|
let albums = artist.albums.iter();
|
||||||
albums
|
albums
|
||||||
.filter(|album| matches!(album.meta.musicbrainz, MbRefOption::None))
|
.filter(|album| matches!(album.meta.musicbrainz, MbRefOption::None))
|
||||||
.map(|album| MbParams::search_release_group(arid.clone(), album.meta.clone()))
|
.map(|album| {
|
||||||
|
MbParams::search_release_group(
|
||||||
|
artist.meta.id.clone(),
|
||||||
|
arid.clone(),
|
||||||
|
album.meta.clone(),
|
||||||
|
)
|
||||||
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
MbRefOption::CannotHaveMbid => return Ok(()),
|
MbRefOption::CannotHaveMbid => VecDeque::new(),
|
||||||
MbRefOption::None => VecDeque::from([MbParams::search_artist(artist.meta.clone())]),
|
MbRefOption::None => VecDeque::from([MbParams::search_artist(artist.meta.clone())]),
|
||||||
};
|
};
|
||||||
musicbrainz.submit_background_job(result_sender, requests)
|
if requests.is_empty() {
|
||||||
|
return Err(FetchError::NothingToFetch);
|
||||||
|
}
|
||||||
|
Ok(musicbrainz.submit_background_job(result_sender, requests)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn submit_lookup_artist_job(
|
fn submit_lookup_artist_job(
|
||||||
@ -168,10 +193,15 @@ impl AppMachine<FetchState> {
|
|||||||
fn submit_lookup_release_group_job(
|
fn submit_lookup_release_group_job(
|
||||||
musicbrainz: &dyn IMbJobSender,
|
musicbrainz: &dyn IMbJobSender,
|
||||||
result_sender: ResultSender,
|
result_sender: ResultSender,
|
||||||
|
artist_id: &ArtistId,
|
||||||
album: &AlbumMeta,
|
album: &AlbumMeta,
|
||||||
mbid: Mbid,
|
mbid: Mbid,
|
||||||
) -> Result<(), DaemonError> {
|
) -> Result<(), DaemonError> {
|
||||||
let requests = VecDeque::from([MbParams::lookup_release_group(album.clone(), mbid)]);
|
let requests = VecDeque::from([MbParams::lookup_release_group(
|
||||||
|
artist_id.clone(),
|
||||||
|
album.clone(),
|
||||||
|
mbid,
|
||||||
|
)]);
|
||||||
musicbrainz.submit_foreground_job(result_sender, requests)
|
musicbrainz.submit_foreground_job(result_sender, requests)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -207,7 +237,11 @@ impl IAppEventFetch for AppMachine<FetchState> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use mockall::predicate;
|
use mockall::predicate;
|
||||||
use musichoard::collection::{album::AlbumMeta, artist::ArtistMeta, musicbrainz::Mbid};
|
use musichoard::collection::{
|
||||||
|
album::AlbumMeta,
|
||||||
|
artist::{ArtistId, ArtistMeta},
|
||||||
|
musicbrainz::Mbid,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::tui::{
|
use crate::tui::{
|
||||||
app::{
|
app::{
|
||||||
@ -257,18 +291,23 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fetch_no_artist() {
|
fn fetch_no_artist() {
|
||||||
let app = AppMachine::app_fetch_new(inner(music_hoard(vec![])));
|
let app = AppMachine::app_fetch_first(inner(music_hoard(vec![])));
|
||||||
assert!(matches!(app.state(), AppState::Error(_)));
|
assert!(matches!(app.state(), AppState::Error(_)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_release_group_expectation(
|
fn search_release_group_expectation(
|
||||||
job_sender: &mut MockIMbJobSender,
|
job_sender: &mut MockIMbJobSender,
|
||||||
arid: &Mbid,
|
artist_id: &ArtistId,
|
||||||
|
artist_mbid: &Mbid,
|
||||||
albums: &[AlbumMeta],
|
albums: &[AlbumMeta],
|
||||||
) {
|
) {
|
||||||
let mut requests = VecDeque::new();
|
let mut requests = VecDeque::new();
|
||||||
for album in albums.iter() {
|
for album in albums.iter() {
|
||||||
requests.push_back(MbParams::search_release_group(arid.clone(), album.clone()));
|
requests.push_back(MbParams::search_release_group(
|
||||||
|
artist_id.clone(),
|
||||||
|
artist_mbid.clone(),
|
||||||
|
album.clone(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
job_sender
|
job_sender
|
||||||
.expect_submit_background_job()
|
.expect_submit_background_job()
|
||||||
@ -281,13 +320,19 @@ mod tests {
|
|||||||
fn fetch_albums() {
|
fn fetch_albums() {
|
||||||
let mut mb_job_sender = MockIMbJobSender::new();
|
let mut mb_job_sender = MockIMbJobSender::new();
|
||||||
|
|
||||||
let arid: Mbid = "11111111-1111-1111-1111-111111111111".try_into().unwrap();
|
let artist_id = COLLECTION[1].meta.id.clone();
|
||||||
|
let artist_mbid: Mbid = "11111111-1111-1111-1111-111111111111".try_into().unwrap();
|
||||||
|
|
||||||
let album_1_meta = COLLECTION[1].albums[0].meta.clone();
|
let album_1_meta = COLLECTION[1].albums[0].meta.clone();
|
||||||
let album_4_meta = COLLECTION[1].albums[3].meta.clone();
|
let album_4_meta = COLLECTION[1].albums[3].meta.clone();
|
||||||
|
|
||||||
// Other albums have an MBID and so they will be skipped.
|
// Other albums have an MBID and so they will be skipped.
|
||||||
search_release_group_expectation(&mut mb_job_sender, &arid, &[album_1_meta, album_4_meta]);
|
search_release_group_expectation(
|
||||||
|
&mut mb_job_sender,
|
||||||
|
&artist_id,
|
||||||
|
&artist_mbid,
|
||||||
|
&[album_1_meta, album_4_meta],
|
||||||
|
);
|
||||||
|
|
||||||
let music_hoard = music_hoard(COLLECTION.to_owned());
|
let music_hoard = music_hoard(COLLECTION.to_owned());
|
||||||
let inner = AppInner::new(music_hoard, mb_job_sender);
|
let inner = AppInner::new(music_hoard, mb_job_sender);
|
||||||
@ -300,8 +345,16 @@ mod tests {
|
|||||||
assert!(matches!(app, AppState::Match(_)));
|
assert!(matches!(app, AppState::Match(_)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_album_expectation(job_sender: &mut MockIMbJobSender, album: &AlbumMeta) {
|
fn lookup_album_expectation(
|
||||||
let requests = VecDeque::from([MbParams::lookup_release_group(album.clone(), mbid())]);
|
job_sender: &mut MockIMbJobSender,
|
||||||
|
artist_id: &ArtistId,
|
||||||
|
album: &AlbumMeta,
|
||||||
|
) {
|
||||||
|
let requests = VecDeque::from([MbParams::lookup_release_group(
|
||||||
|
artist_id.clone(),
|
||||||
|
album.clone(),
|
||||||
|
mbid(),
|
||||||
|
)]);
|
||||||
job_sender
|
job_sender
|
||||||
.expect_submit_foreground_job()
|
.expect_submit_foreground_job()
|
||||||
.with(predicate::always(), predicate::eq(requests))
|
.with(predicate::always(), predicate::eq(requests))
|
||||||
@ -313,8 +366,9 @@ mod tests {
|
|||||||
fn lookup_album() {
|
fn lookup_album() {
|
||||||
let mut mb_job_sender = MockIMbJobSender::new();
|
let mut mb_job_sender = MockIMbJobSender::new();
|
||||||
|
|
||||||
|
let artist_id = COLLECTION[1].meta.id.clone();
|
||||||
let album = COLLECTION[1].albums[0].meta.clone();
|
let album = COLLECTION[1].albums[0].meta.clone();
|
||||||
lookup_album_expectation(&mut mb_job_sender, &album);
|
lookup_album_expectation(&mut mb_job_sender, &artist_id, &album);
|
||||||
|
|
||||||
let music_hoard = music_hoard(COLLECTION.to_owned());
|
let music_hoard = music_hoard(COLLECTION.to_owned());
|
||||||
let inner = AppInner::new(music_hoard, mb_job_sender);
|
let inner = AppInner::new(music_hoard, mb_job_sender);
|
||||||
@ -322,7 +376,7 @@ mod tests {
|
|||||||
let (_fetch_tx, fetch_rx) = mpsc::channel();
|
let (_fetch_tx, fetch_rx) = mpsc::channel();
|
||||||
let fetch = FetchState::new(fetch_rx);
|
let fetch = FetchState::new(fetch_rx);
|
||||||
|
|
||||||
AppMachine::app_lookup_album(inner, fetch, &album, mbid());
|
AppMachine::app_lookup_album(inner, fetch, &artist_id, &album, mbid());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_artist_expectation(job_sender: &mut MockIMbJobSender, artist: &ArtistMeta) {
|
fn search_artist_expectation(job_sender: &mut MockIMbJobSender, artist: &ArtistMeta) {
|
||||||
@ -442,7 +496,7 @@ mod tests {
|
|||||||
|
|
||||||
let inner = inner(music_hoard(COLLECTION.clone()));
|
let inner = inner(music_hoard(COLLECTION.clone()));
|
||||||
let fetch = FetchState::new(rx);
|
let fetch = FetchState::new(rx);
|
||||||
let mut app = AppMachine::app_fetch(inner, fetch, true);
|
let mut app = AppMachine::app_fetch_next(inner, fetch);
|
||||||
assert!(matches!(app, AppState::Match(_)));
|
assert!(matches!(app, AppState::Match(_)));
|
||||||
|
|
||||||
let public = app.get();
|
let public = app.get();
|
||||||
@ -465,7 +519,7 @@ mod tests {
|
|||||||
|
|
||||||
let inner = inner(music_hoard(COLLECTION.clone()));
|
let inner = inner(music_hoard(COLLECTION.clone()));
|
||||||
let fetch = FetchState::new(rx);
|
let fetch = FetchState::new(rx);
|
||||||
let app = AppMachine::app_fetch(inner, fetch, true);
|
let app = AppMachine::app_fetch_next(inner, fetch);
|
||||||
assert!(matches!(app, AppState::Error(_)));
|
assert!(matches!(app, AppState::Error(_)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -475,7 +529,7 @@ mod tests {
|
|||||||
|
|
||||||
let inner = inner(music_hoard(COLLECTION.clone()));
|
let inner = inner(music_hoard(COLLECTION.clone()));
|
||||||
let fetch = FetchState::new(rx);
|
let fetch = FetchState::new(rx);
|
||||||
let app = AppMachine::app_fetch(inner, fetch, true);
|
let app = AppMachine::app_fetch_next(inner, fetch);
|
||||||
assert!(matches!(app, AppState::Fetch(_)));
|
assert!(matches!(app, AppState::Fetch(_)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,7 +539,7 @@ mod tests {
|
|||||||
|
|
||||||
let inner = inner(music_hoard(COLLECTION.clone()));
|
let inner = inner(music_hoard(COLLECTION.clone()));
|
||||||
let fetch = FetchState::new(rx);
|
let fetch = FetchState::new(rx);
|
||||||
let app = AppMachine::app_fetch(inner, fetch, true);
|
let app = AppMachine::app_fetch_next(inner, fetch);
|
||||||
assert!(matches!(app, AppState::Match(_)));
|
assert!(matches!(app, AppState::Match(_)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -504,7 +558,7 @@ mod tests {
|
|||||||
|
|
||||||
let inner = inner(music_hoard(COLLECTION.clone()));
|
let inner = inner(music_hoard(COLLECTION.clone()));
|
||||||
let fetch = FetchState::new(rx);
|
let fetch = FetchState::new(rx);
|
||||||
let app = AppMachine::app_fetch(inner, fetch, true);
|
let app = AppMachine::app_fetch_next(inner, fetch);
|
||||||
assert!(matches!(app, AppState::Fetch(_)));
|
assert!(matches!(app, AppState::Fetch(_)));
|
||||||
|
|
||||||
let artist = COLLECTION[3].meta.clone();
|
let artist = COLLECTION[3].meta.clone();
|
||||||
|
@ -1,13 +1,100 @@
|
|||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
||||||
use musichoard::collection::musicbrainz::Mbid;
|
use musichoard::collection::{
|
||||||
|
album::AlbumMeta,
|
||||||
|
artist::{ArtistId, ArtistMeta},
|
||||||
|
musicbrainz::{MbRefOption, Mbid},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::tui::app::{
|
use crate::tui::{
|
||||||
|
app::{
|
||||||
machine::{fetch_state::FetchState, input::Input, App, AppInner, AppMachine},
|
machine::{fetch_state::FetchState, input::Input, App, AppInner, AppMachine},
|
||||||
AlbumMatches, AppPublicState, AppState, ArtistMatches, IAppInteractMatch, ListOption,
|
AlbumMatches, AppPublicState, AppState, ArtistMatches, IAppInteractMatch, ListOption,
|
||||||
LookupOption, MatchStateInfo, MatchStatePublic, MissOption, SearchOption, WidgetState,
|
LookupOption, MatchStateInfo, MatchStatePublic, MissOption, SearchOption, WidgetState,
|
||||||
|
},
|
||||||
|
lib::IMusicHoard,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
impl LookupOption<ArtistMeta> {
|
||||||
|
fn set(
|
||||||
|
self,
|
||||||
|
music_hoard: &mut dyn IMusicHoard,
|
||||||
|
meta: &ArtistMeta,
|
||||||
|
) -> Result<(), musichoard::Error> {
|
||||||
|
let mbref = match self {
|
||||||
|
LookupOption::Match(lookup) => lookup.item.musicbrainz,
|
||||||
|
LookupOption::None(MissOption::CannotHaveMbid) => MbRefOption::CannotHaveMbid,
|
||||||
|
_ => panic!(),
|
||||||
|
};
|
||||||
|
music_hoard.set_artist_musicbrainz(&meta.id, mbref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SearchOption<ArtistMeta> {
|
||||||
|
fn set(
|
||||||
|
self,
|
||||||
|
music_hoard: &mut dyn IMusicHoard,
|
||||||
|
meta: &ArtistMeta,
|
||||||
|
) -> Result<(), musichoard::Error> {
|
||||||
|
let mbref = match self {
|
||||||
|
SearchOption::Match(search) => search.item.musicbrainz,
|
||||||
|
SearchOption::None(MissOption::CannotHaveMbid) => MbRefOption::CannotHaveMbid,
|
||||||
|
_ => panic!(),
|
||||||
|
};
|
||||||
|
music_hoard.set_artist_musicbrainz(&meta.id, mbref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LookupOption<AlbumMeta> {
|
||||||
|
fn set(
|
||||||
|
self,
|
||||||
|
music_hoard: &mut dyn IMusicHoard,
|
||||||
|
artist: &ArtistId,
|
||||||
|
meta: &AlbumMeta,
|
||||||
|
) -> Result<(), musichoard::Error> {
|
||||||
|
let (mbref, primary_type, secondary_types) = match self {
|
||||||
|
LookupOption::Match(lookup) => (
|
||||||
|
lookup.item.musicbrainz,
|
||||||
|
lookup.item.primary_type,
|
||||||
|
lookup.item.secondary_types,
|
||||||
|
),
|
||||||
|
LookupOption::None(MissOption::CannotHaveMbid) => {
|
||||||
|
(MbRefOption::CannotHaveMbid, None, Vec::new())
|
||||||
|
}
|
||||||
|
_ => panic!(),
|
||||||
|
};
|
||||||
|
music_hoard.set_album_musicbrainz(artist, &meta.id, mbref)?;
|
||||||
|
music_hoard.set_album_primary_type(artist, &meta.id, primary_type)?;
|
||||||
|
music_hoard.set_album_secondary_types(artist, &meta.id, secondary_types)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SearchOption<AlbumMeta> {
|
||||||
|
fn set(
|
||||||
|
self,
|
||||||
|
music_hoard: &mut dyn IMusicHoard,
|
||||||
|
artist: &ArtistId,
|
||||||
|
meta: &AlbumMeta,
|
||||||
|
) -> Result<(), musichoard::Error> {
|
||||||
|
let (mbref, primary_type, secondary_types) = match self {
|
||||||
|
SearchOption::Match(lookup) => (
|
||||||
|
lookup.item.musicbrainz,
|
||||||
|
lookup.item.primary_type,
|
||||||
|
lookup.item.secondary_types,
|
||||||
|
),
|
||||||
|
SearchOption::None(MissOption::CannotHaveMbid) => {
|
||||||
|
(MbRefOption::CannotHaveMbid, None, Vec::new())
|
||||||
|
}
|
||||||
|
_ => panic!(),
|
||||||
|
};
|
||||||
|
music_hoard.set_album_musicbrainz(artist, &meta.id, mbref)?;
|
||||||
|
music_hoard.set_album_primary_type(artist, &meta.id, primary_type)?;
|
||||||
|
music_hoard.set_album_secondary_types(artist, &meta.id, secondary_types)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: PartialEq> ListOption<T> {
|
impl<T: PartialEq> ListOption<T> {
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
@ -42,6 +129,35 @@ impl<T: PartialEq> ListOption<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ListOption<ArtistMeta> {
|
||||||
|
fn set(
|
||||||
|
self,
|
||||||
|
music_hoard: &mut dyn IMusicHoard,
|
||||||
|
meta: &ArtistMeta,
|
||||||
|
index: usize,
|
||||||
|
) -> Result<(), musichoard::Error> {
|
||||||
|
match self {
|
||||||
|
ListOption::Lookup(mut list) => list.swap_remove(index).set(music_hoard, meta),
|
||||||
|
ListOption::Search(mut list) => list.swap_remove(index).set(music_hoard, meta),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ListOption<AlbumMeta> {
|
||||||
|
fn set(
|
||||||
|
self,
|
||||||
|
music_hoard: &mut dyn IMusicHoard,
|
||||||
|
artist: &ArtistId,
|
||||||
|
meta: &AlbumMeta,
|
||||||
|
index: usize,
|
||||||
|
) -> Result<(), musichoard::Error> {
|
||||||
|
match self {
|
||||||
|
ListOption::Lookup(mut list) => list.swap_remove(index).set(music_hoard, artist, meta),
|
||||||
|
ListOption::Search(mut list) => list.swap_remove(index).set(music_hoard, artist, meta),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ArtistMatches {
|
impl ArtistMatches {
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
self.list.len()
|
self.list.len()
|
||||||
@ -58,6 +174,10 @@ impl ArtistMatches {
|
|||||||
fn is_manual_input_mbid(&self, index: usize) -> bool {
|
fn is_manual_input_mbid(&self, index: usize) -> bool {
|
||||||
self.list.is_manual_input_mbid(index)
|
self.list.is_manual_input_mbid(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set(self, music_hoard: &mut dyn IMusicHoard, index: usize) -> Result<(), musichoard::Error> {
|
||||||
|
self.list.set(music_hoard, &self.matching, index)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AlbumMatches {
|
impl AlbumMatches {
|
||||||
@ -76,6 +196,11 @@ impl AlbumMatches {
|
|||||||
fn is_manual_input_mbid(&self, index: usize) -> bool {
|
fn is_manual_input_mbid(&self, index: usize) -> bool {
|
||||||
self.list.is_manual_input_mbid(index)
|
self.list.is_manual_input_mbid(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set(self, music_hoard: &mut dyn IMusicHoard, index: usize) -> Result<(), musichoard::Error> {
|
||||||
|
self.list
|
||||||
|
.set(music_hoard, &self.artist, &self.matching, index)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MatchStateInfo {
|
impl MatchStateInfo {
|
||||||
@ -106,6 +231,13 @@ impl MatchStateInfo {
|
|||||||
Self::Album(a) => a.is_manual_input_mbid(index),
|
Self::Album(a) => a.is_manual_input_mbid(index),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set(self, music_hoard: &mut dyn IMusicHoard, index: usize) -> Result<(), musichoard::Error> {
|
||||||
|
match self {
|
||||||
|
Self::Artist(a) => a.set(music_hoard, index),
|
||||||
|
Self::Album(a) => a.set(music_hoard, index),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MatchState {
|
pub struct MatchState {
|
||||||
@ -146,8 +278,15 @@ impl AppMachine<MatchState> {
|
|||||||
AppMachine::app_lookup_artist(self.inner, self.state.fetch, matching, mbid)
|
AppMachine::app_lookup_artist(self.inner, self.state.fetch, matching, mbid)
|
||||||
}
|
}
|
||||||
MatchStateInfo::Album(album_matches) => {
|
MatchStateInfo::Album(album_matches) => {
|
||||||
|
let artist_id = &album_matches.artist;
|
||||||
let matching = &album_matches.matching;
|
let matching = &album_matches.matching;
|
||||||
AppMachine::app_lookup_album(self.inner, self.state.fetch, matching, mbid)
|
AppMachine::app_lookup_album(
|
||||||
|
self.inner,
|
||||||
|
self.state.fetch,
|
||||||
|
artist_id,
|
||||||
|
matching,
|
||||||
|
mbid,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -197,6 +336,7 @@ impl IAppInteractMatch for AppMachine<MatchState> {
|
|||||||
fn select(mut self) -> Self::APP {
|
fn select(mut self) -> Self::APP {
|
||||||
if let Some(index) = self.state.state.list.selected() {
|
if let Some(index) = self.state.state.list.selected() {
|
||||||
// selected() implies current exists
|
// selected() implies current exists
|
||||||
|
|
||||||
if self
|
if self
|
||||||
.state
|
.state
|
||||||
.current
|
.current
|
||||||
@ -207,7 +347,17 @@ impl IAppInteractMatch for AppMachine<MatchState> {
|
|||||||
self.input.replace(Input::default());
|
self.input.replace(Input::default());
|
||||||
return self.into();
|
return self.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Err(err) = self
|
||||||
|
.state
|
||||||
|
.current
|
||||||
|
.unwrap()
|
||||||
|
.set(&mut *self.inner.music_hoard, index)
|
||||||
|
{
|
||||||
|
return AppMachine::error_state(self.inner, err.to_string()).into();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AppMachine::app_fetch_next(self.inner, self.state.fetch)
|
AppMachine::app_fetch_next(self.inner, self.state.fetch)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,6 +429,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn album_match() -> MatchStateInfo {
|
fn album_match() -> MatchStateInfo {
|
||||||
|
let artist_id = ArtistId::new("Artist");
|
||||||
let album = AlbumMeta::new(
|
let album = AlbumMeta::new(
|
||||||
AlbumId::new("Album"),
|
AlbumId::new("Album"),
|
||||||
AlbumDate::new(Some(1990), Some(5), None),
|
AlbumDate::new(Some(1990), Some(5), None),
|
||||||
@ -295,10 +446,11 @@ mod tests {
|
|||||||
let album_match_2 = Match::new(100, album_2);
|
let album_match_2 = Match::new(100, album_2);
|
||||||
|
|
||||||
let list = vec![album_match_1.clone(), album_match_2.clone()];
|
let list = vec![album_match_1.clone(), album_match_2.clone()];
|
||||||
MatchStateInfo::album_search(album, list)
|
MatchStateInfo::album_search(artist_id, album, list)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn album_lookup() -> MatchStateInfo {
|
fn album_lookup() -> MatchStateInfo {
|
||||||
|
let artist_id = ArtistId::new("Artist");
|
||||||
let album = AlbumMeta::new(
|
let album = AlbumMeta::new(
|
||||||
AlbumId::new("Album"),
|
AlbumId::new("Album"),
|
||||||
AlbumDate::new(Some(1990), Some(5), None),
|
AlbumDate::new(Some(1990), Some(5), None),
|
||||||
@ -306,7 +458,7 @@ mod tests {
|
|||||||
vec![AlbumSecondaryType::Live, AlbumSecondaryType::Compilation],
|
vec![AlbumSecondaryType::Live, AlbumSecondaryType::Compilation],
|
||||||
);
|
);
|
||||||
let lookup = Lookup::new(album.clone());
|
let lookup = Lookup::new(album.clone());
|
||||||
MatchStateInfo::album_lookup(album, lookup)
|
MatchStateInfo::album_lookup(artist_id, album, lookup)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_state() -> FetchState {
|
fn fetch_state() -> FetchState {
|
||||||
@ -518,15 +670,21 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn select_manual_input_album() {
|
fn select_manual_input_album() {
|
||||||
let mut mb_job_sender = MockIMbJobSender::new();
|
let mut mb_job_sender = MockIMbJobSender::new();
|
||||||
|
let artist_id = ArtistId::new("Artist");
|
||||||
let album = AlbumMeta::new("Album", 1990, None, vec![]);
|
let album = AlbumMeta::new("Album", 1990, None, vec![]);
|
||||||
let requests = VecDeque::from([MbParams::lookup_release_group(album.clone(), mbid())]);
|
let requests = VecDeque::from([MbParams::lookup_release_group(
|
||||||
|
artist_id.clone(),
|
||||||
|
album.clone(),
|
||||||
|
mbid(),
|
||||||
|
)]);
|
||||||
mb_job_sender
|
mb_job_sender
|
||||||
.expect_submit_foreground_job()
|
.expect_submit_foreground_job()
|
||||||
.with(predicate::always(), predicate::eq(requests))
|
.with(predicate::always(), predicate::eq(requests))
|
||||||
.return_once(|_, _| Ok(()));
|
.return_once(|_, _| Ok(()));
|
||||||
|
|
||||||
let matches_vec: Vec<Match<AlbumMeta>> = vec![];
|
let matches_vec: Vec<Match<AlbumMeta>> = vec![];
|
||||||
let album_match = MatchStateInfo::album_search(album.clone(), matches_vec);
|
let album_match =
|
||||||
|
MatchStateInfo::album_search(artist_id.clone(), album.clone(), matches_vec);
|
||||||
let matches = AppMachine::match_state(
|
let matches = AppMachine::match_state(
|
||||||
inner_with_mb(music_hoard(vec![]), mb_job_sender),
|
inner_with_mb(music_hoard(vec![]), mb_job_sender),
|
||||||
match_state(Some(album_match)),
|
match_state(Some(album_match)),
|
||||||
|
@ -4,7 +4,11 @@ mod selection;
|
|||||||
pub use machine::App;
|
pub use machine::App;
|
||||||
pub use selection::{Category, Delta, Selection, WidgetState};
|
pub use selection::{Category, Delta, Selection, WidgetState};
|
||||||
|
|
||||||
use musichoard::collection::{album::AlbumMeta, artist::ArtistMeta, Collection};
|
use musichoard::collection::{
|
||||||
|
album::AlbumMeta,
|
||||||
|
artist::{ArtistId, ArtistMeta},
|
||||||
|
Collection,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::tui::lib::interface::musicbrainz::api::Match;
|
use crate::tui::lib::interface::musicbrainz::api::Match;
|
||||||
|
|
||||||
@ -220,6 +224,7 @@ pub struct ArtistMatches {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct AlbumMatches {
|
pub struct AlbumMatches {
|
||||||
|
pub artist: ArtistId,
|
||||||
pub matching: AlbumMeta,
|
pub matching: AlbumMeta,
|
||||||
pub list: ListOption<AlbumMeta>,
|
pub list: ListOption<AlbumMeta>,
|
||||||
}
|
}
|
||||||
@ -240,11 +245,16 @@ impl MatchStateInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn album_search<M: Into<SearchOption<AlbumMeta>>>(
|
pub fn album_search<M: Into<SearchOption<AlbumMeta>>>(
|
||||||
|
artist: ArtistId,
|
||||||
matching: AlbumMeta,
|
matching: AlbumMeta,
|
||||||
list: Vec<M>,
|
list: Vec<M>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let list = ListOption::Search(list.into_iter().map(Into::into).collect());
|
let list = ListOption::Search(list.into_iter().map(Into::into).collect());
|
||||||
MatchStateInfo::Album(AlbumMatches { matching, list })
|
MatchStateInfo::Album(AlbumMatches {
|
||||||
|
artist,
|
||||||
|
matching,
|
||||||
|
list,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn artist_lookup<M: Into<LookupOption<ArtistMeta>>>(matching: ArtistMeta, item: M) -> Self {
|
pub fn artist_lookup<M: Into<LookupOption<ArtistMeta>>>(matching: ArtistMeta, item: M) -> Self {
|
||||||
@ -252,9 +262,17 @@ impl MatchStateInfo {
|
|||||||
MatchStateInfo::Artist(ArtistMatches { matching, list })
|
MatchStateInfo::Artist(ArtistMatches { matching, list })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn album_lookup<M: Into<LookupOption<AlbumMeta>>>(matching: AlbumMeta, item: M) -> Self {
|
pub fn album_lookup<M: Into<LookupOption<AlbumMeta>>>(
|
||||||
|
artist: ArtistId,
|
||||||
|
matching: AlbumMeta,
|
||||||
|
item: M,
|
||||||
|
) -> Self {
|
||||||
let list = ListOption::Lookup(vec![item.into()]);
|
let list = ListOption::Lookup(vec![item.into()]);
|
||||||
MatchStateInfo::Album(AlbumMatches { matching, list })
|
MatchStateInfo::Album(AlbumMatches {
|
||||||
|
artist,
|
||||||
|
matching,
|
||||||
|
list,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
48
src/tui/lib/external/musicbrainz/daemon/mod.rs
vendored
48
src/tui/lib/external/musicbrainz/daemon/mod.rs
vendored
@ -245,15 +245,15 @@ impl JobInstance {
|
|||||||
.map(|rv| MatchStateInfo::artist_lookup(params.artist, rv)),
|
.map(|rv| MatchStateInfo::artist_lookup(params.artist, rv)),
|
||||||
LookupParams::ReleaseGroup(params) => musicbrainz
|
LookupParams::ReleaseGroup(params) => musicbrainz
|
||||||
.lookup_release_group(¶ms.mbid)
|
.lookup_release_group(¶ms.mbid)
|
||||||
.map(|rv| MatchStateInfo::album_lookup(params.album, rv)),
|
.map(|rv| MatchStateInfo::album_lookup(params.artist_id, params.album, rv)),
|
||||||
},
|
},
|
||||||
MbParams::Search(search) => match search {
|
MbParams::Search(search) => match search {
|
||||||
SearchParams::Artist(params) => musicbrainz
|
SearchParams::Artist(params) => musicbrainz
|
||||||
.search_artist(¶ms.artist)
|
.search_artist(¶ms.artist)
|
||||||
.map(|rv| MatchStateInfo::artist_search(params.artist, rv)),
|
.map(|rv| MatchStateInfo::artist_search(params.artist, rv)),
|
||||||
SearchParams::ReleaseGroup(params) => musicbrainz
|
SearchParams::ReleaseGroup(params) => musicbrainz
|
||||||
.search_release_group(¶ms.arid, ¶ms.album)
|
.search_release_group(¶ms.artist_mbid, ¶ms.album)
|
||||||
.map(|rv| MatchStateInfo::album_search(params.album, rv)),
|
.map(|rv| MatchStateInfo::album_search(params.artist_id, params.album, rv)),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
self.return_result(event_sender, result)
|
self.return_result(event_sender, result)
|
||||||
@ -315,7 +315,7 @@ mod tests {
|
|||||||
use mockall::{predicate, Sequence};
|
use mockall::{predicate, Sequence};
|
||||||
use musichoard::collection::{
|
use musichoard::collection::{
|
||||||
album::AlbumMeta,
|
album::AlbumMeta,
|
||||||
artist::ArtistMeta,
|
artist::{ArtistId, ArtistMeta},
|
||||||
musicbrainz::{IMusicBrainzRef, MbRefOption, Mbid},
|
musicbrainz::{IMusicBrainzRef, MbRefOption, Mbid},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -397,9 +397,10 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_release_group_requests() -> VecDeque<MbParams> {
|
fn lookup_release_group_requests() -> VecDeque<MbParams> {
|
||||||
|
let artist_id = COLLECTION[1].meta.id.clone();
|
||||||
let album = COLLECTION[1].albums[0].meta.clone();
|
let album = COLLECTION[1].albums[0].meta.clone();
|
||||||
let mbid = mbid();
|
let mbid = mbid();
|
||||||
VecDeque::from([MbParams::lookup_release_group(album, mbid)])
|
VecDeque::from([MbParams::lookup_release_group(artist_id, album, mbid)])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_artist_requests() -> VecDeque<MbParams> {
|
fn search_artist_requests() -> VecDeque<MbParams> {
|
||||||
@ -421,15 +422,20 @@ mod tests {
|
|||||||
let mbref = mb_ref_opt_as_ref(&COLLECTION[1].meta.musicbrainz);
|
let mbref = mb_ref_opt_as_ref(&COLLECTION[1].meta.musicbrainz);
|
||||||
let arid = mb_ref_opt_unwrap(mbref).mbid().clone();
|
let arid = mb_ref_opt_unwrap(mbref).mbid().clone();
|
||||||
|
|
||||||
|
let artist_id = COLLECTION[1].meta.id.clone();
|
||||||
let album_1 = COLLECTION[1].albums[0].meta.clone();
|
let album_1 = COLLECTION[1].albums[0].meta.clone();
|
||||||
let album_4 = COLLECTION[1].albums[3].meta.clone();
|
let album_4 = COLLECTION[1].albums[3].meta.clone();
|
||||||
|
|
||||||
VecDeque::from([
|
VecDeque::from([
|
||||||
MbParams::search_release_group(arid.clone(), album_1),
|
MbParams::search_release_group(artist_id.clone(), arid.clone(), album_1),
|
||||||
MbParams::search_release_group(arid.clone(), album_4),
|
MbParams::search_release_group(artist_id.clone(), arid.clone(), album_4),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn album_artist_id() -> ArtistId {
|
||||||
|
COLLECTION[1].meta.id.clone()
|
||||||
|
}
|
||||||
|
|
||||||
fn album_arid_expectation() -> Mbid {
|
fn album_arid_expectation() -> Mbid {
|
||||||
let mbref = mb_ref_opt_as_ref(&COLLECTION[1].meta.musicbrainz);
|
let mbref = mb_ref_opt_as_ref(&COLLECTION[1].meta.musicbrainz);
|
||||||
mb_ref_opt_unwrap(mbref).mbid().clone()
|
mb_ref_opt_unwrap(mbref).mbid().clone()
|
||||||
@ -611,7 +617,11 @@ mod tests {
|
|||||||
assert_eq!(result, Ok(()));
|
assert_eq!(result, Ok(()));
|
||||||
|
|
||||||
let result = result_receiver.try_recv().unwrap();
|
let result = result_receiver.try_recv().unwrap();
|
||||||
assert_eq!(result, Ok(MatchStateInfo::album_lookup(album, lookup)));
|
let artist_id = album_artist_id();
|
||||||
|
assert_eq!(
|
||||||
|
result,
|
||||||
|
Ok(MatchStateInfo::album_lookup(artist_id, album, lookup))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_artist_expectation(
|
fn search_artist_expectation(
|
||||||
@ -701,11 +711,27 @@ mod tests {
|
|||||||
let result = daemon.execute_next_job();
|
let result = daemon.execute_next_job();
|
||||||
assert_eq!(result, Ok(()));
|
assert_eq!(result, Ok(()));
|
||||||
|
|
||||||
let result = result_receiver.try_recv().unwrap();
|
let artist_id = album_artist_id();
|
||||||
assert_eq!(result, Ok(MatchStateInfo::album_search(album_1, matches_1)));
|
|
||||||
|
|
||||||
let result = result_receiver.try_recv().unwrap();
|
let result = result_receiver.try_recv().unwrap();
|
||||||
assert_eq!(result, Ok(MatchStateInfo::album_search(album_4, matches_4)));
|
assert_eq!(
|
||||||
|
result,
|
||||||
|
Ok(MatchStateInfo::album_search(
|
||||||
|
artist_id.clone(),
|
||||||
|
album_1,
|
||||||
|
matches_1
|
||||||
|
))
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = result_receiver.try_recv().unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
result,
|
||||||
|
Ok(MatchStateInfo::album_search(
|
||||||
|
artist_id.clone(),
|
||||||
|
album_4,
|
||||||
|
matches_4
|
||||||
|
))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
use std::{collections::VecDeque, fmt, sync::mpsc};
|
use std::{collections::VecDeque, fmt, sync::mpsc};
|
||||||
|
|
||||||
use musichoard::collection::{album::AlbumMeta, artist::ArtistMeta, musicbrainz::Mbid};
|
use musichoard::collection::{
|
||||||
|
album::AlbumMeta,
|
||||||
|
artist::{ArtistId, ArtistMeta},
|
||||||
|
musicbrainz::Mbid,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::tui::{app::MatchStateInfo, lib::interface::musicbrainz::api::Error as MbApiError};
|
use crate::tui::{app::MatchStateInfo, lib::interface::musicbrainz::api::Error as MbApiError};
|
||||||
|
|
||||||
@ -60,6 +64,7 @@ pub struct LookupArtistParams {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct LookupReleaseGroupParams {
|
pub struct LookupReleaseGroupParams {
|
||||||
|
pub artist_id: ArtistId,
|
||||||
pub album: AlbumMeta,
|
pub album: AlbumMeta,
|
||||||
pub mbid: Mbid,
|
pub mbid: Mbid,
|
||||||
}
|
}
|
||||||
@ -77,7 +82,8 @@ pub struct SearchArtistParams {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct SearchReleaseGroupParams {
|
pub struct SearchReleaseGroupParams {
|
||||||
pub arid: Mbid,
|
pub artist_id: ArtistId,
|
||||||
|
pub artist_mbid: Mbid,
|
||||||
pub album: AlbumMeta,
|
pub album: AlbumMeta,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,8 +92,9 @@ impl MbParams {
|
|||||||
MbParams::Lookup(LookupParams::Artist(LookupArtistParams { artist, mbid }))
|
MbParams::Lookup(LookupParams::Artist(LookupArtistParams { artist, mbid }))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup_release_group(album: AlbumMeta, mbid: Mbid) -> Self {
|
pub fn lookup_release_group(artist_id: ArtistId, album: AlbumMeta, mbid: Mbid) -> Self {
|
||||||
MbParams::Lookup(LookupParams::ReleaseGroup(LookupReleaseGroupParams {
|
MbParams::Lookup(LookupParams::ReleaseGroup(LookupReleaseGroupParams {
|
||||||
|
artist_id,
|
||||||
album,
|
album,
|
||||||
mbid,
|
mbid,
|
||||||
}))
|
}))
|
||||||
@ -97,9 +104,10 @@ impl MbParams {
|
|||||||
MbParams::Search(SearchParams::Artist(SearchArtistParams { artist }))
|
MbParams::Search(SearchParams::Artist(SearchArtistParams { artist }))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn search_release_group(arid: Mbid, album: AlbumMeta) -> Self {
|
pub fn search_release_group(artist_id: ArtistId, artist_mbid: Mbid, album: AlbumMeta) -> Self {
|
||||||
MbParams::Search(SearchParams::ReleaseGroup(SearchReleaseGroupParams {
|
MbParams::Search(SearchParams::ReleaseGroup(SearchReleaseGroupParams {
|
||||||
arid,
|
artist_id,
|
||||||
|
artist_mbid,
|
||||||
album,
|
album,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,12 @@ pub mod external;
|
|||||||
pub mod interface;
|
pub mod interface;
|
||||||
|
|
||||||
use musichoard::{
|
use musichoard::{
|
||||||
collection::Collection,
|
collection::{
|
||||||
|
album::{AlbumId, AlbumPrimaryType, AlbumSecondaryType},
|
||||||
|
artist::ArtistId,
|
||||||
|
musicbrainz::{MbAlbumRef, MbArtistRef, MbRefOption},
|
||||||
|
Collection,
|
||||||
|
},
|
||||||
interface::{database::IDatabase, library::ILibrary},
|
interface::{database::IDatabase, library::ILibrary},
|
||||||
IMusicHoardBase, IMusicHoardDatabase, IMusicHoardLibrary, MusicHoard,
|
IMusicHoardBase, IMusicHoardDatabase, IMusicHoardLibrary, MusicHoard,
|
||||||
};
|
};
|
||||||
@ -15,6 +20,30 @@ pub trait IMusicHoard {
|
|||||||
fn rescan_library(&mut self) -> Result<(), musichoard::Error>;
|
fn rescan_library(&mut self) -> Result<(), musichoard::Error>;
|
||||||
fn reload_database(&mut self) -> Result<(), musichoard::Error>;
|
fn reload_database(&mut self) -> Result<(), musichoard::Error>;
|
||||||
fn get_collection(&self) -> &Collection;
|
fn get_collection(&self) -> &Collection;
|
||||||
|
|
||||||
|
fn set_artist_musicbrainz(
|
||||||
|
&mut self,
|
||||||
|
id: &ArtistId,
|
||||||
|
mbref: MbRefOption<MbArtistRef>,
|
||||||
|
) -> Result<(), musichoard::Error>;
|
||||||
|
fn set_album_musicbrainz(
|
||||||
|
&mut self,
|
||||||
|
artist_id: &ArtistId,
|
||||||
|
album_id: &AlbumId,
|
||||||
|
mbref: MbRefOption<MbAlbumRef>,
|
||||||
|
) -> Result<(), musichoard::Error>;
|
||||||
|
fn set_album_primary_type(
|
||||||
|
&mut self,
|
||||||
|
artist_id: &ArtistId,
|
||||||
|
album_id: &AlbumId,
|
||||||
|
primary_type: Option<AlbumPrimaryType>,
|
||||||
|
) -> Result<(), musichoard::Error>;
|
||||||
|
fn set_album_secondary_types(
|
||||||
|
&mut self,
|
||||||
|
artist_id: &ArtistId,
|
||||||
|
album_id: &AlbumId,
|
||||||
|
secondary_types: Vec<AlbumSecondaryType>,
|
||||||
|
) -> Result<(), musichoard::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// GRCOV_EXCL_START
|
// GRCOV_EXCL_START
|
||||||
@ -30,5 +59,50 @@ impl<Database: IDatabase, Library: ILibrary> IMusicHoard for MusicHoard<Database
|
|||||||
fn get_collection(&self) -> &Collection {
|
fn get_collection(&self) -> &Collection {
|
||||||
<Self as IMusicHoardBase>::get_collection(self)
|
<Self as IMusicHoardBase>::get_collection(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_artist_musicbrainz(
|
||||||
|
&mut self,
|
||||||
|
id: &ArtistId,
|
||||||
|
mbref: MbRefOption<MbArtistRef>,
|
||||||
|
) -> Result<(), musichoard::Error> {
|
||||||
|
<Self as IMusicHoardDatabase>::set_artist_musicbrainz(self, id, mbref)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_album_musicbrainz(
|
||||||
|
&mut self,
|
||||||
|
artist_id: &ArtistId,
|
||||||
|
album_id: &AlbumId,
|
||||||
|
mbref: MbRefOption<MbAlbumRef>,
|
||||||
|
) -> Result<(), musichoard::Error> {
|
||||||
|
<Self as IMusicHoardDatabase>::set_album_musicbrainz(self, artist_id, album_id, mbref)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_album_primary_type(
|
||||||
|
&mut self,
|
||||||
|
artist_id: &ArtistId,
|
||||||
|
album_id: &AlbumId,
|
||||||
|
primary_type: Option<AlbumPrimaryType>,
|
||||||
|
) -> Result<(), musichoard::Error> {
|
||||||
|
<Self as IMusicHoardDatabase>::set_album_primary_type(
|
||||||
|
self,
|
||||||
|
artist_id,
|
||||||
|
album_id,
|
||||||
|
primary_type,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_album_secondary_types(
|
||||||
|
&mut self,
|
||||||
|
artist_id: &ArtistId,
|
||||||
|
album_id: &AlbumId,
|
||||||
|
secondary_types: Vec<AlbumSecondaryType>,
|
||||||
|
) -> Result<(), musichoard::Error> {
|
||||||
|
<Self as IMusicHoardDatabase>::set_album_secondary_types(
|
||||||
|
self,
|
||||||
|
artist_id,
|
||||||
|
album_id,
|
||||||
|
secondary_types,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// GRCOV_EXCL_STOP
|
// GRCOV_EXCL_STOP
|
||||||
|
@ -373,6 +373,10 @@ mod tests {
|
|||||||
info
|
info
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn album_artist_id() -> ArtistId {
|
||||||
|
ArtistId::new("Artist")
|
||||||
|
}
|
||||||
|
|
||||||
fn album_meta() -> AlbumMeta {
|
fn album_meta() -> AlbumMeta {
|
||||||
AlbumMeta::new(
|
AlbumMeta::new(
|
||||||
AlbumId::new("An Album"),
|
AlbumId::new("An Album"),
|
||||||
@ -383,21 +387,23 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn album_matches() -> MatchStateInfo {
|
fn album_matches() -> MatchStateInfo {
|
||||||
|
let artist_id = album_artist_id();
|
||||||
let album = album_meta();
|
let album = album_meta();
|
||||||
let album_match = Match::new(80, album.clone());
|
let album_match = Match::new(80, album.clone());
|
||||||
let list = vec![album_match.clone(), album_match.clone()];
|
let list = vec![album_match.clone(), album_match.clone()];
|
||||||
|
|
||||||
let mut info = MatchStateInfo::album_search(album, list);
|
let mut info = MatchStateInfo::album_search(artist_id, album, list);
|
||||||
info.push_cannot_have_mbid();
|
info.push_cannot_have_mbid();
|
||||||
info.push_manual_input_mbid();
|
info.push_manual_input_mbid();
|
||||||
info
|
info
|
||||||
}
|
}
|
||||||
|
|
||||||
fn album_lookup() -> MatchStateInfo {
|
fn album_lookup() -> MatchStateInfo {
|
||||||
|
let artist_id = album_artist_id();
|
||||||
let album = album_meta();
|
let album = album_meta();
|
||||||
let album_lookup = Lookup::new(album.clone());
|
let album_lookup = Lookup::new(album.clone());
|
||||||
|
|
||||||
let mut info = MatchStateInfo::album_lookup(album, album_lookup);
|
let mut info = MatchStateInfo::album_lookup(artist_id, album, album_lookup);
|
||||||
info.push_cannot_have_mbid();
|
info.push_cannot_have_mbid();
|
||||||
info.push_manual_input_mbid();
|
info.push_manual_input_mbid();
|
||||||
info
|
info
|
||||||
|
Loading…
Reference in New Issue
Block a user