Provide a keyboard shortcut to pull all release groups of an artist #233

Merged
wojtek merged 14 commits from 160---provide-a-keyboard-shortcut-to-pull-all-release-groups-of-an-artist into main 2024-12-30 23:42:20 +01:00
3 changed files with 44 additions and 31 deletions
Showing only changes of commit 134165a297 - Show all commits

View File

@ -22,28 +22,41 @@ use crate::tui::{
pub type MbApiReceiver = mpsc::Receiver<MbApiResult>; pub type MbApiReceiver = mpsc::Receiver<MbApiResult>;
pub struct FetchState { pub struct FetchState {
search_rx: MbApiReceiver, search_rx: Option<MbApiReceiver>,
lookup_rx: Option<MbApiReceiver>, lookup_rx: Option<MbApiReceiver>,
fetch_rx: Option<MbApiReceiver>,
}
macro_rules! try_recv_mb_api_receiver {
($rx:expr) => {
if let Some(rx) = &($rx) {
match rx.try_recv() {
x @ Ok(_) | x @ Err(TryRecvError::Empty) => return x,
Err(TryRecvError::Disconnected) => {
($rx).take();
}
}
}
};
} }
impl FetchState { impl FetchState {
pub fn new(search_rx: MbApiReceiver) -> Self { pub fn search(search_rx: MbApiReceiver) -> Self {
FetchState { FetchState {
search_rx, search_rx: Some(search_rx),
lookup_rx: None, lookup_rx: None,
fetch_rx: None,
} }
} }
fn try_recv(&mut self) -> Result<MbApiResult, TryRecvError> { fn try_recv(&mut self) -> Result<MbApiResult, TryRecvError> {
if let Some(lookup_rx) = &self.lookup_rx { try_recv_mb_api_receiver!(self.lookup_rx);
match lookup_rx.try_recv() { try_recv_mb_api_receiver!(self.search_rx);
x @ Ok(_) | x @ Err(TryRecvError::Empty) => return x,
Err(TryRecvError::Disconnected) => { match &self.fetch_rx {
self.lookup_rx.take(); Some(fetch_rx) => fetch_rx.try_recv(),
} None => Err(TryRecvError::Disconnected),
}
} }
self.search_rx.try_recv()
} }
} }
@ -79,7 +92,7 @@ impl AppMachine<FetchState> {
}; };
let (fetch_tx, fetch_rx) = mpsc::channel::<MbApiResult>(); let (fetch_tx, fetch_rx) = mpsc::channel::<MbApiResult>();
let fetch = FetchState::new(fetch_rx); let fetch = FetchState::search(fetch_rx);
let mb = &*inner.musicbrainz; let mb = &*inner.musicbrainz;
let result = match inner.selection.category() { let result = match inner.selection.category() {
@ -203,10 +216,10 @@ impl AppMachine<FetchState> {
artist_mbid: &MbArtistRef, artist_mbid: &MbArtistRef,
album: &Album, album: &Album,
) -> Result<(), FetchError> { ) -> Result<(), FetchError> {
if !matches!(album.meta.info.musicbrainz, MbRefOption::None) { let requests = Self::search_albums_requests(artist_id, artist_mbid, slice::from_ref(album));
if requests.is_empty() {
return Err(FetchError::NothingToFetch); return Err(FetchError::NothingToFetch);
} }
let requests = Self::search_albums_requests(artist_id, artist_mbid, slice::from_ref(album));
Ok(musicbrainz.submit_background_job(result_sender, requests)?) Ok(musicbrainz.submit_background_job(result_sender, requests)?)
} }
@ -312,7 +325,7 @@ mod tests {
let (fetch_tx, fetch_rx) = mpsc::channel(); let (fetch_tx, fetch_rx) = mpsc::channel();
let (lookup_tx, lookup_rx) = mpsc::channel(); let (lookup_tx, lookup_rx) = mpsc::channel();
let mut fetch = FetchState::new(fetch_rx); let mut fetch = FetchState::search(fetch_rx);
fetch.lookup_rx.replace(lookup_rx); fetch.lookup_rx.replace(lookup_rx);
let artist = COLLECTION[3].meta.clone(); let artist = COLLECTION[3].meta.clone();
@ -494,7 +507,7 @@ mod tests {
let inner = AppInner::new(music_hoard, mb_job_sender); let inner = AppInner::new(music_hoard, mb_job_sender);
let (_fetch_tx, fetch_rx) = mpsc::channel(); let (_fetch_tx, fetch_rx) = mpsc::channel();
let fetch = FetchState::new(fetch_rx); let fetch = FetchState::search(fetch_rx);
AppMachine::app_lookup_album(inner, fetch, &artist_id, &album_id, mbid()); AppMachine::app_lookup_album(inner, fetch, &artist_id, &album_id, mbid());
} }
@ -548,7 +561,7 @@ mod tests {
let inner = AppInner::new(music_hoard, mb_job_sender); let inner = AppInner::new(music_hoard, mb_job_sender);
let (_fetch_tx, fetch_rx) = mpsc::channel(); let (_fetch_tx, fetch_rx) = mpsc::channel();
let fetch = FetchState::new(fetch_rx); let fetch = FetchState::search(fetch_rx);
AppMachine::app_lookup_artist(inner, fetch, &artist, mbid()); AppMachine::app_lookup_artist(inner, fetch, &artist, mbid());
} }
@ -597,7 +610,7 @@ mod tests {
let inner = AppInner::new(music_hoard, mb_job_sender); let inner = AppInner::new(music_hoard, mb_job_sender);
let (_fetch_tx, fetch_rx) = mpsc::channel(); let (_fetch_tx, fetch_rx) = mpsc::channel();
let fetch = FetchState::new(fetch_rx); let fetch = FetchState::search(fetch_rx);
let app = AppMachine::app_lookup_artist(inner, fetch, &artist, mbid()); let app = AppMachine::app_lookup_artist(inner, fetch, &artist, mbid());
assert!(matches!(app, AppState::Error(_))); assert!(matches!(app, AppState::Error(_)));
@ -615,7 +628,7 @@ mod tests {
tx.send(fetch_result).unwrap(); tx.send(fetch_result).unwrap();
let inner = inner(music_hoard(COLLECTION.clone())); let inner = inner(music_hoard(COLLECTION.clone()));
let fetch = FetchState::new(rx); let fetch = FetchState::search(rx);
let mut app = AppMachine::app_fetch_next(inner, fetch); let mut app = AppMachine::app_fetch_next(inner, fetch);
assert!(matches!(app, AppState::Match(_))); assert!(matches!(app, AppState::Match(_)));
@ -638,7 +651,7 @@ mod tests {
tx.send(fetch_result).unwrap(); tx.send(fetch_result).unwrap();
let inner = inner(music_hoard(COLLECTION.clone())); let inner = inner(music_hoard(COLLECTION.clone()));
let fetch = FetchState::new(rx); let fetch = FetchState::search(rx);
let app = AppMachine::app_fetch_next(inner, fetch); let app = AppMachine::app_fetch_next(inner, fetch);
assert!(matches!(app, AppState::Error(_))); assert!(matches!(app, AppState::Error(_)));
} }
@ -648,7 +661,7 @@ mod tests {
let (_tx, rx) = mpsc::channel::<MbApiResult>(); let (_tx, rx) = mpsc::channel::<MbApiResult>();
let inner = inner(music_hoard(COLLECTION.clone())); let inner = inner(music_hoard(COLLECTION.clone()));
let fetch = FetchState::new(rx); let fetch = FetchState::search(rx);
let app = AppMachine::app_fetch_next(inner, fetch); let app = AppMachine::app_fetch_next(inner, fetch);
assert!(matches!(app, AppState::Fetch(_))); assert!(matches!(app, AppState::Fetch(_)));
} }
@ -668,7 +681,7 @@ mod tests {
collection[0].albums.clear(); collection[0].albums.clear();
let (_, rx) = mpsc::channel::<MbApiResult>(); let (_, rx) = mpsc::channel::<MbApiResult>();
let fetch = FetchState::new(rx); let fetch = FetchState::search(rx);
let app = AppMachine::app_fetch_next(inner(music_hoard(collection)), fetch); let app = AppMachine::app_fetch_next(inner(music_hoard(collection)), fetch);
assert!(matches!(app, AppState::Browse(_))); assert!(matches!(app, AppState::Browse(_)));
@ -679,7 +692,7 @@ mod tests {
let (tx, rx) = mpsc::channel::<MbApiResult>(); let (tx, rx) = mpsc::channel::<MbApiResult>();
let inner = inner(music_hoard(COLLECTION.clone())); let inner = inner(music_hoard(COLLECTION.clone()));
let fetch = FetchState::new(rx); let fetch = FetchState::search(rx);
let app = AppMachine::app_fetch_next(inner, fetch); let app = AppMachine::app_fetch_next(inner, fetch);
assert!(matches!(app, AppState::Fetch(_))); assert!(matches!(app, AppState::Fetch(_)));
@ -696,7 +709,7 @@ mod tests {
fn abort() { fn abort() {
let (_, rx) = mpsc::channel::<MbApiResult>(); let (_, rx) = mpsc::channel::<MbApiResult>();
let fetch = FetchState::new(rx); let fetch = FetchState::search(rx);
let app = AppMachine::fetch_state(inner(music_hoard(COLLECTION.clone())), fetch); let app = AppMachine::fetch_state(inner(music_hoard(COLLECTION.clone())), fetch);
let app = app.abort(); let app = app.abort();

View File

@ -357,7 +357,7 @@ mod tests {
fn fetch_state() -> FetchState { fn fetch_state() -> FetchState {
let (_, rx) = mpsc::channel(); let (_, rx) = mpsc::channel();
FetchState::new(rx) FetchState::search(rx)
} }
fn match_state(match_state_info: EntityMatches) -> MatchState { fn match_state(match_state_info: EntityMatches) -> MatchState {
@ -388,7 +388,7 @@ mod tests {
fn match_state_flow(mut matches_info: EntityMatches, len: usize) { fn match_state_flow(mut matches_info: EntityMatches, len: usize) {
// tx must exist for rx to return Empty rather than Disconnected. // tx must exist for rx to return Empty rather than Disconnected.
let (_tx, rx) = mpsc::channel(); let (_tx, rx) = mpsc::channel();
let app_matches = MatchState::new(matches_info.clone(), FetchState::new(rx)); let app_matches = MatchState::new(matches_info.clone(), FetchState::search(rx));
let mut music_hoard = music_hoard(vec![]); let mut music_hoard = music_hoard(vec![]);
let artist_id = ArtistId::new("Artist"); let artist_id = ArtistId::new("Artist");
@ -487,7 +487,7 @@ mod tests {
let matches_info = artist_match(); let matches_info = artist_match();
let (_tx, rx) = mpsc::channel(); let (_tx, rx) = mpsc::channel();
let app_matches = MatchState::new(matches_info.clone(), FetchState::new(rx)); let app_matches = MatchState::new(matches_info.clone(), FetchState::search(rx));
let mut music_hoard = music_hoard(vec![]); let mut music_hoard = music_hoard(vec![]);
match matches_info { match matches_info {
@ -511,7 +511,7 @@ mod tests {
let matches_info = album_match(); let matches_info = album_match();
let (_tx, rx) = mpsc::channel(); let (_tx, rx) = mpsc::channel();
let app_matches = MatchState::new(matches_info.clone(), FetchState::new(rx)); let app_matches = MatchState::new(matches_info.clone(), FetchState::search(rx));
let mut music_hoard = music_hoard(vec![]); let mut music_hoard = music_hoard(vec![]);
match matches_info { match matches_info {
@ -535,7 +535,7 @@ mod tests {
let matches_info = artist_match(); let matches_info = artist_match();
let (_tx, rx) = mpsc::channel(); let (_tx, rx) = mpsc::channel();
let app_matches = MatchState::new(matches_info.clone(), FetchState::new(rx)); let app_matches = MatchState::new(matches_info.clone(), FetchState::search(rx));
let mut music_hoard = music_hoard(vec![]); let mut music_hoard = music_hoard(vec![]);
match matches_info { match matches_info {

View File

@ -493,7 +493,7 @@ mod tests {
let (_, rx) = mpsc::channel(); let (_, rx) = mpsc::channel();
let inner = app.unwrap_browse().inner; let inner = app.unwrap_browse().inner;
let state = FetchState::new(rx); let state = FetchState::search(rx);
app = AppMachine::new(inner, state).into(); app = AppMachine::new(inner, state).into();
let state = app.state(); let state = app.state();
@ -518,7 +518,7 @@ mod tests {
assert!(app.is_running()); assert!(app.is_running());
let (_, rx) = mpsc::channel(); let (_, rx) = mpsc::channel();
let fetch = FetchState::new(rx); let fetch = FetchState::search(rx);
let artist = ArtistMeta::new(ArtistId::new("Artist")); let artist = ArtistMeta::new(ArtistId::new("Artist"));
let info = EntityMatches::artist_lookup(artist.clone(), Entity::new(artist.clone())); let info = EntityMatches::artist_lookup(artist.clone(), Entity::new(artist.clone()));
app = app =