Api submodule
This commit is contained in:
parent
38517caf4e
commit
f4472ee95d
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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<FetchState> {
|
||||
fn send_fetch_result(
|
||||
fetch_tx: &FetchSender,
|
||||
events: &EventSender,
|
||||
result: Result<MatchStateInfo, musicbrainz::Error>,
|
||||
result: Result<MatchStateInfo, musicbrainz::api::Error>,
|
||||
) -> 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::<FetchResult>();
|
||||
|
||||
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()));
|
||||
|
@ -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::*;
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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<B, I, R, S, F, M, E, C> {
|
||||
Browse(B),
|
||||
|
104
src/tui/lib/external/musicbrainz/api/mod.rs
vendored
Normal file
104
src/tui/lib/external/musicbrainz/api/mod.rs
vendored
Normal file
@ -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<Http> {
|
||||
client: MusicBrainzClient<Http>,
|
||||
}
|
||||
|
||||
impl<Http> MusicBrainz<Http> {
|
||||
pub fn new(client: MusicBrainzClient<Http>) -> Self {
|
||||
MusicBrainz { client }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Http: IMusicBrainzHttp> IMusicBrainz for MusicBrainz<Http> {
|
||||
fn search_artist(&mut self, artist: &ArtistMeta) -> Result<Vec<Match<ArtistMeta>>, 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<Vec<Match<AlbumMeta>>, 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<ArtistMeta> {
|
||||
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<AlbumMeta> {
|
||||
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
|
105
src/tui/lib/external/musicbrainz/mod.rs
vendored
105
src/tui/lib/external/musicbrainz/mod.rs
vendored
@ -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<Http> {
|
||||
client: MusicBrainzClient<Http>,
|
||||
}
|
||||
|
||||
impl<Http> MusicBrainz<Http> {
|
||||
pub fn new(client: MusicBrainzClient<Http>) -> Self {
|
||||
MusicBrainz { client }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Http: IMusicBrainzHttp> IMusicBrainz for MusicBrainz<Http> {
|
||||
fn search_artist(&mut self, artist: &ArtistMeta) -> Result<Vec<Match<ArtistMeta>>, 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<Vec<Match<AlbumMeta>>, 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<ArtistMeta> {
|
||||
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<AlbumMeta> {
|
||||
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;
|
||||
|
26
src/tui/lib/interface/musicbrainz/api/mod.rs
Normal file
26
src/tui/lib/interface/musicbrainz/api/mod.rs
Normal file
@ -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<Vec<Match<ArtistMeta>>, Error>;
|
||||
fn search_release_group(
|
||||
&mut self,
|
||||
arid: &Mbid,
|
||||
album: &AlbumMeta,
|
||||
) -> Result<Vec<Match<AlbumMeta>>, Error>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Match<T> {
|
||||
pub score: u8,
|
||||
pub item: T,
|
||||
pub disambiguation: Option<String>,
|
||||
}
|
||||
|
||||
pub type Error = musichoard::external::musicbrainz::api::Error;
|
@ -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<Vec<Match<ArtistMeta>>, Error>;
|
||||
fn search_release_group(
|
||||
&mut self,
|
||||
arid: &Mbid,
|
||||
album: &AlbumMeta,
|
||||
) -> Result<Vec<Match<AlbumMeta>>, Error>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Match<T> {
|
||||
pub score: u8,
|
||||
pub item: T,
|
||||
pub disambiguation: Option<String>,
|
||||
}
|
||||
|
||||
pub type Error = musichoard::external::musicbrainz::api::Error;
|
||||
pub mod api;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user