use std::{ convert::{TryFrom, TryInto}, fmt::Debug, ops::Deref, }; use crate::{request::RequestResult, track::Tracks, util::try_from_repeated_message, Metadata}; use librespot_core::{Error, Session, SpotifyId}; use librespot_protocol as protocol; use protocol::metadata::ArtistWithRole as ArtistWithRoleMessage; pub use protocol::metadata::ArtistWithRole_ArtistRole as ArtistRole; use protocol::metadata::TopTracks as TopTracksMessage; #[derive(Debug, Clone)] pub struct Artist { pub id: SpotifyId, pub name: String, pub top_tracks: CountryTopTracks, } #[derive(Debug, Clone, Default)] pub struct Artists(pub Vec); impl Deref for Artists { type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } #[derive(Debug, Clone)] pub struct ArtistWithRole { pub id: SpotifyId, pub name: String, pub role: ArtistRole, } #[derive(Debug, Clone, Default)] pub struct ArtistsWithRole(pub Vec); impl Deref for ArtistsWithRole { type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } #[derive(Debug, Clone)] pub struct TopTracks { pub country: String, pub tracks: Tracks, } #[derive(Debug, Clone, Default)] pub struct CountryTopTracks(pub Vec); impl Deref for CountryTopTracks { type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } impl CountryTopTracks { pub fn for_country(&self, country: &str) -> Tracks { if let Some(country) = self.0.iter().find(|top_track| top_track.country == country) { return country.tracks.clone(); } if let Some(global) = self.0.iter().find(|top_track| top_track.country.is_empty()) { return global.tracks.clone(); } Tracks(vec![]) // none found } } #[async_trait] impl Metadata for Artist { type Message = protocol::metadata::Artist; async fn request(session: &Session, artist_id: SpotifyId) -> RequestResult { session.spclient().get_artist_metadata(artist_id).await } fn parse(msg: &Self::Message, _: SpotifyId) -> Result { Self::try_from(msg) } } impl TryFrom<&::Message> for Artist { type Error = librespot_core::Error; fn try_from(artist: &::Message) -> Result { Ok(Self { id: artist.try_into()?, name: artist.get_name().to_owned(), top_tracks: artist.get_top_track().try_into()?, }) } } try_from_repeated_message!(::Message, Artists); impl TryFrom<&ArtistWithRoleMessage> for ArtistWithRole { type Error = librespot_core::Error; fn try_from(artist_with_role: &ArtistWithRoleMessage) -> Result { Ok(Self { id: artist_with_role.try_into()?, name: artist_with_role.get_artist_name().to_owned(), role: artist_with_role.get_role(), }) } } try_from_repeated_message!(ArtistWithRoleMessage, ArtistsWithRole); impl TryFrom<&TopTracksMessage> for TopTracks { type Error = librespot_core::Error; fn try_from(top_tracks: &TopTracksMessage) -> Result { Ok(Self { country: top_tracks.get_country().to_owned(), tracks: top_tracks.get_track().try_into()?, }) } } try_from_repeated_message!(TopTracksMessage, CountryTopTracks);