Compare commits
3 Commits
2a32fc8ea7
...
6b90f470be
Author | SHA1 | Date | |
---|---|---|---|
6b90f470be | |||
c130519adf | |||
b0ac9bf2c1 |
@ -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,
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user