diff --git a/CHANGELOG.md b/CHANGELOG.md index aa4a1b9a..798fbb04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,7 @@ https://github.com/librespot-org/librespot now follows the setting in the Connect client that controls it. (breaking) - [metadata] Most metadata is now retrieved with the `spclient` (breaking) - [metadata] Playlists are moved to the `playlist4_external` protobuf (breaking) +- [metadata] Handle playlists that are sent with microsecond-based timestamps - [playback] The audio decoder has been switched from `lewton` to `Symphonia`. This improves the Vorbis sound quality, adds support for MP3 as well as for FLAC in the future. (breaking) diff --git a/metadata/src/playlist/list.rs b/metadata/src/playlist/list.rs index c813a14d..dcbd9ea1 100644 --- a/metadata/src/playlist/list.rs +++ b/metadata/src/playlist/list.rs @@ -129,6 +129,22 @@ impl Metadata for Playlist { impl TryFrom<&::Message> for SelectedListContent { type Error = librespot_core::Error; fn try_from(playlist: &::Message) -> Result { + let timestamp = playlist.get_timestamp(); + let timestamp = if timestamp > 9295169800000 { + // timestamp is way out of range for milliseconds. Some seem to be in microseconds? + // Observed on playlists where: + // format: "artist-mix-reader" + // format_attributes { + // key: "mediaListConfig" + // value: "spotify:medialistconfig:artist-seed-mix:default_v18" + // } + warn!("timestamp is very large; assuming it's in microseconds"); + timestamp / 1000 + } else { + timestamp + }; + let timestamp = Date::from_timestamp_ms(timestamp)?; + Ok(Self { revision: playlist.get_revision().to_owned(), length: playlist.get_length(), @@ -144,7 +160,7 @@ impl TryFrom<&::Message> for SelectedListContent { has_multiple_heads: playlist.get_multiple_heads(), is_up_to_date: playlist.get_up_to_date(), nonces: playlist.get_nonces().into(), - timestamp: Date::from_timestamp_ms(playlist.get_timestamp())?, + timestamp, owner_username: playlist.get_owner_username().to_owned(), has_abuse_reporting: playlist.get_abuse_reporting_enabled(), capabilities: playlist.get_capabilities().into(),