mirror of
https://github.com/librespot-org/librespot.git
synced 2025-10-03 09:49:31 +02:00
refactor: Introduce SpotifyUri struct (#1538)
* refactor: Introduce SpotifyUri struct Contributes to #1266 Introduces a new `SpotifyUri` struct which is layered on top of the existing `SpotifyId`, but has the capability to support URIs that do not confirm to the canonical base62 encoded format. This allows it to describe URIs like `spotify:local`, `spotify:genre` and others that `SpotifyId` cannot represent. Changed the internal player state to use these URIs as much as possible, such that the player could in the future accept a URI of the type `spotify:local`, as a means of laying the groundwork for local file support. * fix: Don't pass unknown URIs from deprecated player methods * refactor: remove SpotifyUri::to_base16 This should be deprecated for the same reason to_base62 is, and could unpredictably throw errors -- consumers should match on the inner ID if they need a base62 representation and handle failure appropriately * refactor: Store original data in SpotifyUri::Unknown Instead of assuming Unknown has a u128 SpotifyId, store the original data and type that we failed to parse. * refactor: Remove SpotifyItemType * refactor: Address review feedback * test: Add more SpotifyUri tests * chore: Correctly mark changes as breaking in CHANGELOG.md * refactor: Respond to review feedback * chore: Changelog updates
This commit is contained in:
parent
0e5531ff54
commit
df5f957bdd
23 changed files with 937 additions and 625 deletions
|
@ -17,7 +17,7 @@ use crate::{
|
|||
util::{impl_deref_wrapped, impl_try_from_repeated},
|
||||
};
|
||||
|
||||
use librespot_core::{Error, Session, SpotifyId, date::Date};
|
||||
use librespot_core::{Error, Session, SpotifyUri, date::Date};
|
||||
|
||||
use librespot_protocol as protocol;
|
||||
use protocol::metadata::Disc as DiscMessage;
|
||||
|
@ -25,7 +25,7 @@ pub use protocol::metadata::album::Type as AlbumType;
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Album {
|
||||
pub id: SpotifyId,
|
||||
pub id: SpotifyUri,
|
||||
pub name: String,
|
||||
pub artists: Artists,
|
||||
pub album_type: AlbumType,
|
||||
|
@ -48,9 +48,9 @@ pub struct Album {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Albums(pub Vec<SpotifyId>);
|
||||
pub struct Albums(pub Vec<SpotifyUri>);
|
||||
|
||||
impl_deref_wrapped!(Albums, Vec<SpotifyId>);
|
||||
impl_deref_wrapped!(Albums, Vec<SpotifyUri>);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Disc {
|
||||
|
@ -65,7 +65,7 @@ pub struct Discs(pub Vec<Disc>);
|
|||
impl_deref_wrapped!(Discs, Vec<Disc>);
|
||||
|
||||
impl Album {
|
||||
pub fn tracks(&self) -> impl Iterator<Item = &SpotifyId> {
|
||||
pub fn tracks(&self) -> impl Iterator<Item = &SpotifyUri> {
|
||||
self.discs.iter().flat_map(|disc| disc.tracks.iter())
|
||||
}
|
||||
}
|
||||
|
@ -74,11 +74,15 @@ impl Album {
|
|||
impl Metadata for Album {
|
||||
type Message = protocol::metadata::Album;
|
||||
|
||||
async fn request(session: &Session, album_id: &SpotifyId) -> RequestResult {
|
||||
async fn request(session: &Session, album_uri: &SpotifyUri) -> RequestResult {
|
||||
let SpotifyUri::Album { id: album_id } = album_uri else {
|
||||
return Err(Error::invalid_argument("album_uri"));
|
||||
};
|
||||
|
||||
session.spclient().get_album_metadata(album_id).await
|
||||
}
|
||||
|
||||
fn parse(msg: &Self::Message, _: &SpotifyId) -> Result<Self, Error> {
|
||||
fn parse(msg: &Self::Message, _: &SpotifyUri) -> Result<Self, Error> {
|
||||
Self::try_from(msg)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ use crate::{
|
|||
util::{impl_deref_wrapped, impl_from_repeated, impl_try_from_repeated},
|
||||
};
|
||||
|
||||
use librespot_core::{Error, Session, SpotifyId};
|
||||
use librespot_core::{Error, Session, SpotifyUri};
|
||||
|
||||
use librespot_protocol as protocol;
|
||||
pub use protocol::metadata::artist_with_role::ArtistRole;
|
||||
|
@ -29,7 +29,7 @@ use protocol::metadata::TopTracks as TopTracksMessage;
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Artist {
|
||||
pub id: SpotifyId,
|
||||
pub id: SpotifyUri,
|
||||
pub name: String,
|
||||
pub popularity: i32,
|
||||
pub top_tracks: CountryTopTracks,
|
||||
|
@ -56,7 +56,7 @@ impl_deref_wrapped!(Artists, Vec<Artist>);
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ArtistWithRole {
|
||||
pub id: SpotifyId,
|
||||
pub id: SpotifyUri,
|
||||
pub name: String,
|
||||
pub role: ArtistRole,
|
||||
}
|
||||
|
@ -140,14 +140,14 @@ impl Artist {
|
|||
/// Get the full list of albums, not containing duplicate variants of the same albums.
|
||||
///
|
||||
/// See also [`AlbumGroups`](struct@AlbumGroups) and [`AlbumGroups::current_releases`]
|
||||
pub fn albums_current(&self) -> impl Iterator<Item = &SpotifyId> {
|
||||
pub fn albums_current(&self) -> impl Iterator<Item = &SpotifyUri> {
|
||||
self.albums.current_releases()
|
||||
}
|
||||
|
||||
/// Get the full list of singles, not containing duplicate variants of the same singles.
|
||||
///
|
||||
/// See also [`AlbumGroups`](struct@AlbumGroups) and [`AlbumGroups::current_releases`]
|
||||
pub fn singles_current(&self) -> impl Iterator<Item = &SpotifyId> {
|
||||
pub fn singles_current(&self) -> impl Iterator<Item = &SpotifyUri> {
|
||||
self.singles.current_releases()
|
||||
}
|
||||
|
||||
|
@ -155,14 +155,14 @@ impl Artist {
|
|||
/// compilations.
|
||||
///
|
||||
/// See also [`AlbumGroups`](struct@AlbumGroups) and [`AlbumGroups::current_releases`]
|
||||
pub fn compilations_current(&self) -> impl Iterator<Item = &SpotifyId> {
|
||||
pub fn compilations_current(&self) -> impl Iterator<Item = &SpotifyUri> {
|
||||
self.compilations.current_releases()
|
||||
}
|
||||
|
||||
/// Get the full list of albums, not containing duplicate variants of the same albums.
|
||||
///
|
||||
/// See also [`AlbumGroups`](struct@AlbumGroups) and [`AlbumGroups::current_releases`]
|
||||
pub fn appears_on_albums_current(&self) -> impl Iterator<Item = &SpotifyId> {
|
||||
pub fn appears_on_albums_current(&self) -> impl Iterator<Item = &SpotifyUri> {
|
||||
self.appears_on_albums.current_releases()
|
||||
}
|
||||
}
|
||||
|
@ -171,11 +171,15 @@ impl Artist {
|
|||
impl Metadata for Artist {
|
||||
type Message = protocol::metadata::Artist;
|
||||
|
||||
async fn request(session: &Session, artist_id: &SpotifyId) -> RequestResult {
|
||||
async fn request(session: &Session, artist_uri: &SpotifyUri) -> RequestResult {
|
||||
let SpotifyUri::Artist { id: artist_id } = artist_uri else {
|
||||
return Err(Error::invalid_argument("artist_uri"));
|
||||
};
|
||||
|
||||
session.spclient().get_artist_metadata(artist_id).await
|
||||
}
|
||||
|
||||
fn parse(msg: &Self::Message, _: &SpotifyId) -> Result<Self, Error> {
|
||||
fn parse(msg: &Self::Message, _: &SpotifyUri) -> Result<Self, Error> {
|
||||
Self::try_from(msg)
|
||||
}
|
||||
}
|
||||
|
@ -249,7 +253,7 @@ impl AlbumGroups {
|
|||
/// Get the contained albums. This will only use the latest release / variant of an album if
|
||||
/// multiple variants are available. This should be used if multiple variants of the same album
|
||||
/// are not explicitely desired.
|
||||
pub fn current_releases(&self) -> impl Iterator<Item = &SpotifyId> {
|
||||
pub fn current_releases(&self) -> impl Iterator<Item = &SpotifyUri> {
|
||||
self.iter().filter_map(|agrp| agrp.first())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,9 +13,7 @@ use crate::{
|
|||
|
||||
use super::file::AudioFiles;
|
||||
|
||||
use librespot_core::{
|
||||
Error, Session, SpotifyId, date::Date, session::UserData, spotify_id::SpotifyItemType,
|
||||
};
|
||||
use librespot_core::{Error, Session, SpotifyUri, date::Date, session::UserData};
|
||||
|
||||
pub type AudioItemResult = Result<AudioItem, Error>;
|
||||
|
||||
|
@ -29,7 +27,7 @@ pub struct CoverImage {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AudioItem {
|
||||
pub track_id: SpotifyId,
|
||||
pub track_id: SpotifyUri,
|
||||
pub uri: String,
|
||||
pub files: AudioFiles,
|
||||
pub name: String,
|
||||
|
@ -60,14 +58,14 @@ pub enum UniqueFields {
|
|||
}
|
||||
|
||||
impl AudioItem {
|
||||
pub async fn get_file(session: &Session, id: SpotifyId) -> AudioItemResult {
|
||||
pub async fn get_file(session: &Session, uri: SpotifyUri) -> AudioItemResult {
|
||||
let image_url = session
|
||||
.get_user_attribute("image-url")
|
||||
.unwrap_or_else(|| String::from("https://i.scdn.co/image/{file_id}"));
|
||||
|
||||
match id.item_type {
|
||||
SpotifyItemType::Track => {
|
||||
let track = Track::get(session, &id).await?;
|
||||
match uri {
|
||||
SpotifyUri::Track { .. } => {
|
||||
let track = Track::get(session, &uri).await?;
|
||||
|
||||
if track.duration <= 0 {
|
||||
return Err(Error::unavailable(MetadataError::InvalidDuration(
|
||||
|
@ -79,8 +77,7 @@ impl AudioItem {
|
|||
return Err(Error::unavailable(MetadataError::ExplicitContentFiltered));
|
||||
}
|
||||
|
||||
let track_id = track.id;
|
||||
let uri = track_id.to_uri()?;
|
||||
let uri_string = uri.to_uri()?;
|
||||
let album = track.album.name;
|
||||
|
||||
let album_artists = track
|
||||
|
@ -123,8 +120,8 @@ impl AudioItem {
|
|||
};
|
||||
|
||||
Ok(Self {
|
||||
track_id,
|
||||
uri,
|
||||
track_id: uri,
|
||||
uri: uri_string,
|
||||
files: track.files,
|
||||
name: track.name,
|
||||
covers,
|
||||
|
@ -136,8 +133,8 @@ impl AudioItem {
|
|||
unique_fields,
|
||||
})
|
||||
}
|
||||
SpotifyItemType::Episode => {
|
||||
let episode = Episode::get(session, &id).await?;
|
||||
SpotifyUri::Episode { .. } => {
|
||||
let episode = Episode::get(session, &uri).await?;
|
||||
|
||||
if episode.duration <= 0 {
|
||||
return Err(Error::unavailable(MetadataError::InvalidDuration(
|
||||
|
@ -149,8 +146,7 @@ impl AudioItem {
|
|||
return Err(Error::unavailable(MetadataError::ExplicitContentFiltered));
|
||||
}
|
||||
|
||||
let track_id = episode.id;
|
||||
let uri = track_id.to_uri()?;
|
||||
let uri_string = uri.to_uri()?;
|
||||
|
||||
let covers = get_covers(episode.covers, image_url);
|
||||
|
||||
|
@ -167,8 +163,8 @@ impl AudioItem {
|
|||
};
|
||||
|
||||
Ok(Self {
|
||||
track_id,
|
||||
uri,
|
||||
track_id: uri,
|
||||
uri: uri_string,
|
||||
files: episode.audio,
|
||||
name: episode.name,
|
||||
covers,
|
||||
|
|
|
@ -15,14 +15,14 @@ use crate::{
|
|||
video::VideoFiles,
|
||||
};
|
||||
|
||||
use librespot_core::{Error, Session, SpotifyId, date::Date};
|
||||
use librespot_core::{Error, Session, SpotifyUri, date::Date};
|
||||
|
||||
use librespot_protocol as protocol;
|
||||
pub use protocol::metadata::episode::EpisodeType;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Episode {
|
||||
pub id: SpotifyId,
|
||||
pub id: SpotifyUri,
|
||||
pub name: String,
|
||||
pub duration: i32,
|
||||
pub audio: AudioFiles,
|
||||
|
@ -49,19 +49,23 @@ pub struct Episode {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Episodes(pub Vec<SpotifyId>);
|
||||
pub struct Episodes(pub Vec<SpotifyUri>);
|
||||
|
||||
impl_deref_wrapped!(Episodes, Vec<SpotifyId>);
|
||||
impl_deref_wrapped!(Episodes, Vec<SpotifyUri>);
|
||||
|
||||
#[async_trait]
|
||||
impl Metadata for Episode {
|
||||
type Message = protocol::metadata::Episode;
|
||||
|
||||
async fn request(session: &Session, episode_id: &SpotifyId) -> RequestResult {
|
||||
async fn request(session: &Session, episode_uri: &SpotifyUri) -> RequestResult {
|
||||
let SpotifyUri::Episode { id: episode_id } = episode_uri else {
|
||||
return Err(Error::invalid_argument("episode_uri"));
|
||||
};
|
||||
|
||||
session.spclient().get_episode_metadata(episode_id).await
|
||||
}
|
||||
|
||||
fn parse(msg: &Self::Message, _: &SpotifyId) -> Result<Self, Error> {
|
||||
fn parse(msg: &Self::Message, _: &SpotifyUri) -> Result<Self, Error> {
|
||||
Self::try_from(msg)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::{
|
|||
|
||||
use crate::util::{impl_deref_wrapped, impl_from_repeated, impl_try_from_repeated};
|
||||
|
||||
use librespot_core::{FileId, SpotifyId};
|
||||
use librespot_core::{FileId, SpotifyUri};
|
||||
|
||||
use librespot_protocol as protocol;
|
||||
use protocol::metadata::Image as ImageMessage;
|
||||
|
@ -47,7 +47,7 @@ impl_deref_wrapped!(PictureSizes, Vec<PictureSize>);
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct TranscodedPicture {
|
||||
pub target_name: String,
|
||||
pub uri: SpotifyId,
|
||||
pub uri: SpotifyUri,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
@ -6,7 +6,7 @@ extern crate async_trait;
|
|||
|
||||
use protobuf::Message;
|
||||
|
||||
use librespot_core::{Error, Session, SpotifyId};
|
||||
use librespot_core::{Error, Session, SpotifyUri};
|
||||
|
||||
pub mod album;
|
||||
pub mod artist;
|
||||
|
@ -44,15 +44,15 @@ pub trait Metadata: Send + Sized + 'static {
|
|||
type Message: protobuf::Message + std::fmt::Debug;
|
||||
|
||||
// Request a protobuf
|
||||
async fn request(session: &Session, id: &SpotifyId) -> RequestResult;
|
||||
async fn request(session: &Session, id: &SpotifyUri) -> RequestResult;
|
||||
|
||||
// Request a metadata struct
|
||||
async fn get(session: &Session, id: &SpotifyId) -> Result<Self, Error> {
|
||||
async fn get(session: &Session, id: &SpotifyUri) -> Result<Self, Error> {
|
||||
let response = Self::request(session, id).await?;
|
||||
let msg = Self::Message::parse_from_bytes(&response)?;
|
||||
trace!("Received metadata: {msg:#?}");
|
||||
Self::parse(&msg, id)
|
||||
}
|
||||
|
||||
fn parse(msg: &Self::Message, _: &SpotifyId) -> Result<Self, Error>;
|
||||
fn parse(msg: &Self::Message, _: &SpotifyUri) -> Result<Self, Error>;
|
||||
}
|
||||
|
|
|
@ -8,8 +8,7 @@ use crate::{
|
|||
request::{MercuryRequest, RequestResult},
|
||||
};
|
||||
|
||||
use librespot_core::{Error, Session, SpotifyId};
|
||||
|
||||
use librespot_core::{Error, Session, SpotifyId, SpotifyUri};
|
||||
use librespot_protocol as protocol;
|
||||
pub use protocol::playlist_annotate3::AbuseReportState;
|
||||
|
||||
|
@ -26,12 +25,20 @@ pub struct PlaylistAnnotation {
|
|||
impl Metadata for PlaylistAnnotation {
|
||||
type Message = protocol::playlist_annotate3::PlaylistAnnotation;
|
||||
|
||||
async fn request(session: &Session, playlist_id: &SpotifyId) -> RequestResult {
|
||||
async fn request(session: &Session, playlist_uri: &SpotifyUri) -> RequestResult {
|
||||
let current_user = session.username();
|
||||
|
||||
let SpotifyUri::Playlist {
|
||||
id: playlist_id, ..
|
||||
} = playlist_uri
|
||||
else {
|
||||
return Err(Error::invalid_argument("playlist_uri"));
|
||||
};
|
||||
|
||||
Self::request_for_user(session, ¤t_user, playlist_id).await
|
||||
}
|
||||
|
||||
fn parse(msg: &Self::Message, _: &SpotifyId) -> Result<Self, Error> {
|
||||
fn parse(msg: &Self::Message, _: &SpotifyUri) -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
description: msg.description().to_owned(),
|
||||
picture: msg.picture().to_owned(), // TODO: is this a URL or Spotify URI?
|
||||
|
@ -60,11 +67,18 @@ impl PlaylistAnnotation {
|
|||
async fn get_for_user(
|
||||
session: &Session,
|
||||
username: &str,
|
||||
playlist_id: &SpotifyId,
|
||||
playlist_uri: &SpotifyUri,
|
||||
) -> Result<Self, Error> {
|
||||
let SpotifyUri::Playlist {
|
||||
id: playlist_id, ..
|
||||
} = playlist_uri
|
||||
else {
|
||||
return Err(Error::invalid_argument("playlist_uri"));
|
||||
};
|
||||
|
||||
let response = Self::request_for_user(session, username, playlist_id).await?;
|
||||
let msg = <Self as Metadata>::Message::parse_from_bytes(&response)?;
|
||||
Self::parse(&msg, playlist_id)
|
||||
Self::parse(&msg, playlist_uri)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ use super::{
|
|||
permission::Capabilities,
|
||||
};
|
||||
|
||||
use librespot_core::{SpotifyId, date::Date};
|
||||
use librespot_core::{SpotifyUri, date::Date};
|
||||
|
||||
use librespot_protocol as protocol;
|
||||
use protocol::playlist4_external::Item as PlaylistItemMessage;
|
||||
|
@ -19,7 +19,7 @@ use protocol::playlist4_external::MetaItem as PlaylistMetaItemMessage;
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PlaylistItem {
|
||||
pub id: SpotifyId,
|
||||
pub id: SpotifyUri,
|
||||
pub attributes: PlaylistItemAttributes,
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ pub struct PlaylistItemList {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PlaylistMetaItem {
|
||||
pub revision: SpotifyId,
|
||||
pub revision: SpotifyUri,
|
||||
pub attributes: PlaylistAttributes,
|
||||
pub length: i32,
|
||||
pub timestamp: Date,
|
||||
|
|
|
@ -14,12 +14,7 @@ use super::{
|
|||
permission::Capabilities,
|
||||
};
|
||||
|
||||
use librespot_core::{
|
||||
Error, Session,
|
||||
date::Date,
|
||||
spotify_id::{NamedSpotifyId, SpotifyId},
|
||||
};
|
||||
|
||||
use librespot_core::{Error, Session, SpotifyUri, date::Date, spotify_id::SpotifyId};
|
||||
use librespot_protocol as protocol;
|
||||
use protocol::playlist4_external::GeoblockBlockingType as Geoblock;
|
||||
|
||||
|
@ -30,7 +25,7 @@ impl_deref_wrapped!(Geoblocks, Vec<Geoblock>);
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Playlist {
|
||||
pub id: NamedSpotifyId,
|
||||
pub id: SpotifyUri,
|
||||
pub revision: Vec<u8>,
|
||||
pub length: i32,
|
||||
pub attributes: PlaylistAttributes,
|
||||
|
@ -72,7 +67,7 @@ pub struct SelectedListContent {
|
|||
}
|
||||
|
||||
impl Playlist {
|
||||
pub fn tracks(&self) -> impl ExactSizeIterator<Item = &SpotifyId> {
|
||||
pub fn tracks(&self) -> impl ExactSizeIterator<Item = &SpotifyUri> {
|
||||
let tracks = self.contents.items.iter().map(|item| &item.id);
|
||||
|
||||
let length = tracks.len();
|
||||
|
@ -93,17 +88,35 @@ impl Playlist {
|
|||
impl Metadata for Playlist {
|
||||
type Message = protocol::playlist4_external::SelectedListContent;
|
||||
|
||||
async fn request(session: &Session, playlist_id: &SpotifyId) -> RequestResult {
|
||||
async fn request(session: &Session, playlist_uri: &SpotifyUri) -> RequestResult {
|
||||
let SpotifyUri::Playlist {
|
||||
id: playlist_id, ..
|
||||
} = playlist_uri
|
||||
else {
|
||||
return Err(Error::invalid_argument("playlist_uri"));
|
||||
};
|
||||
|
||||
session.spclient().get_playlist(playlist_id).await
|
||||
}
|
||||
|
||||
fn parse(msg: &Self::Message, id: &SpotifyId) -> Result<Self, Error> {
|
||||
fn parse(msg: &Self::Message, uri: &SpotifyUri) -> Result<Self, Error> {
|
||||
let SpotifyUri::Playlist {
|
||||
id: playlist_id, ..
|
||||
} = uri
|
||||
else {
|
||||
return Err(Error::invalid_argument("playlist_uri"));
|
||||
};
|
||||
|
||||
// the playlist proto doesn't contain the id so we decorate it
|
||||
let playlist = SelectedListContent::try_from(msg)?;
|
||||
let id = NamedSpotifyId::from_spotify_id(*id, &playlist.owner_username);
|
||||
|
||||
let new_uri = SpotifyUri::Playlist {
|
||||
id: *playlist_id,
|
||||
user: Some(playlist.owner_username),
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
id,
|
||||
id: new_uri,
|
||||
revision: playlist.revision,
|
||||
length: playlist.length,
|
||||
attributes: playlist.attributes,
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
episode::Episodes, image::Images, restriction::Restrictions,
|
||||
};
|
||||
|
||||
use librespot_core::{Error, Session, SpotifyId};
|
||||
use librespot_core::{Error, Session, SpotifyUri};
|
||||
|
||||
use librespot_protocol as protocol;
|
||||
pub use protocol::metadata::show::ConsumptionOrder as ShowConsumptionOrder;
|
||||
|
@ -13,7 +13,7 @@ pub use protocol::metadata::show::MediaType as ShowMediaType;
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Show {
|
||||
pub id: SpotifyId,
|
||||
pub id: SpotifyUri,
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub publisher: String,
|
||||
|
@ -27,7 +27,7 @@ pub struct Show {
|
|||
pub media_type: ShowMediaType,
|
||||
pub consumption_order: ShowConsumptionOrder,
|
||||
pub availability: Availabilities,
|
||||
pub trailer_uri: Option<SpotifyId>,
|
||||
pub trailer_uri: Option<SpotifyUri>,
|
||||
pub has_music_and_talk: bool,
|
||||
pub is_audiobook: bool,
|
||||
}
|
||||
|
@ -36,11 +36,15 @@ pub struct Show {
|
|||
impl Metadata for Show {
|
||||
type Message = protocol::metadata::Show;
|
||||
|
||||
async fn request(session: &Session, show_id: &SpotifyId) -> RequestResult {
|
||||
async fn request(session: &Session, show_uri: &SpotifyUri) -> RequestResult {
|
||||
let SpotifyUri::Show { id: show_id } = show_uri else {
|
||||
return Err(Error::invalid_argument("show_uri"));
|
||||
};
|
||||
|
||||
session.spclient().get_show_metadata(show_id).await
|
||||
}
|
||||
|
||||
fn parse(msg: &Self::Message, _: &SpotifyId) -> Result<Self, Error> {
|
||||
fn parse(msg: &Self::Message, _: &SpotifyUri) -> Result<Self, Error> {
|
||||
Self::try_from(msg)
|
||||
}
|
||||
}
|
||||
|
@ -67,7 +71,7 @@ impl TryFrom<&<Self as Metadata>::Message> for Show {
|
|||
.trailer_uri
|
||||
.as_deref()
|
||||
.filter(|s| !s.is_empty())
|
||||
.map(SpotifyId::from_uri)
|
||||
.map(SpotifyUri::from_uri)
|
||||
.transpose()?,
|
||||
has_music_and_talk: show.music_and_talk(),
|
||||
is_audiobook: show.is_audiobook(),
|
||||
|
|
|
@ -17,12 +17,12 @@ use crate::{
|
|||
util::{impl_deref_wrapped, impl_try_from_repeated},
|
||||
};
|
||||
|
||||
use librespot_core::{Error, Session, SpotifyId, date::Date};
|
||||
use librespot_core::{Error, Session, SpotifyUri, date::Date};
|
||||
use librespot_protocol as protocol;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Track {
|
||||
pub id: SpotifyId,
|
||||
pub id: SpotifyUri,
|
||||
pub name: String,
|
||||
pub album: Album,
|
||||
pub artists: Artists,
|
||||
|
@ -50,19 +50,23 @@ pub struct Track {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Tracks(pub Vec<SpotifyId>);
|
||||
pub struct Tracks(pub Vec<SpotifyUri>);
|
||||
|
||||
impl_deref_wrapped!(Tracks, Vec<SpotifyId>);
|
||||
impl_deref_wrapped!(Tracks, Vec<SpotifyUri>);
|
||||
|
||||
#[async_trait]
|
||||
impl Metadata for Track {
|
||||
type Message = protocol::metadata::Track;
|
||||
|
||||
async fn request(session: &Session, track_id: &SpotifyId) -> RequestResult {
|
||||
async fn request(session: &Session, track_uri: &SpotifyUri) -> RequestResult {
|
||||
let SpotifyUri::Track { id: track_id } = track_uri else {
|
||||
return Err(Error::invalid_argument("track_uri"));
|
||||
};
|
||||
|
||||
session.spclient().get_track_metadata(track_id).await
|
||||
}
|
||||
|
||||
fn parse(msg: &Self::Message, _: &SpotifyId) -> Result<Self, Error> {
|
||||
fn parse(msg: &Self::Message, _: &SpotifyUri) -> Result<Self, Error> {
|
||||
Self::try_from(msg)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue