librespot_metadata/
episode.rs1use std::{
2 fmt::Debug,
3 ops::{Deref, DerefMut},
4};
5
6use crate::{
7 Metadata,
8 audio::file::AudioFiles,
9 availability::Availabilities,
10 content_rating::ContentRatings,
11 image::Images,
12 request::RequestResult,
13 restriction::Restrictions,
14 util::{impl_deref_wrapped, impl_try_from_repeated},
15 video::VideoFiles,
16};
17
18use librespot_core::{Error, Session, SpotifyUri, date::Date};
19
20use librespot_protocol as protocol;
21pub use protocol::metadata::episode::EpisodeType;
22
23#[derive(Debug, Clone)]
24pub struct Episode {
25 pub id: SpotifyUri,
26 pub name: String,
27 pub duration: i32,
28 pub audio: AudioFiles,
29 pub description: String,
30 pub number: i32,
31 pub publish_time: Date,
32 pub covers: Images,
33 pub language: String,
34 pub is_explicit: bool,
35 pub show_name: String,
36 pub videos: VideoFiles,
37 pub video_previews: VideoFiles,
38 pub audio_previews: AudioFiles,
39 pub restrictions: Restrictions,
40 pub freeze_frames: Images,
41 pub keywords: Vec<String>,
42 pub allow_background_playback: bool,
43 pub availability: Availabilities,
44 pub external_url: String,
45 pub episode_type: EpisodeType,
46 pub has_music_and_talk: bool,
47 pub content_rating: ContentRatings,
48 pub is_audiobook_chapter: bool,
49}
50
51#[derive(Debug, Clone, Default)]
52pub struct Episodes(pub Vec<SpotifyUri>);
53
54impl_deref_wrapped!(Episodes, Vec<SpotifyUri>);
55
56#[async_trait]
57impl Metadata for Episode {
58 type Message = protocol::metadata::Episode;
59
60 async fn request(session: &Session, episode_uri: &SpotifyUri) -> RequestResult {
61 let SpotifyUri::Episode { .. } = episode_uri else {
62 return Err(Error::invalid_argument("episode_uri"));
63 };
64
65 session.spclient().get_episode_metadata(episode_uri).await
66 }
67
68 fn parse(msg: &Self::Message, _: &SpotifyUri) -> Result<Self, Error> {
69 Self::try_from(msg)
70 }
71}
72
73impl TryFrom<&<Self as Metadata>::Message> for Episode {
74 type Error = librespot_core::Error;
75 fn try_from(episode: &<Self as Metadata>::Message) -> Result<Self, Self::Error> {
76 Ok(Self {
77 id: episode.try_into()?,
78 name: episode.name().to_owned(),
79 duration: episode.duration().to_owned(),
80 audio: episode.audio.as_slice().into(),
81 description: episode.description().to_owned(),
82 number: episode.number(),
83 publish_time: episode.publish_time.get_or_default().try_into()?,
84 covers: episode.cover_image.image.as_slice().into(),
85 language: episode.language().to_owned(),
86 is_explicit: episode.explicit().to_owned(),
87 show_name: episode.show.name().to_owned(),
88 videos: episode.video.as_slice().into(),
89 video_previews: episode.video_preview.as_slice().into(),
90 audio_previews: episode.audio_preview.as_slice().into(),
91 restrictions: episode.restriction.as_slice().into(),
92 freeze_frames: episode.freeze_frame.image.as_slice().into(),
93 keywords: episode.keyword.to_vec(),
94 allow_background_playback: episode.allow_background_playback(),
95 availability: episode.availability.as_slice().try_into()?,
96 external_url: episode.external_url().to_owned(),
97 episode_type: episode.type_(),
98 has_music_and_talk: episode.music_and_talk(),
99 content_rating: episode.content_rating.as_slice().into(),
100 is_audiobook_chapter: episode.is_audiobook_chapter(),
101 })
102 }
103}
104
105impl_try_from_repeated!(<Episode as Metadata>::Message, Episodes);