diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ce7b041..8e98d88d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ **Bugfixes** - ([#494](https://github.com/ramsayleung/rspotify/pull/494)) Fix endless sequential pagination problem. + +**New features** +- ([#496](https://github.com/ramsayleung/rspotify/pull/497)) Add support for searching multiple types + ## 0.13.3 (2024.08.24) **New features** diff --git a/rspotify-model/src/search.rs b/rspotify-model/src/search.rs index b75feba4..ba371aa9 100644 --- a/rspotify-model/src/search.rs +++ b/rspotify-model/src/search.rs @@ -60,3 +60,14 @@ pub enum SearchResult { #[serde(rename = "episodes")] Episodes(Page), } + +/// Search result of any multiple kinds +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +pub struct SearchMultipleResult { + pub playlists: Option>, + pub albums: Option>, + pub artists: Option>, + pub tracks: Option>, + pub shows: Option>, + pub episodes: Option>, +} diff --git a/src/clients/base.rs b/src/clients/base.rs index 5f8f5ff8..508c3470 100644 --- a/src/clients/base.rs +++ b/src/clients/base.rs @@ -427,7 +427,7 @@ where /// - market - An ISO 3166-1 alpha-2 country code or the string from_token. /// - include_external: Optional.Possible values: audio. If /// include_external=audio is specified the response will include any - /// relevant audio content that is hosted externally. + /// relevant audio content that is hosted externally. /// /// [Reference](https://developer.spotify.com/documentation/web-api/reference/#/operations/search) async fn search( @@ -454,6 +454,57 @@ where convert_result(&result) } + /// Search for multiple an Item. Get Spotify catalog information about artists, + /// albums, tracks or playlists that match a keyword string. + /// + /// According to Spotify's doc, if you don't specify a country in the + /// request and your spotify account doesn't set the country, the content + /// might be unavailable for you: + /// > If a valid user access token is specified in the request header, + /// > the country associated with the user account will take priority over this parameter. + /// > Note: If neither market or user country are provided, the content is considered unavailable for the client. + /// > Users can view the country that is associated with their account in the [account settings](https://developer.spotify.com/documentation/web-api/reference/search). + /// + /// Parameters: + /// - q - the search query + /// - limit - the number of items to return + /// - offset - the index of the first item to return + /// - type - the type of item to return. Multiple of 'artist', 'album', 'track', + /// 'playlist', 'show' or 'episode' + /// - market - An ISO 3166-1 alpha-2 country code or the string from_token. + /// - include_external: Optional.Possible values: audio. If + /// include_external=audio is specified the response will include any + /// relevant audio content that is hosted externally. + /// + /// [Reference](https://developer.spotify.com/documentation/web-api/reference/#/operations/search) + async fn search_multiple( + &self, + q: &str, + r#type: impl IntoIterator + Send, + market: Option, + include_external: Option, + limit: Option, + offset: Option, + ) -> ClientResult { + let limit = limit.map(|s| s.to_string()); + let offset = offset.map(|s| s.to_string()); + let mut _type = r#type + .into_iter() + .map(|x| Into::<&str>::into(x).to_string() + ",") + .collect::(); + let params = build_map([ + ("q", Some(q)), + ("type", Some(_type.trim_end_matches(","))), + ("market", market.map(Into::into)), + ("include_external", include_external.map(Into::into)), + ("limit", limit.as_deref()), + ("offset", offset.as_deref()), + ]); + + let result = self.api_get("search", ¶ms).await?; + convert_result(&result) + } + /// Get Spotify catalog information about an album's tracks. /// /// Parameters: diff --git a/tests/test_with_credential.rs b/tests/test_with_credential.rs index dd76a8e3..e56b1959 100644 --- a/tests/test_with_credential.rs +++ b/tests/test_with_credential.rs @@ -8,6 +8,7 @@ use rspotify::{ use maybe_async::maybe_async; +use rspotify_model::SearchType; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; @@ -273,6 +274,41 @@ async fn test_fake_playlist() { assert!(playlist.is_err()); } +#[maybe_async::test( + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) +)] +async fn test_search_album() { + let query = "album:arrival artist:abba"; + creds_client() + .await + .search(query, SearchType::Album, None, None, Some(10), Some(0)) + .await + .unwrap(); +} + +#[maybe_async::test( + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) +)] +async fn test_search_multiple_types() { + let query = "album:arrival artist:abba"; + creds_client() + .await + .search_multiple( + query, + vec![SearchType::Artist, SearchType::Album], + None, + None, + Some(10), + Some(0), + ) + .await + .unwrap(); +} + pub mod test_pagination { use super::*;