use async_trait::async_trait;
use crate::{client::SoundCloudClient, http::build_query, models::{playlist::AlbumPlaylist, track::Track, user::User, SearchItem}, utils::schemas::CollectionParams, ClientResult};
use super::{convert_collection, convert_search_items};
#[async_trait]
pub trait SearchApi {
async fn search(&self, query: String, collection_params: CollectionParams) -> ClientResult<Vec<SearchItem>>;
async fn search_tracks(&self, query: String, collection_params: CollectionParams) -> ClientResult<Vec<Track>>;
async fn search_users(&self, query: String, collection_params: CollectionParams) -> ClientResult<Vec<User>>;
async fn search_albums(&self, query: String, collection_params: CollectionParams) -> ClientResult<Vec<AlbumPlaylist>>;
async fn search_playlists(&self, query: String, collection_params: CollectionParams) -> ClientResult<Vec<AlbumPlaylist>>;
async fn get_tag_tracks_recent(&self, tag: String, collection_params: CollectionParams) -> ClientResult<Vec<Track>>;
}
#[async_trait]
trait SearchApiUtils {
async fn generic_search(&self, query: String, collection_params: CollectionParams, path: &str) -> ClientResult<Vec<SearchItem>>;
}
#[async_trait]
impl SearchApi for SoundCloudClient {
async fn search(&self, query: String, collection_params: CollectionParams) -> ClientResult<Vec<SearchItem>> {
self.generic_search(query, collection_params, "/search").await
}
async fn search_tracks(&self, query: String, collection_params: CollectionParams) -> ClientResult<Vec<Track>> {
Ok(self.generic_search(query, collection_params, "/search/tracks").await?
.into_iter()
.filter_map(|item| if let SearchItem::Track(track) = item { Some(track) } else { None })
.collect())
}
async fn search_users(&self, query: String, collection_params: CollectionParams) -> ClientResult<Vec<User>> {
Ok(self.generic_search(query, collection_params, "/search/users").await?
.into_iter()
.filter_map(|item| if let SearchItem::User(user) = item { Some(user) } else { None })
.collect())
}
async fn search_albums(&self, query: String, collection_params: CollectionParams) -> ClientResult<Vec<AlbumPlaylist>> {
Ok(self.generic_search(query, collection_params, "/search/albums").await?
.into_iter()
.filter_map(|item| if let SearchItem::AlbumPlaylist(album) = item { Some(album) } else { None })
.collect())
}
async fn search_playlists(&self, query: String, collection_params: CollectionParams) -> ClientResult<Vec<AlbumPlaylist>> {
Ok(self.generic_search(query, collection_params, "/search/playlists").await?
.into_iter()
.filter_map(|item| if let SearchItem::AlbumPlaylist(playlist) = item { Some(playlist) } else { None })
.collect())
}
async fn get_tag_tracks_recent(&self, tag: String, collection_params: CollectionParams) -> ClientResult<Vec<Track>> {
let query_params = collection_params.to_query();
let result = self.api_get(format!("/recent-tracks/{}", tag).as_str(), query_params).await?;
convert_collection(&result)
}
}
#[async_trait]
impl SearchApiUtils for SoundCloudClient {
async fn generic_search(&self, query: String, collection_params: CollectionParams, path: &str) -> ClientResult<Vec<SearchItem>> {
let mut query_params = build_query([
("q", query.as_str()),
]);
collection_params.add_to_query(&mut query_params);
let result = self.api_get(path, query_params).await?;
convert_search_items(&result)
}
}