Make fetch also fetch artist MBID if it is missing #201
@ -91,34 +91,35 @@ impl IAppInteractBrowse for AppMachine<AppBrowse> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let arid = match artist.musicbrainz {
|
let mut matches = vec![];
|
||||||
Some(ref mbid) => mbid.mbid(),
|
|
||||||
None => {
|
match artist.musicbrainz {
|
||||||
return AppMachine::error(self.inner, "cannot fetch: missing artist MBID").into()
|
Some(ref mbid) => {
|
||||||
|
let arid = mbid.mbid();
|
||||||
|
|
||||||
|
let mut album_iter = artist.albums.iter().peekable();
|
||||||
|
while let Some(album) = album_iter.next() {
|
||||||
|
if album.musicbrainz.is_some() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.inner.musicbrainz.search_release_group(arid, album) {
|
||||||
|
Ok(list) => matches.push(AppMatchesInfo::album(album.clone(), list)),
|
||||||
|
Err(err) => return AppMachine::error(self.inner, err.to_string()).into(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if album_iter.peek().is_some() {
|
||||||
|
thread::sleep(time::Duration::from_secs(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
None => match self.inner.musicbrainz.search_artist(&artist.id.name) {
|
||||||
|
Ok(list) => matches.push(AppMatchesInfo::artist(artist.clone(), list)),
|
||||||
|
Err(err) => return AppMachine::error(self.inner, err.to_string()).into(),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut artist_album_matches = vec![];
|
AppMachine::matches(self.inner, matches).into()
|
||||||
let mut album_iter = artist.albums.iter().peekable();
|
|
||||||
while let Some(album) = album_iter.next() {
|
|
||||||
if album.musicbrainz.is_some() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.inner.musicbrainz.search_release_group(arid, album) {
|
|
||||||
Ok(matches) => artist_album_matches.push(AppMatchesInfo {
|
|
||||||
matching: album.clone(),
|
|
||||||
matches,
|
|
||||||
}),
|
|
||||||
Err(err) => return AppMachine::error(self.inner, err.to_string()).into(),
|
|
||||||
}
|
|
||||||
|
|
||||||
if album_iter.peek().is_some() {
|
|
||||||
thread::sleep(time::Duration::from_secs(1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AppMachine::matches(self.inner, artist_album_matches).into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn no_op(self) -> Self::APP {
|
fn no_op(self) -> Self::APP {
|
||||||
@ -257,7 +258,15 @@ mod tests {
|
|||||||
|
|
||||||
let public_matches = public.state.unwrap_matches();
|
let public_matches = public.state.unwrap_matches();
|
||||||
|
|
||||||
assert_eq!(public_matches.matches.as_ref().unwrap().album_ref().matching, &album_1);
|
assert_eq!(
|
||||||
|
public_matches
|
||||||
|
.matches
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.album_ref()
|
||||||
|
.matching,
|
||||||
|
&album_1
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
public_matches.matches.as_ref().unwrap().album_ref().list,
|
public_matches.matches.as_ref().unwrap().album_ref().list,
|
||||||
matches_1.as_slice()
|
matches_1.as_slice()
|
||||||
@ -270,7 +279,15 @@ mod tests {
|
|||||||
|
|
||||||
let public_matches = public.state.unwrap_matches();
|
let public_matches = public.state.unwrap_matches();
|
||||||
|
|
||||||
assert_eq!(public_matches.matches.as_ref().unwrap().album_ref().matching, &album_4);
|
assert_eq!(
|
||||||
|
public_matches
|
||||||
|
.matches
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.album_ref()
|
||||||
|
.matching,
|
||||||
|
&album_4
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
public_matches.matches.as_ref().unwrap().album_ref().list,
|
public_matches.matches.as_ref().unwrap().album_ref().list,
|
||||||
matches_4.as_slice()
|
matches_4.as_slice()
|
||||||
|
@ -1,20 +1,117 @@
|
|||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
||||||
use musichoard::collection::album::Album;
|
use musichoard::collection::{album::Album, artist::Artist};
|
||||||
|
|
||||||
use crate::tui::{
|
use crate::tui::{
|
||||||
app::{
|
app::{
|
||||||
machine::{App, AppInner, AppMachine},
|
machine::{App, AppInner, AppMachine},
|
||||||
AppPublic, AppPublicAlbumMatches, AppPublicMatches, AppPublicMatchesKind, AppState,
|
AppPublic, AppPublicAlbumMatches, AppPublicArtistMatches, AppPublicMatches,
|
||||||
IAppInteractMatches, WidgetState,
|
AppPublicMatchesKind, AppState, IAppInteractMatches, WidgetState,
|
||||||
},
|
},
|
||||||
lib::interface::musicbrainz::Match,
|
lib::interface::musicbrainz::Match,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct AppMatchesInfo {
|
pub struct AppArtistMatchesInfo {
|
||||||
|
pub matching: Artist,
|
||||||
|
pub list: Vec<Match<Artist>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppArtistMatchesInfo {
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.list.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.list.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'app> From<&'app AppArtistMatchesInfo> for AppPublicArtistMatches<'app> {
|
||||||
|
fn from(value: &'app AppArtistMatchesInfo) -> Self {
|
||||||
|
AppPublicArtistMatches {
|
||||||
|
matching: &value.matching,
|
||||||
|
list: &value.list,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct AppAlbumMatchesInfo {
|
||||||
pub matching: Album,
|
pub matching: Album,
|
||||||
pub matches: Vec<Match<Album>>,
|
pub list: Vec<Match<Album>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppAlbumMatchesInfo {
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.list.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.list.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'app> From<&'app AppAlbumMatchesInfo> for AppPublicAlbumMatches<'app> {
|
||||||
|
fn from(value: &'app AppAlbumMatchesInfo) -> Self {
|
||||||
|
AppPublicAlbumMatches {
|
||||||
|
matching: &value.matching,
|
||||||
|
list: &value.list,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum AppMatchesInfo {
|
||||||
|
Artist(AppArtistMatchesInfo),
|
||||||
|
Album(AppAlbumMatchesInfo),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppMatchesInfo {
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Artist(a) => a.is_empty(),
|
||||||
|
Self::Album(a) => a.is_empty(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
Self::Artist(a) => a.len(),
|
||||||
|
Self::Album(a) => a.len(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn artist_ref(&self) -> &AppArtistMatchesInfo {
|
||||||
|
match self {
|
||||||
|
Self::Artist(a) => a,
|
||||||
|
Self::Album(_) => panic!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn album_ref(&self) -> &AppAlbumMatchesInfo {
|
||||||
|
match self {
|
||||||
|
Self::Album(a) => a,
|
||||||
|
Self::Artist(_) => panic!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn artist(matching: Artist, list: Vec<Match<Artist>>) -> Self {
|
||||||
|
AppMatchesInfo::Artist(AppArtistMatchesInfo { matching, list })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn album(matching: Album, list: Vec<Match<Album>>) -> Self {
|
||||||
|
AppMatchesInfo::Album(AppAlbumMatchesInfo { matching, list })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'app> From<&'app AppMatchesInfo> for AppPublicMatchesKind<'app> {
|
||||||
|
fn from(value: &'app AppMatchesInfo) -> Self {
|
||||||
|
match value {
|
||||||
|
AppMatchesInfo::Artist(a) => AppPublicMatchesKind::Artist(a.into()),
|
||||||
|
AppMatchesInfo::Album(a) => AppPublicMatchesKind::Album(a.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AppMatches {
|
pub struct AppMatches {
|
||||||
@ -29,7 +126,7 @@ impl AppMachine<AppMatches> {
|
|||||||
let mut state = WidgetState::default();
|
let mut state = WidgetState::default();
|
||||||
if let Some(matches_info) = matches_info_vec.first() {
|
if let Some(matches_info) = matches_info_vec.first() {
|
||||||
index = Some(0);
|
index = Some(0);
|
||||||
if !matches_info.matches.is_empty() {
|
if !matches_info.is_empty() {
|
||||||
state.list.select(Some(0));
|
state.list.select(Some(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,12 +150,10 @@ impl From<AppMachine<AppMatches>> for App {
|
|||||||
|
|
||||||
impl<'a> From<&'a mut AppMachine<AppMatches>> for AppPublic<'a> {
|
impl<'a> From<&'a mut AppMachine<AppMatches>> for AppPublic<'a> {
|
||||||
fn from(machine: &'a mut AppMachine<AppMatches>) -> Self {
|
fn from(machine: &'a mut AppMachine<AppMatches>) -> Self {
|
||||||
let matches = machine.state.index.map(|index| {
|
let matches = machine
|
||||||
AppPublicMatchesKind::Album(AppPublicAlbumMatches {
|
.state
|
||||||
matching: &machine.state.matches_info_vec[index].matching,
|
.index
|
||||||
list: machine.state.matches_info_vec[index].matches.as_slice(),
|
.map(|index| (&machine.state.matches_info_vec[index]).into());
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
AppPublic {
|
AppPublic {
|
||||||
inner: (&mut machine.inner).into(),
|
inner: (&mut machine.inner).into(),
|
||||||
@ -88,7 +183,6 @@ impl IAppInteractMatches for AppMachine<AppMatches> {
|
|||||||
let to = cmp::min(
|
let to = cmp::min(
|
||||||
result,
|
result,
|
||||||
self.state.matches_info_vec[self.state.index.unwrap()]
|
self.state.matches_info_vec[self.state.index.unwrap()]
|
||||||
.matches
|
|
||||||
.len()
|
.len()
|
||||||
.saturating_sub(1),
|
.saturating_sub(1),
|
||||||
);
|
);
|
||||||
@ -103,7 +197,7 @@ impl IAppInteractMatches for AppMachine<AppMatches> {
|
|||||||
self.state.state = WidgetState::default();
|
self.state.state = WidgetState::default();
|
||||||
if let Some(index) = self.state.index {
|
if let Some(index) = self.state.index {
|
||||||
if let Some(matches_info) = self.state.matches_info_vec.get(index) {
|
if let Some(matches_info) = self.state.matches_info_vec.get(index) {
|
||||||
if !matches_info.matches.is_empty() {
|
if !matches_info.is_empty() {
|
||||||
self.state.state.list.select(Some(0));
|
self.state.state.list.select(Some(0));
|
||||||
}
|
}
|
||||||
return self.into();
|
return self.into();
|
||||||
@ -157,10 +251,10 @@ mod tests {
|
|||||||
disambiguation: None,
|
disambiguation: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let matches_info_1 = AppMatchesInfo {
|
let matches_info_1 = AppMatchesInfo::Album(AppAlbumMatchesInfo {
|
||||||
matching: album_1.clone(),
|
matching: album_1.clone(),
|
||||||
matches: vec![album_match_1_1.clone(), album_match_1_2.clone()],
|
list: vec![album_match_1_1.clone(), album_match_1_2.clone()],
|
||||||
};
|
});
|
||||||
|
|
||||||
let album_2 = Album::new(
|
let album_2 = Album::new(
|
||||||
AlbumId::new("Album 2"),
|
AlbumId::new("Album 2"),
|
||||||
@ -176,10 +270,10 @@ mod tests {
|
|||||||
disambiguation: None,
|
disambiguation: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let matches_info_2 = AppMatchesInfo {
|
let matches_info_2 = AppMatchesInfo::Album(AppAlbumMatchesInfo {
|
||||||
matching: album_2.clone(),
|
matching: album_2.clone(),
|
||||||
matches: vec![album_match_2_1.clone()],
|
list: vec![album_match_2_1.clone()],
|
||||||
};
|
});
|
||||||
|
|
||||||
vec![matches_info_1, matches_info_2]
|
vec![matches_info_1, matches_info_2]
|
||||||
}
|
}
|
||||||
@ -219,12 +313,17 @@ mod tests {
|
|||||||
let public_matches = public.state.unwrap_matches();
|
let public_matches = public.state.unwrap_matches();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
public_matches.matches.as_ref().unwrap().album_ref().matching,
|
public_matches
|
||||||
&matches_info_vec[0].matching
|
.matches
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.album_ref()
|
||||||
|
.matching,
|
||||||
|
&matches_info_vec[0].album_ref().matching
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
public_matches.matches.as_ref().unwrap().album_ref().list,
|
public_matches.matches.as_ref().unwrap().album_ref().list,
|
||||||
matches_info_vec[0].matches.as_slice()
|
matches_info_vec[0].album_ref().list.as_slice()
|
||||||
);
|
);
|
||||||
assert_eq!(public_matches.state, &widget_state);
|
assert_eq!(public_matches.state, &widget_state);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user