use async_trait::async_trait;
use crate::{client::SoundCloudClient, http::Query, models::{playlist::{BasicAlbumPlaylist, TrackType}, track::Track, user::User}, utils::schemas::ResourceId, ClientResult, TracksApi};
use super::{convert_collection, convert_result, misc::MiscApi};
#[async_trait]
pub trait PlaylistsApi {
async fn get_playlist(&self, playlist_id: ResourceId) -> ClientResult<BasicAlbumPlaylist>;
async fn get_playlist_tracks(&self, playlist_id: ResourceId) -> ClientResult<Vec<Track>>;
async fn get_playlist_likers(&self, playlist_id: ResourceId) -> ClientResult<Vec<User>>;
async fn get_playlist_reposters(&self, playlist_id: ResourceId) -> ClientResult<Vec<User>>;
async fn extract_playlist_id(&self, playlist_id: ResourceId) -> ClientResult<u64>;
}
#[async_trait]
impl PlaylistsApi for SoundCloudClient {
async fn get_playlist(&self, playlist_id: ResourceId) -> ClientResult<BasicAlbumPlaylist> {
let uri = format!("/playlists/{}", self.extract_playlist_id(playlist_id).await?);
let result = self.api_get(&uri, Query::new()).await?;
convert_result(&result)
}
async fn get_playlist_tracks(&self, playlist_id: ResourceId) -> ClientResult<Vec<Track>> {
let playlist = self.get_playlist(playlist_id).await?;
let track_ids = playlist.album_playlist.tracks.iter().map(|track| match track {
TrackType::Basic(t) => t.track.id,
TrackType::Mini(t) => t.id,
}).collect::<Vec<_>>();
let mut tracks: Vec<Track> = Vec::new();
for chunk in track_ids.chunks(50) {
let chunk_tracks = self.get_tracks(chunk.to_vec(), None, None).await?;
tracks.extend(chunk_tracks);
}
Ok(tracks)
}
async fn get_playlist_likers(&self, playlist_id: ResourceId) -> ClientResult<Vec<User>> {
let uri = format!("/playlists/{}/likers", self.extract_playlist_id(playlist_id).await?);
let result = self.api_get(&uri, Query::new()).await?;
convert_collection(&result)
}
async fn get_playlist_reposters(&self, playlist_id: ResourceId) -> ClientResult<Vec<User>> {
let uri = format!("/playlists/{}/reposters", self.extract_playlist_id(playlist_id).await?);
let result = self.api_get(&uri, Query::new()).await?;
convert_collection(&result)
}
async fn extract_playlist_id(&self, playlist_id: ResourceId) -> ClientResult<u64> {
match playlist_id {
ResourceId::Id(id) => Ok(id),
ResourceId::Url(url) => {
self.resolve_album_playlist(&url).await
.map(|ap| ap.album_playlist.id)
},
ResourceId::Uri(uri) => {
self.resolve_album_playlist(&format!("https://soundcloud.com/{}", uri)).await
.map(|ap| ap.album_playlist.id)
}
}
}
}