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:
eladyn 2022-07-28 18:46:16 +02:00 committed by GitHub
parent 05b9b13cf8
commit 88f7cdbb44
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 29 additions and 32 deletions

View file

@ -1,5 +1,5 @@
use std::{
convert::{TryFrom, TryInto},
convert::TryFrom,
ops::{Deref, DerefMut},
};
@ -152,7 +152,7 @@ impl TryFrom<CdnUrlMessage> for MaybeExpiringUrls {
Ok(MaybeExpiringUrl(
cdn_url.to_owned(),
Some(expiry.try_into()?),
Some(Date::from_timestamp_ms(expiry * 1000)?),
))
} else {
Ok(MaybeExpiringUrl(cdn_url.to_owned(), None))

View file

@ -28,12 +28,12 @@ impl Deref for Date {
}
impl Date {
pub fn as_timestamp(&self) -> i64 {
self.0.unix_timestamp()
pub fn as_timestamp_ms(&self) -> i64 {
(self.0.unix_timestamp_nanos() / 1_000_000) as i64
}
pub fn from_timestamp(timestamp: i64) -> Result<Self, Error> {
let date_time = OffsetDateTime::from_unix_timestamp(timestamp)?;
pub fn from_timestamp_ms(timestamp: i64) -> Result<Self, Error> {
let date_time = OffsetDateTime::from_unix_timestamp_nanos(timestamp as i128 * 1_000_000)?;
Ok(Self(date_time))
}
@ -79,10 +79,3 @@ impl From<OffsetDateTime> for Date {
Self(datetime)
}
}
impl TryFrom<i64> for Date {
type Error = crate::Error;
fn try_from(timestamp: i64) -> Result<Self, Self::Error> {
Self::from_timestamp(timestamp)
}
}

View file

@ -7,7 +7,7 @@ use std::{
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 protocol::playlist4_external::FormatListAttribute as PlaylistFormatAttributeMessage;
@ -24,7 +24,7 @@ use protocol::playlist4_external::UpdateListAttributes as PlaylistUpdateAttribut
pub struct PlaylistAttributes {
pub name: String,
pub description: String,
pub picture: SpotifyId,
pub picture: Vec<u8>,
pub is_collaborative: bool,
pub pl3_version: String,
pub is_deleted_by_owner: bool,
@ -63,7 +63,7 @@ pub struct PlaylistItemAttributes {
pub seen_at: Date,
pub is_public: bool,
pub format_attributes: PlaylistFormatAttribute,
pub item_id: SpotifyId,
pub item_id: Vec<u8>,
}
#[derive(Debug, Clone)]
@ -113,7 +113,7 @@ impl TryFrom<&PlaylistAttributesMessage> for PlaylistAttributes {
Ok(Self {
name: attributes.get_name().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(),
pl3_version: attributes.get_pl3_version().to_owned(),
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> {
Ok(Self {
added_by: attributes.get_added_by().to_owned(),
timestamp: attributes.get_timestamp().try_into()?,
seen_at: attributes.get_seen_at().try_into()?,
timestamp: Date::from_timestamp_ms(attributes.get_timestamp())?,
seen_at: Date::from_timestamp_ms(attributes.get_seen_at())?,
is_public: attributes.get_public(),
format_attributes: attributes.get_format_attributes().into(),
item_id: attributes.get_item_id().try_into()?,
item_id: attributes.get_item_id().to_owned(),
})
}
}

View file

@ -94,7 +94,7 @@ impl TryFrom<&PlaylistMetaItemMessage> for PlaylistMetaItem {
revision: item.try_into()?,
attributes: item.get_attributes().try_into()?,
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(),
has_abuse_reporting: item.get_abuse_reporting_enabled(),
capabilities: item.get_capabilities().into(),

View file

@ -39,12 +39,12 @@ impl Deref for Geoblocks {
#[derive(Debug, Clone)]
pub struct Playlist {
pub id: NamedSpotifyId,
pub revision: SpotifyId,
pub revision: Vec<u8>,
pub length: i32,
pub attributes: PlaylistAttributes,
pub contents: PlaylistItemList,
pub diff: PlaylistDiff,
pub sync_result: PlaylistDiff,
pub diff: Option<PlaylistDiff>,
pub sync_result: Option<PlaylistDiff>,
pub resulting_revisions: Playlists,
pub has_multiple_heads: bool,
pub is_up_to_date: bool,
@ -77,12 +77,12 @@ impl Deref for RootPlaylist {
#[derive(Debug, Clone)]
pub struct SelectedListContent {
pub revision: SpotifyId,
pub revision: Vec<u8>,
pub length: i32,
pub attributes: PlaylistAttributes,
pub contents: PlaylistItemList,
pub diff: PlaylistDiff,
pub sync_result: PlaylistDiff,
pub diff: Option<PlaylistDiff>,
pub sync_result: Option<PlaylistDiff>,
pub resulting_revisions: Playlists,
pub has_multiple_heads: bool,
pub is_up_to_date: bool,
@ -202,17 +202,21 @@ impl TryFrom<&<Playlist as Metadata>::Message> for SelectedListContent {
type Error = librespot_core::Error;
fn try_from(playlist: &<Playlist as Metadata>::Message) -> Result<Self, Self::Error> {
Ok(Self {
revision: playlist.get_revision().try_into()?,
revision: playlist.get_revision().to_owned(),
length: playlist.get_length(),
attributes: playlist.get_attributes().try_into()?,
contents: playlist.get_contents().try_into()?,
diff: playlist.get_diff().try_into()?,
sync_result: playlist.get_sync_result().try_into()?,
diff: playlist.diff.as_ref().map(TryInto::try_into).transpose()?,
sync_result: playlist
.sync_result
.as_ref()
.map(TryInto::try_into)
.transpose()?,
resulting_revisions: playlist.get_resulting_revisions().try_into()?,
has_multiple_heads: playlist.get_multiple_heads(),
is_up_to_date: playlist.get_up_to_date(),
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(),
has_abuse_reporting: playlist.get_abuse_reporting_enabled(),
capabilities: playlist.get_capabilities().into(),

View file

@ -132,7 +132,7 @@ impl TryFrom<&<Self as Metadata>::Message> for Track {
sale_periods: track.get_sale_period().try_into()?,
previews: track.get_preview().into(),
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(),
availability: track.get_availability().try_into()?,
licensor: Uuid::from_slice(track.get_licensor().get_uuid())