use async_trait::async_trait;
use crate::{client::SoundCloudClient, errors::{convert_404_to_invalid_id, ClientError}, http::Query, models::{comment::Comment, conversation::Conversation, message::Message, playlist::BasicAlbumPlaylist, track::BasicTrack, user::{User, UserEmail}, web_profile::WebProfile, LikeItem, RepostItem, SearchItem, StreamItem}, need_authentication, utils::schemas::ResourceId, ClientResult};
use super::{convert_collection, convert_like_items, convert_repost_items, convert_result, convert_stream_items, misc::MiscApi};
#[async_trait]
pub trait UsersApi {
async fn get_user(&self, user_id: ResourceId) -> ClientResult<User>;
async fn get_user_by_username(&self, username: &str) -> ClientResult<User>;
async fn get_user_comments(&self, user_id: ResourceId) -> ClientResult<Vec<Comment>>;
async fn get_user_emails(&self, user_id: ResourceId) -> ClientResult<Vec<UserEmail>>;
async fn get_user_featured_profiles(&self, user_id: ResourceId) -> ClientResult<Vec<User>>;
async fn get_user_followers(&self, user_id: ResourceId) -> ClientResult<Vec<User>>;
async fn get_user_followings(&self, user_id: ResourceId) -> ClientResult<Vec<User>>;
async fn get_user_likes(&self, user_id: ResourceId) -> ClientResult<Vec<LikeItem>>;
async fn get_user_related_artists(&self, user_id: ResourceId) -> ClientResult<Vec<User>>;
async fn get_user_reposts(&self, user_id: ResourceId) -> ClientResult<Vec<RepostItem>>;
async fn get_user_streams(&self, user_id: ResourceId) -> ClientResult<Vec<StreamItem>>;
async fn get_user_tracks(&self, user_id: ResourceId) -> ClientResult<Vec<BasicTrack>>;
async fn get_user_popular_tracks(&self, user_id: ResourceId) -> ClientResult<Vec<BasicTrack>>;
async fn get_user_albums(&self, user_id: ResourceId) -> ClientResult<Vec<BasicAlbumPlaylist>>;
async fn get_user_playlists(&self, user_id: ResourceId) -> ClientResult<Vec<BasicAlbumPlaylist>>;
async fn get_user_links(&self, user_id: ResourceId) -> ClientResult<Vec<WebProfile>>;
async fn get_user_conversations(&self, user_id: ResourceId) -> ClientResult<Vec<Conversation>>;
async fn get_conversation_messages(&self, user_id: ResourceId, conversation_id: u64) -> ClientResult<Vec<Message>>;
async fn get_unread_conversations(&self, user_id: ResourceId) -> ClientResult<Vec<Conversation>>;
async fn extract_user_id(&self, user_id: ResourceId) -> ClientResult<u64>;
}
#[async_trait]
impl UsersApi for SoundCloudClient {
async fn get_user(&self, user_id: ResourceId) -> ClientResult<User> {
let uri = format!("/users/{}", self.extract_user_id(user_id).await?);
let result = self.api_get(&uri, Query::new()).await.map_err(convert_404_to_invalid_id)?;
convert_result(&result)
}
async fn get_user_by_username(&self, username: &str) -> ClientResult<User> {
let resource = self.resolve(format!("https://soundcloud.com/{}", username).as_str()).await?;
match resource {
SearchItem::User(user) => Ok(user),
_ => Err(ClientError::NotFound)
}
}
async fn get_user_comments(&self, user_id: ResourceId) -> ClientResult<Vec<Comment>> {
let uri = format!("/users/{}/comments", self.extract_user_id(user_id).await?);
let result = self.api_get(&uri, Query::new()).await.map_err(convert_404_to_invalid_id)?;
convert_collection(&result)
}
async fn get_user_emails(&self, user_id: ResourceId) -> ClientResult<Vec<UserEmail>> {
need_authentication!(self);
let uri = format!("/users/{}/emails", self.extract_user_id(user_id).await?);
let result = self.api_get(&uri, Query::new()).await.map_err(convert_404_to_invalid_id)?;
convert_collection(&result)
}
async fn get_user_featured_profiles(&self, user_id: ResourceId) -> ClientResult<Vec<User>> {
let uri = format!("/users/{}/featured-profiles", self.extract_user_id(user_id).await?);
let result = self.api_get(&uri, Query::new()).await.map_err(convert_404_to_invalid_id)?;
convert_collection(&result)
}
async fn get_user_followers(&self, user_id: ResourceId) -> ClientResult<Vec<User>> {
let uri = format!("/users/{}/followers", self.extract_user_id(user_id).await?);
let result = self.api_get(&uri, Query::new()).await.map_err(convert_404_to_invalid_id)?;
convert_collection(&result)
}
async fn get_user_followings(&self, user_id: ResourceId) -> ClientResult<Vec<User>> {
let uri = format!("/users/{}/followings", self.extract_user_id(user_id).await?);
let result = self.api_get(&uri, Query::new()).await.map_err(convert_404_to_invalid_id)?;
convert_collection(&result)
}
async fn get_user_likes(&self, user_id: ResourceId) -> ClientResult<Vec<LikeItem>> {
let uri = format!("/users/{}/likes", self.extract_user_id(user_id).await?);
let result = self.api_get(&uri, Query::new()).await.map_err(convert_404_to_invalid_id)?;
convert_like_items(&result)
}
async fn get_user_related_artists(&self, user_id: ResourceId) -> ClientResult<Vec<User>> {
let uri = format!("/users/{}/relatedartists", self.extract_user_id(user_id).await?);
let result = self.api_get(&uri, Query::new()).await.map_err(convert_404_to_invalid_id)?;
convert_collection(&result)
}
async fn get_user_reposts(&self, user_id: ResourceId) -> ClientResult<Vec<RepostItem>> {
let uri = format!("/stream/users/{}/reposts", self.extract_user_id(user_id).await?);
let result = self.api_get(&uri, Query::new()).await.map_err(convert_404_to_invalid_id)?;
convert_repost_items(&result)
}
async fn get_user_streams(&self, user_id: ResourceId) -> ClientResult<Vec<StreamItem>> {
let uri = format!("/stream/users/{}", self.extract_user_id(user_id).await?);
let result = self.api_get(&uri, Query::new()).await.map_err(convert_404_to_invalid_id)?;
convert_stream_items(&result)
}
async fn get_user_tracks(&self, user_id: ResourceId) -> ClientResult<Vec<BasicTrack>> {
let uri = format!("/users/{}/tracks", self.extract_user_id(user_id).await?);
let result = self.api_get(&uri, Query::new()).await.map_err(convert_404_to_invalid_id)?;
convert_collection(&result)
}
async fn get_user_popular_tracks(&self, user_id: ResourceId) -> ClientResult<Vec<BasicTrack>> {
let uri = format!("/users/{}/toptracks", self.extract_user_id(user_id).await?);
let result = self.api_get(&uri, Query::new()).await.map_err(convert_404_to_invalid_id)?;
convert_collection(&result)
}
async fn get_user_albums(&self, user_id: ResourceId) -> ClientResult<Vec<BasicAlbumPlaylist>> {
let uri = format!("/users/{}/albums", self.extract_user_id(user_id).await?);
let result = self.api_get(&uri, Query::new()).await.map_err(convert_404_to_invalid_id)?;
convert_collection(&result)
}
async fn get_user_playlists(&self, user_id: ResourceId) -> ClientResult<Vec<BasicAlbumPlaylist>> {
let uri = format!("/users/{}/playlists_without_albums", self.extract_user_id(user_id).await?);
let result = self.api_get(&uri, Query::new()).await.map_err(convert_404_to_invalid_id)?;
convert_collection(&result)
}
async fn get_user_links(&self, user_id: ResourceId) -> ClientResult<Vec<WebProfile>> {
let uri = format!("/users/soundcloud:users:{}/web-profiles", self.extract_user_id(user_id).await?);
let result = self.api_get(&uri, Query::new()).await.map_err(convert_404_to_invalid_id)?;
convert_result(&result) }
async fn get_user_conversations(&self, user_id: ResourceId) -> ClientResult<Vec<Conversation>> {
need_authentication!(self);
let uri = format!("/users/{}/conversations", self.extract_user_id(user_id).await?);
let result = self.api_get(&uri, Query::new()).await.map_err(convert_404_to_invalid_id)?;
convert_collection(&result)
}
async fn get_conversation_messages(&self, user_id: ResourceId, conversation_id: u64) -> ClientResult<Vec<Message>> {
need_authentication!(self);
let uri = format!("/users/{}/conversations/{}/messages", self.extract_user_id(user_id).await?, conversation_id);
let result = self.api_get(&uri, Query::new()).await.map_err(convert_404_to_invalid_id)?;
convert_collection(&result)
}
async fn get_unread_conversations(&self, user_id: ResourceId) -> ClientResult<Vec<Conversation>> {
need_authentication!(self);
let uri = format!("/users/{}/conversations/unread", self.extract_user_id(user_id).await?);
let result = self.api_get(&uri, Query::new()).await.map_err(convert_404_to_invalid_id)?;
convert_collection(&result)
}
async fn extract_user_id(&self, user_id: ResourceId) -> ClientResult<u64> {
match user_id {
ResourceId::Id(id) => Ok(id),
ResourceId::Url(url) => {
self.resolve_user(&url).await
.map(|u| u.user.id)
},
ResourceId::Uri(uri) => {
self.resolve_user(&format!("https://soundcloud.com/{}", uri)).await
.map(|u| u.user.id)
}
}
}
}