mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-28 17:21:52 +00:00
151 lines
4.7 KiB
Rust
151 lines
4.7 KiB
Rust
|
use std::convert::{TryFrom, TryInto};
|
||
|
use std::fmt::Debug;
|
||
|
use std::ops::Deref;
|
||
|
|
||
|
use chrono::Local;
|
||
|
use uuid::Uuid;
|
||
|
|
||
|
use crate::{
|
||
|
artist::{Artists, ArtistsWithRole},
|
||
|
audio::{
|
||
|
file::AudioFiles,
|
||
|
item::{AudioItem, AudioItemResult, InnerAudioItem},
|
||
|
},
|
||
|
availability::{Availabilities, UnavailabilityReason},
|
||
|
content_rating::ContentRatings,
|
||
|
date::Date,
|
||
|
error::RequestError,
|
||
|
external_id::ExternalIds,
|
||
|
restriction::Restrictions,
|
||
|
sale_period::SalePeriods,
|
||
|
util::try_from_repeated_message,
|
||
|
Metadata, MetadataError, RequestResult,
|
||
|
};
|
||
|
|
||
|
use librespot_core::session::Session;
|
||
|
use librespot_core::spotify_id::SpotifyId;
|
||
|
use librespot_protocol as protocol;
|
||
|
|
||
|
#[derive(Debug, Clone)]
|
||
|
pub struct Track {
|
||
|
pub id: SpotifyId,
|
||
|
pub name: String,
|
||
|
pub album: SpotifyId,
|
||
|
pub artists: Artists,
|
||
|
pub number: i32,
|
||
|
pub disc_number: i32,
|
||
|
pub duration: i32,
|
||
|
pub popularity: i32,
|
||
|
pub is_explicit: bool,
|
||
|
pub external_ids: ExternalIds,
|
||
|
pub restrictions: Restrictions,
|
||
|
pub files: AudioFiles,
|
||
|
pub alternatives: Tracks,
|
||
|
pub sale_periods: SalePeriods,
|
||
|
pub previews: AudioFiles,
|
||
|
pub tags: Vec<String>,
|
||
|
pub earliest_live_timestamp: Date,
|
||
|
pub has_lyrics: bool,
|
||
|
pub availability: Availabilities,
|
||
|
pub licensor: Uuid,
|
||
|
pub language_of_performance: Vec<String>,
|
||
|
pub content_ratings: ContentRatings,
|
||
|
pub original_title: String,
|
||
|
pub version_title: String,
|
||
|
pub artists_with_role: ArtistsWithRole,
|
||
|
}
|
||
|
|
||
|
#[derive(Debug, Clone)]
|
||
|
pub struct Tracks(pub Vec<SpotifyId>);
|
||
|
|
||
|
impl Deref for Tracks {
|
||
|
type Target = Vec<SpotifyId>;
|
||
|
fn deref(&self) -> &Self::Target {
|
||
|
&self.0
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[async_trait]
|
||
|
impl InnerAudioItem for Track {
|
||
|
async fn get_audio_item(session: &Session, id: SpotifyId) -> AudioItemResult {
|
||
|
let track = Self::get(session, id).await?;
|
||
|
let alternatives = {
|
||
|
if track.alternatives.is_empty() {
|
||
|
None
|
||
|
} else {
|
||
|
Some(track.alternatives.clone())
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// TODO: check meaning of earliest_live_timestamp in
|
||
|
let availability = if Local::now() < track.earliest_live_timestamp.as_utc() {
|
||
|
Err(UnavailabilityReason::Embargo)
|
||
|
} else {
|
||
|
Self::available_in_country(&track.availability, &track.restrictions, &session.country())
|
||
|
};
|
||
|
|
||
|
Ok(AudioItem {
|
||
|
id,
|
||
|
spotify_uri: id.to_uri(),
|
||
|
files: track.files,
|
||
|
name: track.name,
|
||
|
duration: track.duration,
|
||
|
availability,
|
||
|
alternatives,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[async_trait]
|
||
|
impl Metadata for Track {
|
||
|
type Message = protocol::metadata::Track;
|
||
|
|
||
|
async fn request(session: &Session, track_id: SpotifyId) -> RequestResult {
|
||
|
session
|
||
|
.spclient()
|
||
|
.get_track_metadata(track_id)
|
||
|
.await
|
||
|
.map_err(RequestError::Http)
|
||
|
}
|
||
|
|
||
|
fn parse(msg: &Self::Message, _: SpotifyId) -> Result<Self, MetadataError> {
|
||
|
Self::try_from(msg)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl TryFrom<&<Self as Metadata>::Message> for Track {
|
||
|
type Error = MetadataError;
|
||
|
fn try_from(track: &<Self as Metadata>::Message) -> Result<Self, Self::Error> {
|
||
|
Ok(Self {
|
||
|
id: track.try_into()?,
|
||
|
name: track.get_name().to_owned(),
|
||
|
album: track.get_album().try_into()?,
|
||
|
artists: track.get_artist().try_into()?,
|
||
|
number: track.get_number(),
|
||
|
disc_number: track.get_disc_number(),
|
||
|
duration: track.get_duration(),
|
||
|
popularity: track.get_popularity(),
|
||
|
is_explicit: track.get_explicit(),
|
||
|
external_ids: track.get_external_id().into(),
|
||
|
restrictions: track.get_restriction().into(),
|
||
|
files: track.get_file().into(),
|
||
|
alternatives: track.get_alternative().try_into()?,
|
||
|
sale_periods: track.get_sale_period().into(),
|
||
|
previews: track.get_preview().into(),
|
||
|
tags: track.get_tags().to_vec(),
|
||
|
earliest_live_timestamp: track.get_earliest_live_timestamp().try_into()?,
|
||
|
has_lyrics: track.get_has_lyrics(),
|
||
|
availability: track.get_availability().into(),
|
||
|
licensor: Uuid::from_slice(track.get_licensor().get_uuid())
|
||
|
.unwrap_or_else(|_| Uuid::nil()),
|
||
|
language_of_performance: track.get_language_of_performance().to_vec(),
|
||
|
content_ratings: track.get_content_rating().into(),
|
||
|
original_title: track.get_original_title().to_owned(),
|
||
|
version_title: track.get_version_title().to_owned(),
|
||
|
artists_with_role: track.get_artist_with_role().try_into()?,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
try_from_repeated_message!(<Track as Metadata>::Message, Tracks);
|