Compare commits

..

3 Commits

Author SHA1 Message Date
6b90f470be Simplify
Some checks failed
Cargo CI / Build and Test (pull_request) Failing after 1m47s
Cargo CI / Lint (pull_request) Successful in 1m8s
2024-09-28 14:11:07 +02:00
c130519adf Small clean up 2024-09-28 12:15:42 +02:00
b0ac9bf2c1 Simplify fetch 2024-09-28 12:05:16 +02:00
2 changed files with 111 additions and 135 deletions

View File

@ -4,9 +4,9 @@ use std::{
}; };
use musichoard::collection::{ use musichoard::collection::{
album::AlbumMeta, album::{Album, AlbumMeta},
artist::{Artist, ArtistId, ArtistMeta}, artist::{Artist, ArtistId, ArtistMeta},
musicbrainz::{IMusicBrainzRef, MbRefOption, Mbid}, musicbrainz::{IMusicBrainzRef, MbArtistRef, MbRefOption, Mbid},
}; };
use crate::tui::{ use crate::tui::{
@ -158,21 +158,10 @@ impl AppMachine<FetchState> {
) -> Result<(), FetchError> { ) -> Result<(), FetchError> {
let requests = match artist.meta.info.musicbrainz { let requests = match artist.meta.info.musicbrainz {
MbRefOption::Some(ref arid) => { MbRefOption::Some(ref arid) => {
let arid = arid.mbid(); Self::fetch_albums_requests(&artist.meta.id, arid, &artist.albums)
let albums = artist.albums.iter();
albums
.filter(|album| matches!(album.meta.info.musicbrainz, MbRefOption::None))
.map(|album| {
MbParams::search_release_group(
artist.meta.id.clone(),
arid.clone(),
album.meta.clone(),
)
})
.collect()
} }
MbRefOption::CannotHaveMbid => VecDeque::new(), MbRefOption::CannotHaveMbid => VecDeque::new(),
MbRefOption::None => VecDeque::from([MbParams::search_artist(artist.meta.clone())]), MbRefOption::None => Self::fetch_artist_request(&artist.meta),
}; };
if requests.is_empty() { if requests.is_empty() {
return Err(FetchError::NothingToFetch); return Err(FetchError::NothingToFetch);
@ -180,6 +169,25 @@ impl AppMachine<FetchState> {
Ok(musicbrainz.submit_background_job(result_sender, requests)?) Ok(musicbrainz.submit_background_job(result_sender, requests)?)
} }
fn fetch_albums_requests(
artist: &ArtistId,
arid: &MbArtistRef,
albums: &[Album],
) -> VecDeque<MbParams> {
let arid = arid.mbid();
albums
.iter()
.filter(|album| matches!(album.meta.info.musicbrainz, MbRefOption::None))
.map(|album| {
MbParams::search_release_group(artist.clone(), arid.clone(), album.meta.clone())
})
.collect()
}
fn fetch_artist_request(meta: &ArtistMeta) -> VecDeque<MbParams> {
VecDeque::from([MbParams::search_artist(meta.clone())])
}
fn submit_lookup_artist_job( fn submit_lookup_artist_job(
musicbrainz: &dyn IMbJobSender, musicbrainz: &dyn IMbJobSender,
result_sender: ResultSender, result_sender: ResultSender,

View File

@ -1,8 +1,8 @@
use std::cmp; use std::cmp;
use musichoard::collection::{ use musichoard::collection::{
album::AlbumMeta, album::{AlbumInfo, AlbumMeta},
artist::{ArtistId, ArtistMeta}, artist::{ArtistInfo, ArtistMeta},
musicbrainz::{MbRefOption, Mbid}, musicbrainz::{MbRefOption, Mbid},
}; };
@ -12,64 +12,70 @@ use crate::tui::{
AlbumMatches, AppPublicState, AppState, ArtistMatches, IAppInteractMatch, ListOption, AlbumMatches, AppPublicState, AppState, ArtistMatches, IAppInteractMatch, ListOption,
MatchOption, MatchStateInfo, MatchStatePublic, WidgetState, MatchOption, MatchStateInfo, MatchStatePublic, WidgetState,
}, },
lib::{ lib::interface::musicbrainz::api::{Lookup, Match},
interface::musicbrainz::api::{Lookup, Match},
IMusicHoard,
},
}; };
macro_rules! item_option_artist_set { trait GetInfoMeta {
type InfoType;
}
impl GetInfoMeta for ArtistMeta {
type InfoType = ArtistInfo;
}
impl GetInfoMeta for AlbumMeta {
type InfoType = AlbumInfo;
}
trait GetInfo {
type InfoType;
fn into_info(self, info: Self::InfoType) -> InfoOption<Self::InfoType>;
}
enum InfoOption<T> {
Info(T),
NeedInput,
}
macro_rules! impl_match_option_artist_into_info {
($holder:ident) => { ($holder:ident) => {
impl MatchOption<$holder<ArtistMeta>> { impl GetInfo for MatchOption<$holder<ArtistMeta>> {
fn set( type InfoType = ArtistInfo;
self,
music_hoard: &mut dyn IMusicHoard, fn into_info(self, mut info: Self::InfoType) -> InfoOption<Self::InfoType> {
meta: &ArtistMeta, match self {
) -> Result<(), musichoard::Error> { MatchOption::Some(option) => info.musicbrainz = option.item.info.musicbrainz,
let mut info = meta.info.clone(); MatchOption::CannotHaveMbid => info.musicbrainz = MbRefOption::CannotHaveMbid,
info.musicbrainz = match self { MatchOption::ManualInputMbid => return InfoOption::NeedInput,
MatchOption::Some(m) => m.item.info.musicbrainz, }
MatchOption::CannotHaveMbid => MbRefOption::CannotHaveMbid, InfoOption::Info(info)
MatchOption::ManualInputMbid => panic!(),
};
music_hoard.set_artist_info(&meta.id, info)
} }
} }
}; };
} }
item_option_artist_set!(Lookup); impl_match_option_artist_into_info!(Match);
item_option_artist_set!(Match); impl_match_option_artist_into_info!(Lookup);
macro_rules! item_option_album_set { macro_rules! impl_match_option_album_into_info {
($holder:ident) => { ($holder:ident) => {
impl MatchOption<$holder<AlbumMeta>> { impl GetInfo for MatchOption<$holder<AlbumMeta>> {
fn set( type InfoType = AlbumInfo;
self,
music_hoard: &mut dyn IMusicHoard, fn into_info(self, mut info: Self::InfoType) -> InfoOption<Self::InfoType> {
artist: &ArtistId, match self {
meta: &AlbumMeta, MatchOption::Some(option) => info = option.item.info,
) -> Result<(), musichoard::Error> { MatchOption::CannotHaveMbid => info.musicbrainz = MbRefOption::CannotHaveMbid,
let mut info = meta.info.clone(); MatchOption::ManualInputMbid => return InfoOption::NeedInput,
(info.musicbrainz, info.primary_type, info.secondary_types) = match self { }
MatchOption::Some(m) => ( InfoOption::Info(info)
m.item.info.musicbrainz,
m.item.info.primary_type,
m.item.info.secondary_types,
),
MatchOption::CannotHaveMbid => (MbRefOption::CannotHaveMbid, None, Vec::new()),
MatchOption::ManualInputMbid => panic!(),
};
music_hoard.set_album_info(artist, &meta.id, info)
} }
} }
}; };
} }
item_option_album_set!(Lookup); impl_match_option_album_into_info!(Match);
item_option_album_set!(Match); impl_match_option_album_into_info!(Lookup);
impl<T: PartialEq> ListOption<T> { impl<T> ListOption<T> {
fn len(&self) -> usize { fn len(&self) -> usize {
match self { match self {
ListOption::Lookup(list) => list.len(), ListOption::Lookup(list) => list.len(),
@ -90,40 +96,24 @@ impl<T: PartialEq> ListOption<T> {
ListOption::Search(list) => list.push(MatchOption::ManualInputMbid), ListOption::Search(list) => list.push(MatchOption::ManualInputMbid),
} }
} }
fn is_manual_input_mbid(&self, index: usize) -> bool {
match self {
ListOption::Lookup(list) => list.get(index) == Some(&MatchOption::ManualInputMbid),
ListOption::Search(list) => list.get(index) == Some(&MatchOption::ManualInputMbid),
}
}
} }
impl ListOption<ArtistMeta> { trait ExtractInfo {
fn set( type InfoType;
self, fn extract_info(&mut self, index: usize, info: Self::InfoType) -> InfoOption<Self::InfoType>;
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> { impl<T: GetInfoMeta> ExtractInfo for ListOption<T>
fn set( where
self, MatchOption<Match<T>>: GetInfo<InfoType = T::InfoType>,
music_hoard: &mut dyn IMusicHoard, MatchOption<Lookup<T>>: GetInfo<InfoType = T::InfoType>,
artist: &ArtistId, {
meta: &AlbumMeta, type InfoType = T::InfoType;
index: usize,
) -> Result<(), musichoard::Error> { fn extract_info(&mut self, index: usize, info: Self::InfoType) -> InfoOption<Self::InfoType> {
match self { match self {
ListOption::Lookup(mut list) => list.swap_remove(index).set(music_hoard, artist, meta), ListOption::Lookup(ref mut list) => list.swap_remove(index).into_info(info),
ListOption::Search(mut list) => list.swap_remove(index).set(music_hoard, artist, meta), ListOption::Search(ref mut list) => list.swap_remove(index).into_info(info),
} }
} }
} }
@ -140,14 +130,6 @@ impl ArtistMatches {
fn push_manual_input_mbid(&mut self) { fn push_manual_input_mbid(&mut self) {
self.list.push_manual_input_mbid(); self.list.push_manual_input_mbid();
} }
fn is_manual_input_mbid(&self, index: usize) -> bool {
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 {
@ -162,15 +144,6 @@ impl AlbumMatches {
fn push_manual_input_mbid(&mut self) { fn push_manual_input_mbid(&mut self) {
self.list.push_manual_input_mbid(); self.list.push_manual_input_mbid();
} }
fn is_manual_input_mbid(&self, index: usize) -> bool {
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 {
@ -194,20 +167,6 @@ impl MatchStateInfo {
Self::Album(a) => a.push_manual_input_mbid(), Self::Album(a) => a.push_manual_input_mbid(),
} }
} }
fn is_manual_input_mbid(&self, index: usize) -> bool {
match self {
Self::Artist(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 {
@ -260,6 +219,11 @@ impl AppMachine<MatchState> {
} }
} }
} }
fn get_input(mut self) -> App {
self.input.replace(Input::default());
self.into()
}
} }
impl From<AppMachine<MatchState>> for App { impl From<AppMachine<MatchState>> for App {
@ -307,23 +271,27 @@ impl IAppInteractMatch for AppMachine<MatchState> {
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 let mh = &mut self.inner.music_hoard;
.state let result = match self.state.current.as_mut().unwrap() {
.current MatchStateInfo::Artist(ref mut matches) => {
.as_ref() let info: ArtistInfo = matches.matching.info.clone();
.unwrap() match matches.list.extract_info(index, info) {
.is_manual_input_mbid(index) InfoOption::Info(info) => mh.set_artist_info(&matches.matching.id, info),
{ InfoOption::NeedInput => return self.get_input(),
self.input.replace(Input::default()); }
return self.into(); }
} MatchStateInfo::Album(matches) => {
let info: AlbumInfo = matches.matching.info.clone();
match matches.list.extract_info(index, info) {
InfoOption::Info(info) => {
mh.set_album_info(&matches.artist, &matches.matching.id, info)
}
InfoOption::NeedInput => return self.get_input(),
}
}
};
if let Err(err) = self if let Err(err) = result {
.state
.current
.unwrap()
.set(&mut *self.inner.music_hoard, index)
{
return AppMachine::error_state(self.inner, err.to_string()).into(); return AppMachine::error_state(self.inner, err.to_string()).into();
} }
} }