diff --git a/src/tui/app/machine/browse_state.rs b/src/tui/app/machine/browse_state.rs index 06c8cfb..1c372d3 100644 --- a/src/tui/app/machine/browse_state.rs +++ b/src/tui/app/machine/browse_state.rs @@ -84,7 +84,7 @@ mod tests { machine::tests::{inner, inner_with_mb, music_hoard}, Category, IApp, IAppAccess, }, - lib::interface::musicbrainz::MockIMusicBrainz, + lib::interface::musicbrainz::api::MockIMusicBrainz, testmod::COLLECTION, }; diff --git a/src/tui/app/machine/fetch_state.rs b/src/tui/app/machine/fetch_state.rs index da01165..117f5b9 100644 --- a/src/tui/app/machine/fetch_state.rs +++ b/src/tui/app/machine/fetch_state.rs @@ -18,7 +18,10 @@ use crate::tui::{ AppPublicState, AppState, IAppEventFetch, IAppInteractFetch, MatchStateInfo, }, event::{Event, EventSender}, - lib::interface::musicbrainz::{self, Error as MbError, IMusicBrainz}, + lib::interface::musicbrainz::{ + self, + api::{Error as MbError, IMusicBrainz}, + }, }; pub struct FetchState { @@ -147,7 +150,7 @@ impl AppMachine { fn send_fetch_result( fetch_tx: &FetchSender, events: &EventSender, - result: Result, + result: Result, ) -> Result<(), ()> { // If receiver disconnects just drop the rest. fetch_tx.send(result).map_err(|_| ())?; @@ -199,7 +202,10 @@ mod tests { AlbumMatches, ArtistMatches, IApp, }, event::EventReceiver, - lib::interface::musicbrainz::{self, Match, MockIMusicBrainz}, + lib::interface::musicbrainz::{ + self, + api::{Match, MockIMusicBrainz}, + }, testmod::COLLECTION, EventChannel, }; @@ -415,7 +421,7 @@ mod tests { fn recv_ok_fetch_err() { let (tx, rx) = mpsc::channel::(); - let fetch_result = Err(musicbrainz::Error::RateLimit); + let fetch_result = Err(musicbrainz::api::Error::RateLimit); tx.send(fetch_result).unwrap(); let inner = inner(music_hoard(COLLECTION.clone())); diff --git a/src/tui/app/machine/match_state.rs b/src/tui/app/machine/match_state.rs index efcf7b7..362fa96 100644 --- a/src/tui/app/machine/match_state.rs +++ b/src/tui/app/machine/match_state.rs @@ -179,7 +179,7 @@ mod tests { machine::tests::{inner, music_hoard}, IApp, IAppAccess, IAppInput, }, - lib::interface::musicbrainz::Match, + lib::interface::musicbrainz::api::Match, }; use super::*; diff --git a/src/tui/app/machine/mod.rs b/src/tui/app/machine/mod.rs index f7c5d08..1ad5332 100644 --- a/src/tui/app/machine/mod.rs +++ b/src/tui/app/machine/mod.rs @@ -16,7 +16,7 @@ use crate::tui::{ IAppAccess, IAppBase, IAppState, }, event::EventSender, - lib::{interface::musicbrainz::IMusicBrainz, IMusicHoard}, + lib::{interface::musicbrainz::api::IMusicBrainz, IMusicHoard}, }; use browse_state::BrowseState; @@ -230,7 +230,7 @@ mod tests { use crate::tui::{ app::{AppState, IApp, IAppInput, IAppInteractBrowse}, - lib::{interface::musicbrainz::MockIMusicBrainz, MockIMusicHoard}, + lib::{interface::musicbrainz::api::MockIMusicBrainz, MockIMusicHoard}, EventChannel, }; diff --git a/src/tui/app/mod.rs b/src/tui/app/mod.rs index dd6b3a9..39ec665 100644 --- a/src/tui/app/mod.rs +++ b/src/tui/app/mod.rs @@ -6,7 +6,7 @@ pub use selection::{Category, Delta, Selection, WidgetState}; use musichoard::collection::{album::AlbumMeta, artist::ArtistMeta, Collection}; -use crate::tui::lib::interface::musicbrainz::Match; +use crate::tui::lib::interface::musicbrainz::api::Match; pub enum AppState { Browse(B), diff --git a/src/tui/lib/external/musicbrainz/api/mod.rs b/src/tui/lib/external/musicbrainz/api/mod.rs new file mode 100644 index 0000000..3730382 --- /dev/null +++ b/src/tui/lib/external/musicbrainz/api/mod.rs @@ -0,0 +1,104 @@ +//! Module for interacting with the [MusicBrainz API](https://musicbrainz.org/doc/MusicBrainz_API). + +use std::collections::HashMap; + +use musichoard::{ + collection::{ + album::{AlbumDate, AlbumMeta, AlbumSeq}, + artist::ArtistMeta, + musicbrainz::Mbid, + }, + external::musicbrainz::{ + api::{ + search::{ + SearchArtistRequest, SearchArtistResponseArtist, SearchReleaseGroupRequest, + SearchReleaseGroupResponseReleaseGroup, + }, + MusicBrainzClient, + }, + IMusicBrainzHttp, + }, +}; + +use crate::tui::lib::interface::musicbrainz::api::{Error, IMusicBrainz, Match}; + +// GRCOV_EXCL_START +pub struct MusicBrainz { + client: MusicBrainzClient, +} + +impl MusicBrainz { + pub fn new(client: MusicBrainzClient) -> Self { + MusicBrainz { client } + } +} + +impl IMusicBrainz for MusicBrainz { + fn search_artist(&mut self, artist: &ArtistMeta) -> Result>, Error> { + let query = SearchArtistRequest::new().string(&artist.id.name); + + let mb_response = self.client.search_artist(query)?; + + Ok(mb_response + .artists + .into_iter() + .map(from_search_artist_response_artist) + .collect()) + } + + fn search_release_group( + &mut self, + arid: &Mbid, + album: &AlbumMeta, + ) -> Result>, Error> { + // Some release groups may have a promotional early release messing up the search. Searching + // with just the year should be enough anyway. + let date = AlbumDate::new(album.date.year, None, None); + + let query = SearchReleaseGroupRequest::new() + .arid(arid) + .and() + .first_release_date(&date) + .and() + .release_group(&album.id.title); + + let mb_response = self.client.search_release_group(query)?; + + Ok(mb_response + .release_groups + .into_iter() + .map(from_search_release_group_response_release_group) + .collect()) + } +} + +fn from_search_artist_response_artist(entity: SearchArtistResponseArtist) -> Match { + Match { + score: entity.score, + item: ArtistMeta { + id: entity.name, + sort: entity.sort.map(Into::into), + musicbrainz: Some(entity.id.into()), + properties: HashMap::new(), + }, + disambiguation: entity.disambiguation, + } +} + +fn from_search_release_group_response_release_group( + entity: SearchReleaseGroupResponseReleaseGroup, +) -> Match { + Match { + score: entity.score, + item: AlbumMeta { + id: entity.title, + date: entity.first_release_date, + seq: AlbumSeq::default(), + musicbrainz: Some(entity.id.into()), + primary_type: Some(entity.primary_type), + secondary_types: entity.secondary_types.unwrap_or_default(), + }, + disambiguation: None, + } +} +// GRCOV_EXCL_STOP diff --git a/src/tui/lib/external/musicbrainz/mod.rs b/src/tui/lib/external/musicbrainz/mod.rs index a7502eb..e5fdf85 100644 --- a/src/tui/lib/external/musicbrainz/mod.rs +++ b/src/tui/lib/external/musicbrainz/mod.rs @@ -1,104 +1 @@ -//! Module for interacting with the [MusicBrainz API](https://musicbrainz.org/doc/MusicBrainz_API). - -use std::collections::HashMap; - -use musichoard::{ - collection::{ - album::{AlbumDate, AlbumMeta, AlbumSeq}, - artist::ArtistMeta, - musicbrainz::Mbid, - }, - external::musicbrainz::{ - api::{ - search::{ - SearchArtistRequest, SearchArtistResponseArtist, SearchReleaseGroupRequest, - SearchReleaseGroupResponseReleaseGroup, - }, - MusicBrainzClient, - }, - IMusicBrainzHttp, - }, -}; - -use crate::tui::lib::interface::musicbrainz::{Error, IMusicBrainz, Match}; - -// GRCOV_EXCL_START -pub struct MusicBrainz { - client: MusicBrainzClient, -} - -impl MusicBrainz { - pub fn new(client: MusicBrainzClient) -> Self { - MusicBrainz { client } - } -} - -impl IMusicBrainz for MusicBrainz { - fn search_artist(&mut self, artist: &ArtistMeta) -> Result>, Error> { - let query = SearchArtistRequest::new().string(&artist.id.name); - - let mb_response = self.client.search_artist(query)?; - - Ok(mb_response - .artists - .into_iter() - .map(from_search_artist_response_artist) - .collect()) - } - - fn search_release_group( - &mut self, - arid: &Mbid, - album: &AlbumMeta, - ) -> Result>, Error> { - // Some release groups may have a promotional early release messing up the search. Searching - // with just the year should be enough anyway. - let date = AlbumDate::new(album.date.year, None, None); - - let query = SearchReleaseGroupRequest::new() - .arid(arid) - .and() - .first_release_date(&date) - .and() - .release_group(&album.id.title); - - let mb_response = self.client.search_release_group(query)?; - - Ok(mb_response - .release_groups - .into_iter() - .map(from_search_release_group_response_release_group) - .collect()) - } -} - -fn from_search_artist_response_artist(entity: SearchArtistResponseArtist) -> Match { - Match { - score: entity.score, - item: ArtistMeta { - id: entity.name, - sort: entity.sort.map(Into::into), - musicbrainz: Some(entity.id.into()), - properties: HashMap::new(), - }, - disambiguation: entity.disambiguation, - } -} - -fn from_search_release_group_response_release_group( - entity: SearchReleaseGroupResponseReleaseGroup, -) -> Match { - Match { - score: entity.score, - item: AlbumMeta { - id: entity.title, - date: entity.first_release_date, - seq: AlbumSeq::default(), - musicbrainz: Some(entity.id.into()), - primary_type: Some(entity.primary_type), - secondary_types: entity.secondary_types.unwrap_or_default(), - }, - disambiguation: None, - } -} -// GRCOV_EXCL_STOP +pub mod api; diff --git a/src/tui/lib/interface/musicbrainz/api/mod.rs b/src/tui/lib/interface/musicbrainz/api/mod.rs new file mode 100644 index 0000000..1bb540e --- /dev/null +++ b/src/tui/lib/interface/musicbrainz/api/mod.rs @@ -0,0 +1,26 @@ +//! Module for accessing MusicBrainz metadata. + +#[cfg(test)] +use mockall::automock; + +use musichoard::collection::{album::AlbumMeta, artist::ArtistMeta, musicbrainz::Mbid}; + +/// Trait for interacting with the MusicBrainz API. +#[cfg_attr(test, automock)] +pub trait IMusicBrainz { + fn search_artist(&mut self, name: &ArtistMeta) -> Result>, Error>; + fn search_release_group( + &mut self, + arid: &Mbid, + album: &AlbumMeta, + ) -> Result>, Error>; +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Match { + pub score: u8, + pub item: T, + pub disambiguation: Option, +} + +pub type Error = musichoard::external::musicbrainz::api::Error; diff --git a/src/tui/lib/interface/musicbrainz/mod.rs b/src/tui/lib/interface/musicbrainz/mod.rs index 1bb540e..e5fdf85 100644 --- a/src/tui/lib/interface/musicbrainz/mod.rs +++ b/src/tui/lib/interface/musicbrainz/mod.rs @@ -1,26 +1 @@ -//! Module for accessing MusicBrainz metadata. - -#[cfg(test)] -use mockall::automock; - -use musichoard::collection::{album::AlbumMeta, artist::ArtistMeta, musicbrainz::Mbid}; - -/// Trait for interacting with the MusicBrainz API. -#[cfg_attr(test, automock)] -pub trait IMusicBrainz { - fn search_artist(&mut self, name: &ArtistMeta) -> Result>, Error>; - fn search_release_group( - &mut self, - arid: &Mbid, - album: &AlbumMeta, - ) -> Result>, Error>; -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Match { - pub score: u8, - pub item: T, - pub disambiguation: Option, -} - -pub type Error = musichoard::external::musicbrainz::api::Error; +pub mod api; diff --git a/src/tui/mod.rs b/src/tui/mod.rs index d7ebffd..e73a74d 100644 --- a/src/tui/mod.rs +++ b/src/tui/mod.rs @@ -8,7 +8,7 @@ mod ui; pub use app::App; pub use event::EventChannel; pub use handler::EventHandler; -pub use lib::external::musicbrainz::MusicBrainz; +pub use lib::external::musicbrainz::api::MusicBrainz; pub use listener::EventListener; pub use ui::Ui; @@ -175,7 +175,7 @@ mod tests { use std::{io, thread}; use event::EventSender; - use lib::interface::musicbrainz::MockIMusicBrainz; + use lib::interface::musicbrainz::api::MockIMusicBrainz; use ratatui::{backend::TestBackend, Terminal}; use musichoard::collection::Collection; diff --git a/src/tui/ui/mod.rs b/src/tui/ui/mod.rs index b87ddfa..fbce47c 100644 --- a/src/tui/ui/mod.rs +++ b/src/tui/ui/mod.rs @@ -207,7 +207,7 @@ mod tests { use crate::tui::{ app::{AppPublic, AppPublicInner, Delta, MatchOption, MatchStatePublic}, - lib::interface::musicbrainz::Match, + lib::interface::musicbrainz::api::Match, testmod::COLLECTION, tests::terminal, };