use crate::error::Error;
use crate::primitive::{PlayParameters, TrackType};
use crate::request::builder::MusicRequestBuilder;
use crate::request::context::ContextContainer;
use crate::request::try_resource_response;
use crate::resource::artwork::Artwork;
use crate::resource::attributes::{DescriptionAttribute, TitleOnlyAttribute};
use crate::resource::catalog::artist::Artist;
use crate::resource::library::playlist::LibraryPlaylist;
use crate::resource::relationship::Relationship;
use crate::resource::view::View;
use crate::resource::{Resource, ResourceHeader};
use crate::ApiClient;
use am_api_proc_macro::{Context, ResourceProperty};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use time::OffsetDateTime;
#[derive(Context, Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
#[serde(rename_all = "camelCase")]
pub struct Playlist {
#[context(skip)]
#[serde(flatten)]
pub header: ResourceHeader,
#[context(skip)]
#[serde(default)]
pub attributes: Option<PlaylistAttributes>,
#[serde(default)]
pub relationships: PlaylistRelationships,
#[serde(default)]
pub views: PlaylistViews,
}
impl Playlist {
pub fn get<'a>() -> PlaylistGetRequestBuilder<'a> {
PlaylistGetRequestBuilder::default()
}
}
#[derive(ResourceProperty, Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
#[serde(rename_all = "camelCase")]
#[resource_property(
PlaylistAttributesExtension,
object = "playlists",
extension,
whitelist
)]
pub struct PlaylistAttributes {
#[serde(default)]
pub artwork: Option<Artwork>,
pub curator_name: String,
#[serde(default)]
pub description: Option<DescriptionAttribute>,
pub is_chart: bool,
#[serde(with = "time::serde::iso8601")]
pub last_modified_date: OffsetDateTime,
pub name: String,
pub playlist_type: PlaylistType,
#[serde(default)]
pub play_params: Option<PlayParameters>,
pub url: String,
#[resource_property(whitelist, name = "trackTypes")]
#[serde(default)]
pub track_types: Option<Vec<TrackType>>,
}
#[derive(
Context, ResourceProperty, Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq, Hash,
)]
#[serde(rename_all = "camelCase", default)]
#[resource_property(PlaylistRelationshipType, object = "playlists", relationship)]
pub struct PlaylistRelationships {
pub curator: Option<Relationship<Resource>>,
pub library: Option<Relationship<LibraryPlaylist>>,
pub tracks: Option<Relationship<Resource>>,
}
#[derive(
Context, ResourceProperty, Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq, Hash,
)]
#[serde(rename_all = "camelCase", default)]
#[resource_property(PlaylistViewType, object = "playlists", view)]
pub struct PlaylistViews {
#[serde(rename = "featured-artists")]
pub featured_artists: Option<View<TitleOnlyAttribute, Artist>>,
#[serde(rename = "more-by-curator")]
pub more_by_curator: Option<View<TitleOnlyAttribute, Playlist>>,
}
#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq, Hash)]
pub enum PlaylistType {
#[serde(rename = "editorial")]
Editorial,
#[serde(rename = "external")]
External,
#[serde(rename = "personal-mix")]
PersonalMix,
#[serde(rename = "replay")]
Replay,
#[serde(rename = "user-shared")]
#[default]
UserShared,
}
pub struct PlaylistRequestBuilder;
pub type PlaylistGetRequestBuilder<'a> = MusicRequestBuilder<'a, PlaylistRequestBuilder>;
impl<'a> PlaylistGetRequestBuilder<'a> {
pub async fn one(mut self, client: &ApiClient, id: &str) -> Result<Option<Playlist>, Error> {
let request_context = Arc::new(self.get_request_context_drain(client));
let response = client
.get(&format!(
"/v1/catalog/{storefront}/playlists/{id}",
storefront = request_context.storefront.alpha2.to_lowercase()
))
.query(&request_context.query)
.send()
.await?;
let mut response = try_resource_response(response).await?;
response.data.set_context(request_context);
Ok(response.data.into_iter().next())
}
pub async fn many(mut self, client: &ApiClient, ids: &[&str]) -> Result<Vec<Playlist>, Error> {
let mut request_context = self.get_request_context_drain(client);
request_context
.query
.push((String::from("ids"), ids.to_vec().join(",")));
let request_context = Arc::new(request_context);
let response = client
.get(&format!(
"/v1/catalog/{storefront}/playlists",
storefront = request_context.storefront.alpha2.to_lowercase()
))
.query(&request_context.query)
.send()
.await?;
let mut response = try_resource_response(response).await?;
response.data.set_context(request_context);
Ok(response.data)
}
pub async fn chart(
mut self,
client: &ApiClient,
storefront: &str,
) -> Result<Vec<Playlist>, Error> {
let mut request_context = self.get_request_context_drain(client);
request_context.query.push((
String::from("filter[storefront-chart]"),
storefront.to_string(),
));
let request_context = Arc::new(request_context);
let response = client
.get(&format!(
"/v1/catalog/{storefront}/playlists",
storefront = request_context.storefront.alpha2.to_lowercase()
))
.query(&request_context.query)
.send()
.await?;
let mut response = try_resource_response(response).await?;
response.data.set_context(request_context);
Ok(response.data)
}
}