735 lines
19 KiB
Rust
735 lines
19 KiB
Rust
//! Data model for the Spotify API
|
|
|
|
use std::num::NonZeroU32;
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
use serde_with::{serde_as, DefaultOnError, DisplayFromStr, VecSkipError};
|
|
use time::OffsetDateTime;
|
|
|
|
use spotifyio_model::{
|
|
AlbumId, ArtistId, ConcertId, PlaylistId, PrereleaseId, SongwriterId, TrackId, UserId,
|
|
UserlikeId,
|
|
};
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub(crate) struct LyricsWrap {
|
|
pub lyrics: Lyrics,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[non_exhaustive]
|
|
pub struct GqlWrap<T> {
|
|
pub data: T,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(tag = "__typename")]
|
|
#[allow(clippy::large_enum_variant)]
|
|
pub enum ArtistOption {
|
|
Artist(ArtistItem),
|
|
#[serde(alias = "GenericError")]
|
|
NotFound,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(tag = "__typename")]
|
|
#[allow(clippy::large_enum_variant)]
|
|
pub enum AlbumOption {
|
|
Album(AlbumItem),
|
|
#[serde(alias = "GenericError")]
|
|
NotFound,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(tag = "__typename")]
|
|
#[allow(clippy::large_enum_variant)]
|
|
pub enum TrackOption {
|
|
Track(TrackItem),
|
|
#[serde(alias = "GenericError")]
|
|
NotFound,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(tag = "__typename")]
|
|
#[allow(clippy::large_enum_variant)]
|
|
pub enum PlaylistOption {
|
|
Playlist(GqlPlaylistItem),
|
|
#[serde(alias = "GenericError")]
|
|
NotFound,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(tag = "__typename")]
|
|
#[allow(clippy::large_enum_variant)]
|
|
pub enum ConcertOption {
|
|
ConcertV2(ConcertGql),
|
|
#[serde(alias = "GenericError")]
|
|
NotFound,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[non_exhaustive]
|
|
pub struct GqlPagination<T> {
|
|
pub items: Vec<T>,
|
|
pub total_count: Option<NonZeroU32>,
|
|
}
|
|
|
|
impl<T> Default for GqlPagination<T> {
|
|
fn default() -> Self {
|
|
Self {
|
|
items: Vec::new(),
|
|
total_count: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[serde_as]
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct Lyrics {
|
|
#[serde_as(as = "DefaultOnError")]
|
|
pub sync_type: Option<SyncType>,
|
|
pub lines: Vec<LyricsLine>,
|
|
pub provider: Option<String>,
|
|
pub provider_lyrics_id: Option<String>,
|
|
pub provider_display_name: Option<String>,
|
|
pub language: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
|
#[non_exhaustive]
|
|
pub enum SyncType {
|
|
LineSynced,
|
|
}
|
|
|
|
#[serde_as]
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct LyricsLine {
|
|
#[serde_as(as = "Option<DisplayFromStr>")]
|
|
pub start_time_ms: Option<u32>,
|
|
pub words: String,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub(crate) struct ArtistGqlWrap {
|
|
pub artist_union: ArtistGql,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct ArtistGql {
|
|
pub uri: ArtistId<'static>,
|
|
pub profile: ArtistProfile,
|
|
pub related_content: Option<RelatedContent>,
|
|
pub stats: Option<ArtistStats>,
|
|
#[serde(default)]
|
|
pub visuals: Visuals,
|
|
pub pre_release: Option<PrereleaseItem>,
|
|
#[serde(default)]
|
|
pub goods: Goods,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct ArtistProfile {
|
|
pub name: String,
|
|
#[serde(default)]
|
|
pub verified: bool,
|
|
#[serde(default)]
|
|
pub biography: Biography,
|
|
#[serde(default)]
|
|
pub external_links: GqlPagination<ExternalLink>,
|
|
#[serde(default)]
|
|
pub playlists_v2: GqlPagination<GqlWrap<PlaylistOption>>,
|
|
}
|
|
|
|
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
|
#[non_exhaustive]
|
|
pub struct Biography {
|
|
pub text: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[non_exhaustive]
|
|
pub struct ExternalLink {
|
|
pub name: String,
|
|
pub url: String,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct ArtistStats {
|
|
pub followers: u32,
|
|
pub monthly_listeners: u32,
|
|
pub world_rank: u32,
|
|
pub top_cities: GqlPagination<City>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct City {
|
|
pub city: String,
|
|
pub country: String,
|
|
pub number_of_listeners: u32,
|
|
pub region: String,
|
|
}
|
|
|
|
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(default, rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct Visuals {
|
|
pub avatar_image: Option<Image>,
|
|
pub gallery: GqlPagination<Image>,
|
|
pub header_image: Option<Image>,
|
|
}
|
|
|
|
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(default, rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct Goods {
|
|
pub events: Events,
|
|
pub merch: GqlPagination<MerchItem>,
|
|
}
|
|
|
|
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct Events {
|
|
pub concerts: GqlPagination<Concert>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct Concert {
|
|
pub uri: ConcertId<'static>,
|
|
pub title: String,
|
|
pub date: DateWrap,
|
|
#[serde(default)]
|
|
pub festival: bool,
|
|
pub partner_links: Option<GqlPagination<PartnerLink>>,
|
|
pub venue: Venue,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct PartnerLink {
|
|
pub partner_name: String,
|
|
pub url: String,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct Venue {
|
|
pub name: String,
|
|
pub location: Option<Location>,
|
|
pub coordinates: Option<Coordinates>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct Location {
|
|
pub name: String,
|
|
pub city: Option<String>,
|
|
pub coordinates: Option<Coordinates>,
|
|
// ISO-3166 country code
|
|
pub country: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct Coordinates {
|
|
pub latitude: f64,
|
|
pub longitude: f64,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct MerchItem {
|
|
pub uri: String,
|
|
pub url: String,
|
|
pub name: String,
|
|
pub price: String,
|
|
pub description: String,
|
|
pub image: Image,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct Image {
|
|
pub sources: Vec<ImageSource>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[non_exhaustive]
|
|
pub struct ImageSource {
|
|
pub url: String,
|
|
pub height: Option<u16>,
|
|
pub width: Option<u16>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[non_exhaustive]
|
|
pub struct Name {
|
|
pub name: String,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct GqlPlaylistItem {
|
|
pub uri: PlaylistId<'static>,
|
|
pub name: String,
|
|
pub images: GqlPagination<Image>,
|
|
pub owner_v2: GqlWrap<UserItem>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct UserItem {
|
|
pub uri: Option<UserId<'static>>,
|
|
#[serde(alias = "displayName")]
|
|
pub name: Option<String>,
|
|
pub avatar: Option<Image>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct ArtistItem {
|
|
pub uri: ArtistId<'static>,
|
|
pub profile: Name,
|
|
pub visuals: Option<Visuals>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct RelatedContent {
|
|
#[serde(default)]
|
|
pub discovered_on_v2: GqlPagination<GqlWrap<PlaylistOption>>,
|
|
#[serde(default)]
|
|
pub featuring_v2: GqlPagination<GqlWrap<PlaylistOption>>,
|
|
#[serde(default)]
|
|
pub related_artists: GqlPagination<ArtistItem>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub(crate) struct PrereleaseLookup {
|
|
pub lookup: Vec<GqlWrap<PrereleaseItem>>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct PrereleaseItem {
|
|
/// URI of the prerelease
|
|
pub uri: PrereleaseId<'static>,
|
|
pub pre_release_content: PrereleaseContent,
|
|
pub release_date: DateWrap,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct PrereleaseContent {
|
|
/// URI of the to-be-released album
|
|
pub uri: Option<AlbumId<'static>>,
|
|
pub name: String,
|
|
pub cover_art: Option<Image>,
|
|
pub artists: Option<GqlPagination<GqlWrap<ArtistItem>>>,
|
|
pub tracks: Option<GqlPagination<PrereleaseTrackItem>>,
|
|
pub copyright: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct PrereleaseTrackItem {
|
|
pub uri: TrackId<'static>,
|
|
pub name: String,
|
|
pub duration: Option<DurationWrap>,
|
|
pub artists: GqlPagination<GqlWrap<ArtistItem>>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct DateWrap {
|
|
#[serde(with = "time::serde::iso8601")]
|
|
pub iso_string: OffsetDateTime,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct DateYear {
|
|
pub year: Option<u16>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct DurationWrap {
|
|
pub total_milliseconds: u32,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub(crate) struct SearchResultWrap {
|
|
pub search_v2: GqlSearchResult,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
|
#[non_exhaustive]
|
|
pub enum MatchedField {
|
|
Lyrics,
|
|
}
|
|
|
|
#[serde_as]
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[non_exhaustive]
|
|
pub struct GqlSearchTrackWrap {
|
|
pub item: GqlWrap<TrackOption>,
|
|
#[serde(default)]
|
|
#[serde_as(as = "VecSkipError<_>")]
|
|
pub matched_fields: Vec<MatchedField>,
|
|
}
|
|
|
|
#[serde_as]
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ChipOrder {
|
|
#[serde_as(as = "VecSkipError<_>")]
|
|
pub items: Vec<Chip>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct Chip {
|
|
type_name: SearchItemType,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct GqlSearchResult {
|
|
#[serde(default)]
|
|
pub artists: GqlPagination<GqlWrap<ArtistOption>>,
|
|
#[serde(default)]
|
|
pub albums_v2: GqlPagination<AlbumItemWrap>,
|
|
#[serde(default)]
|
|
pub tracks_v2: GqlPagination<GqlSearchTrackWrap>,
|
|
#[serde(default)]
|
|
pub playlists: GqlPagination<GqlWrap<PlaylistOption>>,
|
|
#[serde(default)]
|
|
pub users: GqlPagination<GqlWrap<UserItem>>,
|
|
pub chip_order: ChipOrder,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(tag = "__typename")]
|
|
pub enum AlbumItemWrap {
|
|
AlbumResponseWrapper {
|
|
data: AlbumItem,
|
|
},
|
|
PreReleaseResponseWrapper {
|
|
data: PrereleaseItem,
|
|
},
|
|
#[serde(alias = "GenericError")]
|
|
NotFound,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct AlbumItem {
|
|
pub uri: AlbumId<'static>,
|
|
pub name: String,
|
|
pub date: Option<DateYear>,
|
|
pub cover_art: Option<Image>,
|
|
pub artists: Option<GqlPagination<ArtistItem>>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct TrackItem {
|
|
pub uri: TrackId<'static>,
|
|
pub name: String,
|
|
pub duration: DurationWrap,
|
|
pub artists: GqlPagination<ArtistItem>,
|
|
pub album_of_track: AlbumItem,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub(crate) struct ConcertGqlWrap {
|
|
pub concert: ConcertOption,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct ConcertGql {
|
|
pub uri: ConcertId<'static>,
|
|
pub title: String,
|
|
#[serde(default)]
|
|
pub artists: GqlPagination<GqlWrap<ArtistItem>>,
|
|
#[serde(default, with = "time::serde::iso8601::option")]
|
|
pub start_date_iso_string: Option<OffsetDateTime>,
|
|
#[serde(default, with = "time::serde::iso8601::option")]
|
|
pub doors_open_time_iso_string: Option<OffsetDateTime>,
|
|
#[serde(default)]
|
|
pub festival: bool,
|
|
pub html_description: Option<String>,
|
|
pub location: Option<Location>,
|
|
#[serde(default)]
|
|
pub offers: GqlPagination<ConcertOffer>,
|
|
#[serde(default)]
|
|
pub related_concerts: GqlPagination<GqlWrap<ConcertOption>>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct ConcertOffer {
|
|
pub access_code: String,
|
|
pub currency: Option<String>,
|
|
pub dates: Option<ConcertOfferDates>,
|
|
#[serde(default)]
|
|
pub first_party: bool,
|
|
pub max_price: Option<f32>,
|
|
pub min_price: Option<f32>,
|
|
pub provider_image_url: Option<String>,
|
|
pub provider_name: Option<String>,
|
|
pub sale_type: Option<String>,
|
|
pub sold_out: Option<bool>,
|
|
pub url: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[non_exhaustive]
|
|
pub struct ConcertOfferDates {
|
|
#[serde(with = "time::serde::iso8601")]
|
|
pub start_date_iso_string: OffsetDateTime,
|
|
#[serde(with = "time::serde::iso8601")]
|
|
pub end_date_iso_string: OffsetDateTime,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
|
pub enum SearchItemType {
|
|
Artists,
|
|
Albums,
|
|
Tracks,
|
|
Playlists,
|
|
Users,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[non_exhaustive]
|
|
pub struct UserProfile {
|
|
pub uri: UserId<'static>,
|
|
pub name: Option<String>,
|
|
pub image_url: Option<String>,
|
|
pub followers_count: Option<u32>,
|
|
pub following_count: Option<u32>,
|
|
#[serde(default)]
|
|
pub public_playlists: Vec<PublicPlaylistItem>,
|
|
pub total_public_playlists_count: Option<u32>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[non_exhaustive]
|
|
pub struct UserPlaylists {
|
|
#[serde(default)]
|
|
pub public_playlists: Vec<PublicPlaylistItem>,
|
|
pub total_public_playlists_count: Option<u32>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[non_exhaustive]
|
|
pub struct PublicPlaylistItem {
|
|
pub uri: PlaylistId<'static>,
|
|
pub name: String,
|
|
pub owner_name: String,
|
|
pub owner_uri: UserId<'static>,
|
|
/// UID-based image id
|
|
///
|
|
/// - `spotify:image:ab67706c0000da8474fffd106bb7f5be3ba4b758`
|
|
/// - `spotify:mosaic:ab67616d00001e021c04efd2804b16cf689de7f0:ab67616d00001e0269f63a842ea91ca7c522593a:ab67616d00001e0270dbc9f47669d120ad874ec1:ab67616d00001e027d384516b23347e92a587ed1`
|
|
pub image_url: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub(crate) struct UserProfilesWrap<T> {
|
|
pub profiles: Vec<T>,
|
|
}
|
|
|
|
/// May be an artist or an user
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[non_exhaustive]
|
|
pub struct FollowerItem {
|
|
pub uri: UserId<'static>,
|
|
pub name: Option<String>,
|
|
pub followers_count: Option<u32>,
|
|
pub image_url: Option<String>,
|
|
}
|
|
|
|
/// May be an artist or an user
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[non_exhaustive]
|
|
pub(crate) struct FollowerItemUserlike {
|
|
pub uri: UserlikeId<'static>,
|
|
pub name: Option<String>,
|
|
pub followers_count: Option<u32>,
|
|
pub image_url: Option<String>,
|
|
}
|
|
|
|
/// Seektable for AAC tracks
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct Seektable {
|
|
pub padding_samples: u32,
|
|
pub encoder_delay_samples: u32,
|
|
pub pssh: String,
|
|
pub timescale: u32,
|
|
pub init_range: Option<(u32, u32)>,
|
|
pub index_range: Option<(u32, u32)>,
|
|
pub segments: Vec<(u32, u32)>,
|
|
pub offset: usize,
|
|
}
|
|
|
|
/// Information about a track's artists, writers and producers
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct TrackCredits {
|
|
pub track_uri: TrackId<'static>,
|
|
pub track_title: String,
|
|
#[serde(default)]
|
|
pub role_credits: Vec<RoleCredits>,
|
|
// pub extended_credits: (),
|
|
#[serde(default)]
|
|
pub source_names: Vec<String>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct RoleCredits {
|
|
pub role_title: String,
|
|
pub artists: Vec<CreditedArtist>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CreditedArtist {
|
|
pub name: String,
|
|
pub uri: Option<ArtistId<'static>>,
|
|
pub creator_uri: Option<SongwriterId<'static>>,
|
|
pub external_url: Option<String>,
|
|
/// Image URL
|
|
pub image_uri: Option<String>,
|
|
pub subroles: Vec<String>,
|
|
pub weight: f32,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PlaylistWrap {
|
|
pub playlist_v2: PlaylistOption,
|
|
}
|
|
|
|
impl ArtistOption {
|
|
pub fn into_option(self) -> Option<ArtistItem> {
|
|
match self {
|
|
ArtistOption::Artist(artist_item) => Some(artist_item),
|
|
ArtistOption::NotFound => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TrackOption {
|
|
pub fn into_option(self) -> Option<TrackItem> {
|
|
match self {
|
|
TrackOption::Track(track_item) => Some(track_item),
|
|
TrackOption::NotFound => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PlaylistOption {
|
|
pub fn into_option(self) -> Option<GqlPlaylistItem> {
|
|
match self {
|
|
PlaylistOption::Playlist(playlist_item) => Some(playlist_item),
|
|
PlaylistOption::NotFound => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ConcertOption {
|
|
pub fn into_option(self) -> Option<ConcertGql> {
|
|
match self {
|
|
ConcertOption::ConcertV2(concert) => Some(concert),
|
|
ConcertOption::NotFound => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<GqlWrap<ArtistOption>> for Option<ArtistItem> {
|
|
fn from(value: GqlWrap<ArtistOption>) -> Self {
|
|
value.data.into_option()
|
|
}
|
|
}
|
|
|
|
impl From<GqlWrap<TrackOption>> for Option<TrackItem> {
|
|
fn from(value: GqlWrap<TrackOption>) -> Self {
|
|
value.data.into_option()
|
|
}
|
|
}
|
|
|
|
impl From<GqlWrap<PlaylistOption>> for Option<GqlPlaylistItem> {
|
|
fn from(value: GqlWrap<PlaylistOption>) -> Self {
|
|
value.data.into_option()
|
|
}
|
|
}
|
|
|
|
impl From<GqlWrap<ConcertOption>> for Option<ConcertGql> {
|
|
fn from(value: GqlWrap<ConcertOption>) -> Self {
|
|
value.data.into_option()
|
|
}
|
|
}
|
|
|
|
impl TryFrom<FollowerItemUserlike> for FollowerItem {
|
|
type Error = ();
|
|
|
|
fn try_from(value: FollowerItemUserlike) -> Result<Self, Self::Error> {
|
|
if let UserlikeId::User(uri) = value.uri {
|
|
Ok(Self {
|
|
uri,
|
|
name: value.name,
|
|
followers_count: value.followers_count,
|
|
image_url: value.image_url,
|
|
})
|
|
} else {
|
|
Err(())
|
|
}
|
|
}
|
|
}
|