librespot_metadata/
episode.rs

1use 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);