librespot_metadata/playlist/
annotation.rs

1use std::fmt::Debug;
2
3use protobuf::Message;
4
5use crate::{
6    Metadata,
7    image::TranscodedPictures,
8    request::{MercuryRequest, RequestResult},
9};
10
11use librespot_core::{Error, Session, SpotifyId, SpotifyUri};
12use librespot_protocol as protocol;
13pub use protocol::playlist_annotate3::AbuseReportState;
14
15#[derive(Debug, Clone)]
16pub struct PlaylistAnnotation {
17    pub description: String,
18    pub picture: String,
19    pub transcoded_pictures: TranscodedPictures,
20    pub has_abuse_reporting: bool,
21    pub abuse_report_state: AbuseReportState,
22}
23
24#[async_trait]
25impl Metadata for PlaylistAnnotation {
26    type Message = protocol::playlist_annotate3::PlaylistAnnotation;
27
28    async fn request(session: &Session, playlist_uri: &SpotifyUri) -> RequestResult {
29        let current_user = session.username();
30
31        let SpotifyUri::Playlist {
32            id: playlist_id, ..
33        } = playlist_uri
34        else {
35            return Err(Error::invalid_argument("playlist_uri"));
36        };
37
38        Self::request_for_user(session, &current_user, playlist_id).await
39    }
40
41    fn parse(msg: &Self::Message, _: &SpotifyUri) -> Result<Self, Error> {
42        Ok(Self {
43            description: msg.description().to_owned(),
44            picture: msg.picture().to_owned(), // TODO: is this a URL or Spotify URI?
45            transcoded_pictures: msg.transcoded_picture.as_slice().try_into()?,
46            has_abuse_reporting: msg.is_abuse_reporting_enabled(),
47            abuse_report_state: msg.abuse_report_state(),
48        })
49    }
50}
51
52impl PlaylistAnnotation {
53    async fn request_for_user(
54        session: &Session,
55        username: &str,
56        playlist_id: &SpotifyId,
57    ) -> RequestResult {
58        let uri = format!(
59            "hm://playlist-annotate/v1/annotation/user/{}/playlist/{}",
60            username,
61            playlist_id.to_base62()?
62        );
63        <Self as MercuryRequest>::request(session, &uri).await
64    }
65
66    #[allow(dead_code)]
67    async fn get_for_user(
68        session: &Session,
69        username: &str,
70        playlist_uri: &SpotifyUri,
71    ) -> Result<Self, Error> {
72        let SpotifyUri::Playlist {
73            id: playlist_id, ..
74        } = playlist_uri
75        else {
76            return Err(Error::invalid_argument("playlist_uri"));
77        };
78
79        let response = Self::request_for_user(session, username, playlist_id).await?;
80        let msg = <Self as Metadata>::Message::parse_from_bytes(&response)?;
81        Self::parse(&msg, playlist_uri)
82    }
83}
84
85impl MercuryRequest for PlaylistAnnotation {}
86
87impl TryFrom<&<PlaylistAnnotation as Metadata>::Message> for PlaylistAnnotation {
88    type Error = librespot_core::Error;
89    fn try_from(
90        annotation: &<PlaylistAnnotation as Metadata>::Message,
91    ) -> Result<Self, Self::Error> {
92        Ok(Self {
93            description: annotation.description().to_owned(),
94            picture: annotation.picture().to_owned(),
95            transcoded_pictures: annotation.transcoded_picture.as_slice().try_into()?,
96            has_abuse_reporting: annotation.is_abuse_reporting_enabled(),
97            abuse_report_state: annotation.abuse_report_state(),
98        })
99    }
100}