use crate::endpoints::albums::get_album;
use crate::endpoints::artists::{
get_artist, get_artist_top_tracks, get_artists_albums, get_artists_related_artists,
};
use crate::endpoints::tracks::get_track;
use crate::io::output::{ErrorKind, Response};
use crate::types::{Album, Artist, ArtistTopTracksResponse, RelatedArtistsResponse, Track};
use super::{extract_id, now_playing, with_client};
#[derive(Debug, Clone, Copy, Default)]
pub enum ArtistView {
#[default]
Details,
TopTracks,
Albums,
Related,
}
#[derive(Debug, Clone)]
pub struct ArtistQuery {
pub id: Option<String>,
pub id_only: bool,
pub view: ArtistView,
pub market: String,
pub limit: u8,
pub offset: u32,
}
impl ArtistQuery {
pub fn new() -> Self {
Self {
id: None,
id_only: false,
view: ArtistView::Details,
market: "US".to_string(),
limit: 20,
offset: 0,
}
}
pub fn with_id(mut self, id: Option<String>) -> Self {
self.id = id;
self
}
pub fn id_only(mut self, id_only: bool) -> Self {
self.id_only = id_only;
self
}
pub fn view(mut self, view: ArtistView) -> Self {
self.view = view;
self
}
pub fn market(mut self, market: String) -> Self {
self.market = market;
self
}
pub fn paginate(mut self, limit: u8, offset: u32) -> Self {
self.limit = limit;
self.offset = offset;
self
}
}
impl Default for ArtistQuery {
fn default() -> Self {
Self::new()
}
}
pub async fn info_track(id: Option<&str>, id_only: bool) -> Response {
with_client(|client| async move {
let track_id = match id {
Some(id) => extract_id(id),
None => match now_playing::get_track_id(&client).await {
Ok(id) => id,
Err(e) => return e,
},
};
if id_only {
return Response::success(200, &track_id);
}
match get_track::get_track(&client, &track_id).await {
Ok(Some(payload)) => {
match serde_json::from_value::<Track>(payload.clone()) {
Ok(track) => {
let msg = format!("{} - {}", track.name, track.artist_names());
Response::success_with_payload(200, msg, payload)
}
Err(_) => Response::success_with_payload(200, "Track details", payload),
}
}
Ok(None) => Response::err(404, "Track not found", ErrorKind::NotFound),
Err(e) => Response::from_http_error(&e, "Failed to get track"),
}
})
.await
}
pub async fn info_album(id: Option<&str>, id_only: bool) -> Response {
with_client(|client| async move {
let album_id = match id {
Some(id) => extract_id(id),
None => match now_playing::get_album_id(&client).await {
Ok(id) => id,
Err(e) => return e,
},
};
if id_only {
return Response::success(200, &album_id);
}
match get_album::get_album(&client, &album_id).await {
Ok(Some(payload)) => {
match serde_json::from_value::<Album>(payload.clone()) {
Ok(album) => {
let artist = album.artist_name().unwrap_or("Unknown Artist");
let msg = format!("{} - {}", album.name, artist);
Response::success_with_payload(200, msg, payload)
}
Err(_) => Response::success_with_payload(200, "Album details", payload),
}
}
Ok(None) => Response::err(404, "Album not found", ErrorKind::NotFound),
Err(e) => Response::from_http_error(&e, "Failed to get album"),
}
})
.await
}
pub async fn info_artist(query: ArtistQuery) -> Response {
let ArtistQuery {
id,
id_only,
view,
market,
limit,
offset,
} = query;
with_client(|client| async move {
let artist_id = match id.as_deref() {
Some(id) => extract_id(id),
None => match now_playing::get_artist_id(&client).await {
Ok(id) => id,
Err(e) => return e,
},
};
if id_only {
return Response::success(200, &artist_id);
}
match view {
ArtistView::TopTracks => {
match get_artist_top_tracks::get_artist_top_tracks(
&client,
&artist_id,
Some(&market),
)
.await
{
Ok(Some(payload)) => {
match serde_json::from_value::<ArtistTopTracksResponse>(payload.clone()) {
Ok(resp) => {
let count = resp.tracks.len();
Response::success_with_payload(
200,
format!("Top {} tracks", count),
payload,
)
}
Err(_) => Response::success_with_payload(200, "Top tracks", payload),
}
}
Ok(None) => Response::success_with_payload(
200,
"No top tracks",
serde_json::json!({ "tracks": [] }),
),
Err(e) => Response::from_http_error(&e, "Failed to get top tracks"),
}
}
ArtistView::Albums => {
match get_artists_albums::get_artists_albums(
&client,
&artist_id,
Some(limit),
Some(offset),
)
.await
{
Ok(Some(payload)) => {
Response::success_with_payload(200, "Artist albums", payload)
}
Ok(None) => Response::success_with_payload(
200,
"No albums",
serde_json::json!({ "items": [] }),
),
Err(e) => Response::from_http_error(&e, "Failed to get artist albums"),
}
}
ArtistView::Related => {
match get_artists_related_artists::get_artists_related_artists(&client, &artist_id)
.await
{
Ok(Some(payload)) => {
match serde_json::from_value::<RelatedArtistsResponse>(payload.clone()) {
Ok(resp) => {
let count = resp.artists.len();
Response::success_with_payload(
200,
format!("{} related artists", count),
payload,
)
}
Err(_) => {
Response::success_with_payload(200, "Related artists", payload)
}
}
}
Ok(None) => Response::success_with_payload(
200,
"No related artists",
serde_json::json!({ "artists": [] }),
),
Err(e) => Response::from_http_error(&e, "Failed to get related artists"),
}
}
ArtistView::Details => match get_artist::get_artist(&client, &artist_id).await {
Ok(Some(payload)) => match serde_json::from_value::<Artist>(payload.clone()) {
Ok(artist) => Response::success_with_payload(200, artist.name.clone(), payload),
Err(_) => Response::success_with_payload(200, "Artist details", payload),
},
Ok(None) => Response::err(404, "Artist not found", ErrorKind::NotFound),
Err(e) => Response::from_http_error(&e, "Failed to get artist"),
},
}
})
.await
}