librespot_metadata/
album.rs1use std::{
2 fmt::Debug,
3 ops::{Deref, DerefMut},
4};
5
6use crate::{
7 Metadata,
8 artist::Artists,
9 availability::Availabilities,
10 copyright::Copyrights,
11 external_id::ExternalIds,
12 image::Images,
13 request::RequestResult,
14 restriction::Restrictions,
15 sale_period::SalePeriods,
16 track::Tracks,
17 util::{impl_deref_wrapped, impl_try_from_repeated},
18};
19
20use librespot_core::{Error, Session, SpotifyId, date::Date};
21
22use librespot_protocol as protocol;
23use protocol::metadata::Disc as DiscMessage;
24pub use protocol::metadata::album::Type as AlbumType;
25
26#[derive(Debug, Clone)]
27pub struct Album {
28 pub id: SpotifyId,
29 pub name: String,
30 pub artists: Artists,
31 pub album_type: AlbumType,
32 pub label: String,
33 pub date: Date,
34 pub popularity: i32,
35 pub covers: Images,
36 pub external_ids: ExternalIds,
37 pub discs: Discs,
38 pub reviews: Vec<String>,
39 pub copyrights: Copyrights,
40 pub restrictions: Restrictions,
41 pub related: Albums,
42 pub sale_periods: SalePeriods,
43 pub cover_group: Images,
44 pub original_title: String,
45 pub version_title: String,
46 pub type_str: String,
47 pub availability: Availabilities,
48}
49
50#[derive(Debug, Clone, Default)]
51pub struct Albums(pub Vec<SpotifyId>);
52
53impl_deref_wrapped!(Albums, Vec<SpotifyId>);
54
55#[derive(Debug, Clone)]
56pub struct Disc {
57 pub number: i32,
58 pub name: String,
59 pub tracks: Tracks,
60}
61
62#[derive(Debug, Clone, Default)]
63pub struct Discs(pub Vec<Disc>);
64
65impl_deref_wrapped!(Discs, Vec<Disc>);
66
67impl Album {
68 pub fn tracks(&self) -> impl Iterator<Item = &SpotifyId> {
69 self.discs.iter().flat_map(|disc| disc.tracks.iter())
70 }
71}
72
73#[async_trait]
74impl Metadata for Album {
75 type Message = protocol::metadata::Album;
76
77 async fn request(session: &Session, album_id: &SpotifyId) -> RequestResult {
78 session.spclient().get_album_metadata(album_id).await
79 }
80
81 fn parse(msg: &Self::Message, _: &SpotifyId) -> Result<Self, Error> {
82 Self::try_from(msg)
83 }
84}
85
86impl TryFrom<&<Self as Metadata>::Message> for Album {
87 type Error = librespot_core::Error;
88 fn try_from(album: &<Self as Metadata>::Message) -> Result<Self, Self::Error> {
89 Ok(Self {
90 id: album.try_into()?,
91 name: album.name().to_owned(),
92 artists: album.artist.as_slice().try_into()?,
93 album_type: album.type_(),
94 label: album.label().to_owned(),
95 date: album.date.get_or_default().try_into()?,
96 popularity: album.popularity(),
97 covers: album.cover_group.get_or_default().into(),
98 external_ids: album.external_id.as_slice().into(),
99 discs: album.disc.as_slice().try_into()?,
100 reviews: album.review.to_vec(),
101 copyrights: album.copyright.as_slice().into(),
102 restrictions: album.restriction.as_slice().into(),
103 related: album.related.as_slice().try_into()?,
104 sale_periods: album.sale_period.as_slice().try_into()?,
105 cover_group: album.cover_group.image.as_slice().into(),
106 original_title: album.original_title().to_owned(),
107 version_title: album.version_title().to_owned(),
108 type_str: album.type_str().to_owned(),
109 availability: album.availability.as_slice().try_into()?,
110 })
111 }
112}
113
114impl_try_from_repeated!(<Album as Metadata>::Message, Albums);
115
116impl TryFrom<&DiscMessage> for Disc {
117 type Error = librespot_core::Error;
118 fn try_from(disc: &DiscMessage) -> Result<Self, Self::Error> {
119 Ok(Self {
120 number: disc.number(),
121 name: disc.name().to_owned(),
122 tracks: disc.track.as_slice().try_into()?,
123 })
124 }
125}
126
127impl_try_from_repeated!(DiscMessage, Discs);