sunk/
annotate.rs

1use query::Query;
2use {Album, Artist, Client, Error, Result, Song};
3
4/// Allows starring, rating, and scrobbling media.
5pub trait Annotatable {
6    /// Attaches a star to the content.
7    fn star(&self, client: &Client) -> Result<()>;
8
9    /// Removes a star from the content.
10    fn unstar(&self, client: &Client) -> Result<()>;
11
12    /// Sets the rating for the content.
13    fn set_rating(&self, client: &Client, rating: u8) -> Result<()>;
14
15    /// Registers the local playback of the content. Typically used when playing
16    /// media that is cached on the client. This operation includes the
17    /// following:
18    ///
19    /// - "Scrobbles" the media files on last.fm if the user has configured
20    /// their last.fm credentials on the Subsonic server.
21    /// - Updates the play count and last played timestamp for the content.
22    /// - Makes the content appear in the "Now Playing" page in the web app,
23    /// and appear in the list of songs returned by
24    /// [`Client::now_playing()`] (since API version 1.11.0).
25    ///
26    /// [`Client::now_playing()`]: ./struct.Client.html#method.now_playing
27    ///
28    /// `time` should be a valid ISO8601 timestamp. In the future, this will be
29    /// validated.
30    fn scrobble<'a, B, T>(&self, client: &Client, time: T, now_playing: B) -> Result<()>
31    where
32        B: Into<Option<bool>>,
33        T: Into<Option<&'a str>>;
34}
35
36impl Annotatable for Artist {
37    fn star(&self, client: &Client) -> Result<()> {
38        client.get("star", Query::with("artistId", self.id))?;
39        Ok(())
40    }
41
42    fn unstar(&self, client: &Client) -> Result<()> {
43        client.get("unstar", Query::with("artistId", self.id))?;
44        Ok(())
45    }
46
47    fn set_rating(&self, client: &Client, rating: u8) -> Result<()> {
48        if rating > 5 {
49            return Err(Error::Other("rating must be between 0 and 5 inclusive"));
50        }
51
52        let args = Query::with("id", self.id).arg("rating", rating).build();
53        client.get("setRating", args)?;
54        Ok(())
55    }
56
57    fn scrobble<'a, B, T>(&self, client: &Client, time: T, now_playing: B) -> Result<()>
58    where
59        B: Into<Option<bool>>,
60        T: Into<Option<&'a str>>,
61    {
62        let args = Query::with("id", self.id)
63            .arg("time", time.into())
64            .arg("submission", now_playing.into().map(|b| !b))
65            .build();
66        client.get("scrobble", args)?;
67        Ok(())
68    }
69}
70
71impl Annotatable for Album {
72    fn star(&self, client: &Client) -> Result<()> {
73        client.get("star", Query::with("albumId", self.id))?;
74        Ok(())
75    }
76
77    fn unstar(&self, client: &Client) -> Result<()> {
78        client.get("unstar", Query::with("albumId", self.id))?;
79        Ok(())
80    }
81
82    fn set_rating(&self, client: &Client, rating: u8) -> Result<()> {
83        if rating > 5 {
84            return Err(Error::Other("rating must be between 0 and 5 inclusive"));
85        }
86
87        let args = Query::with("id", self.id).arg("rating", rating).build();
88        client.get("setRating", args)?;
89        Ok(())
90    }
91
92    fn scrobble<'a, B, T>(&self, client: &Client, time: T, now_playing: B) -> Result<()>
93    where
94        B: Into<Option<bool>>,
95        T: Into<Option<&'a str>>,
96    {
97        let args = Query::with("id", self.id)
98            .arg("time", time.into())
99            .arg("submission", now_playing.into().map(|b| !b))
100            .build();
101        client.get("scrobble", args)?;
102        Ok(())
103    }
104}
105
106impl Annotatable for Song {
107    fn star(&self, client: &Client) -> Result<()> {
108        client.get("star", Query::with("id", self.id))?;
109        Ok(())
110    }
111
112    fn unstar(&self, client: &Client) -> Result<()> {
113        client.get("unstar", Query::with("id", self.id))?;
114        Ok(())
115    }
116
117    fn set_rating(&self, client: &Client, rating: u8) -> Result<()> {
118        if rating > 5 {
119            return Err(Error::Other("rating must be between 0 and 5 inclusive"));
120        }
121
122        let args = Query::with("id", self.id).arg("rating", rating).build();
123        client.get("setRating", args)?;
124        Ok(())
125    }
126
127    fn scrobble<'a, B, T>(&self, client: &Client, time: T, now_playing: B) -> Result<()>
128    where
129        B: Into<Option<bool>>,
130        T: Into<Option<&'a str>>,
131    {
132        let args = Query::with("id", self.id)
133            .arg("time", time.into())
134            .arg("submission", now_playing.into().map(|b| !b))
135            .build();
136        client.get("scrobble", args)?;
137        Ok(())
138    }
139}