From 62351fc0e682acd585fd8556d6ebde6475d92d04 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Thu, 19 May 2022 19:57:27 -0400 Subject: [PATCH 1/7] Eliminate more warnings --- Cargo.toml | 1 + src/collections/album.rs | 9 +++--- src/collections/mod.rs | 6 ++-- src/collections/playlist.rs | 25 ++++++++------- src/lib.rs | 3 -- src/media/podcast.rs | 64 +++++++++++++++++++------------------ src/media/radio.rs | 3 +- src/media/song.rs | 25 ++++++++------- src/media/video.rs | 39 +++++++++++----------- 9 files changed, 90 insertions(+), 85 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f08f643..763da24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ failure = "0.1.3" log = "0.4.6" md5 = "0.6.0" rand = "0.6.1" +readonly = "0.2" serde = "1.0.80" serde_derive = "1.0.80" serde_json = "1.0.33" diff --git a/src/collections/album.rs b/src/collections/album.rs index d975a47..6c82713 100644 --- a/src/collections/album.rs +++ b/src/collections/album.rs @@ -48,17 +48,18 @@ impl IntoArg for ListType { } #[derive(Debug, Clone)] +#[readonly::make] pub struct Album { pub id: u64, pub name: String, pub artist: Option, - artist_id: Option, - cover_id: Option, + pub artist_id: Option, + pub cover_id: Option, pub duration: u64, pub year: Option, pub genre: Option, pub song_count: u64, - songs: Vec, + pub songs: Vec, } impl Album { @@ -121,7 +122,7 @@ impl<'de> Deserialize<'de> for Album { where D: Deserializer<'de>, { - #[derive(Debug, Deserialize)] + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct _Album { id: String, diff --git a/src/collections/mod.rs b/src/collections/mod.rs index 299c950..cec8ff5 100644 --- a/src/collections/mod.rs +++ b/src/collections/mod.rs @@ -2,9 +2,9 @@ use std::result; use serde::de::{Deserialize, Deserializer}; -mod album; -mod artist; -mod playlist; +pub mod album; +pub mod artist; +pub mod playlist; pub use self::album::{Album, AlbumInfo, ListType}; pub use self::artist::{Artist, ArtistInfo}; diff --git a/src/collections/playlist.rs b/src/collections/playlist.rs index b3121ef..b9112e3 100644 --- a/src/collections/playlist.rs +++ b/src/collections/playlist.rs @@ -6,13 +6,14 @@ use serde_json; use {Client, Error, Media, Result, Song}; #[derive(Debug)] +#[readonly::make] pub struct Playlist { - id: u64, - name: String, - duration: u64, - cover_id: String, - song_count: u64, - songs: Vec, + pub id: u64, + pub name: String, + pub duration: u64, + pub cover_id: String, + pub song_count: u64, + pub songs: Vec, } impl Playlist { @@ -31,7 +32,7 @@ impl<'de> Deserialize<'de> for Playlist { where D: Deserializer<'de>, { - #[derive(Debug, Deserialize)] + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct _Playlist { id: String, @@ -85,12 +86,12 @@ impl Media for Playlist { } } -fn get_playlists(client: &Client, user: Option) -> Result> { +pub fn get_playlists(client: &Client, user: Option) -> Result> { let playlist = client.get("getPlaylists", Query::with("username", user))?; Ok(get_list_as!(playlist, Playlist)) } -fn get_playlist(client: &Client, id: u64) -> Result { +pub fn get_playlist(client: &Client, id: u64) -> Result { let res = client.get("getPlaylist", Query::with("id", id))?; Ok(serde_json::from_value::(res)?) } @@ -99,7 +100,7 @@ fn get_playlist(client: &Client, id: u64) -> Result { /// /// Since API version 1.14.0, the newly created playlist is returned. In earlier /// versions, an empty response is returned. -fn create_playlist(client: &Client, name: String, songs: &[u64]) -> Result> { +pub fn create_playlist(client: &Client, name: String, songs: &[u64]) -> Result> { let args = Query::new() .arg("name", name) .arg_list("songId", songs) @@ -116,7 +117,7 @@ fn create_playlist(client: &Client, name: String, songs: &[u64]) -> Result( +pub fn update_playlist<'a, B, S>( client: &Client, id: u64, name: S, @@ -142,7 +143,7 @@ where Ok(()) } -fn delete_playlist(client: &Client, id: u64) -> Result<()> { +pub fn delete_playlist(client: &Client, id: u64) -> Result<()> { client.get("deletePlaylist", Query::with("id", id))?; Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index ee2c9d2..0d780af 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,3 @@ -#![warn(missing_docs)] -#![doc(html_root_url = "https://docs.rs/sunk/0.1.2")] - //! # sunk //! //! `sunk` provides natural Rust bindings to the [Subsonic] music server API. diff --git a/src/media/podcast.rs b/src/media/podcast.rs index a168312..742c9e5 100644 --- a/src/media/podcast.rs +++ b/src/media/podcast.rs @@ -5,42 +5,44 @@ use serde::de::{Deserialize, Deserializer}; use {Client, Result}; #[derive(Debug)] +#[readonly::make] pub struct Podcast { - id: usize, - url: String, - title: String, - description: String, - cover_art: String, - image_url: String, - status: String, - episodes: Vec, - error: Option, + pub id: usize, + pub url: String, + pub title: String, + pub description: String, + pub cover_art: String, + pub image_url: String, + pub status: String, + pub episodes: Vec, + pub error: Option, } #[derive(Debug)] +#[readonly::make] pub struct Episode { - id: usize, - parent: usize, - is_dir: bool, - title: String, - album: String, - artist: String, - year: usize, - cover_art: String, - size: usize, - content_type: String, - suffix: String, - duration: usize, - bitrate: usize, - is_video: bool, - created: String, - artist_id: String, - media_type: String, - stream_id: String, - channel_id: String, - description: String, - status: String, - publish_date: String, + pub id: usize, + pub parent: usize, + pub is_dir: bool, + pub title: String, + pub album: String, + pub artist: String, + pub year: usize, + pub cover_art: String, + pub size: usize, + pub content_type: String, + pub suffix: String, + pub duration: usize, + pub bitrate: usize, + pub is_video: bool, + pub created: String, + pub artist_id: String, + pub media_type: String, + pub stream_id: String, + pub channel_id: String, + pub description: String, + pub status: String, + pub publish_date: String, } impl Podcast { diff --git a/src/media/radio.rs b/src/media/radio.rs index ec71c96..ede3f97 100644 --- a/src/media/radio.rs +++ b/src/media/radio.rs @@ -5,8 +5,9 @@ use serde::de::{Deserialize, Deserializer}; use {Client, Result}; #[derive(Debug)] +#[readonly::make] pub struct RadioStation { - id: usize, + pub id: usize, pub name: String, pub stream_url: String, pub homepage_url: Option, diff --git a/src/media/song.rs b/src/media/song.rs index c72f1ba..bc20cfb 100644 --- a/src/media/song.rs +++ b/src/media/song.rs @@ -9,6 +9,7 @@ use {Client, Error, HlsPlaylist, Media, Result, Streamable}; /// A work of music contained on a Subsonic server. #[derive(Debug, Clone)] +#[readonly::make] pub struct Song { /// Unique identifier for the song. pub id: u64, @@ -18,11 +19,11 @@ pub struct Song { /// Album the song belongs to. Reads from the song's ID3 tags. pub album: Option, /// The ID of the released album. - album_id: Option, + pub album_id: Option, /// Credited artist for the song. Reads from the song's ID3 tags. pub artist: Option, /// The ID of the releasing artist. - artist_id: Option, + pub artist_id: Option, /// Position of the song in the album. pub track: Option, /// Year the song was released. @@ -30,27 +31,27 @@ pub struct Song { /// Genre of the song. pub genre: Option, /// ID of the song's cover art. Defaults to the parent album's cover. - cover_id: Option, + pub cover_id: Option, /// File size of the song, in bytes. pub size: u64, /// An audio MIME type. - content_type: String, + pub content_type: String, /// The file extension of the song. - suffix: String, + pub suffix: String, /// The MIME type that the song will be transcoded to. - transcoded_content_type: Option, + pub transcoded_content_type: Option, /// The file extension that the song will be transcoded to. - transcoded_suffix: Option, + pub transcoded_suffix: Option, /// Duration of the song, in seconds. pub duration: Option, /// The absolute path of the song in the server database. - path: String, + pub path: String, /// Will always be "song". - media_type: String, + pub media_type: String, /// Bit rate the song will be downsampled to. - stream_br: Option, + pub stream_br: Option, /// Format the song will be transcoded to. - stream_tc: Option, + pub stream_tc: Option, } impl Song { @@ -246,7 +247,7 @@ impl<'de> Deserialize<'de> for Song { where D: Deserializer<'de>, { - #[derive(Debug, Deserialize)] + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct _Song { id: String, diff --git a/src/media/video.rs b/src/media/video.rs index fc4c636..10bc586 100644 --- a/src/media/video.rs +++ b/src/media/video.rs @@ -6,32 +6,33 @@ use serde_json; use {Client, Error, Media, Result, Streamable}; #[derive(Debug)] +#[readonly::make] pub struct Video { pub id: usize, - parent: usize, - is_dir: bool, + pub parent: usize, + pub is_dir: bool, pub title: String, pub album: Option, - cover_id: Option, + pub cover_id: Option, pub size: usize, - content_type: String, - suffix: String, - transcoded_suffix: Option, - transcoded_content_type: Option, + pub content_type: String, + pub suffix: String, + pub transcoded_suffix: Option, + pub transcoded_content_type: Option, pub duration: usize, - bitrate: usize, - path: String, - is_video: bool, - created: String, - play_count: Option, + pub bitrate: usize, + pub path: String, + pub is_video: bool, + pub created: String, + pub play_count: Option, pub media_type: String, - bookmark_position: Option, - original_height: Option, - original_width: Option, - stream_br: Option, - stream_size: Option<(usize, usize)>, - stream_offset: usize, - stream_tc: Option, + pub bookmark_position: Option, + pub original_height: Option, + pub original_width: Option, + pub stream_br: Option, + pub stream_size: Option<(usize, usize)>, + pub stream_offset: usize, + pub stream_tc: Option, } impl Video { From 6e197765e95a6555523df6963a6ec05d638901f7 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Thu, 19 May 2022 20:25:04 -0400 Subject: [PATCH 2/7] treewide: remove more warnings --- src/client.rs | 12 +++++------- src/collections/album.rs | 2 +- src/collections/playlist.rs | 10 +++++----- src/lib.rs | 16 ++++++++-------- src/media/mod.rs | 22 +++++++++++----------- src/media/song.rs | 14 +++++++------- src/response.rs | 8 ++++---- src/user.rs | 36 ++++++++++++++++++------------------ 8 files changed, 59 insertions(+), 61 deletions(-) diff --git a/src/client.rs b/src/client.rs index 1dac510..3efa589 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,5 +1,10 @@ +use std::io::Read; +use std::iter; + +use md5; use media::NowPlaying; use query::Query; +use rand::{distributions::Alphanumeric, thread_rng, Rng}; use reqwest::Client as ReqwestClient; use reqwest::Url; use response::Response; @@ -73,11 +78,6 @@ impl SubsonicAuth { fn to_url(&self, ver: Version) -> String { // First md5 support. let auth = if ver >= "1.13.0".into() { - use std::iter; - - use md5; - use rand::{distributions::Alphanumeric, thread_rng, Rng}; - let mut rng = thread_rng(); let salt: String = iter::repeat(()) .map(|()| rng.sample(Alphanumeric)) @@ -205,7 +205,6 @@ impl Client { /// Returns a response as a vector of bytes rather than serialising it. pub(crate) fn get_bytes(&self, query: &str, args: Query) -> Result> { - use std::io::Read; let uri: Url = self.build_url(query, args)?.parse().unwrap(); let res = self.reqclient.get(uri).send()?; Ok(res.bytes().map(|b| b.unwrap()).collect()) @@ -213,7 +212,6 @@ impl Client { /// Returns the raw bytes of a HLS slice. pub fn hls_bytes(&self, hls: &Hls) -> Result> { - use std::io::Read; let url: Url = self.url.join(&hls.url)?; let res = self.reqclient.get(url).send()?; Ok(res.bytes().map(|b| b.unwrap()).collect()) diff --git a/src/collections/album.rs b/src/collections/album.rs index 6c82713..e79a2f6 100644 --- a/src/collections/album.rs +++ b/src/collections/album.rs @@ -132,7 +132,7 @@ impl<'de> Deserialize<'de> for Album { cover_art: Option, song_count: u64, duration: u64, - created: String, + // created: String, year: Option, genre: Option, #[serde(default)] diff --git a/src/collections/playlist.rs b/src/collections/playlist.rs index b9112e3..c48c433 100644 --- a/src/collections/playlist.rs +++ b/src/collections/playlist.rs @@ -37,13 +37,13 @@ impl<'de> Deserialize<'de> for Playlist { struct _Playlist { id: String, name: String, - #[serde(default)] - comment: String, - owner: String, + // #[serde(default)] + // comment: String, + // owner: String, song_count: u64, duration: u64, - created: String, - changed: String, + // created: String, + // changed: String, cover_art: String, #[serde(default)] songs: Vec, diff --git a/src/lib.rs b/src/lib.rs index 0d780af..82d23d8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -115,16 +115,16 @@ mod macros; mod client; mod error; -mod collections; -mod media; +pub mod collections; +pub mod media; -mod annotate; -mod jukebox; -mod query; -mod response; +pub mod annotate; +pub mod jukebox; +pub mod query; +pub mod response; pub mod search; -mod user; -mod version; +pub mod user; +pub mod version; #[cfg(test)] mod test_util; diff --git a/src/media/mod.rs b/src/media/mod.rs index 37cebdf..1ad0336 100644 --- a/src/media/mod.rs +++ b/src/media/mod.rs @@ -298,18 +298,18 @@ impl<'de> Deserialize<'de> for NowPlaying { minutes_ago: usize, player_id: usize, id: String, - is_dir: bool, - title: String, - size: usize, - content_type: String, - suffix: String, - transcoded_content_type: Option, - transcoded_suffix: Option, - path: String, + // is_dir: bool, + // title: String, + // size: usize, + // content_type: String, + // suffix: String, + // transcoded_content_type: Option, + // transcoded_suffix: Option, + // path: String, is_video: bool, - created: String, - #[serde(rename = "type")] - media_type: String, + // created: String, + // #[serde(rename = "type")] + // media_type: String, } let raw = _NowPlaying::deserialize(de)?; diff --git a/src/media/song.rs b/src/media/song.rs index bc20cfb..c8aba57 100644 --- a/src/media/song.rs +++ b/src/media/song.rs @@ -251,8 +251,8 @@ impl<'de> Deserialize<'de> for Song { #[serde(rename_all = "camelCase")] struct _Song { id: String, - parent: String, - is_dir: bool, + // parent: String, + // is_dir: bool, title: String, album: Option, artist: Option, @@ -266,12 +266,12 @@ impl<'de> Deserialize<'de> for Song { transcoded_content_type: Option, transcoded_suffix: Option, duration: Option, - bit_rate: Option, + // bit_rate: Option, path: String, - is_video: Option, - play_count: u64, - disc_number: Option, - created: String, + // is_video: Option, + // play_count: u64, + // disc_number: Option, + // created: String, album_id: Option, artist_id: Option, #[serde(rename = "type")] diff --git a/src/response.rs b/src/response.rs index 59aa6fb..26a66a5 100644 --- a/src/response.rs +++ b/src/response.rs @@ -2,18 +2,18 @@ use serde_json; use ApiError; /// A top-level response from a Subsonic server. -#[derive(Debug, Deserialize)] +#[derive(Deserialize)] pub struct Response { #[serde(rename = "subsonic-response")] inner: InnerResponse, } /// A struct containing the possible responses of the Subsonic API. -#[derive(Debug, Deserialize)] +#[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct InnerResponse { - status: String, - version: String, + // status: String, + // version: String, error: Option, license: Option, music_folders: Option, diff --git a/src/user.rs b/src/user.rs index a5929d1..ac7a1fe 100644 --- a/src/user.rs +++ b/src/user.rs @@ -220,40 +220,40 @@ impl UserBuilder { } } - /// Sets the user's username. + // Sets the user's username. build!(username: &str); - /// Sets the user's password. + // Sets the user's password. build!(password: &str); - /// Set's the user's email. + // Set's the user's email. build!(email: &str); - /// Enables LDAP authentication for the user. + // Enables LDAP authentication for the user. build!(ldap_authenticated: bool); - /// Bestows admin rights onto the user. + // Bestows admin rights onto the user. build!(admin_role: bool); - /// Allows the user to change personal settings and their own password. + // Allows the user to change personal settings and their own password. build!(settings_role: bool); - /// Allows the user to play files. + // Allows the user to play files. build!(stream_role: bool); - /// Allows the user to play files in jukebox mode. + // Allows the user to play files in jukebox mode. build!(jukebox_role: bool); - /// Allows the user to download files. + // Allows the user to download files. build!(download_role: bool); - /// Allows the user to upload files. + // Allows the user to upload files. build!(upload_role: bool); - /// Allows the user to change cover art and tags. + // Allows the user to change cover art and tags. build!(cover_art_role: bool); - /// Allows the user to create and edit comments and ratings. + // Allows the user to create and edit comments and ratings. build!(comment_role: bool); - /// Allows the user to administrate podcasts. + // Allows the user to administrate podcasts. build!(podcast_role: bool); - /// Allows the user to share files with others. + // Allows the user to share files with others. build!(share_role: bool); - /// Allows the user to start video coversions. + // Allows the user to start video coversions. build!(video_conversion_role: bool); - /// IDs of the music folders the user is allowed to access. + // IDs of the music folders the user is allowed to access. build!(folders: &[u64]); - /// The maximum bit rate (in Kbps) the user is allowed to stream at. Higher - /// bit rate streams will be downsampled to their limit. + // The maximum bit rate (in Kbps) the user is allowed to stream at. Higher + // bit rate streams will be downsampled to their limit. build!(max_bit_rate: u64); /// Pushes a defined new user to the Subsonic server. From 5d04e2189cdd74f895d309df61d73b1e4e4f00f1 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Thu, 19 May 2022 20:33:33 -0400 Subject: [PATCH 3/7] client: update test This is an online test, and the value seems to have changed. --- src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client.rs b/src/client.rs index 3efa589..8431cec 100644 --- a/src/client.rs +++ b/src/client.rs @@ -423,7 +423,7 @@ mod tests { let cli = test_util::demo_site().unwrap(); let (status, n) = cli.scan_status().unwrap(); assert_eq!(status, false); - assert_eq!(n, 521); + assert_eq!(n, 525); } #[test] From 090838c0f3c18c36231d6c9d3a83b78b22dbbec8 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Thu, 19 May 2022 20:36:27 -0400 Subject: [PATCH 4/7] `cargo clippy` --- src/client.rs | 2 +- src/collections/album.rs | 4 ++-- src/collections/artist.rs | 8 ++++---- src/collections/playlist.rs | 13 ++++++------- src/media/mod.rs | 5 +++++ src/media/song.rs | 6 +++--- src/query.rs | 2 +- src/user.rs | 4 ++-- 8 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/client.rs b/src/client.rs index 8431cec..241183e 100644 --- a/src/client.rs +++ b/src/client.rs @@ -422,7 +422,7 @@ mod tests { fn demo_scan_status() { let cli = test_util::demo_site().unwrap(); let (status, n) = cli.scan_status().unwrap(); - assert_eq!(status, false); + assert!(!status); assert_eq!(n, 525); } diff --git a/src/collections/album.rs b/src/collections/album.rs index e79a2f6..cd0e850 100644 --- a/src/collections/album.rs +++ b/src/collections/album.rs @@ -253,8 +253,8 @@ mod tests { #[test] fn demo_get_albums() { - let mut srv = test_util::demo_site().unwrap(); - let albums = get_albums(&mut srv, ListType::AlphaByArtist, None, None, None).unwrap(); + let srv = test_util::demo_site().unwrap(); + let albums = get_albums(&srv, ListType::AlphaByArtist, None, None, None).unwrap(); assert!(!albums.is_empty()) } diff --git a/src/collections/artist.rs b/src/collections/artist.rs index 96c9286..468f473 100644 --- a/src/collections/artist.rs +++ b/src/collections/artist.rs @@ -212,9 +212,9 @@ mod tests { #[test] fn remote_artist_album_list() { - let mut srv = test_util::demo_site().unwrap(); + let srv = test_util::demo_site().unwrap(); let parsed = serde_json::from_value::(raw()).unwrap(); - let albums = parsed.albums(&mut srv).unwrap(); + let albums = parsed.albums(&srv).unwrap(); assert_eq!(albums[0].id, 1); assert_eq!(albums[0].name, String::from("Bellevue")); @@ -223,11 +223,11 @@ mod tests { #[test] fn remote_artist_cover_art() { - let mut srv = test_util::demo_site().unwrap(); + let srv = test_util::demo_site().unwrap(); let parsed = serde_json::from_value::(raw()).unwrap(); assert_eq!(parsed.cover_id, Some(String::from("ar-1"))); - let cover = parsed.cover_art(&mut srv, None).unwrap(); + let cover = parsed.cover_art(&srv, None).unwrap(); assert!(!cover.is_empty()) } diff --git a/src/collections/playlist.rs b/src/collections/playlist.rs index c48c433..2016f23 100644 --- a/src/collections/playlist.rs +++ b/src/collections/playlist.rs @@ -158,14 +158,13 @@ mod tests { #[test] fn remote_playlist_songs() { let parsed = serde_json::from_value::(raw()).unwrap(); - let mut srv = test_util::demo_site().unwrap(); - let songs = parsed.songs(&mut srv); + let srv = test_util::demo_site().unwrap(); + let songs = parsed.songs(&srv); - match songs { - Err(::error::Error::Api(::error::ApiError::NotAuthorized(_))) => assert!(true), - Err(e) => panic!("unexpected error: {}", e), - Ok(_) => panic!("test should have failed; insufficient privilege"), - } + assert!(matches!( + songs, + Err(::error::Error::Api(::error::ApiError::NotAuthorized(_))) + )); } fn raw() -> serde_json::Value { diff --git a/src/media/mod.rs b/src/media/mod.rs index 1ad0336..ca33671 100644 --- a/src/media/mod.rs +++ b/src/media/mod.rs @@ -202,6 +202,11 @@ impl HlsPlaylist { self.hls.len() } + /// Returns whether this playlist is empty. + pub fn is_empty(&self) -> bool { + self.hls.is_empty() + } + /// Returns the total duration of the playlist. pub fn duration(&self) -> usize { self.hls.iter().fold(0, |c, h| c + h.inc) diff --git a/src/media/song.rs b/src/media/song.rs index c8aba57..f2e926f 100644 --- a/src/media/song.rs +++ b/src/media/song.rs @@ -105,7 +105,7 @@ impl Song { /// the builder. /// /// [struct level documentation]: ./struct.RandomSongs.html - pub fn random_with<'a>(client: &Client) -> RandomSongs { + pub fn random_with(client: &Client) -> RandomSongs { RandomSongs::new(client, 10) } @@ -460,10 +460,10 @@ mod tests { #[test] fn get_hls() { - let mut srv = test_util::demo_site().unwrap(); + let srv = test_util::demo_site().unwrap(); let song = serde_json::from_value::(raw()).unwrap(); - let hls = song.hls(&mut srv, &[]).unwrap(); + let hls = song.hls(&srv, &[]).unwrap(); assert_eq!(hls.len(), 20) } diff --git a/src/query.rs b/src/query.rs index ea9dd28..3d2ff55 100644 --- a/src/query.rs +++ b/src/query.rs @@ -84,7 +84,7 @@ impl Query { /// assert_eq!(query_list, query_manual); /// ``` pub fn arg_list(&mut self, key: &str, values: &[A]) -> &mut Query { - for v in values.to_owned() { + for v in values.iter().cloned() { self.inner.push((key.to_string(), v.into_arg())) } self diff --git a/src/user.rs b/src/user.rs index ac7a1fe..6fd11c5 100644 --- a/src/user.rs +++ b/src/user.rs @@ -289,8 +289,8 @@ mod tests { #[test] fn remote_parse_user() { - let mut srv = test_util::demo_site().unwrap(); - let guest = User::get(&mut srv, "guest3").unwrap(); + let srv = test_util::demo_site().unwrap(); + let guest = User::get(&srv, "guest3").unwrap(); assert_eq!(guest.username, "guest3"); assert!(guest.stream_role); From d9a7651b49f981bb0c099d6f05353b2372b9eb86 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Wed, 25 May 2022 23:49:08 -0400 Subject: [PATCH 5/7] Cargo, src: upgrade to Rust 2018 --- Cargo.toml | 1 + src/annotate.rs | 4 ++-- src/client.rs | 14 +++++++------- src/collections/album.rs | 10 +++++----- src/collections/artist.rs | 8 ++++---- src/collections/playlist.rs | 12 +++++++----- src/jukebox.rs | 5 +++-- src/media/mod.rs | 3 ++- src/media/podcast.rs | 5 +++-- src/media/radio.rs | 5 +++-- src/media/song.rs | 10 +++++----- src/media/video.rs | 5 +++-- src/response.rs | 3 ++- src/search.rs | 4 ++-- src/test_util.rs | 4 ++-- src/user.rs | 8 ++++---- 16 files changed, 55 insertions(+), 46 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 763da24..4961f52 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ readme = "README.md" keywords = ["subsonic", "airsonic", "music", "api", "webapi"] categories = ["api-bindings"] license = "Apache-2.0/MIT" +edition = "2018" [dependencies] failure = "0.1.3" diff --git a/src/annotate.rs b/src/annotate.rs index 95d2b60..bb819bd 100644 --- a/src/annotate.rs +++ b/src/annotate.rs @@ -1,5 +1,5 @@ -use query::Query; -use {Album, Artist, Client, Error, Result, Song}; +use crate::query::Query; +use crate::{Album, Artist, Client, Error, Result, Song}; /// Allows starring, rating, and scrobbling media. pub trait Annotatable { diff --git a/src/client.rs b/src/client.rs index 241183e..78b3836 100644 --- a/src/client.rs +++ b/src/client.rs @@ -2,15 +2,16 @@ use std::io::Read; use std::iter; use md5; -use media::NowPlaying; -use query::Query; use rand::{distributions::Alphanumeric, thread_rng, Rng}; use reqwest::Client as ReqwestClient; use reqwest::Url; -use response::Response; -use search::{SearchPage, SearchResult}; use serde_json; -use {Error, Genre, Hls, Lyrics, MusicFolder, Result, UrlError, Version}; + +use crate::media::NowPlaying; +use crate::query::Query; +use crate::response::Response; +use crate::search::{SearchPage, SearchResult}; +use crate::{Error, Genre, Hls, Lyrics, MusicFolder, Result, UrlError, Version}; const SALT_SIZE: usize = 36; // Minimum 6 characters. @@ -385,9 +386,8 @@ pub struct License { #[cfg(test)] mod tests { - use test_util; - use super::*; + use crate::test_util; #[test] fn test_token_auth() { diff --git a/src/collections/album.rs b/src/collections/album.rs index cd0e850..4f6a28d 100644 --- a/src/collections/album.rs +++ b/src/collections/album.rs @@ -1,10 +1,11 @@ use std::{fmt, result}; -use query::{Arg, IntoArg, Query}; -use search::SearchPage; use serde::de::{Deserialize, Deserializer}; use serde_json; -use {Client, Error, Media, Result, Song}; + +use crate::query::{Arg, IntoArg, Query}; +use crate::search::SearchPage; +use crate::{Client, Error, Media, Result, Song}; #[derive(Debug, Clone, Copy)] pub enum ListType { @@ -247,9 +248,8 @@ where #[cfg(test)] mod tests { - use test_util; - use super::*; + use crate::test_util; #[test] fn demo_get_albums() { diff --git a/src/collections/artist.rs b/src/collections/artist.rs index 468f473..577f369 100644 --- a/src/collections/artist.rs +++ b/src/collections/artist.rs @@ -1,9 +1,10 @@ use std::{fmt, result}; -use query::Query; use serde::de::{Deserialize, Deserializer}; use serde_json; -use {Album, Client, Error, Media, Result, Song}; + +use crate::query::Query; +use crate::{Album, Client, Error, Media, Result, Song}; /// Basic information about an artist. #[derive(Debug, Clone)] @@ -187,9 +188,8 @@ fn get_artist(client: &Client, id: usize) -> Result { #[cfg(test)] mod tests { - use test_util; - use super::*; + use crate::test_util; #[test] fn parse_artist() { diff --git a/src/collections/playlist.rs b/src/collections/playlist.rs index 2016f23..46fed08 100644 --- a/src/collections/playlist.rs +++ b/src/collections/playlist.rs @@ -1,9 +1,10 @@ use std::result; -use query::Query; use serde::de::{Deserialize, Deserializer}; use serde_json; -use {Client, Error, Media, Result, Song}; + +use crate::query::Query; +use crate::{Client, Error, Media, Result, Song}; #[derive(Debug)] #[readonly::make] @@ -150,9 +151,8 @@ pub fn delete_playlist(client: &Client, id: u64) -> Result<()> { #[cfg(test)] mod tests { - use test_util; - use super::*; + use crate::test_util; // The demo playlist exists, but can't be accessed #[test] @@ -163,7 +163,9 @@ mod tests { assert!(matches!( songs, - Err(::error::Error::Api(::error::ApiError::NotAuthorized(_))) + Err(crate::error::Error::Api( + crate::error::ApiError::NotAuthorized(_) + )) )); } diff --git a/src/jukebox.rs b/src/jukebox.rs index 3bae77f..8aa74cf 100644 --- a/src/jukebox.rs +++ b/src/jukebox.rs @@ -1,9 +1,10 @@ use std::result; -use query::Query; use serde::de::{Deserialize, Deserializer}; use serde_json; -use {Client, Result, Song}; + +use crate::query::Query; +use crate::{Client, Result, Song}; /// A wrapper on a `Client` to control just the jukebox. /// diff --git a/src/media/mod.rs b/src/media/mod.rs index ca33671..93a5cb9 100644 --- a/src/media/mod.rs +++ b/src/media/mod.rs @@ -3,7 +3,8 @@ use std::result; use std::str::FromStr; use serde::de::{Deserialize, Deserializer}; -use {Client, Error, Result}; + +use crate::{Client, Error, Result}; // pub mod format; pub mod podcast; diff --git a/src/media/podcast.rs b/src/media/podcast.rs index 742c9e5..a790229 100644 --- a/src/media/podcast.rs +++ b/src/media/podcast.rs @@ -1,8 +1,9 @@ use std::result; -use query::Query; use serde::de::{Deserialize, Deserializer}; -use {Client, Result}; + +use crate::query::Query; +use crate::{Client, Result}; #[derive(Debug)] #[readonly::make] diff --git a/src/media/radio.rs b/src/media/radio.rs index ede3f97..2334dc5 100644 --- a/src/media/radio.rs +++ b/src/media/radio.rs @@ -1,8 +1,9 @@ use std::result; -use query::Query; use serde::de::{Deserialize, Deserializer}; -use {Client, Result}; + +use crate::query::Query; +use crate::{Client, Result}; #[derive(Debug)] #[readonly::make] diff --git a/src/media/song.rs b/src/media/song.rs index f2e926f..2fea759 100644 --- a/src/media/song.rs +++ b/src/media/song.rs @@ -1,11 +1,12 @@ use std::fmt; use std::ops::Range; -use query::Query; -use search::SearchPage; use serde::de::{Deserialize, Deserializer}; use serde_json; -use {Client, Error, HlsPlaylist, Media, Result, Streamable}; + +use crate::query::Query; +use crate::search::SearchPage; +use crate::{Client, Error, HlsPlaylist, Media, Result, Streamable}; /// A work of music contained on a Subsonic server. #[derive(Debug, Clone)] @@ -445,9 +446,8 @@ impl<'a> RandomSongs<'a> { #[cfg(test)] mod tests { - use test_util; - use super::*; + use crate::test_util; #[test] fn parse_song() { diff --git a/src/media/video.rs b/src/media/video.rs index 10bc586..4793382 100644 --- a/src/media/video.rs +++ b/src/media/video.rs @@ -1,9 +1,10 @@ use std::result; -use query::Query; use serde::de::{Deserialize, Deserializer}; use serde_json; -use {Client, Error, Media, Result, Streamable}; + +use crate::query::Query; +use crate::{Client, Error, Media, Result, Streamable}; #[derive(Debug)] #[readonly::make] diff --git a/src/response.rs b/src/response.rs index 26a66a5..1c9a35d 100644 --- a/src/response.rs +++ b/src/response.rs @@ -1,5 +1,6 @@ use serde_json; -use ApiError; + +use crate::ApiError; /// A top-level response from a Subsonic server. #[derive(Deserialize)] diff --git a/src/search.rs b/src/search.rs index ebd4098..8289d3c 100644 --- a/src/search.rs +++ b/src/search.rs @@ -172,8 +172,8 @@ use std::fmt; -use song::Song; -use {Album, Artist}; +use crate::song::Song; +use crate::{Album, Artist}; /// The maximum number of results most searches will accept. pub const ALL: SearchPage = SearchPage { diff --git a/src/test_util.rs b/src/test_util.rs index ae77944..80b28d3 100644 --- a/src/test_util.rs +++ b/src/test_util.rs @@ -1,5 +1,5 @@ -use client; -use error; +use crate::client; +use crate::error; pub fn demo_site() -> error::Result { let site = "http://demo.subsonic.org"; diff --git a/src/user.rs b/src/user.rs index 6fd11c5..3bcae64 100644 --- a/src/user.rs +++ b/src/user.rs @@ -1,6 +1,7 @@ -use query::Query; use serde_json; -use {Client, Result}; + +use crate::query::Query; +use crate::{Client, Result}; /// A struct representing a Subsonic user. #[derive(Debug, Deserialize)] @@ -283,9 +284,8 @@ impl UserBuilder { #[cfg(test)] mod tests { - use test_util; - use super::*; + use crate::test_util; #[test] fn remote_parse_user() { From 289a4c03d965b0449cfcdd1929b7c321d8cf8877 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Wed, 25 May 2022 23:49:30 -0400 Subject: [PATCH 6/7] Cargo: upgrade to Rust 2021 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4961f52..d47d162 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ readme = "README.md" keywords = ["subsonic", "airsonic", "music", "api", "webapi"] categories = ["api-bindings"] license = "Apache-2.0/MIT" -edition = "2018" +edition = "2021" [dependencies] failure = "0.1.3" From 95698882979d4f842f5f6c09ec89b9239c6436cb Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Thu, 26 May 2022 00:05:27 -0400 Subject: [PATCH 7/7] src: add missing docs, allow missing docs selectively --- src/annotate.rs | 2 ++ src/collections/album.rs | 5 +++++ src/collections/artist.rs | 4 ++++ src/collections/mod.rs | 2 ++ src/collections/playlist.rs | 6 ++++++ src/jukebox.rs | 3 +++ src/lib.rs | 7 ++++--- src/media/format.rs | 15 ++++++++++++--- src/media/mod.rs | 4 +++- src/media/podcast.rs | 4 ++++ src/media/radio.rs | 4 ++++ src/media/song.rs | 2 ++ src/media/video.rs | 10 ++++++++++ src/query.rs | 5 +++++ src/response.rs | 2 ++ src/user.rs | 3 +++ src/version.rs | 3 +++ 17 files changed, 74 insertions(+), 7 deletions(-) diff --git a/src/annotate.rs b/src/annotate.rs index bb819bd..b1afb58 100644 --- a/src/annotate.rs +++ b/src/annotate.rs @@ -1,3 +1,5 @@ +//! Annotation APIs. + use crate::query::Query; use crate::{Album, Artist, Client, Error, Result, Song}; diff --git a/src/collections/album.rs b/src/collections/album.rs index 4f6a28d..a556b1d 100644 --- a/src/collections/album.rs +++ b/src/collections/album.rs @@ -1,3 +1,5 @@ +//! Album APIs. + use std::{fmt, result}; use serde::de::{Deserialize, Deserializer}; @@ -7,6 +9,7 @@ use crate::query::{Arg, IntoArg, Query}; use crate::search::SearchPage; use crate::{Client, Error, Media, Result, Song}; +#[allow(missing_docs)] #[derive(Debug, Clone, Copy)] pub enum ListType { AlphaByArtist, @@ -48,6 +51,7 @@ impl IntoArg for ListType { } } +#[allow(missing_docs)] #[derive(Debug, Clone)] #[readonly::make] pub struct Album { @@ -181,6 +185,7 @@ impl Media for Album { } } +#[allow(missing_docs)] #[derive(Debug)] pub struct AlbumInfo { pub notes: String, diff --git a/src/collections/artist.rs b/src/collections/artist.rs index 577f369..08549a3 100644 --- a/src/collections/artist.rs +++ b/src/collections/artist.rs @@ -1,3 +1,5 @@ +//! Artist APIs. + use std::{fmt, result}; use serde::de::{Deserialize, Deserializer}; @@ -7,6 +9,7 @@ use crate::query::Query; use crate::{Album, Client, Error, Media, Result, Song}; /// Basic information about an artist. +#[allow(missing_docs)] #[derive(Debug, Clone)] pub struct Artist { pub id: usize, @@ -32,6 +35,7 @@ pub struct ArtistInfo { } impl Artist { + #[allow(missing_docs)] pub fn get(client: &Client, id: usize) -> Result { self::get_artist(client, id) } diff --git a/src/collections/mod.rs b/src/collections/mod.rs index cec8ff5..7204690 100644 --- a/src/collections/mod.rs +++ b/src/collections/mod.rs @@ -1,3 +1,5 @@ +//! Collections management APIs. + use std::result; use serde::de::{Deserialize, Deserializer}; diff --git a/src/collections/playlist.rs b/src/collections/playlist.rs index 46fed08..0745618 100644 --- a/src/collections/playlist.rs +++ b/src/collections/playlist.rs @@ -1,3 +1,5 @@ +//! Playlist APIs. + use std::result; use serde::de::{Deserialize, Deserializer}; @@ -6,6 +8,7 @@ use serde_json; use crate::query::Query; use crate::{Client, Error, Media, Result, Song}; +#[allow(missing_docs)] #[derive(Debug)] #[readonly::make] pub struct Playlist { @@ -87,11 +90,13 @@ impl Media for Playlist { } } +#[allow(missing_docs)] pub fn get_playlists(client: &Client, user: Option) -> Result> { let playlist = client.get("getPlaylists", Query::with("username", user))?; Ok(get_list_as!(playlist, Playlist)) } +#[allow(missing_docs)] pub fn get_playlist(client: &Client, id: u64) -> Result { let res = client.get("getPlaylist", Query::with("id", id))?; Ok(serde_json::from_value::(res)?) @@ -144,6 +149,7 @@ where Ok(()) } +#[allow(missing_docs)] pub fn delete_playlist(client: &Client, id: u64) -> Result<()> { client.get("deletePlaylist", Query::with("id", id))?; Ok(()) diff --git a/src/jukebox.rs b/src/jukebox.rs index 8aa74cf..7c3d5a5 100644 --- a/src/jukebox.rs +++ b/src/jukebox.rs @@ -1,3 +1,5 @@ +//! Jukebox management and control APIs. + use std::result; use serde::de::{Deserialize, Deserializer}; @@ -27,6 +29,7 @@ pub struct JukeboxStatus { /// Volume level of the jukebox, from `0` to `1.0`. #[serde(rename = "gain")] pub volume: f32, + #[allow(missing_docs)] pub position: usize, } diff --git a/src/lib.rs b/src/lib.rs index 82d23d8..e589310 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -98,6 +98,8 @@ //! Bug reports and broken features are encouraged to be reported! **If //! something does not work as reported, it's probably broken.** +#![deny(missing_docs)] + #[macro_use] extern crate failure; #[macro_use] @@ -115,11 +117,10 @@ mod macros; mod client; mod error; -pub mod collections; -pub mod media; - pub mod annotate; +pub mod collections; pub mod jukebox; +pub mod media; pub mod query; pub mod response; pub mod search; diff --git a/src/media/format.rs b/src/media/format.rs index 241a691..d778853 100644 --- a/src/media/format.rs +++ b/src/media/format.rs @@ -1,9 +1,13 @@ -use query::{Arg, IntoArg}; +//! Audio and video format APIs. + use std::fmt; +use crate::query::{Arg, IntoArg}; + /// Audio encoding format. /// /// Recognises all of Subsonic's default transcoding formats. +#[allow(missing_docs)] #[derive(Debug)] pub enum AudioFormat { Aac, @@ -32,9 +36,12 @@ impl fmt::Display for AudioFormat { } impl IntoArg for AudioFormat { - fn into_arg(self) -> Arg { self.to_string().into_arg() } + fn into_arg(self) -> Arg { + self.to_string().into_arg() + } } +#[allow(missing_docs)] #[derive(Debug)] pub enum VideoFormat { Avi, @@ -57,5 +64,7 @@ impl fmt::Display for VideoFormat { } impl IntoArg for VideoFormat { - fn into_arg(self) -> Arg { self.to_string().into_arg() } + fn into_arg(self) -> Arg { + self.to_string().into_arg() + } } diff --git a/src/media/mod.rs b/src/media/mod.rs index 93a5cb9..1615ba3 100644 --- a/src/media/mod.rs +++ b/src/media/mod.rs @@ -1,3 +1,5 @@ +//! Individual media APIs. + use std::ops::Index; use std::result; use std::str::FromStr; @@ -6,7 +8,7 @@ use serde::de::{Deserialize, Deserializer}; use crate::{Client, Error, Result}; -// pub mod format; +pub mod format; pub mod podcast; mod radio; pub mod song; diff --git a/src/media/podcast.rs b/src/media/podcast.rs index a790229..6fd43d8 100644 --- a/src/media/podcast.rs +++ b/src/media/podcast.rs @@ -1,3 +1,5 @@ +//! Podcast APIs. + use std::result; use serde::de::{Deserialize, Deserializer}; @@ -5,6 +7,7 @@ use serde::de::{Deserialize, Deserializer}; use crate::query::Query; use crate::{Client, Result}; +#[allow(missing_docs)] #[derive(Debug)] #[readonly::make] pub struct Podcast { @@ -19,6 +22,7 @@ pub struct Podcast { pub error: Option, } +#[allow(missing_docs)] #[derive(Debug)] #[readonly::make] pub struct Episode { diff --git a/src/media/radio.rs b/src/media/radio.rs index 2334dc5..84b17f2 100644 --- a/src/media/radio.rs +++ b/src/media/radio.rs @@ -1,3 +1,5 @@ +//! Radio APIs. + use std::result; use serde::de::{Deserialize, Deserializer}; @@ -5,6 +7,7 @@ use serde::de::{Deserialize, Deserializer}; use crate::query::Query; use crate::{Client, Result}; +#[allow(missing_docs)] #[derive(Debug)] #[readonly::make] pub struct RadioStation { @@ -37,6 +40,7 @@ impl<'de> Deserialize<'de> for RadioStation { } } +#[allow(missing_docs)] impl RadioStation { pub fn id(&self) -> usize { self.id diff --git a/src/media/song.rs b/src/media/song.rs index 2fea759..2d0cc29 100644 --- a/src/media/song.rs +++ b/src/media/song.rs @@ -1,3 +1,5 @@ +//! Song APIs. + use std::fmt; use std::ops::Range; diff --git a/src/media/video.rs b/src/media/video.rs index 4793382..c021c5c 100644 --- a/src/media/video.rs +++ b/src/media/video.rs @@ -1,3 +1,5 @@ +//! Video APIs. + use std::result; use serde::de::{Deserialize, Deserializer}; @@ -6,6 +8,7 @@ use serde_json; use crate::query::Query; use crate::{Client, Error, Media, Result, Streamable}; +#[allow(missing_docs)] #[derive(Debug)] #[readonly::make] pub struct Video { @@ -37,6 +40,7 @@ pub struct Video { } impl Video { + #[allow(missing_docs)] pub fn get(client: &Client, id: usize) -> Result