mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
Fix playlist metadata fields parsing (#1019)
Some fields were wrongly parsed as `SpotifyId`s, although they do not always encode exactly 16 bytes in practice. Also, some optional fields caused `[]` to be parsed as `SpotifyId`, which obviously failed as well.
This commit is contained in:
parent
05b9b13cf8
commit
88f7cdbb44
6 changed files with 29 additions and 32 deletions
|
@ -1,5 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
convert::{TryFrom, TryInto},
|
convert::TryFrom,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ impl TryFrom<CdnUrlMessage> for MaybeExpiringUrls {
|
||||||
|
|
||||||
Ok(MaybeExpiringUrl(
|
Ok(MaybeExpiringUrl(
|
||||||
cdn_url.to_owned(),
|
cdn_url.to_owned(),
|
||||||
Some(expiry.try_into()?),
|
Some(Date::from_timestamp_ms(expiry * 1000)?),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok(MaybeExpiringUrl(cdn_url.to_owned(), None))
|
Ok(MaybeExpiringUrl(cdn_url.to_owned(), None))
|
||||||
|
|
|
@ -28,12 +28,12 @@ impl Deref for Date {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Date {
|
impl Date {
|
||||||
pub fn as_timestamp(&self) -> i64 {
|
pub fn as_timestamp_ms(&self) -> i64 {
|
||||||
self.0.unix_timestamp()
|
(self.0.unix_timestamp_nanos() / 1_000_000) as i64
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_timestamp(timestamp: i64) -> Result<Self, Error> {
|
pub fn from_timestamp_ms(timestamp: i64) -> Result<Self, Error> {
|
||||||
let date_time = OffsetDateTime::from_unix_timestamp(timestamp)?;
|
let date_time = OffsetDateTime::from_unix_timestamp_nanos(timestamp as i128 * 1_000_000)?;
|
||||||
Ok(Self(date_time))
|
Ok(Self(date_time))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,10 +79,3 @@ impl From<OffsetDateTime> for Date {
|
||||||
Self(datetime)
|
Self(datetime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<i64> for Date {
|
|
||||||
type Error = crate::Error;
|
|
||||||
fn try_from(timestamp: i64) -> Result<Self, Self::Error> {
|
|
||||||
Self::from_timestamp(timestamp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use std::{
|
||||||
|
|
||||||
use crate::{image::PictureSizes, util::from_repeated_enum};
|
use crate::{image::PictureSizes, util::from_repeated_enum};
|
||||||
|
|
||||||
use librespot_core::{date::Date, SpotifyId};
|
use librespot_core::date::Date;
|
||||||
|
|
||||||
use librespot_protocol as protocol;
|
use librespot_protocol as protocol;
|
||||||
use protocol::playlist4_external::FormatListAttribute as PlaylistFormatAttributeMessage;
|
use protocol::playlist4_external::FormatListAttribute as PlaylistFormatAttributeMessage;
|
||||||
|
@ -24,7 +24,7 @@ use protocol::playlist4_external::UpdateListAttributes as PlaylistUpdateAttribut
|
||||||
pub struct PlaylistAttributes {
|
pub struct PlaylistAttributes {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub description: String,
|
pub description: String,
|
||||||
pub picture: SpotifyId,
|
pub picture: Vec<u8>,
|
||||||
pub is_collaborative: bool,
|
pub is_collaborative: bool,
|
||||||
pub pl3_version: String,
|
pub pl3_version: String,
|
||||||
pub is_deleted_by_owner: bool,
|
pub is_deleted_by_owner: bool,
|
||||||
|
@ -63,7 +63,7 @@ pub struct PlaylistItemAttributes {
|
||||||
pub seen_at: Date,
|
pub seen_at: Date,
|
||||||
pub is_public: bool,
|
pub is_public: bool,
|
||||||
pub format_attributes: PlaylistFormatAttribute,
|
pub format_attributes: PlaylistFormatAttribute,
|
||||||
pub item_id: SpotifyId,
|
pub item_id: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -113,7 +113,7 @@ impl TryFrom<&PlaylistAttributesMessage> for PlaylistAttributes {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
name: attributes.get_name().to_owned(),
|
name: attributes.get_name().to_owned(),
|
||||||
description: attributes.get_description().to_owned(),
|
description: attributes.get_description().to_owned(),
|
||||||
picture: attributes.get_picture().try_into()?,
|
picture: attributes.get_picture().to_owned(),
|
||||||
is_collaborative: attributes.get_collaborative(),
|
is_collaborative: attributes.get_collaborative(),
|
||||||
pl3_version: attributes.get_pl3_version().to_owned(),
|
pl3_version: attributes.get_pl3_version().to_owned(),
|
||||||
is_deleted_by_owner: attributes.get_deleted_by_owner(),
|
is_deleted_by_owner: attributes.get_deleted_by_owner(),
|
||||||
|
@ -146,11 +146,11 @@ impl TryFrom<&PlaylistItemAttributesMessage> for PlaylistItemAttributes {
|
||||||
fn try_from(attributes: &PlaylistItemAttributesMessage) -> Result<Self, Self::Error> {
|
fn try_from(attributes: &PlaylistItemAttributesMessage) -> Result<Self, Self::Error> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
added_by: attributes.get_added_by().to_owned(),
|
added_by: attributes.get_added_by().to_owned(),
|
||||||
timestamp: attributes.get_timestamp().try_into()?,
|
timestamp: Date::from_timestamp_ms(attributes.get_timestamp())?,
|
||||||
seen_at: attributes.get_seen_at().try_into()?,
|
seen_at: Date::from_timestamp_ms(attributes.get_seen_at())?,
|
||||||
is_public: attributes.get_public(),
|
is_public: attributes.get_public(),
|
||||||
format_attributes: attributes.get_format_attributes().into(),
|
format_attributes: attributes.get_format_attributes().into(),
|
||||||
item_id: attributes.get_item_id().try_into()?,
|
item_id: attributes.get_item_id().to_owned(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,7 @@ impl TryFrom<&PlaylistMetaItemMessage> for PlaylistMetaItem {
|
||||||
revision: item.try_into()?,
|
revision: item.try_into()?,
|
||||||
attributes: item.get_attributes().try_into()?,
|
attributes: item.get_attributes().try_into()?,
|
||||||
length: item.get_length(),
|
length: item.get_length(),
|
||||||
timestamp: item.get_timestamp().try_into()?,
|
timestamp: Date::from_timestamp_ms(item.get_timestamp())?,
|
||||||
owner_username: item.get_owner_username().to_owned(),
|
owner_username: item.get_owner_username().to_owned(),
|
||||||
has_abuse_reporting: item.get_abuse_reporting_enabled(),
|
has_abuse_reporting: item.get_abuse_reporting_enabled(),
|
||||||
capabilities: item.get_capabilities().into(),
|
capabilities: item.get_capabilities().into(),
|
||||||
|
|
|
@ -39,12 +39,12 @@ impl Deref for Geoblocks {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Playlist {
|
pub struct Playlist {
|
||||||
pub id: NamedSpotifyId,
|
pub id: NamedSpotifyId,
|
||||||
pub revision: SpotifyId,
|
pub revision: Vec<u8>,
|
||||||
pub length: i32,
|
pub length: i32,
|
||||||
pub attributes: PlaylistAttributes,
|
pub attributes: PlaylistAttributes,
|
||||||
pub contents: PlaylistItemList,
|
pub contents: PlaylistItemList,
|
||||||
pub diff: PlaylistDiff,
|
pub diff: Option<PlaylistDiff>,
|
||||||
pub sync_result: PlaylistDiff,
|
pub sync_result: Option<PlaylistDiff>,
|
||||||
pub resulting_revisions: Playlists,
|
pub resulting_revisions: Playlists,
|
||||||
pub has_multiple_heads: bool,
|
pub has_multiple_heads: bool,
|
||||||
pub is_up_to_date: bool,
|
pub is_up_to_date: bool,
|
||||||
|
@ -77,12 +77,12 @@ impl Deref for RootPlaylist {
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SelectedListContent {
|
pub struct SelectedListContent {
|
||||||
pub revision: SpotifyId,
|
pub revision: Vec<u8>,
|
||||||
pub length: i32,
|
pub length: i32,
|
||||||
pub attributes: PlaylistAttributes,
|
pub attributes: PlaylistAttributes,
|
||||||
pub contents: PlaylistItemList,
|
pub contents: PlaylistItemList,
|
||||||
pub diff: PlaylistDiff,
|
pub diff: Option<PlaylistDiff>,
|
||||||
pub sync_result: PlaylistDiff,
|
pub sync_result: Option<PlaylistDiff>,
|
||||||
pub resulting_revisions: Playlists,
|
pub resulting_revisions: Playlists,
|
||||||
pub has_multiple_heads: bool,
|
pub has_multiple_heads: bool,
|
||||||
pub is_up_to_date: bool,
|
pub is_up_to_date: bool,
|
||||||
|
@ -202,17 +202,21 @@ impl TryFrom<&<Playlist as Metadata>::Message> for SelectedListContent {
|
||||||
type Error = librespot_core::Error;
|
type Error = librespot_core::Error;
|
||||||
fn try_from(playlist: &<Playlist as Metadata>::Message) -> Result<Self, Self::Error> {
|
fn try_from(playlist: &<Playlist as Metadata>::Message) -> Result<Self, Self::Error> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
revision: playlist.get_revision().try_into()?,
|
revision: playlist.get_revision().to_owned(),
|
||||||
length: playlist.get_length(),
|
length: playlist.get_length(),
|
||||||
attributes: playlist.get_attributes().try_into()?,
|
attributes: playlist.get_attributes().try_into()?,
|
||||||
contents: playlist.get_contents().try_into()?,
|
contents: playlist.get_contents().try_into()?,
|
||||||
diff: playlist.get_diff().try_into()?,
|
diff: playlist.diff.as_ref().map(TryInto::try_into).transpose()?,
|
||||||
sync_result: playlist.get_sync_result().try_into()?,
|
sync_result: playlist
|
||||||
|
.sync_result
|
||||||
|
.as_ref()
|
||||||
|
.map(TryInto::try_into)
|
||||||
|
.transpose()?,
|
||||||
resulting_revisions: playlist.get_resulting_revisions().try_into()?,
|
resulting_revisions: playlist.get_resulting_revisions().try_into()?,
|
||||||
has_multiple_heads: playlist.get_multiple_heads(),
|
has_multiple_heads: playlist.get_multiple_heads(),
|
||||||
is_up_to_date: playlist.get_up_to_date(),
|
is_up_to_date: playlist.get_up_to_date(),
|
||||||
nonces: playlist.get_nonces().into(),
|
nonces: playlist.get_nonces().into(),
|
||||||
timestamp: playlist.get_timestamp().try_into()?,
|
timestamp: Date::from_timestamp_ms(playlist.get_timestamp())?,
|
||||||
owner_username: playlist.get_owner_username().to_owned(),
|
owner_username: playlist.get_owner_username().to_owned(),
|
||||||
has_abuse_reporting: playlist.get_abuse_reporting_enabled(),
|
has_abuse_reporting: playlist.get_abuse_reporting_enabled(),
|
||||||
capabilities: playlist.get_capabilities().into(),
|
capabilities: playlist.get_capabilities().into(),
|
||||||
|
|
|
@ -132,7 +132,7 @@ impl TryFrom<&<Self as Metadata>::Message> for Track {
|
||||||
sale_periods: track.get_sale_period().try_into()?,
|
sale_periods: track.get_sale_period().try_into()?,
|
||||||
previews: track.get_preview().into(),
|
previews: track.get_preview().into(),
|
||||||
tags: track.get_tags().to_vec(),
|
tags: track.get_tags().to_vec(),
|
||||||
earliest_live_timestamp: track.get_earliest_live_timestamp().try_into()?,
|
earliest_live_timestamp: Date::from_timestamp_ms(track.get_earliest_live_timestamp())?,
|
||||||
has_lyrics: track.get_has_lyrics(),
|
has_lyrics: track.get_has_lyrics(),
|
||||||
availability: track.get_availability().try_into()?,
|
availability: track.get_availability().try_into()?,
|
||||||
licensor: Uuid::from_slice(track.get_licensor().get_uuid())
|
licensor: Uuid::from_slice(track.get_licensor().get_uuid())
|
||||||
|
|
Loading…
Reference in a new issue