use std::convert::{TryFrom, TryInto}; use std::fmt::Debug; use std::ops::Deref; use crate::{ artist::Artists, availability::Availabilities, copyright::Copyrights, error::{MetadataError, RequestError}, external_id::ExternalIds, image::Images, request::RequestResult, restriction::Restrictions, sale_period::SalePeriods, track::Tracks, util::try_from_repeated_message, Metadata, }; use librespot_core::date::Date; use librespot_core::session::Session; use librespot_core::spotify_id::SpotifyId; use librespot_protocol as protocol; use protocol::metadata::Disc as DiscMessage; pub use protocol::metadata::Album_Type as AlbumType; #[derive(Debug, Clone)] pub struct Album { pub id: SpotifyId, pub name: String, pub artists: Artists, pub album_type: AlbumType, pub label: String, pub date: Date, pub popularity: i32, pub genres: Vec, pub covers: Images, pub external_ids: ExternalIds, pub discs: Discs, pub reviews: Vec, pub copyrights: Copyrights, pub restrictions: Restrictions, pub related: Albums, pub sale_periods: SalePeriods, pub cover_group: Images, pub original_title: String, pub version_title: String, pub type_str: String, pub availability: Availabilities, } #[derive(Debug, Clone)] pub struct Albums(pub Vec); impl Deref for Albums { type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } #[derive(Debug, Clone)] pub struct Disc { pub number: i32, pub name: String, pub tracks: Tracks, } #[derive(Debug, Clone)] pub struct Discs(pub Vec); impl Deref for Discs { type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } impl Album { pub fn tracks(&self) -> Tracks { let result = self .discs .iter() .flat_map(|disc| disc.tracks.deref().clone()) .collect(); Tracks(result) } } #[async_trait] impl Metadata for Album { type Message = protocol::metadata::Album; async fn request(session: &Session, album_id: SpotifyId) -> RequestResult { session .spclient() .get_album_metadata(album_id) .await .map_err(RequestError::Http) } fn parse(msg: &Self::Message, _: SpotifyId) -> Result { Self::try_from(msg) } } impl TryFrom<&::Message> for Album { type Error = MetadataError; fn try_from(album: &::Message) -> Result { Ok(Self { id: album.try_into()?, name: album.get_name().to_owned(), artists: album.get_artist().try_into()?, album_type: album.get_field_type(), label: album.get_label().to_owned(), date: album.get_date().into(), popularity: album.get_popularity(), genres: album.get_genre().to_vec(), covers: album.get_cover().into(), external_ids: album.get_external_id().into(), discs: album.get_disc().try_into()?, reviews: album.get_review().to_vec(), copyrights: album.get_copyright().into(), restrictions: album.get_restriction().into(), related: album.get_related().try_into()?, sale_periods: album.get_sale_period().into(), cover_group: album.get_cover_group().get_image().into(), original_title: album.get_original_title().to_owned(), version_title: album.get_version_title().to_owned(), type_str: album.get_type_str().to_owned(), availability: album.get_availability().into(), }) } } try_from_repeated_message!(::Message, Albums); impl TryFrom<&DiscMessage> for Disc { type Error = MetadataError; fn try_from(disc: &DiscMessage) -> Result { Ok(Self { number: disc.get_number(), name: disc.get_name().to_owned(), tracks: disc.get_track().try_into()?, }) } } try_from_repeated_message!(DiscMessage, Discs);