use {
serde::{Deserialize, Serialize},
serde_json::Value,
};
use crate::{
api::content::record_media::{
AudioInfo, Biography, Genre, Image, Label, deserialize_flexible_name,
deserialize_flexible_string_id, deserialize_picture,
},
credentials::Credential,
};
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct Album {
pub id: Option<String>,
pub title: Option<String>,
pub version: Option<String>,
pub upc: Option<String>,
pub url: Option<String>,
pub artist: Option<Box<Artist>>,
pub artists: Option<Vec<Box<Artist>>>,
pub composer: Option<Box<Artist>>,
pub label: Option<Label>,
pub genre: Option<Genre>,
pub genres: Option<Vec<Genre>>,
pub image: Option<Image>,
pub duration: Option<i32>,
pub tracks_count: Option<i32>,
pub media_count: Option<i32>,
pub release_date_original: Option<String>,
pub release_date_stream: Option<String>,
pub release_date_download: Option<String>,
pub product_type: Option<String>,
pub release_type: Option<String>,
pub hires: Option<bool>,
pub hires_streamable: Option<bool>,
pub downloadable: Option<bool>,
pub streamable: Option<bool>,
pub track_ids: Option<Vec<i32>>,
pub product_url: Option<String>,
pub released_at: Option<i64>,
pub copyright: Option<String>,
pub product_sales_factors: Option<Value>,
pub maximum_bit_depth: Option<i32>,
pub maximum_sampling_rate: Option<f64>,
pub maximum_channel_count: Option<i32>,
}
impl Album {
#[must_use]
pub const fn extension_for_format(format_id: i32) -> &'static str {
match format_id {
5 => "mp3",
_ => "flac",
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct AlbumSearchResponse {
pub albums: ItemSearchResult<Box<Album>>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct Artist {
pub id: Option<i32>,
#[serde(default, deserialize_with = "deserialize_flexible_name")]
pub name: Option<String>,
pub slug: Option<String>,
#[serde(default, deserialize_with = "deserialize_picture")]
pub picture: Option<Image>,
pub image: Option<Image>,
pub biography: Option<Biography>,
pub albums_count: Option<i32>,
pub roles: Option<Vec<String>>,
pub albums: Option<ItemSearchResult<Box<Album>>>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct ArtistSearchResponse {
pub artists: ItemSearchResult<Box<Artist>>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct ItemSearchResult<T> {
pub items: Option<Vec<T>>,
pub total: Option<i32>,
pub limit: Option<i32>,
pub offset: Option<i32>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct Playlist {
#[serde(default, deserialize_with = "deserialize_flexible_string_id")]
pub id: Option<String>,
pub name: Option<String>,
pub description: Option<String>,
pub tracks_count: Option<i32>,
pub duration: Option<i32>,
pub is_public: Option<bool>,
pub creator: Option<User>,
pub owner: Option<PlaylistOwner>,
pub image: Option<Image>,
pub image_rectangle: Option<Vec<String>>,
pub image_rectangle_mini: Option<Vec<String>>,
pub images: Option<Vec<String>>,
pub images150: Option<Vec<String>>,
pub images300: Option<Vec<String>>,
pub tracks: Option<ItemSearchResult<Box<Track>>>,
pub created_at: Option<i64>,
pub updated_at: Option<i64>,
}
impl Playlist {
#[must_use]
pub fn creator_name(&self) -> Option<&str> {
self.creator
.as_ref()
.and_then(|c| c.display_name.as_deref())
.or_else(|| {
let o = self.owner.as_ref()?;
o.name.as_deref()
})
}
#[must_use]
pub fn best_image_url(&self, large: bool) -> Option<String> {
if large {
first_img_url(self.image_rectangle.as_ref())
.or_else(|| first_img_url(self.images300.as_ref()))
.or_else(|| first_img_url(self.images150.as_ref()))
.or_else(|| first_img_url(self.images.as_ref()))
} else {
first_img_url(self.image_rectangle_mini.as_ref())
.or_else(|| first_img_url(self.image_rectangle.as_ref()))
.or_else(|| first_img_url(self.images150.as_ref()))
.or_else(|| first_img_url(self.images.as_ref()))
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct PlaylistOwner {
pub id: Option<i32>,
pub name: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct PlaylistSearchResponse {
pub playlists: ItemSearchResult<Box<Playlist>>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct SearchResult {
pub albums: Option<ItemSearchResult<Box<Album>>>,
pub artists: Option<ItemSearchResult<Box<Artist>>>,
pub tracks: Option<ItemSearchResult<Box<Track>>>,
pub playlists: Option<ItemSearchResult<Box<Playlist>>>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct Subscription {
pub id: Option<i32>,
pub offer: Option<String>,
pub start_date: Option<String>,
pub end_date: Option<String>,
pub status: Option<String>,
pub is_active: Option<bool>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct Track {
pub id: Option<i32>,
pub title: Option<String>,
pub version: Option<String>,
pub isrc: Option<String>,
pub track_number: Option<i32>,
pub duration: Option<i32>,
pub media_number: Option<i32>,
pub work: Option<String>,
pub album: Option<Box<Album>>,
pub performer: Option<Box<Artist>>,
pub performers: Option<String>,
pub composer: Option<Box<Artist>>,
pub audio_info: Option<AudioInfo>,
pub copyright: Option<String>,
pub streamable: Option<bool>,
pub downloadable: Option<bool>,
pub hires: Option<bool>,
pub maximum_bit_depth: Option<i32>,
pub maximum_sampling_rate: Option<f64>,
pub maximum_channel_count: Option<i32>,
pub release_date_original: Option<String>,
pub release_date_stream: Option<String>,
pub parental_warning: Option<bool>,
pub product_sales_factors: Option<Value>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct TrackSearchResponse {
pub tracks: ItemSearchResult<Box<Track>>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct User {
pub id: Option<i32>,
pub credential: Option<Credential>,
pub subscription: Option<Subscription>,
pub display_name: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct UserFavorites {
pub albums: Option<ItemSearchResult<Box<Album>>>,
pub artists: Option<ItemSearchResult<Box<Artist>>>,
pub tracks: Option<ItemSearchResult<Box<Track>>>,
pub article_ids: Option<Vec<i32>>,
pub artist_ids: Option<Vec<i32>>,
pub album_ids: Option<Vec<i32>>,
pub track_ids: Option<Vec<i32>>,
}
fn first_img_url(v: Option<&Vec<String>>) -> Option<String> {
v?.first().cloned()
}