From 06680f106cdd684c4671a1fbbd8d1420ace1d01d Mon Sep 17 00:00:00 2001 From: ashthespy Date: Tue, 16 Jul 2019 19:36:20 +0200 Subject: [PATCH 01/43] Add `pkg-config` to docker build container --- contrib/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/Dockerfile b/contrib/Dockerfile index 0fcdafff..9cf2d134 100644 --- a/contrib/Dockerfile +++ b/contrib/Dockerfile @@ -21,7 +21,7 @@ RUN dpkg --add-architecture armel RUN dpkg --add-architecture mipsel RUN apt-get update -RUN apt-get install -y curl git build-essential crossbuild-essential-arm64 crossbuild-essential-armel crossbuild-essential-armhf crossbuild-essential-mipsel +RUN apt-get install -y curl git build-essential crossbuild-essential-arm64 crossbuild-essential-armel crossbuild-essential-armhf crossbuild-essential-mipsel pkg-config RUN apt-get install -y libasound2-dev libasound2-dev:arm64 libasound2-dev:armel libasound2-dev:armhf libasound2-dev:mipsel RUN curl https://sh.rustup.rs -sSf | sh -s -- -y @@ -43,6 +43,7 @@ RUN mkdir /build && \ ENV CARGO_TARGET_DIR /build ENV CARGO_HOME /build/cache +ENV PKG_CONFIG_ALLOW_CROSS=1 ADD . /src WORKDIR /src From 0cb7a3f7c85b3d7baf5d0d80dea14d0172062caf Mon Sep 17 00:00:00 2001 From: ashthespy Date: Fri, 28 Sep 2018 20:10:22 +0200 Subject: [PATCH 02/43] WIP: Podcast support --- connect/src/spirc.rs | 11 +- core/src/spotify_id.rs | 44 +- metadata/src/lib.rs | 107 ++ playback/src/player.rs | 99 +- protocol/files.rs | 9 + protocol/proto/metadata.proto | 79 +- protocol/src/metadata.rs | 2780 ++++++++++++++++++++++++++++++++- 7 files changed, 3073 insertions(+), 56 deletions(-) create mode 100644 protocol/files.rs diff --git a/connect/src/spirc.rs b/connect/src/spirc.rs index 37576a9e..92e26ce0 100644 --- a/connect/src/spirc.rs +++ b/connect/src/spirc.rs @@ -168,6 +168,7 @@ fn initial_device_state(config: ConnectConfig) -> DeviceState { let repeated = msg.mut_stringValue(); repeated.push(::std::convert::Into::into("audio/local")); repeated.push(::std::convert::Into::into("audio/track")); + repeated.push(::std::convert::Into::into("audio/episode")); repeated.push(::std::convert::Into::into("local")); repeated.push(::std::convert::Into::into("track")) }; @@ -796,6 +797,7 @@ impl SpircTask { } fn update_tracks(&mut self, frame: &protocol::spirc::Frame) { + // debug!("State: {:?}", frame.get_state()); let index = frame.get_state().get_playing_track_index(); let context_uri = frame.get_state().get_context_uri().to_owned(); let tracks = frame.get_state().get_track(); @@ -812,7 +814,14 @@ impl SpircTask { } fn load_track(&mut self, play: bool) { - let track = { + let context_uri = self.state.get_context_uri().to_owned(); + let index = self.state.get_playing_track_index(); + info!("context: {}", context_uri); + // Redundant check here + let track = if context_uri.contains(":show:") || context_uri.contains(":episode:") { + let uri = self.state.get_track()[index as usize].get_uri(); + SpotifyId::from_uri(uri).expect("Unable to parse uri") + } else { let mut index = self.state.get_playing_track_index(); // Check for malformed gid let tracks_len = self.state.get_track().len() as u32; diff --git a/core/src/spotify_id.rs b/core/src/spotify_id.rs index 79414a18..01c4ddd4 100644 --- a/core/src/spotify_id.rs +++ b/core/src/spotify_id.rs @@ -1,8 +1,17 @@ use std; use std::fmt; -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct SpotifyId(u128); +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum SpotifyTrackType { + Track, + Podcast, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct SpotifyId { + pub id: u128, + pub track_type: SpotifyTrackType, +} #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct SpotifyIdError; @@ -11,6 +20,13 @@ const BASE62_DIGITS: &'static [u8] = b"0123456789abcdefghijklmnopqrstuvwxyzABCDE const BASE16_DIGITS: &'static [u8] = b"0123456789abcdef"; impl SpotifyId { + fn as_track(n: u128) -> SpotifyId { + SpotifyId { + id: n.to_owned(), + track_type: SpotifyTrackType::Track, + } + } + pub fn from_base16(id: &str) -> Result { let data = id.as_bytes(); @@ -24,7 +40,7 @@ impl SpotifyId { n = n + d; } - Ok(SpotifyId(n)) + Ok(SpotifyId::as_track(n)) } pub fn from_base62(id: &str) -> Result { @@ -39,8 +55,7 @@ impl SpotifyId { n = n * 62; n = n + d; } - - Ok(SpotifyId(n)) + Ok(SpotifyId::as_track(n)) } pub fn from_raw(data: &[u8]) -> Result { @@ -51,15 +66,26 @@ impl SpotifyId { let mut arr: [u8; 16] = Default::default(); arr.copy_from_slice(&data[0..16]); - Ok(SpotifyId(u128::from_be_bytes(arr))) + Ok(SpotifyId::as_track(u128::from_be_bytes(arr))) + } + + pub fn from_uri(uri: &str) -> Result { + let parts = uri.split(":").collect::>(); + if uri.contains(":show:") || uri.contains(":episode:") { + let mut spotify_id = SpotifyId::from_base62(parts[2]).unwrap(); + spotify_id.track_type = SpotifyTrackType::Podcast; + Ok(spotify_id) + } else { + SpotifyId::from_base62(parts[2]) + } } pub fn to_base16(&self) -> String { - format!("{:032x}", self.0) + format!("{:032x}", self.id) } pub fn to_base62(&self) -> String { - let &SpotifyId(mut n) = self; + let &SpotifyId { id: mut n, .. } = self; let mut data = [0u8; 22]; for i in 0..22 { @@ -71,7 +97,7 @@ impl SpotifyId { } pub fn to_raw(&self) -> [u8; 16] { - self.0.to_be_bytes() + self.id.to_be_bytes() } } diff --git a/metadata/src/lib.rs b/metadata/src/lib.rs index 60ca2738..6aa6a5bd 100644 --- a/metadata/src/lib.rs +++ b/metadata/src/lib.rs @@ -93,6 +93,28 @@ pub struct Album { pub covers: Vec, } +#[derive(Debug, Clone)] +pub struct Episode { + pub id: SpotifyId, + pub name: String, + pub external_url: String, + pub duration: i32, + pub language: String, + pub show: SpotifyId, + pub files: LinearMap, + pub covers: Vec, + pub available: bool, + pub explicit: bool, +} + +#[derive(Debug, Clone)] +pub struct Show { + pub id: SpotifyId, + pub name: String, + pub episodes: Vec, + pub covers: Vec, +} + #[derive(Debug, Clone)] pub struct Artist { pub id: SpotifyId, @@ -222,6 +244,91 @@ impl Metadata for Artist { } } +// Podcast +impl Metadata for Episode { + type Message = protocol::metadata::Episode; + + fn base_url() -> &'static str { + "hm://metadata/3/episode" + } + + fn parse(msg: &Self::Message, session: &Session) -> Self { + let country = session.country(); + + let files = msg + .get_file() + .iter() + .filter(|file| file.has_file_id()) + .map(|file| { + let mut dst = [0u8; 20]; + dst.clone_from_slice(file.get_file_id()); + (file.get_format(), FileId(dst)) + }) + .collect(); + + let covers = msg + .get_covers() + .get_image() + .iter() + .filter(|image| image.has_file_id()) + .map(|image| { + let mut dst = [0u8; 20]; + dst.clone_from_slice(image.get_file_id()); + FileId(dst) + }) + .collect::>(); + + Episode { + id: SpotifyId::from_raw(msg.get_gid()).unwrap(), + name: msg.get_name().to_owned(), + external_url: msg.get_external_url().to_owned(), + duration: msg.get_duration().to_owned(), + language: msg.get_language().to_owned(), + show: SpotifyId::from_raw(msg.get_show().get_gid()).unwrap(), + covers: covers, + files: files, + available: parse_restrictions(msg.get_restriction(), &country, "premium"), + explicit: msg.get_explicit().to_owned(), + } + } +} + +impl Metadata for Show { + type Message = protocol::metadata::Show; + + fn base_url() -> &'static str { + "hm://metadata/3/show" + } + + fn parse(msg: &Self::Message, _: &Session) -> Self { + let episodes = msg + .get_episode() + .iter() + .filter(|episode| episode.has_gid()) + .map(|episode| SpotifyId::from_raw(episode.get_gid()).unwrap()) + .collect::>(); + + let covers = msg + .get_covers() + .get_image() + .iter() + .filter(|image| image.has_file_id()) + .map(|image| { + let mut dst = [0u8; 20]; + dst.clone_from_slice(image.get_file_id()); + FileId(dst) + }) + .collect::>(); + + Show { + id: SpotifyId::from_raw(msg.get_gid()).unwrap(), + name: msg.get_name().to_owned(), + episodes: episodes, + covers: covers, + } + } +} + struct StrChunks<'s>(&'s str, usize); trait StrChunksExt { diff --git a/playback/src/player.rs b/playback/src/player.rs index 4be73acd..3b48a594 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -12,12 +12,12 @@ use std::time::Duration; use config::{Bitrate, PlayerConfig}; use librespot_core::session::Session; -use librespot_core::spotify_id::SpotifyId; +use librespot_core::spotify_id::{FileId, SpotifyId, SpotifyTrackType}; use audio::{AudioDecrypt, AudioFile}; use audio::{VorbisDecoder, VorbisPacket}; use audio_backend::Sink; -use metadata::{FileFormat, Metadata, Track}; +use metadata::{Episode, FileFormat, Metadata, Track}; use mixer::AudioFilter; pub struct Player { @@ -526,44 +526,77 @@ impl PlayerInternal { } } - fn load_track(&self, track_id: SpotifyId, position: i64) -> Option<(Decoder, f32)> { - let track = Track::get(&self.session, track_id).wait().unwrap(); + fn get_file_id(&self, spotify_id: SpotifyId) -> Option { + let file_id = match spotify_id.track_type { + SpotifyTrackType::Track => { + let track = Track::get(&self.session, spotify_id).wait().unwrap(); - info!( - "Loading track \"{}\" with Spotify URI \"spotify:track:{}\"", - track.name, - track_id.to_base62() - ); + info!( + "Loading track \"{}\" with Spotify URI \"spotify:track:{}\"", + track.name, + spotify_id.to_base62() + ); - let track = match self.find_available_alternative(&track) { - Some(track) => track, - None => { - warn!("Track \"{}\" is not available", track.name); - return None; + let track = match self.find_available_alternative(&track) { + Some(track) => track, + None => { + warn!("Track \"{}\" is not available", track.name); + return None; + } + }; + + let format = match self.config.bitrate { + Bitrate::Bitrate96 => FileFormat::OGG_VORBIS_96, + Bitrate::Bitrate160 => FileFormat::OGG_VORBIS_160, + Bitrate::Bitrate320 => FileFormat::OGG_VORBIS_320, + }; + match track.files.get(&format) { + Some(&file_id) => file_id, + None => { + warn!("Track \"{}\" is not available in format {:?}", track.name, format); + return None; + } + } + } + // This should be refactored! + SpotifyTrackType::Podcast => { + let episode = Episode::get(&self.session, spotify_id).wait().unwrap(); + info!("Episode {:?}", episode); + + info!( + "Loading episode \"{}\" with Spotify URI \"spotify:episode:{}\"", + episode.name, + spotify_id.to_base62() + ); + + // Podcasts seem to have only 96 OGG_VORBIS support, other filetypes indicate + // AAC_24, MP4_128, MP4_128_DUAL, MP3_96 among others + let format = match self.config.bitrate { + _ => FileFormat::OGG_VORBIS_96, + }; + + match episode.files.get(&format) { + Some(&file_id) => file_id, + None => { + warn!( + "Episode \"{}\" is not available in format {:?}", + episode.name, format + ); + return None; + } + } } }; + return Some(file_id); + } - let format = match self.config.bitrate { - Bitrate::Bitrate96 => FileFormat::OGG_VORBIS_96, - Bitrate::Bitrate160 => FileFormat::OGG_VORBIS_160, - Bitrate::Bitrate320 => FileFormat::OGG_VORBIS_320, - }; + fn load_track(&self, spotify_id: SpotifyId, position: i64) -> Option<(Decoder, f32)> { + let file_id = self.get_file_id(spotify_id).unwrap(); + info!("{:?} -> {:?}", spotify_id, file_id); - let file_id = match track.files.get(&format) { - Some(&file_id) => file_id, - None => { - warn!("Track \"{}\" is not available in format {:?}", track.name, format); - return None; - } - }; - - let key = self - .session - .audio_key() - .request(track.id, file_id); + let key = self.session.audio_key().request(spotify_id, file_id); let encrypted_file = AudioFile::open(&self.session, file_id); - let encrypted_file = encrypted_file.wait().unwrap(); let key = key.wait().unwrap(); let mut decrypted_file = AudioDecrypt::new(key, encrypted_file); @@ -587,7 +620,7 @@ impl PlayerInternal { } } - info!("Track \"{}\" loaded", track.name); + // info!("Track \"{}\" loaded", track.name); Some((decoder, normalisation_factor)) } diff --git a/protocol/files.rs b/protocol/files.rs new file mode 100644 index 00000000..f4ddd9ad --- /dev/null +++ b/protocol/files.rs @@ -0,0 +1,9 @@ +// Autogenerated by build.rs +pub const FILES: &'static [(&'static str, u32)] = &[ + ("proto/authentication.proto", 2098196376), + ("proto/keyexchange.proto", 451735664), + ("proto/mercury.proto", 709993906), + ("proto/metadata.proto", 1409162985), + ("proto/pubsub.proto", 2686584829), + ("proto/spirc.proto", 1587493382), +]; diff --git a/protocol/proto/metadata.proto b/protocol/proto/metadata.proto index 1a7a900b..c3730ca7 100644 --- a/protocol/proto/metadata.proto +++ b/protocol/proto/metadata.proto @@ -156,12 +156,87 @@ message AudioFile { MP3_160 = 0x5; MP3_96 = 0x6; MP3_160_ENC = 0x7; - OTHER2 = 0x8; + MP4_128_DUAL = 0x8; OTHER3 = 0x9; AAC_160 = 0xa; AAC_320 = 0xb; - OTHER4 = 0xc; + MP4_128 = 0xc; OTHER5 = 0xd; } } +// Podcast Protos +message PublishTime { + optional sint32 year = 0x1; + optional sint32 month = 0x2; + optional sint32 day = 0x3; + // These seem to be differently encoded + optional sint32 minute = 0x5; + optional sint32 hour = 0x4; +} + +message Show { + optional bytes gid = 0x1; + optional string name = 0x2; + repeated Episode episode = 0x46; + // Educated guesses + optional string description = 0x40; + optional string publisher = 0x42; + optional string language = 0x43; + optional bool explicit = 0x44; + optional ImageGroup covers = 0x45; + repeated Restriction restriction = 0x48; + optional MediaType media_type = 0x4A; + optional ConsumptionOrder consumption_order = 0x4B; + optional bool interpret_restriction_using_geoip = 0x4C; + optional string country_of_origin = 0x4F; + repeated Category categories = 0x50; + optional PassthroughEnum passthrough = 0x51; +} + +enum ConsumptionOrder { + SEQUENTIAL = 1; + EPISODIC = 2; + RECENT = 3; + } +enum MediaType { + MIXED = 0; + AUDIO = 1; + VIDEO = 2; +} +enum PassthroughEnum { + UNKNOWN = 0; + NONE = 1; +} + +message Episode { + optional bytes gid = 0x1; + optional string name = 0x2; + optional sint32 duration = 0x7; + optional sint32 popularity = 0x8; + repeated AudioFile file = 0xc; + // Educated guesses + optional string description = 0x40; + optional Date publish_time = 0x42; + optional ImageGroup covers = 0x44; + optional string language = 0x45; + optional bool explicit = 0x46; + optional Show show = 0x47; + repeated AudioFile preview = 0x4A; + repeated Restriction restriction = 0x4B; + // Order of these flags might be wrong! + optional bool suppress_monetization = 0x4E; + optional bool allow_background_playback = 0x4F; + optional bool interpret_restriction_using_geoip = 0x51; + optional string external_url = 0x53; + optional OriginalAudio original_audio = 0x54; +} + +message Category { + optional string name = 0x1; + repeated Category subcategories = 0x2; +} + +message OriginalAudio { + optional bytes uuid = 0x1; +} diff --git a/protocol/src/metadata.rs b/protocol/src/metadata.rs index 7cfa964d..1a1a7f00 100644 --- a/protocol/src/metadata.rs +++ b/protocol/src/metadata.rs @@ -6143,11 +6143,11 @@ pub enum AudioFile_Format { MP3_160 = 5, MP3_96 = 6, MP3_160_ENC = 7, - OTHER2 = 8, + MP4_128_DUAL = 8, OTHER3 = 9, AAC_160 = 10, AAC_320 = 11, - OTHER4 = 12, + MP4_128 = 12, OTHER5 = 13, } @@ -6166,11 +6166,11 @@ impl ::protobuf::ProtobufEnum for AudioFile_Format { 5 => ::std::option::Option::Some(AudioFile_Format::MP3_160), 6 => ::std::option::Option::Some(AudioFile_Format::MP3_96), 7 => ::std::option::Option::Some(AudioFile_Format::MP3_160_ENC), - 8 => ::std::option::Option::Some(AudioFile_Format::OTHER2), + 8 => ::std::option::Option::Some(AudioFile_Format::MP4_128_DUAL), 9 => ::std::option::Option::Some(AudioFile_Format::OTHER3), 10 => ::std::option::Option::Some(AudioFile_Format::AAC_160), 11 => ::std::option::Option::Some(AudioFile_Format::AAC_320), - 12 => ::std::option::Option::Some(AudioFile_Format::OTHER4), + 12 => ::std::option::Option::Some(AudioFile_Format::MP4_128), 13 => ::std::option::Option::Some(AudioFile_Format::OTHER5), _ => ::std::option::Option::None } @@ -6186,11 +6186,11 @@ impl ::protobuf::ProtobufEnum for AudioFile_Format { AudioFile_Format::MP3_160, AudioFile_Format::MP3_96, AudioFile_Format::MP3_160_ENC, - AudioFile_Format::OTHER2, + AudioFile_Format::MP4_128_DUAL, AudioFile_Format::OTHER3, AudioFile_Format::AAC_160, AudioFile_Format::AAC_320, - AudioFile_Format::OTHER4, + AudioFile_Format::MP4_128, AudioFile_Format::OTHER5, ]; values @@ -6224,6 +6224,2729 @@ impl ::protobuf::reflect::ProtobufValue for AudioFile_Format { } } +#[derive(PartialEq,Clone,Default)] +pub struct PublishTime { + // message fields + year: ::std::option::Option, + month: ::std::option::Option, + day: ::std::option::Option, + minute: ::std::option::Option, + hour: ::std::option::Option, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a PublishTime { + fn default() -> &'a PublishTime { + ::default_instance() + } +} + +impl PublishTime { + pub fn new() -> PublishTime { + ::std::default::Default::default() + } + + // optional sint32 year = 1; + + + pub fn get_year(&self) -> i32 { + self.year.unwrap_or(0) + } + pub fn clear_year(&mut self) { + self.year = ::std::option::Option::None; + } + + pub fn has_year(&self) -> bool { + self.year.is_some() + } + + // Param is passed by value, moved + pub fn set_year(&mut self, v: i32) { + self.year = ::std::option::Option::Some(v); + } + + // optional sint32 month = 2; + + + pub fn get_month(&self) -> i32 { + self.month.unwrap_or(0) + } + pub fn clear_month(&mut self) { + self.month = ::std::option::Option::None; + } + + pub fn has_month(&self) -> bool { + self.month.is_some() + } + + // Param is passed by value, moved + pub fn set_month(&mut self, v: i32) { + self.month = ::std::option::Option::Some(v); + } + + // optional sint32 day = 3; + + + pub fn get_day(&self) -> i32 { + self.day.unwrap_or(0) + } + pub fn clear_day(&mut self) { + self.day = ::std::option::Option::None; + } + + pub fn has_day(&self) -> bool { + self.day.is_some() + } + + // Param is passed by value, moved + pub fn set_day(&mut self, v: i32) { + self.day = ::std::option::Option::Some(v); + } + + // optional sint32 minute = 5; + + + pub fn get_minute(&self) -> i32 { + self.minute.unwrap_or(0) + } + pub fn clear_minute(&mut self) { + self.minute = ::std::option::Option::None; + } + + pub fn has_minute(&self) -> bool { + self.minute.is_some() + } + + // Param is passed by value, moved + pub fn set_minute(&mut self, v: i32) { + self.minute = ::std::option::Option::Some(v); + } + + // optional sint32 hour = 4; + + + pub fn get_hour(&self) -> i32 { + self.hour.unwrap_or(0) + } + pub fn clear_hour(&mut self) { + self.hour = ::std::option::Option::None; + } + + pub fn has_hour(&self) -> bool { + self.hour.is_some() + } + + // Param is passed by value, moved + pub fn set_hour(&mut self, v: i32) { + self.hour = ::std::option::Option::Some(v); + } +} + +impl ::protobuf::Message for PublishTime { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_sint32()?; + self.year = ::std::option::Option::Some(tmp); + }, + 2 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_sint32()?; + self.month = ::std::option::Option::Some(tmp); + }, + 3 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_sint32()?; + self.day = ::std::option::Option::Some(tmp); + }, + 5 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_sint32()?; + self.minute = ::std::option::Option::Some(tmp); + }, + 4 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_sint32()?; + self.hour = ::std::option::Option::Some(tmp); + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if let Some(v) = self.year { + my_size += ::protobuf::rt::value_varint_zigzag_size(1, v); + } + if let Some(v) = self.month { + my_size += ::protobuf::rt::value_varint_zigzag_size(2, v); + } + if let Some(v) = self.day { + my_size += ::protobuf::rt::value_varint_zigzag_size(3, v); + } + if let Some(v) = self.minute { + my_size += ::protobuf::rt::value_varint_zigzag_size(5, v); + } + if let Some(v) = self.hour { + my_size += ::protobuf::rt::value_varint_zigzag_size(4, v); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + if let Some(v) = self.year { + os.write_sint32(1, v)?; + } + if let Some(v) = self.month { + os.write_sint32(2, v)?; + } + if let Some(v) = self.day { + os.write_sint32(3, v)?; + } + if let Some(v) = self.minute { + os.write_sint32(5, v)?; + } + if let Some(v) = self.hour { + os.write_sint32(4, v)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> PublishTime { + PublishTime::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeSint32>( + "year", + |m: &PublishTime| { &m.year }, + |m: &mut PublishTime| { &mut m.year }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeSint32>( + "month", + |m: &PublishTime| { &m.month }, + |m: &mut PublishTime| { &mut m.month }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeSint32>( + "day", + |m: &PublishTime| { &m.day }, + |m: &mut PublishTime| { &mut m.day }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeSint32>( + "minute", + |m: &PublishTime| { &m.minute }, + |m: &mut PublishTime| { &mut m.minute }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeSint32>( + "hour", + |m: &PublishTime| { &m.hour }, + |m: &mut PublishTime| { &mut m.hour }, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "PublishTime", + fields, + file_descriptor_proto() + ) + }) + } + } + + fn default_instance() -> &'static PublishTime { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const PublishTime, + }; + unsafe { + instance.get(PublishTime::new) + } + } +} + +impl ::protobuf::Clear for PublishTime { + fn clear(&mut self) { + self.year = ::std::option::Option::None; + self.month = ::std::option::Option::None; + self.day = ::std::option::Option::None; + self.minute = ::std::option::Option::None; + self.hour = ::std::option::Option::None; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for PublishTime { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for PublishTime { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct Show { + // message fields + gid: ::protobuf::SingularField<::std::vec::Vec>, + name: ::protobuf::SingularField<::std::string::String>, + episode: ::protobuf::RepeatedField, + description: ::protobuf::SingularField<::std::string::String>, + publisher: ::protobuf::SingularField<::std::string::String>, + language: ::protobuf::SingularField<::std::string::String>, + explicit: ::std::option::Option, + covers: ::protobuf::SingularPtrField, + restriction: ::protobuf::RepeatedField, + media_type: ::std::option::Option, + consumption_order: ::std::option::Option, + interpret_restriction_using_geoip: ::std::option::Option, + country_of_origin: ::protobuf::SingularField<::std::string::String>, + categories: ::protobuf::RepeatedField, + passthrough: ::std::option::Option, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a Show { + fn default() -> &'a Show { + ::default_instance() + } +} + +impl Show { + pub fn new() -> Show { + ::std::default::Default::default() + } + + // optional bytes gid = 1; + + + pub fn get_gid(&self) -> &[u8] { + match self.gid.as_ref() { + Some(v) => &v, + None => &[], + } + } + pub fn clear_gid(&mut self) { + self.gid.clear(); + } + + pub fn has_gid(&self) -> bool { + self.gid.is_some() + } + + // Param is passed by value, moved + pub fn set_gid(&mut self, v: ::std::vec::Vec) { + self.gid = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_gid(&mut self) -> &mut ::std::vec::Vec { + if self.gid.is_none() { + self.gid.set_default(); + } + self.gid.as_mut().unwrap() + } + + // Take field + pub fn take_gid(&mut self) -> ::std::vec::Vec { + self.gid.take().unwrap_or_else(|| ::std::vec::Vec::new()) + } + + // optional string name = 2; + + + pub fn get_name(&self) -> &str { + match self.name.as_ref() { + Some(v) => &v, + None => "", + } + } + pub fn clear_name(&mut self) { + self.name.clear(); + } + + pub fn has_name(&self) -> bool { + self.name.is_some() + } + + // Param is passed by value, moved + pub fn set_name(&mut self, v: ::std::string::String) { + self.name = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_name(&mut self) -> &mut ::std::string::String { + if self.name.is_none() { + self.name.set_default(); + } + self.name.as_mut().unwrap() + } + + // Take field + pub fn take_name(&mut self) -> ::std::string::String { + self.name.take().unwrap_or_else(|| ::std::string::String::new()) + } + + // repeated .Episode episode = 70; + + + pub fn get_episode(&self) -> &[Episode] { + &self.episode + } + pub fn clear_episode(&mut self) { + self.episode.clear(); + } + + // Param is passed by value, moved + pub fn set_episode(&mut self, v: ::protobuf::RepeatedField) { + self.episode = v; + } + + // Mutable pointer to the field. + pub fn mut_episode(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.episode + } + + // Take field + pub fn take_episode(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.episode, ::protobuf::RepeatedField::new()) + } + + // optional string description = 64; + + + pub fn get_description(&self) -> &str { + match self.description.as_ref() { + Some(v) => &v, + None => "", + } + } + pub fn clear_description(&mut self) { + self.description.clear(); + } + + pub fn has_description(&self) -> bool { + self.description.is_some() + } + + // Param is passed by value, moved + pub fn set_description(&mut self, v: ::std::string::String) { + self.description = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_description(&mut self) -> &mut ::std::string::String { + if self.description.is_none() { + self.description.set_default(); + } + self.description.as_mut().unwrap() + } + + // Take field + pub fn take_description(&mut self) -> ::std::string::String { + self.description.take().unwrap_or_else(|| ::std::string::String::new()) + } + + // optional string publisher = 66; + + + pub fn get_publisher(&self) -> &str { + match self.publisher.as_ref() { + Some(v) => &v, + None => "", + } + } + pub fn clear_publisher(&mut self) { + self.publisher.clear(); + } + + pub fn has_publisher(&self) -> bool { + self.publisher.is_some() + } + + // Param is passed by value, moved + pub fn set_publisher(&mut self, v: ::std::string::String) { + self.publisher = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_publisher(&mut self) -> &mut ::std::string::String { + if self.publisher.is_none() { + self.publisher.set_default(); + } + self.publisher.as_mut().unwrap() + } + + // Take field + pub fn take_publisher(&mut self) -> ::std::string::String { + self.publisher.take().unwrap_or_else(|| ::std::string::String::new()) + } + + // optional string language = 67; + + + pub fn get_language(&self) -> &str { + match self.language.as_ref() { + Some(v) => &v, + None => "", + } + } + pub fn clear_language(&mut self) { + self.language.clear(); + } + + pub fn has_language(&self) -> bool { + self.language.is_some() + } + + // Param is passed by value, moved + pub fn set_language(&mut self, v: ::std::string::String) { + self.language = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_language(&mut self) -> &mut ::std::string::String { + if self.language.is_none() { + self.language.set_default(); + } + self.language.as_mut().unwrap() + } + + // Take field + pub fn take_language(&mut self) -> ::std::string::String { + self.language.take().unwrap_or_else(|| ::std::string::String::new()) + } + + // optional bool explicit = 68; + + + pub fn get_explicit(&self) -> bool { + self.explicit.unwrap_or(false) + } + pub fn clear_explicit(&mut self) { + self.explicit = ::std::option::Option::None; + } + + pub fn has_explicit(&self) -> bool { + self.explicit.is_some() + } + + // Param is passed by value, moved + pub fn set_explicit(&mut self, v: bool) { + self.explicit = ::std::option::Option::Some(v); + } + + // optional .ImageGroup covers = 69; + + + pub fn get_covers(&self) -> &ImageGroup { + self.covers.as_ref().unwrap_or_else(|| ImageGroup::default_instance()) + } + pub fn clear_covers(&mut self) { + self.covers.clear(); + } + + pub fn has_covers(&self) -> bool { + self.covers.is_some() + } + + // Param is passed by value, moved + pub fn set_covers(&mut self, v: ImageGroup) { + self.covers = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_covers(&mut self) -> &mut ImageGroup { + if self.covers.is_none() { + self.covers.set_default(); + } + self.covers.as_mut().unwrap() + } + + // Take field + pub fn take_covers(&mut self) -> ImageGroup { + self.covers.take().unwrap_or_else(|| ImageGroup::new()) + } + + // repeated .Restriction restriction = 72; + + + pub fn get_restriction(&self) -> &[Restriction] { + &self.restriction + } + pub fn clear_restriction(&mut self) { + self.restriction.clear(); + } + + // Param is passed by value, moved + pub fn set_restriction(&mut self, v: ::protobuf::RepeatedField) { + self.restriction = v; + } + + // Mutable pointer to the field. + pub fn mut_restriction(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.restriction + } + + // Take field + pub fn take_restriction(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.restriction, ::protobuf::RepeatedField::new()) + } + + // optional .MediaType media_type = 74; + + + pub fn get_media_type(&self) -> MediaType { + self.media_type.unwrap_or(MediaType::MIXED) + } + pub fn clear_media_type(&mut self) { + self.media_type = ::std::option::Option::None; + } + + pub fn has_media_type(&self) -> bool { + self.media_type.is_some() + } + + // Param is passed by value, moved + pub fn set_media_type(&mut self, v: MediaType) { + self.media_type = ::std::option::Option::Some(v); + } + + // optional .ConsumptionOrder consumption_order = 75; + + + pub fn get_consumption_order(&self) -> ConsumptionOrder { + self.consumption_order.unwrap_or(ConsumptionOrder::SEQUENTIAL) + } + pub fn clear_consumption_order(&mut self) { + self.consumption_order = ::std::option::Option::None; + } + + pub fn has_consumption_order(&self) -> bool { + self.consumption_order.is_some() + } + + // Param is passed by value, moved + pub fn set_consumption_order(&mut self, v: ConsumptionOrder) { + self.consumption_order = ::std::option::Option::Some(v); + } + + // optional bool interpret_restriction_using_geoip = 76; + + + pub fn get_interpret_restriction_using_geoip(&self) -> bool { + self.interpret_restriction_using_geoip.unwrap_or(false) + } + pub fn clear_interpret_restriction_using_geoip(&mut self) { + self.interpret_restriction_using_geoip = ::std::option::Option::None; + } + + pub fn has_interpret_restriction_using_geoip(&self) -> bool { + self.interpret_restriction_using_geoip.is_some() + } + + // Param is passed by value, moved + pub fn set_interpret_restriction_using_geoip(&mut self, v: bool) { + self.interpret_restriction_using_geoip = ::std::option::Option::Some(v); + } + + // optional string country_of_origin = 79; + + + pub fn get_country_of_origin(&self) -> &str { + match self.country_of_origin.as_ref() { + Some(v) => &v, + None => "", + } + } + pub fn clear_country_of_origin(&mut self) { + self.country_of_origin.clear(); + } + + pub fn has_country_of_origin(&self) -> bool { + self.country_of_origin.is_some() + } + + // Param is passed by value, moved + pub fn set_country_of_origin(&mut self, v: ::std::string::String) { + self.country_of_origin = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_country_of_origin(&mut self) -> &mut ::std::string::String { + if self.country_of_origin.is_none() { + self.country_of_origin.set_default(); + } + self.country_of_origin.as_mut().unwrap() + } + + // Take field + pub fn take_country_of_origin(&mut self) -> ::std::string::String { + self.country_of_origin.take().unwrap_or_else(|| ::std::string::String::new()) + } + + // repeated .Category categories = 80; + + + pub fn get_categories(&self) -> &[Category] { + &self.categories + } + pub fn clear_categories(&mut self) { + self.categories.clear(); + } + + // Param is passed by value, moved + pub fn set_categories(&mut self, v: ::protobuf::RepeatedField) { + self.categories = v; + } + + // Mutable pointer to the field. + pub fn mut_categories(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.categories + } + + // Take field + pub fn take_categories(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.categories, ::protobuf::RepeatedField::new()) + } + + // optional .PassthroughEnum passthrough = 81; + + + pub fn get_passthrough(&self) -> PassthroughEnum { + self.passthrough.unwrap_or(PassthroughEnum::UNKNOWN) + } + pub fn clear_passthrough(&mut self) { + self.passthrough = ::std::option::Option::None; + } + + pub fn has_passthrough(&self) -> bool { + self.passthrough.is_some() + } + + // Param is passed by value, moved + pub fn set_passthrough(&mut self, v: PassthroughEnum) { + self.passthrough = ::std::option::Option::Some(v); + } +} + +impl ::protobuf::Message for Show { + fn is_initialized(&self) -> bool { + for v in &self.episode { + if !v.is_initialized() { + return false; + } + }; + for v in &self.covers { + if !v.is_initialized() { + return false; + } + }; + for v in &self.restriction { + if !v.is_initialized() { + return false; + } + }; + for v in &self.categories { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.gid)?; + }, + 2 => { + ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.name)?; + }, + 70 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.episode)?; + }, + 64 => { + ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.description)?; + }, + 66 => { + ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.publisher)?; + }, + 67 => { + ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.language)?; + }, + 68 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_bool()?; + self.explicit = ::std::option::Option::Some(tmp); + }, + 69 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.covers)?; + }, + 72 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.restriction)?; + }, + 74 => { + ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.media_type, 74, &mut self.unknown_fields)? + }, + 75 => { + ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.consumption_order, 75, &mut self.unknown_fields)? + }, + 76 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_bool()?; + self.interpret_restriction_using_geoip = ::std::option::Option::Some(tmp); + }, + 79 => { + ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.country_of_origin)?; + }, + 80 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.categories)?; + }, + 81 => { + ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.passthrough, 81, &mut self.unknown_fields)? + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if let Some(ref v) = self.gid.as_ref() { + my_size += ::protobuf::rt::bytes_size(1, &v); + } + if let Some(ref v) = self.name.as_ref() { + my_size += ::protobuf::rt::string_size(2, &v); + } + for value in &self.episode { + let len = value.compute_size(); + my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + if let Some(ref v) = self.description.as_ref() { + my_size += ::protobuf::rt::string_size(64, &v); + } + if let Some(ref v) = self.publisher.as_ref() { + my_size += ::protobuf::rt::string_size(66, &v); + } + if let Some(ref v) = self.language.as_ref() { + my_size += ::protobuf::rt::string_size(67, &v); + } + if let Some(v) = self.explicit { + my_size += 3; + } + if let Some(ref v) = self.covers.as_ref() { + let len = v.compute_size(); + my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + for value in &self.restriction { + let len = value.compute_size(); + my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + if let Some(v) = self.media_type { + my_size += ::protobuf::rt::enum_size(74, v); + } + if let Some(v) = self.consumption_order { + my_size += ::protobuf::rt::enum_size(75, v); + } + if let Some(v) = self.interpret_restriction_using_geoip { + my_size += 3; + } + if let Some(ref v) = self.country_of_origin.as_ref() { + my_size += ::protobuf::rt::string_size(79, &v); + } + for value in &self.categories { + let len = value.compute_size(); + my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + if let Some(v) = self.passthrough { + my_size += ::protobuf::rt::enum_size(81, v); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + if let Some(ref v) = self.gid.as_ref() { + os.write_bytes(1, &v)?; + } + if let Some(ref v) = self.name.as_ref() { + os.write_string(2, &v)?; + } + for v in &self.episode { + os.write_tag(70, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + if let Some(ref v) = self.description.as_ref() { + os.write_string(64, &v)?; + } + if let Some(ref v) = self.publisher.as_ref() { + os.write_string(66, &v)?; + } + if let Some(ref v) = self.language.as_ref() { + os.write_string(67, &v)?; + } + if let Some(v) = self.explicit { + os.write_bool(68, v)?; + } + if let Some(ref v) = self.covers.as_ref() { + os.write_tag(69, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + for v in &self.restriction { + os.write_tag(72, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + if let Some(v) = self.media_type { + os.write_enum(74, v.value())?; + } + if let Some(v) = self.consumption_order { + os.write_enum(75, v.value())?; + } + if let Some(v) = self.interpret_restriction_using_geoip { + os.write_bool(76, v)?; + } + if let Some(ref v) = self.country_of_origin.as_ref() { + os.write_string(79, &v)?; + } + for v in &self.categories { + os.write_tag(80, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + if let Some(v) = self.passthrough { + os.write_enum(81, v.value())?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> Show { + Show::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( + "gid", + |m: &Show| { &m.gid }, + |m: &mut Show| { &mut m.gid }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "name", + |m: &Show| { &m.name }, + |m: &mut Show| { &mut m.name }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "episode", + |m: &Show| { &m.episode }, + |m: &mut Show| { &mut m.episode }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "description", + |m: &Show| { &m.description }, + |m: &mut Show| { &mut m.description }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "publisher", + |m: &Show| { &m.publisher }, + |m: &mut Show| { &mut m.publisher }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "language", + |m: &Show| { &m.language }, + |m: &mut Show| { &mut m.language }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeBool>( + "explicit", + |m: &Show| { &m.explicit }, + |m: &mut Show| { &mut m.explicit }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "covers", + |m: &Show| { &m.covers }, + |m: &mut Show| { &mut m.covers }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "restriction", + |m: &Show| { &m.restriction }, + |m: &mut Show| { &mut m.restriction }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( + "media_type", + |m: &Show| { &m.media_type }, + |m: &mut Show| { &mut m.media_type }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( + "consumption_order", + |m: &Show| { &m.consumption_order }, + |m: &mut Show| { &mut m.consumption_order }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeBool>( + "interpret_restriction_using_geoip", + |m: &Show| { &m.interpret_restriction_using_geoip }, + |m: &mut Show| { &mut m.interpret_restriction_using_geoip }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "country_of_origin", + |m: &Show| { &m.country_of_origin }, + |m: &mut Show| { &mut m.country_of_origin }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "categories", + |m: &Show| { &m.categories }, + |m: &mut Show| { &mut m.categories }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( + "passthrough", + |m: &Show| { &m.passthrough }, + |m: &mut Show| { &mut m.passthrough }, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "Show", + fields, + file_descriptor_proto() + ) + }) + } + } + + fn default_instance() -> &'static Show { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const Show, + }; + unsafe { + instance.get(Show::new) + } + } +} + +impl ::protobuf::Clear for Show { + fn clear(&mut self) { + self.gid.clear(); + self.name.clear(); + self.episode.clear(); + self.description.clear(); + self.publisher.clear(); + self.language.clear(); + self.explicit = ::std::option::Option::None; + self.covers.clear(); + self.restriction.clear(); + self.media_type = ::std::option::Option::None; + self.consumption_order = ::std::option::Option::None; + self.interpret_restriction_using_geoip = ::std::option::Option::None; + self.country_of_origin.clear(); + self.categories.clear(); + self.passthrough = ::std::option::Option::None; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for Show { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for Show { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct Episode { + // message fields + gid: ::protobuf::SingularField<::std::vec::Vec>, + name: ::protobuf::SingularField<::std::string::String>, + duration: ::std::option::Option, + popularity: ::std::option::Option, + file: ::protobuf::RepeatedField, + description: ::protobuf::SingularField<::std::string::String>, + publish_time: ::protobuf::SingularPtrField, + covers: ::protobuf::SingularPtrField, + language: ::protobuf::SingularField<::std::string::String>, + explicit: ::std::option::Option, + show: ::protobuf::SingularPtrField, + preview: ::protobuf::RepeatedField, + restriction: ::protobuf::RepeatedField, + suppress_monetization: ::std::option::Option, + allow_background_playback: ::std::option::Option, + interpret_restriction_using_geoip: ::std::option::Option, + external_url: ::protobuf::SingularField<::std::string::String>, + original_audio: ::protobuf::SingularPtrField, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a Episode { + fn default() -> &'a Episode { + ::default_instance() + } +} + +impl Episode { + pub fn new() -> Episode { + ::std::default::Default::default() + } + + // optional bytes gid = 1; + + + pub fn get_gid(&self) -> &[u8] { + match self.gid.as_ref() { + Some(v) => &v, + None => &[], + } + } + pub fn clear_gid(&mut self) { + self.gid.clear(); + } + + pub fn has_gid(&self) -> bool { + self.gid.is_some() + } + + // Param is passed by value, moved + pub fn set_gid(&mut self, v: ::std::vec::Vec) { + self.gid = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_gid(&mut self) -> &mut ::std::vec::Vec { + if self.gid.is_none() { + self.gid.set_default(); + } + self.gid.as_mut().unwrap() + } + + // Take field + pub fn take_gid(&mut self) -> ::std::vec::Vec { + self.gid.take().unwrap_or_else(|| ::std::vec::Vec::new()) + } + + // optional string name = 2; + + + pub fn get_name(&self) -> &str { + match self.name.as_ref() { + Some(v) => &v, + None => "", + } + } + pub fn clear_name(&mut self) { + self.name.clear(); + } + + pub fn has_name(&self) -> bool { + self.name.is_some() + } + + // Param is passed by value, moved + pub fn set_name(&mut self, v: ::std::string::String) { + self.name = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_name(&mut self) -> &mut ::std::string::String { + if self.name.is_none() { + self.name.set_default(); + } + self.name.as_mut().unwrap() + } + + // Take field + pub fn take_name(&mut self) -> ::std::string::String { + self.name.take().unwrap_or_else(|| ::std::string::String::new()) + } + + // optional sint32 duration = 7; + + + pub fn get_duration(&self) -> i32 { + self.duration.unwrap_or(0) + } + pub fn clear_duration(&mut self) { + self.duration = ::std::option::Option::None; + } + + pub fn has_duration(&self) -> bool { + self.duration.is_some() + } + + // Param is passed by value, moved + pub fn set_duration(&mut self, v: i32) { + self.duration = ::std::option::Option::Some(v); + } + + // optional sint32 popularity = 8; + + + pub fn get_popularity(&self) -> i32 { + self.popularity.unwrap_or(0) + } + pub fn clear_popularity(&mut self) { + self.popularity = ::std::option::Option::None; + } + + pub fn has_popularity(&self) -> bool { + self.popularity.is_some() + } + + // Param is passed by value, moved + pub fn set_popularity(&mut self, v: i32) { + self.popularity = ::std::option::Option::Some(v); + } + + // repeated .AudioFile file = 12; + + + pub fn get_file(&self) -> &[AudioFile] { + &self.file + } + pub fn clear_file(&mut self) { + self.file.clear(); + } + + // Param is passed by value, moved + pub fn set_file(&mut self, v: ::protobuf::RepeatedField) { + self.file = v; + } + + // Mutable pointer to the field. + pub fn mut_file(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.file + } + + // Take field + pub fn take_file(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.file, ::protobuf::RepeatedField::new()) + } + + // optional string description = 64; + + + pub fn get_description(&self) -> &str { + match self.description.as_ref() { + Some(v) => &v, + None => "", + } + } + pub fn clear_description(&mut self) { + self.description.clear(); + } + + pub fn has_description(&self) -> bool { + self.description.is_some() + } + + // Param is passed by value, moved + pub fn set_description(&mut self, v: ::std::string::String) { + self.description = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_description(&mut self) -> &mut ::std::string::String { + if self.description.is_none() { + self.description.set_default(); + } + self.description.as_mut().unwrap() + } + + // Take field + pub fn take_description(&mut self) -> ::std::string::String { + self.description.take().unwrap_or_else(|| ::std::string::String::new()) + } + + // optional .Date publish_time = 66; + + + pub fn get_publish_time(&self) -> &Date { + self.publish_time.as_ref().unwrap_or_else(|| Date::default_instance()) + } + pub fn clear_publish_time(&mut self) { + self.publish_time.clear(); + } + + pub fn has_publish_time(&self) -> bool { + self.publish_time.is_some() + } + + // Param is passed by value, moved + pub fn set_publish_time(&mut self, v: Date) { + self.publish_time = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_publish_time(&mut self) -> &mut Date { + if self.publish_time.is_none() { + self.publish_time.set_default(); + } + self.publish_time.as_mut().unwrap() + } + + // Take field + pub fn take_publish_time(&mut self) -> Date { + self.publish_time.take().unwrap_or_else(|| Date::new()) + } + + // optional .ImageGroup covers = 68; + + + pub fn get_covers(&self) -> &ImageGroup { + self.covers.as_ref().unwrap_or_else(|| ImageGroup::default_instance()) + } + pub fn clear_covers(&mut self) { + self.covers.clear(); + } + + pub fn has_covers(&self) -> bool { + self.covers.is_some() + } + + // Param is passed by value, moved + pub fn set_covers(&mut self, v: ImageGroup) { + self.covers = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_covers(&mut self) -> &mut ImageGroup { + if self.covers.is_none() { + self.covers.set_default(); + } + self.covers.as_mut().unwrap() + } + + // Take field + pub fn take_covers(&mut self) -> ImageGroup { + self.covers.take().unwrap_or_else(|| ImageGroup::new()) + } + + // optional string language = 69; + + + pub fn get_language(&self) -> &str { + match self.language.as_ref() { + Some(v) => &v, + None => "", + } + } + pub fn clear_language(&mut self) { + self.language.clear(); + } + + pub fn has_language(&self) -> bool { + self.language.is_some() + } + + // Param is passed by value, moved + pub fn set_language(&mut self, v: ::std::string::String) { + self.language = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_language(&mut self) -> &mut ::std::string::String { + if self.language.is_none() { + self.language.set_default(); + } + self.language.as_mut().unwrap() + } + + // Take field + pub fn take_language(&mut self) -> ::std::string::String { + self.language.take().unwrap_or_else(|| ::std::string::String::new()) + } + + // optional bool explicit = 70; + + + pub fn get_explicit(&self) -> bool { + self.explicit.unwrap_or(false) + } + pub fn clear_explicit(&mut self) { + self.explicit = ::std::option::Option::None; + } + + pub fn has_explicit(&self) -> bool { + self.explicit.is_some() + } + + // Param is passed by value, moved + pub fn set_explicit(&mut self, v: bool) { + self.explicit = ::std::option::Option::Some(v); + } + + // optional .Show show = 71; + + + pub fn get_show(&self) -> &Show { + self.show.as_ref().unwrap_or_else(|| Show::default_instance()) + } + pub fn clear_show(&mut self) { + self.show.clear(); + } + + pub fn has_show(&self) -> bool { + self.show.is_some() + } + + // Param is passed by value, moved + pub fn set_show(&mut self, v: Show) { + self.show = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_show(&mut self) -> &mut Show { + if self.show.is_none() { + self.show.set_default(); + } + self.show.as_mut().unwrap() + } + + // Take field + pub fn take_show(&mut self) -> Show { + self.show.take().unwrap_or_else(|| Show::new()) + } + + // repeated .AudioFile preview = 74; + + + pub fn get_preview(&self) -> &[AudioFile] { + &self.preview + } + pub fn clear_preview(&mut self) { + self.preview.clear(); + } + + // Param is passed by value, moved + pub fn set_preview(&mut self, v: ::protobuf::RepeatedField) { + self.preview = v; + } + + // Mutable pointer to the field. + pub fn mut_preview(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.preview + } + + // Take field + pub fn take_preview(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.preview, ::protobuf::RepeatedField::new()) + } + + // repeated .Restriction restriction = 75; + + + pub fn get_restriction(&self) -> &[Restriction] { + &self.restriction + } + pub fn clear_restriction(&mut self) { + self.restriction.clear(); + } + + // Param is passed by value, moved + pub fn set_restriction(&mut self, v: ::protobuf::RepeatedField) { + self.restriction = v; + } + + // Mutable pointer to the field. + pub fn mut_restriction(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.restriction + } + + // Take field + pub fn take_restriction(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.restriction, ::protobuf::RepeatedField::new()) + } + + // optional bool suppress_monetization = 78; + + + pub fn get_suppress_monetization(&self) -> bool { + self.suppress_monetization.unwrap_or(false) + } + pub fn clear_suppress_monetization(&mut self) { + self.suppress_monetization = ::std::option::Option::None; + } + + pub fn has_suppress_monetization(&self) -> bool { + self.suppress_monetization.is_some() + } + + // Param is passed by value, moved + pub fn set_suppress_monetization(&mut self, v: bool) { + self.suppress_monetization = ::std::option::Option::Some(v); + } + + // optional bool allow_background_playback = 79; + + + pub fn get_allow_background_playback(&self) -> bool { + self.allow_background_playback.unwrap_or(false) + } + pub fn clear_allow_background_playback(&mut self) { + self.allow_background_playback = ::std::option::Option::None; + } + + pub fn has_allow_background_playback(&self) -> bool { + self.allow_background_playback.is_some() + } + + // Param is passed by value, moved + pub fn set_allow_background_playback(&mut self, v: bool) { + self.allow_background_playback = ::std::option::Option::Some(v); + } + + // optional bool interpret_restriction_using_geoip = 81; + + + pub fn get_interpret_restriction_using_geoip(&self) -> bool { + self.interpret_restriction_using_geoip.unwrap_or(false) + } + pub fn clear_interpret_restriction_using_geoip(&mut self) { + self.interpret_restriction_using_geoip = ::std::option::Option::None; + } + + pub fn has_interpret_restriction_using_geoip(&self) -> bool { + self.interpret_restriction_using_geoip.is_some() + } + + // Param is passed by value, moved + pub fn set_interpret_restriction_using_geoip(&mut self, v: bool) { + self.interpret_restriction_using_geoip = ::std::option::Option::Some(v); + } + + // optional string external_url = 83; + + + pub fn get_external_url(&self) -> &str { + match self.external_url.as_ref() { + Some(v) => &v, + None => "", + } + } + pub fn clear_external_url(&mut self) { + self.external_url.clear(); + } + + pub fn has_external_url(&self) -> bool { + self.external_url.is_some() + } + + // Param is passed by value, moved + pub fn set_external_url(&mut self, v: ::std::string::String) { + self.external_url = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_external_url(&mut self) -> &mut ::std::string::String { + if self.external_url.is_none() { + self.external_url.set_default(); + } + self.external_url.as_mut().unwrap() + } + + // Take field + pub fn take_external_url(&mut self) -> ::std::string::String { + self.external_url.take().unwrap_or_else(|| ::std::string::String::new()) + } + + // optional .OriginalAudio original_audio = 84; + + + pub fn get_original_audio(&self) -> &OriginalAudio { + self.original_audio.as_ref().unwrap_or_else(|| OriginalAudio::default_instance()) + } + pub fn clear_original_audio(&mut self) { + self.original_audio.clear(); + } + + pub fn has_original_audio(&self) -> bool { + self.original_audio.is_some() + } + + // Param is passed by value, moved + pub fn set_original_audio(&mut self, v: OriginalAudio) { + self.original_audio = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_original_audio(&mut self) -> &mut OriginalAudio { + if self.original_audio.is_none() { + self.original_audio.set_default(); + } + self.original_audio.as_mut().unwrap() + } + + // Take field + pub fn take_original_audio(&mut self) -> OriginalAudio { + self.original_audio.take().unwrap_or_else(|| OriginalAudio::new()) + } +} + +impl ::protobuf::Message for Episode { + fn is_initialized(&self) -> bool { + for v in &self.file { + if !v.is_initialized() { + return false; + } + }; + for v in &self.publish_time { + if !v.is_initialized() { + return false; + } + }; + for v in &self.covers { + if !v.is_initialized() { + return false; + } + }; + for v in &self.show { + if !v.is_initialized() { + return false; + } + }; + for v in &self.preview { + if !v.is_initialized() { + return false; + } + }; + for v in &self.restriction { + if !v.is_initialized() { + return false; + } + }; + for v in &self.original_audio { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.gid)?; + }, + 2 => { + ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.name)?; + }, + 7 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_sint32()?; + self.duration = ::std::option::Option::Some(tmp); + }, + 8 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_sint32()?; + self.popularity = ::std::option::Option::Some(tmp); + }, + 12 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.file)?; + }, + 64 => { + ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.description)?; + }, + 66 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.publish_time)?; + }, + 68 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.covers)?; + }, + 69 => { + ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.language)?; + }, + 70 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_bool()?; + self.explicit = ::std::option::Option::Some(tmp); + }, + 71 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.show)?; + }, + 74 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.preview)?; + }, + 75 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.restriction)?; + }, + 78 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_bool()?; + self.suppress_monetization = ::std::option::Option::Some(tmp); + }, + 79 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_bool()?; + self.allow_background_playback = ::std::option::Option::Some(tmp); + }, + 81 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_bool()?; + self.interpret_restriction_using_geoip = ::std::option::Option::Some(tmp); + }, + 83 => { + ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.external_url)?; + }, + 84 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.original_audio)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if let Some(ref v) = self.gid.as_ref() { + my_size += ::protobuf::rt::bytes_size(1, &v); + } + if let Some(ref v) = self.name.as_ref() { + my_size += ::protobuf::rt::string_size(2, &v); + } + if let Some(v) = self.duration { + my_size += ::protobuf::rt::value_varint_zigzag_size(7, v); + } + if let Some(v) = self.popularity { + my_size += ::protobuf::rt::value_varint_zigzag_size(8, v); + } + for value in &self.file { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + if let Some(ref v) = self.description.as_ref() { + my_size += ::protobuf::rt::string_size(64, &v); + } + if let Some(ref v) = self.publish_time.as_ref() { + let len = v.compute_size(); + my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + if let Some(ref v) = self.covers.as_ref() { + let len = v.compute_size(); + my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + if let Some(ref v) = self.language.as_ref() { + my_size += ::protobuf::rt::string_size(69, &v); + } + if let Some(v) = self.explicit { + my_size += 3; + } + if let Some(ref v) = self.show.as_ref() { + let len = v.compute_size(); + my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + for value in &self.preview { + let len = value.compute_size(); + my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + for value in &self.restriction { + let len = value.compute_size(); + my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + if let Some(v) = self.suppress_monetization { + my_size += 3; + } + if let Some(v) = self.allow_background_playback { + my_size += 3; + } + if let Some(v) = self.interpret_restriction_using_geoip { + my_size += 3; + } + if let Some(ref v) = self.external_url.as_ref() { + my_size += ::protobuf::rt::string_size(83, &v); + } + if let Some(ref v) = self.original_audio.as_ref() { + let len = v.compute_size(); + my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + if let Some(ref v) = self.gid.as_ref() { + os.write_bytes(1, &v)?; + } + if let Some(ref v) = self.name.as_ref() { + os.write_string(2, &v)?; + } + if let Some(v) = self.duration { + os.write_sint32(7, v)?; + } + if let Some(v) = self.popularity { + os.write_sint32(8, v)?; + } + for v in &self.file { + os.write_tag(12, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + if let Some(ref v) = self.description.as_ref() { + os.write_string(64, &v)?; + } + if let Some(ref v) = self.publish_time.as_ref() { + os.write_tag(66, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + if let Some(ref v) = self.covers.as_ref() { + os.write_tag(68, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + if let Some(ref v) = self.language.as_ref() { + os.write_string(69, &v)?; + } + if let Some(v) = self.explicit { + os.write_bool(70, v)?; + } + if let Some(ref v) = self.show.as_ref() { + os.write_tag(71, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + for v in &self.preview { + os.write_tag(74, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + for v in &self.restriction { + os.write_tag(75, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + if let Some(v) = self.suppress_monetization { + os.write_bool(78, v)?; + } + if let Some(v) = self.allow_background_playback { + os.write_bool(79, v)?; + } + if let Some(v) = self.interpret_restriction_using_geoip { + os.write_bool(81, v)?; + } + if let Some(ref v) = self.external_url.as_ref() { + os.write_string(83, &v)?; + } + if let Some(ref v) = self.original_audio.as_ref() { + os.write_tag(84, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> Episode { + Episode::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( + "gid", + |m: &Episode| { &m.gid }, + |m: &mut Episode| { &mut m.gid }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "name", + |m: &Episode| { &m.name }, + |m: &mut Episode| { &mut m.name }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeSint32>( + "duration", + |m: &Episode| { &m.duration }, + |m: &mut Episode| { &mut m.duration }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeSint32>( + "popularity", + |m: &Episode| { &m.popularity }, + |m: &mut Episode| { &mut m.popularity }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "file", + |m: &Episode| { &m.file }, + |m: &mut Episode| { &mut m.file }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "description", + |m: &Episode| { &m.description }, + |m: &mut Episode| { &mut m.description }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "publish_time", + |m: &Episode| { &m.publish_time }, + |m: &mut Episode| { &mut m.publish_time }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "covers", + |m: &Episode| { &m.covers }, + |m: &mut Episode| { &mut m.covers }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "language", + |m: &Episode| { &m.language }, + |m: &mut Episode| { &mut m.language }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeBool>( + "explicit", + |m: &Episode| { &m.explicit }, + |m: &mut Episode| { &mut m.explicit }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "show", + |m: &Episode| { &m.show }, + |m: &mut Episode| { &mut m.show }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "preview", + |m: &Episode| { &m.preview }, + |m: &mut Episode| { &mut m.preview }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "restriction", + |m: &Episode| { &m.restriction }, + |m: &mut Episode| { &mut m.restriction }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeBool>( + "suppress_monetization", + |m: &Episode| { &m.suppress_monetization }, + |m: &mut Episode| { &mut m.suppress_monetization }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeBool>( + "allow_background_playback", + |m: &Episode| { &m.allow_background_playback }, + |m: &mut Episode| { &mut m.allow_background_playback }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeBool>( + "interpret_restriction_using_geoip", + |m: &Episode| { &m.interpret_restriction_using_geoip }, + |m: &mut Episode| { &mut m.interpret_restriction_using_geoip }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "external_url", + |m: &Episode| { &m.external_url }, + |m: &mut Episode| { &mut m.external_url }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "original_audio", + |m: &Episode| { &m.original_audio }, + |m: &mut Episode| { &mut m.original_audio }, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "Episode", + fields, + file_descriptor_proto() + ) + }) + } + } + + fn default_instance() -> &'static Episode { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const Episode, + }; + unsafe { + instance.get(Episode::new) + } + } +} + +impl ::protobuf::Clear for Episode { + fn clear(&mut self) { + self.gid.clear(); + self.name.clear(); + self.duration = ::std::option::Option::None; + self.popularity = ::std::option::Option::None; + self.file.clear(); + self.description.clear(); + self.publish_time.clear(); + self.covers.clear(); + self.language.clear(); + self.explicit = ::std::option::Option::None; + self.show.clear(); + self.preview.clear(); + self.restriction.clear(); + self.suppress_monetization = ::std::option::Option::None; + self.allow_background_playback = ::std::option::Option::None; + self.interpret_restriction_using_geoip = ::std::option::Option::None; + self.external_url.clear(); + self.original_audio.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for Episode { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for Episode { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct Category { + // message fields + name: ::protobuf::SingularField<::std::string::String>, + subcategories: ::protobuf::RepeatedField, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a Category { + fn default() -> &'a Category { + ::default_instance() + } +} + +impl Category { + pub fn new() -> Category { + ::std::default::Default::default() + } + + // optional string name = 1; + + + pub fn get_name(&self) -> &str { + match self.name.as_ref() { + Some(v) => &v, + None => "", + } + } + pub fn clear_name(&mut self) { + self.name.clear(); + } + + pub fn has_name(&self) -> bool { + self.name.is_some() + } + + // Param is passed by value, moved + pub fn set_name(&mut self, v: ::std::string::String) { + self.name = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_name(&mut self) -> &mut ::std::string::String { + if self.name.is_none() { + self.name.set_default(); + } + self.name.as_mut().unwrap() + } + + // Take field + pub fn take_name(&mut self) -> ::std::string::String { + self.name.take().unwrap_or_else(|| ::std::string::String::new()) + } + + // repeated .Category subcategories = 2; + + + pub fn get_subcategories(&self) -> &[Category] { + &self.subcategories + } + pub fn clear_subcategories(&mut self) { + self.subcategories.clear(); + } + + // Param is passed by value, moved + pub fn set_subcategories(&mut self, v: ::protobuf::RepeatedField) { + self.subcategories = v; + } + + // Mutable pointer to the field. + pub fn mut_subcategories(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.subcategories + } + + // Take field + pub fn take_subcategories(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.subcategories, ::protobuf::RepeatedField::new()) + } +} + +impl ::protobuf::Message for Category { + fn is_initialized(&self) -> bool { + for v in &self.subcategories { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.name)?; + }, + 2 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.subcategories)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if let Some(ref v) = self.name.as_ref() { + my_size += ::protobuf::rt::string_size(1, &v); + } + for value in &self.subcategories { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + if let Some(ref v) = self.name.as_ref() { + os.write_string(1, &v)?; + } + for v in &self.subcategories { + os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> Category { + Category::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "name", + |m: &Category| { &m.name }, + |m: &mut Category| { &mut m.name }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "subcategories", + |m: &Category| { &m.subcategories }, + |m: &mut Category| { &mut m.subcategories }, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "Category", + fields, + file_descriptor_proto() + ) + }) + } + } + + fn default_instance() -> &'static Category { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const Category, + }; + unsafe { + instance.get(Category::new) + } + } +} + +impl ::protobuf::Clear for Category { + fn clear(&mut self) { + self.name.clear(); + self.subcategories.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for Category { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for Category { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct OriginalAudio { + // message fields + uuid: ::protobuf::SingularField<::std::vec::Vec>, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a OriginalAudio { + fn default() -> &'a OriginalAudio { + ::default_instance() + } +} + +impl OriginalAudio { + pub fn new() -> OriginalAudio { + ::std::default::Default::default() + } + + // optional bytes uuid = 1; + + + pub fn get_uuid(&self) -> &[u8] { + match self.uuid.as_ref() { + Some(v) => &v, + None => &[], + } + } + pub fn clear_uuid(&mut self) { + self.uuid.clear(); + } + + pub fn has_uuid(&self) -> bool { + self.uuid.is_some() + } + + // Param is passed by value, moved + pub fn set_uuid(&mut self, v: ::std::vec::Vec) { + self.uuid = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_uuid(&mut self) -> &mut ::std::vec::Vec { + if self.uuid.is_none() { + self.uuid.set_default(); + } + self.uuid.as_mut().unwrap() + } + + // Take field + pub fn take_uuid(&mut self) -> ::std::vec::Vec { + self.uuid.take().unwrap_or_else(|| ::std::vec::Vec::new()) + } +} + +impl ::protobuf::Message for OriginalAudio { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.uuid)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if let Some(ref v) = self.uuid.as_ref() { + my_size += ::protobuf::rt::bytes_size(1, &v); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + if let Some(ref v) = self.uuid.as_ref() { + os.write_bytes(1, &v)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> OriginalAudio { + OriginalAudio::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( + "uuid", + |m: &OriginalAudio| { &m.uuid }, + |m: &mut OriginalAudio| { &mut m.uuid }, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "OriginalAudio", + fields, + file_descriptor_proto() + ) + }) + } + } + + fn default_instance() -> &'static OriginalAudio { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const OriginalAudio, + }; + unsafe { + instance.get(OriginalAudio::new) + } + } +} + +impl ::protobuf::Clear for OriginalAudio { + fn clear(&mut self) { + self.uuid.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for OriginalAudio { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for OriginalAudio { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Message(self) + } +} + +#[derive(Clone,PartialEq,Eq,Debug,Hash)] +pub enum ConsumptionOrder { + SEQUENTIAL = 1, + EPISODIC = 2, + RECENT = 3, +} + +impl ::protobuf::ProtobufEnum for ConsumptionOrder { + fn value(&self) -> i32 { + *self as i32 + } + + fn from_i32(value: i32) -> ::std::option::Option { + match value { + 1 => ::std::option::Option::Some(ConsumptionOrder::SEQUENTIAL), + 2 => ::std::option::Option::Some(ConsumptionOrder::EPISODIC), + 3 => ::std::option::Option::Some(ConsumptionOrder::RECENT), + _ => ::std::option::Option::None + } + } + + fn values() -> &'static [Self] { + static values: &'static [ConsumptionOrder] = &[ + ConsumptionOrder::SEQUENTIAL, + ConsumptionOrder::EPISODIC, + ConsumptionOrder::RECENT, + ]; + values + } + + fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::EnumDescriptor, + }; + unsafe { + descriptor.get(|| { + ::protobuf::reflect::EnumDescriptor::new("ConsumptionOrder", file_descriptor_proto()) + }) + } + } +} + +impl ::std::marker::Copy for ConsumptionOrder { +} + +// Note, `Default` is implemented although default value is not 0 +impl ::std::default::Default for ConsumptionOrder { + fn default() -> Self { + ConsumptionOrder::SEQUENTIAL + } +} + +impl ::protobuf::reflect::ProtobufValue for ConsumptionOrder { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Enum(self.descriptor()) + } +} + +#[derive(Clone,PartialEq,Eq,Debug,Hash)] +pub enum MediaType { + MIXED = 0, + AUDIO = 1, + VIDEO = 2, +} + +impl ::protobuf::ProtobufEnum for MediaType { + fn value(&self) -> i32 { + *self as i32 + } + + fn from_i32(value: i32) -> ::std::option::Option { + match value { + 0 => ::std::option::Option::Some(MediaType::MIXED), + 1 => ::std::option::Option::Some(MediaType::AUDIO), + 2 => ::std::option::Option::Some(MediaType::VIDEO), + _ => ::std::option::Option::None + } + } + + fn values() -> &'static [Self] { + static values: &'static [MediaType] = &[ + MediaType::MIXED, + MediaType::AUDIO, + MediaType::VIDEO, + ]; + values + } + + fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::EnumDescriptor, + }; + unsafe { + descriptor.get(|| { + ::protobuf::reflect::EnumDescriptor::new("MediaType", file_descriptor_proto()) + }) + } + } +} + +impl ::std::marker::Copy for MediaType { +} + +impl ::std::default::Default for MediaType { + fn default() -> Self { + MediaType::MIXED + } +} + +impl ::protobuf::reflect::ProtobufValue for MediaType { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Enum(self.descriptor()) + } +} + +#[derive(Clone,PartialEq,Eq,Debug,Hash)] +pub enum PassthroughEnum { + UNKNOWN = 0, + NONE = 1, +} + +impl ::protobuf::ProtobufEnum for PassthroughEnum { + fn value(&self) -> i32 { + *self as i32 + } + + fn from_i32(value: i32) -> ::std::option::Option { + match value { + 0 => ::std::option::Option::Some(PassthroughEnum::UNKNOWN), + 1 => ::std::option::Option::Some(PassthroughEnum::NONE), + _ => ::std::option::Option::None + } + } + + fn values() -> &'static [Self] { + static values: &'static [PassthroughEnum] = &[ + PassthroughEnum::UNKNOWN, + PassthroughEnum::NONE, + ]; + values + } + + fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::EnumDescriptor, + }; + unsafe { + descriptor.get(|| { + ::protobuf::reflect::EnumDescriptor::new("PassthroughEnum", file_descriptor_proto()) + }) + } + } +} + +impl ::std::marker::Copy for PassthroughEnum { +} + +impl ::std::default::Default for PassthroughEnum { + fn default() -> Self { + PassthroughEnum::UNKNOWN + } +} + +impl ::protobuf::reflect::ProtobufValue for PassthroughEnum { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Enum(self.descriptor()) + } +} + static file_descriptor_proto_data: &'static [u8] = b"\ \n\x0emetadata.proto\x12\0\"9\n\tTopTracks\x12\x11\n\x07country\x18\x01\ \x20\x01(\tB\0\x12\x17\n\x05track\x18\x02\x20\x03(\x0b2\x06.TrackB\0:\0\ @@ -6293,15 +9016,50 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x18\x01\x20\x03(\x0b2\x0c.RestrictionB\0\x12\x16\n\x05start\x18\x02\x20\ \x01(\x0b2\x05.DateB\0\x12\x14\n\x03end\x18\x03\x20\x01(\x0b2\x05.DateB\ \0:\0\"+\n\nExternalId\x12\r\n\x03typ\x18\x01\x20\x01(\tB\0\x12\x0c\n\ - \x02id\x18\x02\x20\x01(\tB\0:\0\"\x9b\x02\n\tAudioFile\x12\x11\n\x07file\ + \x02id\x18\x02\x20\x01(\tB\0:\0\"\xa2\x02\n\tAudioFile\x12\x11\n\x07file\ _id\x18\x01\x20\x01(\x0cB\0\x12#\n\x06format\x18\x02\x20\x01(\x0e2\x11.A\ - udioFile.FormatB\0\"\xd3\x01\n\x06Format\x12\x11\n\rOGG_VORBIS_96\x10\0\ + udioFile.FormatB\0\"\xda\x01\n\x06Format\x12\x11\n\rOGG_VORBIS_96\x10\0\ \x12\x12\n\x0eOGG_VORBIS_160\x10\x01\x12\x12\n\x0eOGG_VORBIS_320\x10\x02\ \x12\x0b\n\x07MP3_256\x10\x03\x12\x0b\n\x07MP3_320\x10\x04\x12\x0b\n\x07\ MP3_160\x10\x05\x12\n\n\x06MP3_96\x10\x06\x12\x0f\n\x0bMP3_160_ENC\x10\ - \x07\x12\n\n\x06OTHER2\x10\x08\x12\n\n\x06OTHER3\x10\t\x12\x0b\n\x07AAC_\ - 160\x10\n\x12\x0b\n\x07AAC_320\x10\x0b\x12\n\n\x06OTHER4\x10\x0c\x12\n\n\ - \x06OTHER5\x10\r\x1a\0:\0B\0b\x06proto2\ + \x07\x12\x10\n\x0cMP4_128_DUAL\x10\x08\x12\n\n\x06OTHER3\x10\t\x12\x0b\n\ + \x07AAC_160\x10\n\x12\x0b\n\x07AAC_320\x10\x0b\x12\x0b\n\x07MP4_128\x10\ + \x0c\x12\n\n\x06OTHER5\x10\r\x1a\0:\0\"a\n\x0bPublishTime\x12\x0e\n\x04y\ + ear\x18\x01\x20\x01(\x11B\0\x12\x0f\n\x05month\x18\x02\x20\x01(\x11B\0\ + \x12\r\n\x03day\x18\x03\x20\x01(\x11B\0\x12\x10\n\x06minute\x18\x05\x20\ + \x01(\x11B\0\x12\x0e\n\x04hour\x18\x04\x20\x01(\x11B\0:\0\"\xc2\x03\n\ + \x04Show\x12\r\n\x03gid\x18\x01\x20\x01(\x0cB\0\x12\x0e\n\x04name\x18\ + \x02\x20\x01(\tB\0\x12\x1b\n\x07episode\x18F\x20\x03(\x0b2\x08.EpisodeB\ + \0\x12\x15\n\x0bdescription\x18@\x20\x01(\tB\0\x12\x13\n\tpublisher\x18B\ + \x20\x01(\tB\0\x12\x12\n\x08language\x18C\x20\x01(\tB\0\x12\x12\n\x08exp\ + licit\x18D\x20\x01(\x08B\0\x12\x1d\n\x06covers\x18E\x20\x01(\x0b2\x0b.Im\ + ageGroupB\0\x12#\n\x0brestriction\x18H\x20\x03(\x0b2\x0c.RestrictionB\0\ + \x12\x20\n\nmedia_type\x18J\x20\x01(\x0e2\n.MediaTypeB\0\x12.\n\x11consu\ + mption_order\x18K\x20\x01(\x0e2\x11.ConsumptionOrderB\0\x12+\n!interpret\ + _restriction_using_geoip\x18L\x20\x01(\x08B\0\x12\x1b\n\x11country_of_or\ + igin\x18O\x20\x01(\tB\0\x12\x1f\n\ncategories\x18P\x20\x03(\x0b2\t.Categ\ + oryB\0\x12'\n\x0bpassthrough\x18Q\x20\x01(\x0e2\x10.PassthroughEnumB\0:\ + \0\"\xfd\x03\n\x07Episode\x12\r\n\x03gid\x18\x01\x20\x01(\x0cB\0\x12\x0e\ + \n\x04name\x18\x02\x20\x01(\tB\0\x12\x12\n\x08duration\x18\x07\x20\x01(\ + \x11B\0\x12\x14\n\npopularity\x18\x08\x20\x01(\x11B\0\x12\x1a\n\x04file\ + \x18\x0c\x20\x03(\x0b2\n.AudioFileB\0\x12\x15\n\x0bdescription\x18@\x20\ + \x01(\tB\0\x12\x1d\n\x0cpublish_time\x18B\x20\x01(\x0b2\x05.DateB\0\x12\ + \x1d\n\x06covers\x18D\x20\x01(\x0b2\x0b.ImageGroupB\0\x12\x12\n\x08langu\ + age\x18E\x20\x01(\tB\0\x12\x12\n\x08explicit\x18F\x20\x01(\x08B\0\x12\ + \x15\n\x04show\x18G\x20\x01(\x0b2\x05.ShowB\0\x12\x1d\n\x07preview\x18J\ + \x20\x03(\x0b2\n.AudioFileB\0\x12#\n\x0brestriction\x18K\x20\x03(\x0b2\ + \x0c.RestrictionB\0\x12\x1f\n\x15suppress_monetization\x18N\x20\x01(\x08\ + B\0\x12#\n\x19allow_background_playback\x18O\x20\x01(\x08B\0\x12+\n!inte\ + rpret_restriction_using_geoip\x18Q\x20\x01(\x08B\0\x12\x16\n\x0cexternal\ + _url\x18S\x20\x01(\tB\0\x12(\n\x0eoriginal_audio\x18T\x20\x01(\x0b2\x0e.\ + OriginalAudioB\0:\0\"@\n\x08Category\x12\x0e\n\x04name\x18\x01\x20\x01(\ + \tB\0\x12\"\n\rsubcategories\x18\x02\x20\x03(\x0b2\t.CategoryB\0:\0\"!\n\ + \rOriginalAudio\x12\x0e\n\x04uuid\x18\x01\x20\x01(\x0cB\0:\0*>\n\x10Cons\ + umptionOrder\x12\x0e\n\nSEQUENTIAL\x10\x01\x12\x0c\n\x08EPISODIC\x10\x02\ + \x12\n\n\x06RECENT\x10\x03\x1a\0*.\n\tMediaType\x12\t\n\x05MIXED\x10\0\ + \x12\t\n\x05AUDIO\x10\x01\x12\t\n\x05VIDEO\x10\x02\x1a\0**\n\x0fPassthro\ + ughEnum\x12\x0b\n\x07UNKNOWN\x10\0\x12\x08\n\x04NONE\x10\x01\x1a\0B\0b\ + \x06proto2\ "; static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { From 8eb51e9b55d6051ced1275ac15a5578b307a3eb0 Mon Sep 17 00:00:00 2001 From: ashthespy Date: Tue, 8 Oct 2019 00:27:26 +0200 Subject: [PATCH 03/43] Streamline and refactor Podcast support, Add publisher to `Show` Add `ALLOWED` to `PassthroughEnum` --- core/src/spotify_id.rs | 8 +-- metadata/src/lib.rs | 71 +++++++++++++++++- playback/src/player.rs | 132 ++++++++++++++-------------------- protocol/files.rs | 2 +- protocol/proto/metadata.proto | 1 + protocol/src/metadata.rs | 9 ++- 6 files changed, 135 insertions(+), 88 deletions(-) diff --git a/core/src/spotify_id.rs b/core/src/spotify_id.rs index 01c4ddd4..c8f01674 100644 --- a/core/src/spotify_id.rs +++ b/core/src/spotify_id.rs @@ -2,7 +2,7 @@ use std; use std::fmt; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum SpotifyTrackType { +pub enum SpotifyAudioType { Track, Podcast, } @@ -10,7 +10,7 @@ pub enum SpotifyTrackType { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct SpotifyId { pub id: u128, - pub track_type: SpotifyTrackType, + pub audio_type: SpotifyAudioType, } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -23,7 +23,7 @@ impl SpotifyId { fn as_track(n: u128) -> SpotifyId { SpotifyId { id: n.to_owned(), - track_type: SpotifyTrackType::Track, + audio_type: SpotifyAudioType::Track, } } @@ -73,7 +73,7 @@ impl SpotifyId { let parts = uri.split(":").collect::>(); if uri.contains(":show:") || uri.contains(":episode:") { let mut spotify_id = SpotifyId::from_base62(parts[2]).unwrap(); - spotify_id.track_type = SpotifyTrackType::Podcast; + let _ = std::mem::replace(&mut spotify_id.audio_type, SpotifyAudioType::Podcast); Ok(spotify_id) } else { SpotifyId::from_base62(parts[2]) diff --git a/metadata/src/lib.rs b/metadata/src/lib.rs index 6aa6a5bd..75a42e2f 100644 --- a/metadata/src/lib.rs +++ b/metadata/src/lib.rs @@ -13,7 +13,7 @@ use linear_map::LinearMap; use librespot_core::mercury::MercuryError; use librespot_core::session::Session; -use librespot_core::spotify_id::{FileId, SpotifyId}; +use librespot_core::spotify_id::{FileId, SpotifyAudioType, SpotifyId}; pub use protocol::metadata::AudioFile_Format as FileFormat; @@ -52,13 +52,78 @@ where && (!has_allowed || countrylist_contains(allowed.as_str(), country)) } +// A wrapper with fields the player needs +#[derive(Debug, Clone)] +pub struct AudioItem { + pub id: SpotifyId, + pub uri: String, + pub files: LinearMap, + pub name: String, + pub available: bool, + pub alternatives: Option>, +} + +impl AudioItem { + pub fn get_audio_item( + session: &Session, + id: SpotifyId, + ) -> Box> { + match id.audio_type { + SpotifyAudioType::Track => Track::get_audio_item(session, id), + SpotifyAudioType::Podcast => Episode::get_audio_item(session, id), + } + } +} + +trait AudioFiles { + fn get_audio_item( + session: &Session, + id: SpotifyId, + ) -> Box>; +} + +impl AudioFiles for Track { + fn get_audio_item( + session: &Session, + id: SpotifyId, + ) -> Box> { + Box::new(Self::get(session, id).and_then(move |item| { + Ok(AudioItem { + id: id, + uri: format!("spotify:track:{}", id.to_base62()), + files: item.files, + name: item.name, + available: item.available, + alternatives: Some(item.alternatives), + }) + })) + } +} + +impl AudioFiles for Episode { + fn get_audio_item( + session: &Session, + id: SpotifyId, + ) -> Box> { + Box::new(Self::get(session, id).and_then(move |item| { + Ok(AudioItem { + id: id, + uri: format!("spotify:episode:{}", id.to_base62()), + files: item.files, + name: item.name, + available: item.available, + alternatives: None, + }) + })) + } +} pub trait Metadata: Send + Sized + 'static { type Message: protobuf::Message; fn base_url() -> &'static str; fn parse(msg: &Self::Message, session: &Session) -> Self; - fn get(session: &Session, id: SpotifyId) -> Box> { + fn get(session: &Session, id: SpotifyId) -> Box> { let uri = format!("{}/{}", Self::base_url(), id.to_base16()); let request = session.mercury().get(uri); @@ -111,6 +176,7 @@ pub struct Episode { pub struct Show { pub id: SpotifyId, pub name: String, + pub publisher: String, pub episodes: Vec, pub covers: Vec, } @@ -323,6 +389,7 @@ impl Metadata for Show { Show { id: SpotifyId::from_raw(msg.get_gid()).unwrap(), name: msg.get_name().to_owned(), + publisher: msg.get_publisher().to_owned(), episodes: episodes, covers: covers, } diff --git a/playback/src/player.rs b/playback/src/player.rs index 3b48a594..95eb549d 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -12,12 +12,12 @@ use std::time::Duration; use config::{Bitrate, PlayerConfig}; use librespot_core::session::Session; -use librespot_core::spotify_id::{FileId, SpotifyId, SpotifyTrackType}; +use librespot_core::spotify_id::SpotifyId; use audio::{AudioDecrypt, AudioFile}; use audio::{VorbisDecoder, VorbisPacket}; use audio_backend::Sink; -use metadata::{Episode, FileFormat, Metadata, Track}; +use metadata::{AudioItem, FileFormat}; use mixer::AudioFilter; pub struct Player { @@ -512,87 +512,65 @@ impl PlayerInternal { let _ = self.event_sender.unbounded_send(event.clone()); } - fn find_available_alternative<'a>(&self, track: &'a Track) -> Option> { - if track.available { - Some(Cow::Borrowed(track)) + fn find_available_alternative<'a>(&self, audio: &'a AudioItem) -> Option> { + if audio.available { + Some(Cow::Borrowed(audio)) } else { - let alternatives = track - .alternatives - .iter() - .map(|alt_id| Track::get(&self.session, *alt_id)); - let alternatives = future::join_all(alternatives).wait().unwrap(); - - alternatives.into_iter().find(|alt| alt.available).map(Cow::Owned) + if let Some(alternatives) = &audio.alternatives { + let alternatives = alternatives + .iter() + .map(|alt_id| AudioItem::get_audio_item(&self.session, *alt_id)); + let alternatives = future::join_all(alternatives).wait().unwrap(); + alternatives.into_iter().find(|alt| alt.available).map(Cow::Owned) + } else { + None + } } } - fn get_file_id(&self, spotify_id: SpotifyId) -> Option { - let file_id = match spotify_id.track_type { - SpotifyTrackType::Track => { - let track = Track::get(&self.session, spotify_id).wait().unwrap(); + fn load_track(&self, spotify_id: SpotifyId, position: i64) -> Option<(Decoder, f32)> { + let audio = AudioItem::get_audio_item(&self.session, spotify_id) + .wait() + .unwrap(); + info!("Loading <{}> with Spotify URI <{}>", audio.name, audio.uri); - info!( - "Loading track \"{}\" with Spotify URI \"spotify:track:{}\"", - track.name, - spotify_id.to_base62() - ); - - let track = match self.find_available_alternative(&track) { - Some(track) => track, - None => { - warn!("Track \"{}\" is not available", track.name); - return None; - } - }; - - let format = match self.config.bitrate { - Bitrate::Bitrate96 => FileFormat::OGG_VORBIS_96, - Bitrate::Bitrate160 => FileFormat::OGG_VORBIS_160, - Bitrate::Bitrate320 => FileFormat::OGG_VORBIS_320, - }; - match track.files.get(&format) { - Some(&file_id) => file_id, - None => { - warn!("Track \"{}\" is not available in format {:?}", track.name, format); - return None; - } - } - } - // This should be refactored! - SpotifyTrackType::Podcast => { - let episode = Episode::get(&self.session, spotify_id).wait().unwrap(); - info!("Episode {:?}", episode); - - info!( - "Loading episode \"{}\" with Spotify URI \"spotify:episode:{}\"", - episode.name, - spotify_id.to_base62() - ); - - // Podcasts seem to have only 96 OGG_VORBIS support, other filetypes indicate - // AAC_24, MP4_128, MP4_128_DUAL, MP3_96 among others - let format = match self.config.bitrate { - _ => FileFormat::OGG_VORBIS_96, - }; - - match episode.files.get(&format) { - Some(&file_id) => file_id, - None => { - warn!( - "Episode \"{}\" is not available in format {:?}", - episode.name, format - ); - return None; - } - } + let audio = match self.find_available_alternative(&audio) { + Some(audio) => audio, + None => { + warn!("<{}> is not available", audio.uri); + return None; } }; - return Some(file_id); - } + // (Most) podcasts seem to support only 96 bit Vorbis, so fall back to it + let formats = match self.config.bitrate { + Bitrate::Bitrate96 => [ + FileFormat::OGG_VORBIS_96, + FileFormat::OGG_VORBIS_160, + FileFormat::OGG_VORBIS_320, + ], + Bitrate::Bitrate160 => [ + FileFormat::OGG_VORBIS_160, + FileFormat::OGG_VORBIS_96, + FileFormat::OGG_VORBIS_320, + ], + Bitrate::Bitrate320 => [ + FileFormat::OGG_VORBIS_320, + FileFormat::OGG_VORBIS_160, + FileFormat::OGG_VORBIS_96, + ], + }; + let format = formats + .iter() + .find(|format| audio.files.contains_key(format)) + .unwrap(); - fn load_track(&self, spotify_id: SpotifyId, position: i64) -> Option<(Decoder, f32)> { - let file_id = self.get_file_id(spotify_id).unwrap(); - info!("{:?} -> {:?}", spotify_id, file_id); + let file_id = match audio.files.get(&format) { + Some(&file_id) => file_id, + None => { + warn!("<{}> in not available in format {:?}", audio.name, format); + return None; + } + }; let key = self.session.audio_key().request(spotify_id, file_id); let encrypted_file = AudioFile::open(&self.session, file_id); @@ -619,9 +597,7 @@ impl PlayerInternal { Err(err) => error!("Vorbis error: {:?}", err), } } - - // info!("Track \"{}\" loaded", track.name); - + info!("<{}> loaded", audio.name); Some((decoder, normalisation_factor)) } } diff --git a/protocol/files.rs b/protocol/files.rs index f4ddd9ad..7086bd3d 100644 --- a/protocol/files.rs +++ b/protocol/files.rs @@ -3,7 +3,7 @@ pub const FILES: &'static [(&'static str, u32)] = &[ ("proto/authentication.proto", 2098196376), ("proto/keyexchange.proto", 451735664), ("proto/mercury.proto", 709993906), - ("proto/metadata.proto", 1409162985), + ("proto/metadata.proto", 334477813), ("proto/pubsub.proto", 2686584829), ("proto/spirc.proto", 1587493382), ]; diff --git a/protocol/proto/metadata.proto b/protocol/proto/metadata.proto index c3730ca7..c6c86ab6 100644 --- a/protocol/proto/metadata.proto +++ b/protocol/proto/metadata.proto @@ -207,6 +207,7 @@ enum MediaType { enum PassthroughEnum { UNKNOWN = 0; NONE = 1; + ALLOWED = 2; } message Episode { diff --git a/protocol/src/metadata.rs b/protocol/src/metadata.rs index 1a1a7f00..7d38e02d 100644 --- a/protocol/src/metadata.rs +++ b/protocol/src/metadata.rs @@ -8896,6 +8896,7 @@ impl ::protobuf::reflect::ProtobufValue for MediaType { pub enum PassthroughEnum { UNKNOWN = 0, NONE = 1, + ALLOWED = 2, } impl ::protobuf::ProtobufEnum for PassthroughEnum { @@ -8907,6 +8908,7 @@ impl ::protobuf::ProtobufEnum for PassthroughEnum { match value { 0 => ::std::option::Option::Some(PassthroughEnum::UNKNOWN), 1 => ::std::option::Option::Some(PassthroughEnum::NONE), + 2 => ::std::option::Option::Some(PassthroughEnum::ALLOWED), _ => ::std::option::Option::None } } @@ -8915,6 +8917,7 @@ impl ::protobuf::ProtobufEnum for PassthroughEnum { static values: &'static [PassthroughEnum] = &[ PassthroughEnum::UNKNOWN, PassthroughEnum::NONE, + PassthroughEnum::ALLOWED, ]; values } @@ -9057,9 +9060,9 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \rOriginalAudio\x12\x0e\n\x04uuid\x18\x01\x20\x01(\x0cB\0:\0*>\n\x10Cons\ umptionOrder\x12\x0e\n\nSEQUENTIAL\x10\x01\x12\x0c\n\x08EPISODIC\x10\x02\ \x12\n\n\x06RECENT\x10\x03\x1a\0*.\n\tMediaType\x12\t\n\x05MIXED\x10\0\ - \x12\t\n\x05AUDIO\x10\x01\x12\t\n\x05VIDEO\x10\x02\x1a\0**\n\x0fPassthro\ - ughEnum\x12\x0b\n\x07UNKNOWN\x10\0\x12\x08\n\x04NONE\x10\x01\x1a\0B\0b\ - \x06proto2\ + \x12\t\n\x05AUDIO\x10\x01\x12\t\n\x05VIDEO\x10\x02\x1a\0*7\n\x0fPassthro\ + ughEnum\x12\x0b\n\x07UNKNOWN\x10\0\x12\x08\n\x04NONE\x10\x01\x12\x0b\n\ + \x07ALLOWED\x10\x02\x1a\0B\0b\x06proto2\ "; static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { From 6786c093ad31a69e66ab6782287d4b4b7242bc9d Mon Sep 17 00:00:00 2001 From: ashthespy Date: Tue, 8 Oct 2019 19:20:18 +0200 Subject: [PATCH 04/43] Update `metadata.proto` --- protocol/files.rs | 9 - protocol/proto/metadata.proto | 91 +- protocol/src/metadata.rs | 1876 +++++++++++++++++++++++---------- 3 files changed, 1384 insertions(+), 592 deletions(-) delete mode 100644 protocol/files.rs diff --git a/protocol/files.rs b/protocol/files.rs deleted file mode 100644 index 7086bd3d..00000000 --- a/protocol/files.rs +++ /dev/null @@ -1,9 +0,0 @@ -// Autogenerated by build.rs -pub const FILES: &'static [(&'static str, u32)] = &[ - ("proto/authentication.proto", 2098196376), - ("proto/keyexchange.proto", 451735664), - ("proto/mercury.proto", 709993906), - ("proto/metadata.proto", 334477813), - ("proto/pubsub.proto", 2686584829), - ("proto/spirc.proto", 1587493382), -]; diff --git a/protocol/proto/metadata.proto b/protocol/proto/metadata.proto index c6c86ab6..3812f94e 100644 --- a/protocol/proto/metadata.proto +++ b/protocol/proto/metadata.proto @@ -39,6 +39,8 @@ message Date { optional sint32 year = 0x1; optional sint32 month = 0x2; optional sint32 day = 0x3; + optional sint32 hour = 0x4; + optional sint32 minute = 0x5; } message Album { @@ -124,15 +126,29 @@ message Copyright { } message Restriction { - optional string countries_allowed = 0x2; - optional string countries_forbidden = 0x3; - optional Type typ = 0x4; + enum Catalogue { + AD = 0; + SUBSCRIPTION = 1; + CATALOGUE_ALL = 2; + SHUFFLE = 3; + COMMERCIAL = 4; + } enum Type { STREAMING = 0x0; } + repeated Catalogue catalogue = 0x1; + optional string countries_allowed = 0x2; + optional string countries_forbidden = 0x3; + optional Type typ = 0x4; + repeated string catalogue_str = 0x5; } +message Availability { + repeated string catalogue_str = 0x1; + optional Date start = 0x2; +} + message SalePeriod { repeated Restriction restriction = 0x1; optional Date start = 0x2; @@ -156,6 +172,9 @@ message AudioFile { MP3_160 = 0x5; MP3_96 = 0x6; MP3_160_ENC = 0x7; + // v4 + // AAC_24 = 0x8; + // AAC_48 = 0x9; MP4_128_DUAL = 0x8; OTHER3 = 0x9; AAC_160 = 0xa; @@ -165,70 +184,74 @@ message AudioFile { } } -// Podcast Protos -message PublishTime { - optional sint32 year = 0x1; - optional sint32 month = 0x2; - optional sint32 day = 0x3; - // These seem to be differently encoded - optional sint32 minute = 0x5; - optional sint32 hour = 0x4; +message VideoFile { + optional bytes file_id = 1; } +// Podcast Protos message Show { + enum MediaType { + MIXED = 0; + AUDIO = 1; + VIDEO = 2; + } + enum ConsumptionOrder { + SEQUENTIAL = 1; + EPISODIC = 2; + RECENT = 3; + } + enum PassthroughEnum { + UNKNOWN = 0; + NONE = 1; + ALLOWED = 2; + } optional bytes gid = 0x1; optional string name = 0x2; - repeated Episode episode = 0x46; - // Educated guesses optional string description = 0x40; + optional sint32 deprecated_popularity = 0x41; optional string publisher = 0x42; optional string language = 0x43; optional bool explicit = 0x44; optional ImageGroup covers = 0x45; + repeated Episode episode = 0x46; + repeated Copyright copyright = 0x47; repeated Restriction restriction = 0x48; + repeated string keyword = 0x49; optional MediaType media_type = 0x4A; optional ConsumptionOrder consumption_order = 0x4B; optional bool interpret_restriction_using_geoip = 0x4C; + repeated Availability availability = 0x4E; optional string country_of_origin = 0x4F; repeated Category categories = 0x50; optional PassthroughEnum passthrough = 0x51; } -enum ConsumptionOrder { - SEQUENTIAL = 1; - EPISODIC = 2; - RECENT = 3; - } -enum MediaType { - MIXED = 0; - AUDIO = 1; - VIDEO = 2; -} -enum PassthroughEnum { - UNKNOWN = 0; - NONE = 1; - ALLOWED = 2; -} - message Episode { optional bytes gid = 0x1; optional string name = 0x2; optional sint32 duration = 0x7; optional sint32 popularity = 0x8; repeated AudioFile file = 0xc; - // Educated guesses optional string description = 0x40; + optional sint32 number = 0x41; optional Date publish_time = 0x42; + optional sint32 deprecated_popularity = 0x43; optional ImageGroup covers = 0x44; optional string language = 0x45; optional bool explicit = 0x46; optional Show show = 0x47; - repeated AudioFile preview = 0x4A; + repeated VideoFile video = 0x48; + repeated VideoFile video_preview = 0x49; + repeated AudioFile audio_preview = 0x4A; repeated Restriction restriction = 0x4B; - // Order of these flags might be wrong! + optional ImageGroup freeze_frame = 0x4C; + repeated string keyword = 0x4D; + // Order of these two flags might be wrong! optional bool suppress_monetization = 0x4E; - optional bool allow_background_playback = 0x4F; - optional bool interpret_restriction_using_geoip = 0x51; + optional bool interpret_restriction_using_geoip = 0x4F; + + optional bool allow_background_playback = 0x51; + repeated Availability availability = 0x52; optional string external_url = 0x53; optional OriginalAudio original_audio = 0x54; } diff --git a/protocol/src/metadata.rs b/protocol/src/metadata.rs index 7d38e02d..386213ab 100644 --- a/protocol/src/metadata.rs +++ b/protocol/src/metadata.rs @@ -1626,6 +1626,8 @@ pub struct Date { year: ::std::option::Option, month: ::std::option::Option, day: ::std::option::Option, + hour: ::std::option::Option, + minute: ::std::option::Option, // special fields pub unknown_fields: ::protobuf::UnknownFields, pub cached_size: ::protobuf::CachedSize, @@ -1698,6 +1700,44 @@ impl Date { pub fn set_day(&mut self, v: i32) { self.day = ::std::option::Option::Some(v); } + + // optional sint32 hour = 4; + + + pub fn get_hour(&self) -> i32 { + self.hour.unwrap_or(0) + } + pub fn clear_hour(&mut self) { + self.hour = ::std::option::Option::None; + } + + pub fn has_hour(&self) -> bool { + self.hour.is_some() + } + + // Param is passed by value, moved + pub fn set_hour(&mut self, v: i32) { + self.hour = ::std::option::Option::Some(v); + } + + // optional sint32 minute = 5; + + + pub fn get_minute(&self) -> i32 { + self.minute.unwrap_or(0) + } + pub fn clear_minute(&mut self) { + self.minute = ::std::option::Option::None; + } + + pub fn has_minute(&self) -> bool { + self.minute.is_some() + } + + // Param is passed by value, moved + pub fn set_minute(&mut self, v: i32) { + self.minute = ::std::option::Option::Some(v); + } } impl ::protobuf::Message for Date { @@ -1730,6 +1770,20 @@ impl ::protobuf::Message for Date { let tmp = is.read_sint32()?; self.day = ::std::option::Option::Some(tmp); }, + 4 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_sint32()?; + self.hour = ::std::option::Option::Some(tmp); + }, + 5 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_sint32()?; + self.minute = ::std::option::Option::Some(tmp); + }, _ => { ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; }, @@ -1751,6 +1805,12 @@ impl ::protobuf::Message for Date { if let Some(v) = self.day { my_size += ::protobuf::rt::value_varint_zigzag_size(3, v); } + if let Some(v) = self.hour { + my_size += ::protobuf::rt::value_varint_zigzag_size(4, v); + } + if let Some(v) = self.minute { + my_size += ::protobuf::rt::value_varint_zigzag_size(5, v); + } my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); my_size @@ -1766,6 +1826,12 @@ impl ::protobuf::Message for Date { if let Some(v) = self.day { os.write_sint32(3, v)?; } + if let Some(v) = self.hour { + os.write_sint32(4, v)?; + } + if let Some(v) = self.minute { + os.write_sint32(5, v)?; + } os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) } @@ -1823,6 +1889,16 @@ impl ::protobuf::Message for Date { |m: &Date| { &m.day }, |m: &mut Date| { &mut m.day }, )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeSint32>( + "hour", + |m: &Date| { &m.hour }, + |m: &mut Date| { &mut m.hour }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeSint32>( + "minute", + |m: &Date| { &m.minute }, + |m: &mut Date| { &mut m.minute }, + )); ::protobuf::reflect::MessageDescriptor::new::( "Date", fields, @@ -1848,6 +1924,8 @@ impl ::protobuf::Clear for Date { self.year = ::std::option::Option::None; self.month = ::std::option::Option::None; self.day = ::std::option::Option::None; + self.hour = ::std::option::Option::None; + self.minute = ::std::option::Option::None; self.unknown_fields.clear(); } } @@ -5042,6 +5120,7 @@ impl ::protobuf::reflect::ProtobufValue for Copyright_Type { #[derive(PartialEq,Clone,Default)] pub struct Restriction { // message fields + catalogue: ::std::vec::Vec, countries_allowed: ::protobuf::SingularField<::std::string::String>, countries_forbidden: ::protobuf::SingularField<::std::string::String>, typ: ::std::option::Option, @@ -5062,6 +5141,31 @@ impl Restriction { ::std::default::Default::default() } + // repeated .Restriction.Catalogue catalogue = 1; + + + pub fn get_catalogue(&self) -> &[Restriction_Catalogue] { + &self.catalogue + } + pub fn clear_catalogue(&mut self) { + self.catalogue.clear(); + } + + // Param is passed by value, moved + pub fn set_catalogue(&mut self, v: ::std::vec::Vec) { + self.catalogue = v; + } + + // Mutable pointer to the field. + pub fn mut_catalogue(&mut self) -> &mut ::std::vec::Vec { + &mut self.catalogue + } + + // Take field + pub fn take_catalogue(&mut self) -> ::std::vec::Vec { + ::std::mem::replace(&mut self.catalogue, ::std::vec::Vec::new()) + } + // optional string countries_allowed = 2; @@ -5188,6 +5292,9 @@ impl ::protobuf::Message for Restriction { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { + 1 => { + ::protobuf::rt::read_repeated_enum_with_unknown_fields_into(wire_type, is, &mut self.catalogue, 1, &mut self.unknown_fields)? + }, 2 => { ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.countries_allowed)?; }, @@ -5212,6 +5319,9 @@ impl ::protobuf::Message for Restriction { #[allow(unused_variables)] fn compute_size(&self) -> u32 { let mut my_size = 0; + for value in &self.catalogue { + my_size += ::protobuf::rt::enum_size(1, *value); + }; if let Some(ref v) = self.countries_allowed.as_ref() { my_size += ::protobuf::rt::string_size(2, &v); } @@ -5230,6 +5340,9 @@ impl ::protobuf::Message for Restriction { } fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + for v in &self.catalogue { + os.write_enum(1, v.value())?; + }; if let Some(ref v) = self.countries_allowed.as_ref() { os.write_string(2, &v)?; } @@ -5284,6 +5397,11 @@ impl ::protobuf::Message for Restriction { unsafe { descriptor.get(|| { let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_vec_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( + "catalogue", + |m: &Restriction| { &m.catalogue }, + |m: &mut Restriction| { &mut m.catalogue }, + )); fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( "countries_allowed", |m: &Restriction| { &m.countries_allowed }, @@ -5326,6 +5444,7 @@ impl ::protobuf::Message for Restriction { impl ::protobuf::Clear for Restriction { fn clear(&mut self) { + self.catalogue.clear(); self.countries_allowed.clear(); self.countries_forbidden.clear(); self.typ = ::std::option::Option::None; @@ -5346,6 +5465,70 @@ impl ::protobuf::reflect::ProtobufValue for Restriction { } } +#[derive(Clone,PartialEq,Eq,Debug,Hash)] +pub enum Restriction_Catalogue { + AD = 0, + SUBSCRIPTION = 1, + CATALOGUE_ALL = 2, + SHUFFLE = 3, + COMMERCIAL = 4, +} + +impl ::protobuf::ProtobufEnum for Restriction_Catalogue { + fn value(&self) -> i32 { + *self as i32 + } + + fn from_i32(value: i32) -> ::std::option::Option { + match value { + 0 => ::std::option::Option::Some(Restriction_Catalogue::AD), + 1 => ::std::option::Option::Some(Restriction_Catalogue::SUBSCRIPTION), + 2 => ::std::option::Option::Some(Restriction_Catalogue::CATALOGUE_ALL), + 3 => ::std::option::Option::Some(Restriction_Catalogue::SHUFFLE), + 4 => ::std::option::Option::Some(Restriction_Catalogue::COMMERCIAL), + _ => ::std::option::Option::None + } + } + + fn values() -> &'static [Self] { + static values: &'static [Restriction_Catalogue] = &[ + Restriction_Catalogue::AD, + Restriction_Catalogue::SUBSCRIPTION, + Restriction_Catalogue::CATALOGUE_ALL, + Restriction_Catalogue::SHUFFLE, + Restriction_Catalogue::COMMERCIAL, + ]; + values + } + + fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::EnumDescriptor, + }; + unsafe { + descriptor.get(|| { + ::protobuf::reflect::EnumDescriptor::new("Restriction_Catalogue", file_descriptor_proto()) + }) + } + } +} + +impl ::std::marker::Copy for Restriction_Catalogue { +} + +impl ::std::default::Default for Restriction_Catalogue { + fn default() -> Self { + Restriction_Catalogue::AD + } +} + +impl ::protobuf::reflect::ProtobufValue for Restriction_Catalogue { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Enum(self.descriptor()) + } +} + #[derive(Clone,PartialEq,Eq,Debug,Hash)] pub enum Restriction_Type { STREAMING = 0, @@ -5398,6 +5581,231 @@ impl ::protobuf::reflect::ProtobufValue for Restriction_Type { } } +#[derive(PartialEq,Clone,Default)] +pub struct Availability { + // message fields + catalogue_str: ::protobuf::RepeatedField<::std::string::String>, + start: ::protobuf::SingularPtrField, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a Availability { + fn default() -> &'a Availability { + ::default_instance() + } +} + +impl Availability { + pub fn new() -> Availability { + ::std::default::Default::default() + } + + // repeated string catalogue_str = 1; + + + pub fn get_catalogue_str(&self) -> &[::std::string::String] { + &self.catalogue_str + } + pub fn clear_catalogue_str(&mut self) { + self.catalogue_str.clear(); + } + + // Param is passed by value, moved + pub fn set_catalogue_str(&mut self, v: ::protobuf::RepeatedField<::std::string::String>) { + self.catalogue_str = v; + } + + // Mutable pointer to the field. + pub fn mut_catalogue_str(&mut self) -> &mut ::protobuf::RepeatedField<::std::string::String> { + &mut self.catalogue_str + } + + // Take field + pub fn take_catalogue_str(&mut self) -> ::protobuf::RepeatedField<::std::string::String> { + ::std::mem::replace(&mut self.catalogue_str, ::protobuf::RepeatedField::new()) + } + + // optional .Date start = 2; + + + pub fn get_start(&self) -> &Date { + self.start.as_ref().unwrap_or_else(|| Date::default_instance()) + } + pub fn clear_start(&mut self) { + self.start.clear(); + } + + pub fn has_start(&self) -> bool { + self.start.is_some() + } + + // Param is passed by value, moved + pub fn set_start(&mut self, v: Date) { + self.start = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_start(&mut self) -> &mut Date { + if self.start.is_none() { + self.start.set_default(); + } + self.start.as_mut().unwrap() + } + + // Take field + pub fn take_start(&mut self) -> Date { + self.start.take().unwrap_or_else(|| Date::new()) + } +} + +impl ::protobuf::Message for Availability { + fn is_initialized(&self) -> bool { + for v in &self.start { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_repeated_string_into(wire_type, is, &mut self.catalogue_str)?; + }, + 2 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.start)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + for value in &self.catalogue_str { + my_size += ::protobuf::rt::string_size(1, &value); + }; + if let Some(ref v) = self.start.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + for v in &self.catalogue_str { + os.write_string(1, &v)?; + }; + if let Some(ref v) = self.start.as_ref() { + os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> Availability { + Availability::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "catalogue_str", + |m: &Availability| { &m.catalogue_str }, + |m: &mut Availability| { &mut m.catalogue_str }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "start", + |m: &Availability| { &m.start }, + |m: &mut Availability| { &mut m.start }, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "Availability", + fields, + file_descriptor_proto() + ) + }) + } + } + + fn default_instance() -> &'static Availability { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const Availability, + }; + unsafe { + instance.get(Availability::new) + } + } +} + +impl ::protobuf::Clear for Availability { + fn clear(&mut self) { + self.catalogue_str.clear(); + self.start.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for Availability { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for Availability { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Message(self) + } +} + #[derive(PartialEq,Clone,Default)] pub struct SalePeriod { // message fields @@ -6225,126 +6633,63 @@ impl ::protobuf::reflect::ProtobufValue for AudioFile_Format { } #[derive(PartialEq,Clone,Default)] -pub struct PublishTime { +pub struct VideoFile { // message fields - year: ::std::option::Option, - month: ::std::option::Option, - day: ::std::option::Option, - minute: ::std::option::Option, - hour: ::std::option::Option, + file_id: ::protobuf::SingularField<::std::vec::Vec>, // special fields pub unknown_fields: ::protobuf::UnknownFields, pub cached_size: ::protobuf::CachedSize, } -impl<'a> ::std::default::Default for &'a PublishTime { - fn default() -> &'a PublishTime { - ::default_instance() +impl<'a> ::std::default::Default for &'a VideoFile { + fn default() -> &'a VideoFile { + ::default_instance() } } -impl PublishTime { - pub fn new() -> PublishTime { +impl VideoFile { + pub fn new() -> VideoFile { ::std::default::Default::default() } - // optional sint32 year = 1; + // optional bytes file_id = 1; - pub fn get_year(&self) -> i32 { - self.year.unwrap_or(0) + pub fn get_file_id(&self) -> &[u8] { + match self.file_id.as_ref() { + Some(v) => &v, + None => &[], + } } - pub fn clear_year(&mut self) { - self.year = ::std::option::Option::None; + pub fn clear_file_id(&mut self) { + self.file_id.clear(); } - pub fn has_year(&self) -> bool { - self.year.is_some() + pub fn has_file_id(&self) -> bool { + self.file_id.is_some() } // Param is passed by value, moved - pub fn set_year(&mut self, v: i32) { - self.year = ::std::option::Option::Some(v); + pub fn set_file_id(&mut self, v: ::std::vec::Vec) { + self.file_id = ::protobuf::SingularField::some(v); } - // optional sint32 month = 2; - - - pub fn get_month(&self) -> i32 { - self.month.unwrap_or(0) - } - pub fn clear_month(&mut self) { - self.month = ::std::option::Option::None; + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_file_id(&mut self) -> &mut ::std::vec::Vec { + if self.file_id.is_none() { + self.file_id.set_default(); + } + self.file_id.as_mut().unwrap() } - pub fn has_month(&self) -> bool { - self.month.is_some() - } - - // Param is passed by value, moved - pub fn set_month(&mut self, v: i32) { - self.month = ::std::option::Option::Some(v); - } - - // optional sint32 day = 3; - - - pub fn get_day(&self) -> i32 { - self.day.unwrap_or(0) - } - pub fn clear_day(&mut self) { - self.day = ::std::option::Option::None; - } - - pub fn has_day(&self) -> bool { - self.day.is_some() - } - - // Param is passed by value, moved - pub fn set_day(&mut self, v: i32) { - self.day = ::std::option::Option::Some(v); - } - - // optional sint32 minute = 5; - - - pub fn get_minute(&self) -> i32 { - self.minute.unwrap_or(0) - } - pub fn clear_minute(&mut self) { - self.minute = ::std::option::Option::None; - } - - pub fn has_minute(&self) -> bool { - self.minute.is_some() - } - - // Param is passed by value, moved - pub fn set_minute(&mut self, v: i32) { - self.minute = ::std::option::Option::Some(v); - } - - // optional sint32 hour = 4; - - - pub fn get_hour(&self) -> i32 { - self.hour.unwrap_or(0) - } - pub fn clear_hour(&mut self) { - self.hour = ::std::option::Option::None; - } - - pub fn has_hour(&self) -> bool { - self.hour.is_some() - } - - // Param is passed by value, moved - pub fn set_hour(&mut self, v: i32) { - self.hour = ::std::option::Option::Some(v); + // Take field + pub fn take_file_id(&mut self) -> ::std::vec::Vec { + self.file_id.take().unwrap_or_else(|| ::std::vec::Vec::new()) } } -impl ::protobuf::Message for PublishTime { +impl ::protobuf::Message for VideoFile { fn is_initialized(&self) -> bool { true } @@ -6354,39 +6699,7 @@ impl ::protobuf::Message for PublishTime { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { 1 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_sint32()?; - self.year = ::std::option::Option::Some(tmp); - }, - 2 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_sint32()?; - self.month = ::std::option::Option::Some(tmp); - }, - 3 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_sint32()?; - self.day = ::std::option::Option::Some(tmp); - }, - 5 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_sint32()?; - self.minute = ::std::option::Option::Some(tmp); - }, - 4 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_sint32()?; - self.hour = ::std::option::Option::Some(tmp); + ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.file_id)?; }, _ => { ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; @@ -6400,20 +6713,8 @@ impl ::protobuf::Message for PublishTime { #[allow(unused_variables)] fn compute_size(&self) -> u32 { let mut my_size = 0; - if let Some(v) = self.year { - my_size += ::protobuf::rt::value_varint_zigzag_size(1, v); - } - if let Some(v) = self.month { - my_size += ::protobuf::rt::value_varint_zigzag_size(2, v); - } - if let Some(v) = self.day { - my_size += ::protobuf::rt::value_varint_zigzag_size(3, v); - } - if let Some(v) = self.minute { - my_size += ::protobuf::rt::value_varint_zigzag_size(5, v); - } - if let Some(v) = self.hour { - my_size += ::protobuf::rt::value_varint_zigzag_size(4, v); + if let Some(ref v) = self.file_id.as_ref() { + my_size += ::protobuf::rt::bytes_size(1, &v); } my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); @@ -6421,20 +6722,8 @@ impl ::protobuf::Message for PublishTime { } fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { - if let Some(v) = self.year { - os.write_sint32(1, v)?; - } - if let Some(v) = self.month { - os.write_sint32(2, v)?; - } - if let Some(v) = self.day { - os.write_sint32(3, v)?; - } - if let Some(v) = self.minute { - os.write_sint32(5, v)?; - } - if let Some(v) = self.hour { - os.write_sint32(4, v)?; + if let Some(ref v) = self.file_id.as_ref() { + os.write_bytes(1, &v)?; } os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) @@ -6466,8 +6755,8 @@ impl ::protobuf::Message for PublishTime { Self::descriptor_static() } - fn new() -> PublishTime { - PublishTime::new() + fn new() -> VideoFile { + VideoFile::new() } fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { @@ -6478,33 +6767,13 @@ impl ::protobuf::Message for PublishTime { unsafe { descriptor.get(|| { let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeSint32>( - "year", - |m: &PublishTime| { &m.year }, - |m: &mut PublishTime| { &mut m.year }, + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( + "file_id", + |m: &VideoFile| { &m.file_id }, + |m: &mut VideoFile| { &mut m.file_id }, )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeSint32>( - "month", - |m: &PublishTime| { &m.month }, - |m: &mut PublishTime| { &mut m.month }, - )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeSint32>( - "day", - |m: &PublishTime| { &m.day }, - |m: &mut PublishTime| { &mut m.day }, - )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeSint32>( - "minute", - |m: &PublishTime| { &m.minute }, - |m: &mut PublishTime| { &mut m.minute }, - )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeSint32>( - "hour", - |m: &PublishTime| { &m.hour }, - |m: &mut PublishTime| { &mut m.hour }, - )); - ::protobuf::reflect::MessageDescriptor::new::( - "PublishTime", + ::protobuf::reflect::MessageDescriptor::new::( + "VideoFile", fields, file_descriptor_proto() ) @@ -6512,35 +6781,31 @@ impl ::protobuf::Message for PublishTime { } } - fn default_instance() -> &'static PublishTime { - static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + fn default_instance() -> &'static VideoFile { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const PublishTime, + ptr: 0 as *const VideoFile, }; unsafe { - instance.get(PublishTime::new) + instance.get(VideoFile::new) } } } -impl ::protobuf::Clear for PublishTime { +impl ::protobuf::Clear for VideoFile { fn clear(&mut self) { - self.year = ::std::option::Option::None; - self.month = ::std::option::Option::None; - self.day = ::std::option::Option::None; - self.minute = ::std::option::Option::None; - self.hour = ::std::option::Option::None; + self.file_id.clear(); self.unknown_fields.clear(); } } -impl ::std::fmt::Debug for PublishTime { +impl ::std::fmt::Debug for VideoFile { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } -impl ::protobuf::reflect::ProtobufValue for PublishTime { +impl ::protobuf::reflect::ProtobufValue for VideoFile { fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { ::protobuf::reflect::ProtobufValueRef::Message(self) } @@ -6551,19 +6816,23 @@ pub struct Show { // message fields gid: ::protobuf::SingularField<::std::vec::Vec>, name: ::protobuf::SingularField<::std::string::String>, - episode: ::protobuf::RepeatedField, description: ::protobuf::SingularField<::std::string::String>, + deprecated_popularity: ::std::option::Option, publisher: ::protobuf::SingularField<::std::string::String>, language: ::protobuf::SingularField<::std::string::String>, explicit: ::std::option::Option, covers: ::protobuf::SingularPtrField, + episode: ::protobuf::RepeatedField, + copyright: ::protobuf::RepeatedField, restriction: ::protobuf::RepeatedField, - media_type: ::std::option::Option, - consumption_order: ::std::option::Option, + keyword: ::protobuf::RepeatedField<::std::string::String>, + media_type: ::std::option::Option, + consumption_order: ::std::option::Option, interpret_restriction_using_geoip: ::std::option::Option, + availability: ::protobuf::RepeatedField, country_of_origin: ::protobuf::SingularField<::std::string::String>, categories: ::protobuf::RepeatedField, - passthrough: ::std::option::Option, + passthrough: ::std::option::Option, // special fields pub unknown_fields: ::protobuf::UnknownFields, pub cached_size: ::protobuf::CachedSize, @@ -6652,31 +6921,6 @@ impl Show { self.name.take().unwrap_or_else(|| ::std::string::String::new()) } - // repeated .Episode episode = 70; - - - pub fn get_episode(&self) -> &[Episode] { - &self.episode - } - pub fn clear_episode(&mut self) { - self.episode.clear(); - } - - // Param is passed by value, moved - pub fn set_episode(&mut self, v: ::protobuf::RepeatedField) { - self.episode = v; - } - - // Mutable pointer to the field. - pub fn mut_episode(&mut self) -> &mut ::protobuf::RepeatedField { - &mut self.episode - } - - // Take field - pub fn take_episode(&mut self) -> ::protobuf::RepeatedField { - ::std::mem::replace(&mut self.episode, ::protobuf::RepeatedField::new()) - } - // optional string description = 64; @@ -6713,6 +6957,25 @@ impl Show { self.description.take().unwrap_or_else(|| ::std::string::String::new()) } + // optional sint32 deprecated_popularity = 65; + + + pub fn get_deprecated_popularity(&self) -> i32 { + self.deprecated_popularity.unwrap_or(0) + } + pub fn clear_deprecated_popularity(&mut self) { + self.deprecated_popularity = ::std::option::Option::None; + } + + pub fn has_deprecated_popularity(&self) -> bool { + self.deprecated_popularity.is_some() + } + + // Param is passed by value, moved + pub fn set_deprecated_popularity(&mut self, v: i32) { + self.deprecated_popularity = ::std::option::Option::Some(v); + } + // optional string publisher = 66; @@ -6837,6 +7100,56 @@ impl Show { self.covers.take().unwrap_or_else(|| ImageGroup::new()) } + // repeated .Episode episode = 70; + + + pub fn get_episode(&self) -> &[Episode] { + &self.episode + } + pub fn clear_episode(&mut self) { + self.episode.clear(); + } + + // Param is passed by value, moved + pub fn set_episode(&mut self, v: ::protobuf::RepeatedField) { + self.episode = v; + } + + // Mutable pointer to the field. + pub fn mut_episode(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.episode + } + + // Take field + pub fn take_episode(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.episode, ::protobuf::RepeatedField::new()) + } + + // repeated .Copyright copyright = 71; + + + pub fn get_copyright(&self) -> &[Copyright] { + &self.copyright + } + pub fn clear_copyright(&mut self) { + self.copyright.clear(); + } + + // Param is passed by value, moved + pub fn set_copyright(&mut self, v: ::protobuf::RepeatedField) { + self.copyright = v; + } + + // Mutable pointer to the field. + pub fn mut_copyright(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.copyright + } + + // Take field + pub fn take_copyright(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.copyright, ::protobuf::RepeatedField::new()) + } + // repeated .Restriction restriction = 72; @@ -6862,11 +7175,36 @@ impl Show { ::std::mem::replace(&mut self.restriction, ::protobuf::RepeatedField::new()) } - // optional .MediaType media_type = 74; + // repeated string keyword = 73; - pub fn get_media_type(&self) -> MediaType { - self.media_type.unwrap_or(MediaType::MIXED) + pub fn get_keyword(&self) -> &[::std::string::String] { + &self.keyword + } + pub fn clear_keyword(&mut self) { + self.keyword.clear(); + } + + // Param is passed by value, moved + pub fn set_keyword(&mut self, v: ::protobuf::RepeatedField<::std::string::String>) { + self.keyword = v; + } + + // Mutable pointer to the field. + pub fn mut_keyword(&mut self) -> &mut ::protobuf::RepeatedField<::std::string::String> { + &mut self.keyword + } + + // Take field + pub fn take_keyword(&mut self) -> ::protobuf::RepeatedField<::std::string::String> { + ::std::mem::replace(&mut self.keyword, ::protobuf::RepeatedField::new()) + } + + // optional .Show.MediaType media_type = 74; + + + pub fn get_media_type(&self) -> Show_MediaType { + self.media_type.unwrap_or(Show_MediaType::MIXED) } pub fn clear_media_type(&mut self) { self.media_type = ::std::option::Option::None; @@ -6877,15 +7215,15 @@ impl Show { } // Param is passed by value, moved - pub fn set_media_type(&mut self, v: MediaType) { + pub fn set_media_type(&mut self, v: Show_MediaType) { self.media_type = ::std::option::Option::Some(v); } - // optional .ConsumptionOrder consumption_order = 75; + // optional .Show.ConsumptionOrder consumption_order = 75; - pub fn get_consumption_order(&self) -> ConsumptionOrder { - self.consumption_order.unwrap_or(ConsumptionOrder::SEQUENTIAL) + pub fn get_consumption_order(&self) -> Show_ConsumptionOrder { + self.consumption_order.unwrap_or(Show_ConsumptionOrder::SEQUENTIAL) } pub fn clear_consumption_order(&mut self) { self.consumption_order = ::std::option::Option::None; @@ -6896,7 +7234,7 @@ impl Show { } // Param is passed by value, moved - pub fn set_consumption_order(&mut self, v: ConsumptionOrder) { + pub fn set_consumption_order(&mut self, v: Show_ConsumptionOrder) { self.consumption_order = ::std::option::Option::Some(v); } @@ -6919,6 +7257,31 @@ impl Show { self.interpret_restriction_using_geoip = ::std::option::Option::Some(v); } + // repeated .Availability availability = 78; + + + pub fn get_availability(&self) -> &[Availability] { + &self.availability + } + pub fn clear_availability(&mut self) { + self.availability.clear(); + } + + // Param is passed by value, moved + pub fn set_availability(&mut self, v: ::protobuf::RepeatedField) { + self.availability = v; + } + + // Mutable pointer to the field. + pub fn mut_availability(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.availability + } + + // Take field + pub fn take_availability(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.availability, ::protobuf::RepeatedField::new()) + } + // optional string country_of_origin = 79; @@ -6980,11 +7343,11 @@ impl Show { ::std::mem::replace(&mut self.categories, ::protobuf::RepeatedField::new()) } - // optional .PassthroughEnum passthrough = 81; + // optional .Show.PassthroughEnum passthrough = 81; - pub fn get_passthrough(&self) -> PassthroughEnum { - self.passthrough.unwrap_or(PassthroughEnum::UNKNOWN) + pub fn get_passthrough(&self) -> Show_PassthroughEnum { + self.passthrough.unwrap_or(Show_PassthroughEnum::UNKNOWN) } pub fn clear_passthrough(&mut self) { self.passthrough = ::std::option::Option::None; @@ -6995,28 +7358,38 @@ impl Show { } // Param is passed by value, moved - pub fn set_passthrough(&mut self, v: PassthroughEnum) { + pub fn set_passthrough(&mut self, v: Show_PassthroughEnum) { self.passthrough = ::std::option::Option::Some(v); } } impl ::protobuf::Message for Show { fn is_initialized(&self) -> bool { - for v in &self.episode { - if !v.is_initialized() { - return false; - } - }; for v in &self.covers { if !v.is_initialized() { return false; } }; + for v in &self.episode { + if !v.is_initialized() { + return false; + } + }; + for v in &self.copyright { + if !v.is_initialized() { + return false; + } + }; for v in &self.restriction { if !v.is_initialized() { return false; } }; + for v in &self.availability { + if !v.is_initialized() { + return false; + } + }; for v in &self.categories { if !v.is_initialized() { return false; @@ -7035,12 +7408,16 @@ impl ::protobuf::Message for Show { 2 => { ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.name)?; }, - 70 => { - ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.episode)?; - }, 64 => { ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.description)?; }, + 65 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_sint32()?; + self.deprecated_popularity = ::std::option::Option::Some(tmp); + }, 66 => { ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.publisher)?; }, @@ -7057,9 +7434,18 @@ impl ::protobuf::Message for Show { 69 => { ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.covers)?; }, + 70 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.episode)?; + }, + 71 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.copyright)?; + }, 72 => { ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.restriction)?; }, + 73 => { + ::protobuf::rt::read_repeated_string_into(wire_type, is, &mut self.keyword)?; + }, 74 => { ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.media_type, 74, &mut self.unknown_fields)? }, @@ -7073,6 +7459,9 @@ impl ::protobuf::Message for Show { let tmp = is.read_bool()?; self.interpret_restriction_using_geoip = ::std::option::Option::Some(tmp); }, + 78 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.availability)?; + }, 79 => { ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.country_of_origin)?; }, @@ -7100,13 +7489,12 @@ impl ::protobuf::Message for Show { if let Some(ref v) = self.name.as_ref() { my_size += ::protobuf::rt::string_size(2, &v); } - for value in &self.episode { - let len = value.compute_size(); - my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; - }; if let Some(ref v) = self.description.as_ref() { my_size += ::protobuf::rt::string_size(64, &v); } + if let Some(v) = self.deprecated_popularity { + my_size += ::protobuf::rt::value_varint_zigzag_size(65, v); + } if let Some(ref v) = self.publisher.as_ref() { my_size += ::protobuf::rt::string_size(66, &v); } @@ -7120,10 +7508,21 @@ impl ::protobuf::Message for Show { let len = v.compute_size(); my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; } + for value in &self.episode { + let len = value.compute_size(); + my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + for value in &self.copyright { + let len = value.compute_size(); + my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; for value in &self.restriction { let len = value.compute_size(); my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; }; + for value in &self.keyword { + my_size += ::protobuf::rt::string_size(73, &value); + }; if let Some(v) = self.media_type { my_size += ::protobuf::rt::enum_size(74, v); } @@ -7133,6 +7532,10 @@ impl ::protobuf::Message for Show { if let Some(v) = self.interpret_restriction_using_geoip { my_size += 3; } + for value in &self.availability { + let len = value.compute_size(); + my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; if let Some(ref v) = self.country_of_origin.as_ref() { my_size += ::protobuf::rt::string_size(79, &v); } @@ -7155,14 +7558,12 @@ impl ::protobuf::Message for Show { if let Some(ref v) = self.name.as_ref() { os.write_string(2, &v)?; } - for v in &self.episode { - os.write_tag(70, ::protobuf::wire_format::WireTypeLengthDelimited)?; - os.write_raw_varint32(v.get_cached_size())?; - v.write_to_with_cached_sizes(os)?; - }; if let Some(ref v) = self.description.as_ref() { os.write_string(64, &v)?; } + if let Some(v) = self.deprecated_popularity { + os.write_sint32(65, v)?; + } if let Some(ref v) = self.publisher.as_ref() { os.write_string(66, &v)?; } @@ -7177,11 +7578,24 @@ impl ::protobuf::Message for Show { os.write_raw_varint32(v.get_cached_size())?; v.write_to_with_cached_sizes(os)?; } + for v in &self.episode { + os.write_tag(70, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + for v in &self.copyright { + os.write_tag(71, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; for v in &self.restriction { os.write_tag(72, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; v.write_to_with_cached_sizes(os)?; }; + for v in &self.keyword { + os.write_string(73, &v)?; + }; if let Some(v) = self.media_type { os.write_enum(74, v.value())?; } @@ -7191,6 +7605,11 @@ impl ::protobuf::Message for Show { if let Some(v) = self.interpret_restriction_using_geoip { os.write_bool(76, v)?; } + for v in &self.availability { + os.write_tag(78, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; if let Some(ref v) = self.country_of_origin.as_ref() { os.write_string(79, &v)?; } @@ -7254,16 +7673,16 @@ impl ::protobuf::Message for Show { |m: &Show| { &m.name }, |m: &mut Show| { &mut m.name }, )); - fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( - "episode", - |m: &Show| { &m.episode }, - |m: &mut Show| { &mut m.episode }, - )); fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( "description", |m: &Show| { &m.description }, |m: &mut Show| { &mut m.description }, )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeSint32>( + "deprecated_popularity", + |m: &Show| { &m.deprecated_popularity }, + |m: &mut Show| { &mut m.deprecated_popularity }, + )); fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( "publisher", |m: &Show| { &m.publisher }, @@ -7284,17 +7703,32 @@ impl ::protobuf::Message for Show { |m: &Show| { &m.covers }, |m: &mut Show| { &mut m.covers }, )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "episode", + |m: &Show| { &m.episode }, + |m: &mut Show| { &mut m.episode }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "copyright", + |m: &Show| { &m.copyright }, + |m: &mut Show| { &mut m.copyright }, + )); fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( "restriction", |m: &Show| { &m.restriction }, |m: &mut Show| { &mut m.restriction }, )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "keyword", + |m: &Show| { &m.keyword }, + |m: &mut Show| { &mut m.keyword }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( "media_type", |m: &Show| { &m.media_type }, |m: &mut Show| { &mut m.media_type }, )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( "consumption_order", |m: &Show| { &m.consumption_order }, |m: &mut Show| { &mut m.consumption_order }, @@ -7304,6 +7738,11 @@ impl ::protobuf::Message for Show { |m: &Show| { &m.interpret_restriction_using_geoip }, |m: &mut Show| { &mut m.interpret_restriction_using_geoip }, )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "availability", + |m: &Show| { &m.availability }, + |m: &mut Show| { &mut m.availability }, + )); fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( "country_of_origin", |m: &Show| { &m.country_of_origin }, @@ -7314,7 +7753,7 @@ impl ::protobuf::Message for Show { |m: &Show| { &m.categories }, |m: &mut Show| { &mut m.categories }, )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( "passthrough", |m: &Show| { &m.passthrough }, |m: &mut Show| { &mut m.passthrough }, @@ -7343,16 +7782,20 @@ impl ::protobuf::Clear for Show { fn clear(&mut self) { self.gid.clear(); self.name.clear(); - self.episode.clear(); self.description.clear(); + self.deprecated_popularity = ::std::option::Option::None; self.publisher.clear(); self.language.clear(); self.explicit = ::std::option::Option::None; self.covers.clear(); + self.episode.clear(); + self.copyright.clear(); self.restriction.clear(); + self.keyword.clear(); self.media_type = ::std::option::Option::None; self.consumption_order = ::std::option::Option::None; self.interpret_restriction_using_geoip = ::std::option::Option::None; + self.availability.clear(); self.country_of_origin.clear(); self.categories.clear(); self.passthrough = ::std::option::Option::None; @@ -7372,6 +7815,181 @@ impl ::protobuf::reflect::ProtobufValue for Show { } } +#[derive(Clone,PartialEq,Eq,Debug,Hash)] +pub enum Show_MediaType { + MIXED = 0, + AUDIO = 1, + VIDEO = 2, +} + +impl ::protobuf::ProtobufEnum for Show_MediaType { + fn value(&self) -> i32 { + *self as i32 + } + + fn from_i32(value: i32) -> ::std::option::Option { + match value { + 0 => ::std::option::Option::Some(Show_MediaType::MIXED), + 1 => ::std::option::Option::Some(Show_MediaType::AUDIO), + 2 => ::std::option::Option::Some(Show_MediaType::VIDEO), + _ => ::std::option::Option::None + } + } + + fn values() -> &'static [Self] { + static values: &'static [Show_MediaType] = &[ + Show_MediaType::MIXED, + Show_MediaType::AUDIO, + Show_MediaType::VIDEO, + ]; + values + } + + fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::EnumDescriptor, + }; + unsafe { + descriptor.get(|| { + ::protobuf::reflect::EnumDescriptor::new("Show_MediaType", file_descriptor_proto()) + }) + } + } +} + +impl ::std::marker::Copy for Show_MediaType { +} + +impl ::std::default::Default for Show_MediaType { + fn default() -> Self { + Show_MediaType::MIXED + } +} + +impl ::protobuf::reflect::ProtobufValue for Show_MediaType { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Enum(self.descriptor()) + } +} + +#[derive(Clone,PartialEq,Eq,Debug,Hash)] +pub enum Show_ConsumptionOrder { + SEQUENTIAL = 1, + EPISODIC = 2, + RECENT = 3, +} + +impl ::protobuf::ProtobufEnum for Show_ConsumptionOrder { + fn value(&self) -> i32 { + *self as i32 + } + + fn from_i32(value: i32) -> ::std::option::Option { + match value { + 1 => ::std::option::Option::Some(Show_ConsumptionOrder::SEQUENTIAL), + 2 => ::std::option::Option::Some(Show_ConsumptionOrder::EPISODIC), + 3 => ::std::option::Option::Some(Show_ConsumptionOrder::RECENT), + _ => ::std::option::Option::None + } + } + + fn values() -> &'static [Self] { + static values: &'static [Show_ConsumptionOrder] = &[ + Show_ConsumptionOrder::SEQUENTIAL, + Show_ConsumptionOrder::EPISODIC, + Show_ConsumptionOrder::RECENT, + ]; + values + } + + fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::EnumDescriptor, + }; + unsafe { + descriptor.get(|| { + ::protobuf::reflect::EnumDescriptor::new("Show_ConsumptionOrder", file_descriptor_proto()) + }) + } + } +} + +impl ::std::marker::Copy for Show_ConsumptionOrder { +} + +// Note, `Default` is implemented although default value is not 0 +impl ::std::default::Default for Show_ConsumptionOrder { + fn default() -> Self { + Show_ConsumptionOrder::SEQUENTIAL + } +} + +impl ::protobuf::reflect::ProtobufValue for Show_ConsumptionOrder { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Enum(self.descriptor()) + } +} + +#[derive(Clone,PartialEq,Eq,Debug,Hash)] +pub enum Show_PassthroughEnum { + UNKNOWN = 0, + NONE = 1, + ALLOWED = 2, +} + +impl ::protobuf::ProtobufEnum for Show_PassthroughEnum { + fn value(&self) -> i32 { + *self as i32 + } + + fn from_i32(value: i32) -> ::std::option::Option { + match value { + 0 => ::std::option::Option::Some(Show_PassthroughEnum::UNKNOWN), + 1 => ::std::option::Option::Some(Show_PassthroughEnum::NONE), + 2 => ::std::option::Option::Some(Show_PassthroughEnum::ALLOWED), + _ => ::std::option::Option::None + } + } + + fn values() -> &'static [Self] { + static values: &'static [Show_PassthroughEnum] = &[ + Show_PassthroughEnum::UNKNOWN, + Show_PassthroughEnum::NONE, + Show_PassthroughEnum::ALLOWED, + ]; + values + } + + fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::EnumDescriptor, + }; + unsafe { + descriptor.get(|| { + ::protobuf::reflect::EnumDescriptor::new("Show_PassthroughEnum", file_descriptor_proto()) + }) + } + } +} + +impl ::std::marker::Copy for Show_PassthroughEnum { +} + +impl ::std::default::Default for Show_PassthroughEnum { + fn default() -> Self { + Show_PassthroughEnum::UNKNOWN + } +} + +impl ::protobuf::reflect::ProtobufValue for Show_PassthroughEnum { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Enum(self.descriptor()) + } +} + #[derive(PartialEq,Clone,Default)] pub struct Episode { // message fields @@ -7381,16 +7999,23 @@ pub struct Episode { popularity: ::std::option::Option, file: ::protobuf::RepeatedField, description: ::protobuf::SingularField<::std::string::String>, + number: ::std::option::Option, publish_time: ::protobuf::SingularPtrField, + deprecated_popularity: ::std::option::Option, covers: ::protobuf::SingularPtrField, language: ::protobuf::SingularField<::std::string::String>, explicit: ::std::option::Option, show: ::protobuf::SingularPtrField, - preview: ::protobuf::RepeatedField, + video: ::protobuf::RepeatedField, + video_preview: ::protobuf::RepeatedField, + audio_preview: ::protobuf::RepeatedField, restriction: ::protobuf::RepeatedField, + freeze_frame: ::protobuf::SingularPtrField, + keyword: ::protobuf::RepeatedField<::std::string::String>, suppress_monetization: ::std::option::Option, - allow_background_playback: ::std::option::Option, interpret_restriction_using_geoip: ::std::option::Option, + allow_background_playback: ::std::option::Option, + availability: ::protobuf::RepeatedField, external_url: ::protobuf::SingularField<::std::string::String>, original_audio: ::protobuf::SingularPtrField, // special fields @@ -7580,6 +8205,25 @@ impl Episode { self.description.take().unwrap_or_else(|| ::std::string::String::new()) } + // optional sint32 number = 65; + + + pub fn get_number(&self) -> i32 { + self.number.unwrap_or(0) + } + pub fn clear_number(&mut self) { + self.number = ::std::option::Option::None; + } + + pub fn has_number(&self) -> bool { + self.number.is_some() + } + + // Param is passed by value, moved + pub fn set_number(&mut self, v: i32) { + self.number = ::std::option::Option::Some(v); + } + // optional .Date publish_time = 66; @@ -7613,6 +8257,25 @@ impl Episode { self.publish_time.take().unwrap_or_else(|| Date::new()) } + // optional sint32 deprecated_popularity = 67; + + + pub fn get_deprecated_popularity(&self) -> i32 { + self.deprecated_popularity.unwrap_or(0) + } + pub fn clear_deprecated_popularity(&mut self) { + self.deprecated_popularity = ::std::option::Option::None; + } + + pub fn has_deprecated_popularity(&self) -> bool { + self.deprecated_popularity.is_some() + } + + // Param is passed by value, moved + pub fn set_deprecated_popularity(&mut self, v: i32) { + self.deprecated_popularity = ::std::option::Option::Some(v); + } + // optional .ImageGroup covers = 68; @@ -7734,29 +8397,79 @@ impl Episode { self.show.take().unwrap_or_else(|| Show::new()) } - // repeated .AudioFile preview = 74; + // repeated .VideoFile video = 72; - pub fn get_preview(&self) -> &[AudioFile] { - &self.preview + pub fn get_video(&self) -> &[VideoFile] { + &self.video } - pub fn clear_preview(&mut self) { - self.preview.clear(); + pub fn clear_video(&mut self) { + self.video.clear(); } // Param is passed by value, moved - pub fn set_preview(&mut self, v: ::protobuf::RepeatedField) { - self.preview = v; + pub fn set_video(&mut self, v: ::protobuf::RepeatedField) { + self.video = v; } // Mutable pointer to the field. - pub fn mut_preview(&mut self) -> &mut ::protobuf::RepeatedField { - &mut self.preview + pub fn mut_video(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.video } // Take field - pub fn take_preview(&mut self) -> ::protobuf::RepeatedField { - ::std::mem::replace(&mut self.preview, ::protobuf::RepeatedField::new()) + pub fn take_video(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.video, ::protobuf::RepeatedField::new()) + } + + // repeated .VideoFile video_preview = 73; + + + pub fn get_video_preview(&self) -> &[VideoFile] { + &self.video_preview + } + pub fn clear_video_preview(&mut self) { + self.video_preview.clear(); + } + + // Param is passed by value, moved + pub fn set_video_preview(&mut self, v: ::protobuf::RepeatedField) { + self.video_preview = v; + } + + // Mutable pointer to the field. + pub fn mut_video_preview(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.video_preview + } + + // Take field + pub fn take_video_preview(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.video_preview, ::protobuf::RepeatedField::new()) + } + + // repeated .AudioFile audio_preview = 74; + + + pub fn get_audio_preview(&self) -> &[AudioFile] { + &self.audio_preview + } + pub fn clear_audio_preview(&mut self) { + self.audio_preview.clear(); + } + + // Param is passed by value, moved + pub fn set_audio_preview(&mut self, v: ::protobuf::RepeatedField) { + self.audio_preview = v; + } + + // Mutable pointer to the field. + pub fn mut_audio_preview(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.audio_preview + } + + // Take field + pub fn take_audio_preview(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.audio_preview, ::protobuf::RepeatedField::new()) } // repeated .Restriction restriction = 75; @@ -7784,6 +8497,64 @@ impl Episode { ::std::mem::replace(&mut self.restriction, ::protobuf::RepeatedField::new()) } + // optional .ImageGroup freeze_frame = 76; + + + pub fn get_freeze_frame(&self) -> &ImageGroup { + self.freeze_frame.as_ref().unwrap_or_else(|| ImageGroup::default_instance()) + } + pub fn clear_freeze_frame(&mut self) { + self.freeze_frame.clear(); + } + + pub fn has_freeze_frame(&self) -> bool { + self.freeze_frame.is_some() + } + + // Param is passed by value, moved + pub fn set_freeze_frame(&mut self, v: ImageGroup) { + self.freeze_frame = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_freeze_frame(&mut self) -> &mut ImageGroup { + if self.freeze_frame.is_none() { + self.freeze_frame.set_default(); + } + self.freeze_frame.as_mut().unwrap() + } + + // Take field + pub fn take_freeze_frame(&mut self) -> ImageGroup { + self.freeze_frame.take().unwrap_or_else(|| ImageGroup::new()) + } + + // repeated string keyword = 77; + + + pub fn get_keyword(&self) -> &[::std::string::String] { + &self.keyword + } + pub fn clear_keyword(&mut self) { + self.keyword.clear(); + } + + // Param is passed by value, moved + pub fn set_keyword(&mut self, v: ::protobuf::RepeatedField<::std::string::String>) { + self.keyword = v; + } + + // Mutable pointer to the field. + pub fn mut_keyword(&mut self) -> &mut ::protobuf::RepeatedField<::std::string::String> { + &mut self.keyword + } + + // Take field + pub fn take_keyword(&mut self) -> ::protobuf::RepeatedField<::std::string::String> { + ::std::mem::replace(&mut self.keyword, ::protobuf::RepeatedField::new()) + } + // optional bool suppress_monetization = 78; @@ -7803,7 +8574,26 @@ impl Episode { self.suppress_monetization = ::std::option::Option::Some(v); } - // optional bool allow_background_playback = 79; + // optional bool interpret_restriction_using_geoip = 79; + + + pub fn get_interpret_restriction_using_geoip(&self) -> bool { + self.interpret_restriction_using_geoip.unwrap_or(false) + } + pub fn clear_interpret_restriction_using_geoip(&mut self) { + self.interpret_restriction_using_geoip = ::std::option::Option::None; + } + + pub fn has_interpret_restriction_using_geoip(&self) -> bool { + self.interpret_restriction_using_geoip.is_some() + } + + // Param is passed by value, moved + pub fn set_interpret_restriction_using_geoip(&mut self, v: bool) { + self.interpret_restriction_using_geoip = ::std::option::Option::Some(v); + } + + // optional bool allow_background_playback = 81; pub fn get_allow_background_playback(&self) -> bool { @@ -7822,23 +8612,29 @@ impl Episode { self.allow_background_playback = ::std::option::Option::Some(v); } - // optional bool interpret_restriction_using_geoip = 81; + // repeated .Availability availability = 82; - pub fn get_interpret_restriction_using_geoip(&self) -> bool { - self.interpret_restriction_using_geoip.unwrap_or(false) + pub fn get_availability(&self) -> &[Availability] { + &self.availability } - pub fn clear_interpret_restriction_using_geoip(&mut self) { - self.interpret_restriction_using_geoip = ::std::option::Option::None; - } - - pub fn has_interpret_restriction_using_geoip(&self) -> bool { - self.interpret_restriction_using_geoip.is_some() + pub fn clear_availability(&mut self) { + self.availability.clear(); } // Param is passed by value, moved - pub fn set_interpret_restriction_using_geoip(&mut self, v: bool) { - self.interpret_restriction_using_geoip = ::std::option::Option::Some(v); + pub fn set_availability(&mut self, v: ::protobuf::RepeatedField) { + self.availability = v; + } + + // Mutable pointer to the field. + pub fn mut_availability(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.availability + } + + // Take field + pub fn take_availability(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.availability, ::protobuf::RepeatedField::new()) } // optional string external_url = 83; @@ -7933,7 +8729,17 @@ impl ::protobuf::Message for Episode { return false; } }; - for v in &self.preview { + for v in &self.video { + if !v.is_initialized() { + return false; + } + }; + for v in &self.video_preview { + if !v.is_initialized() { + return false; + } + }; + for v in &self.audio_preview { if !v.is_initialized() { return false; } @@ -7943,6 +8749,16 @@ impl ::protobuf::Message for Episode { return false; } }; + for v in &self.freeze_frame { + if !v.is_initialized() { + return false; + } + }; + for v in &self.availability { + if !v.is_initialized() { + return false; + } + }; for v in &self.original_audio { if !v.is_initialized() { return false; @@ -7981,9 +8797,23 @@ impl ::protobuf::Message for Episode { 64 => { ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.description)?; }, + 65 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_sint32()?; + self.number = ::std::option::Option::Some(tmp); + }, 66 => { ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.publish_time)?; }, + 67 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_sint32()?; + self.deprecated_popularity = ::std::option::Option::Some(tmp); + }, 68 => { ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.covers)?; }, @@ -8000,12 +8830,24 @@ impl ::protobuf::Message for Episode { 71 => { ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.show)?; }, + 72 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.video)?; + }, + 73 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.video_preview)?; + }, 74 => { - ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.preview)?; + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.audio_preview)?; }, 75 => { ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.restriction)?; }, + 76 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.freeze_frame)?; + }, + 77 => { + ::protobuf::rt::read_repeated_string_into(wire_type, is, &mut self.keyword)?; + }, 78 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); @@ -8018,14 +8860,17 @@ impl ::protobuf::Message for Episode { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); } let tmp = is.read_bool()?; - self.allow_background_playback = ::std::option::Option::Some(tmp); + self.interpret_restriction_using_geoip = ::std::option::Option::Some(tmp); }, 81 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); } let tmp = is.read_bool()?; - self.interpret_restriction_using_geoip = ::std::option::Option::Some(tmp); + self.allow_background_playback = ::std::option::Option::Some(tmp); + }, + 82 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.availability)?; }, 83 => { ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.external_url)?; @@ -8064,10 +8909,16 @@ impl ::protobuf::Message for Episode { if let Some(ref v) = self.description.as_ref() { my_size += ::protobuf::rt::string_size(64, &v); } + if let Some(v) = self.number { + my_size += ::protobuf::rt::value_varint_zigzag_size(65, v); + } if let Some(ref v) = self.publish_time.as_ref() { let len = v.compute_size(); my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; } + if let Some(v) = self.deprecated_popularity { + my_size += ::protobuf::rt::value_varint_zigzag_size(67, v); + } if let Some(ref v) = self.covers.as_ref() { let len = v.compute_size(); my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; @@ -8082,7 +8933,15 @@ impl ::protobuf::Message for Episode { let len = v.compute_size(); my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; } - for value in &self.preview { + for value in &self.video { + let len = value.compute_size(); + my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + for value in &self.video_preview { + let len = value.compute_size(); + my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + for value in &self.audio_preview { let len = value.compute_size(); my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; }; @@ -8090,15 +8949,26 @@ impl ::protobuf::Message for Episode { let len = value.compute_size(); my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; }; - if let Some(v) = self.suppress_monetization { - my_size += 3; + if let Some(ref v) = self.freeze_frame.as_ref() { + let len = v.compute_size(); + my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; } - if let Some(v) = self.allow_background_playback { + for value in &self.keyword { + my_size += ::protobuf::rt::string_size(77, &value); + }; + if let Some(v) = self.suppress_monetization { my_size += 3; } if let Some(v) = self.interpret_restriction_using_geoip { my_size += 3; } + if let Some(v) = self.allow_background_playback { + my_size += 3; + } + for value in &self.availability { + let len = value.compute_size(); + my_size += 2 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; if let Some(ref v) = self.external_url.as_ref() { my_size += ::protobuf::rt::string_size(83, &v); } @@ -8132,11 +9002,17 @@ impl ::protobuf::Message for Episode { if let Some(ref v) = self.description.as_ref() { os.write_string(64, &v)?; } + if let Some(v) = self.number { + os.write_sint32(65, v)?; + } if let Some(ref v) = self.publish_time.as_ref() { os.write_tag(66, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; v.write_to_with_cached_sizes(os)?; } + if let Some(v) = self.deprecated_popularity { + os.write_sint32(67, v)?; + } if let Some(ref v) = self.covers.as_ref() { os.write_tag(68, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -8153,7 +9029,17 @@ impl ::protobuf::Message for Episode { os.write_raw_varint32(v.get_cached_size())?; v.write_to_with_cached_sizes(os)?; } - for v in &self.preview { + for v in &self.video { + os.write_tag(72, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + for v in &self.video_preview { + os.write_tag(73, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + for v in &self.audio_preview { os.write_tag(74, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; v.write_to_with_cached_sizes(os)?; @@ -8163,15 +9049,28 @@ impl ::protobuf::Message for Episode { os.write_raw_varint32(v.get_cached_size())?; v.write_to_with_cached_sizes(os)?; }; + if let Some(ref v) = self.freeze_frame.as_ref() { + os.write_tag(76, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + for v in &self.keyword { + os.write_string(77, &v)?; + }; if let Some(v) = self.suppress_monetization { os.write_bool(78, v)?; } - if let Some(v) = self.allow_background_playback { + if let Some(v) = self.interpret_restriction_using_geoip { os.write_bool(79, v)?; } - if let Some(v) = self.interpret_restriction_using_geoip { + if let Some(v) = self.allow_background_playback { os.write_bool(81, v)?; } + for v in &self.availability { + os.write_tag(82, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; if let Some(ref v) = self.external_url.as_ref() { os.write_string(83, &v)?; } @@ -8252,11 +9151,21 @@ impl ::protobuf::Message for Episode { |m: &Episode| { &m.description }, |m: &mut Episode| { &mut m.description }, )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeSint32>( + "number", + |m: &Episode| { &m.number }, + |m: &mut Episode| { &mut m.number }, + )); fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( "publish_time", |m: &Episode| { &m.publish_time }, |m: &mut Episode| { &mut m.publish_time }, )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeSint32>( + "deprecated_popularity", + |m: &Episode| { &m.deprecated_popularity }, + |m: &mut Episode| { &mut m.deprecated_popularity }, + )); fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( "covers", |m: &Episode| { &m.covers }, @@ -8277,30 +9186,55 @@ impl ::protobuf::Message for Episode { |m: &Episode| { &m.show }, |m: &mut Episode| { &mut m.show }, )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "video", + |m: &Episode| { &m.video }, + |m: &mut Episode| { &mut m.video }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "video_preview", + |m: &Episode| { &m.video_preview }, + |m: &mut Episode| { &mut m.video_preview }, + )); fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( - "preview", - |m: &Episode| { &m.preview }, - |m: &mut Episode| { &mut m.preview }, + "audio_preview", + |m: &Episode| { &m.audio_preview }, + |m: &mut Episode| { &mut m.audio_preview }, )); fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( "restriction", |m: &Episode| { &m.restriction }, |m: &mut Episode| { &mut m.restriction }, )); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "freeze_frame", + |m: &Episode| { &m.freeze_frame }, + |m: &mut Episode| { &mut m.freeze_frame }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "keyword", + |m: &Episode| { &m.keyword }, + |m: &mut Episode| { &mut m.keyword }, + )); fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeBool>( "suppress_monetization", |m: &Episode| { &m.suppress_monetization }, |m: &mut Episode| { &mut m.suppress_monetization }, )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeBool>( + "interpret_restriction_using_geoip", + |m: &Episode| { &m.interpret_restriction_using_geoip }, + |m: &mut Episode| { &mut m.interpret_restriction_using_geoip }, + )); fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeBool>( "allow_background_playback", |m: &Episode| { &m.allow_background_playback }, |m: &mut Episode| { &mut m.allow_background_playback }, )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeBool>( - "interpret_restriction_using_geoip", - |m: &Episode| { &m.interpret_restriction_using_geoip }, - |m: &mut Episode| { &mut m.interpret_restriction_using_geoip }, + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "availability", + |m: &Episode| { &m.availability }, + |m: &mut Episode| { &mut m.availability }, )); fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( "external_url", @@ -8340,16 +9274,23 @@ impl ::protobuf::Clear for Episode { self.popularity = ::std::option::Option::None; self.file.clear(); self.description.clear(); + self.number = ::std::option::Option::None; self.publish_time.clear(); + self.deprecated_popularity = ::std::option::Option::None; self.covers.clear(); self.language.clear(); self.explicit = ::std::option::Option::None; self.show.clear(); - self.preview.clear(); + self.video.clear(); + self.video_preview.clear(); + self.audio_preview.clear(); self.restriction.clear(); + self.freeze_frame.clear(); + self.keyword.clear(); self.suppress_monetization = ::std::option::Option::None; - self.allow_background_playback = ::std::option::Option::None; self.interpret_restriction_using_geoip = ::std::option::Option::None; + self.allow_background_playback = ::std::option::Option::None; + self.availability.clear(); self.external_url.clear(); self.original_audio.clear(); self.unknown_fields.clear(); @@ -8775,181 +9716,6 @@ impl ::protobuf::reflect::ProtobufValue for OriginalAudio { } } -#[derive(Clone,PartialEq,Eq,Debug,Hash)] -pub enum ConsumptionOrder { - SEQUENTIAL = 1, - EPISODIC = 2, - RECENT = 3, -} - -impl ::protobuf::ProtobufEnum for ConsumptionOrder { - fn value(&self) -> i32 { - *self as i32 - } - - fn from_i32(value: i32) -> ::std::option::Option { - match value { - 1 => ::std::option::Option::Some(ConsumptionOrder::SEQUENTIAL), - 2 => ::std::option::Option::Some(ConsumptionOrder::EPISODIC), - 3 => ::std::option::Option::Some(ConsumptionOrder::RECENT), - _ => ::std::option::Option::None - } - } - - fn values() -> &'static [Self] { - static values: &'static [ConsumptionOrder] = &[ - ConsumptionOrder::SEQUENTIAL, - ConsumptionOrder::EPISODIC, - ConsumptionOrder::RECENT, - ]; - values - } - - fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::EnumDescriptor, - }; - unsafe { - descriptor.get(|| { - ::protobuf::reflect::EnumDescriptor::new("ConsumptionOrder", file_descriptor_proto()) - }) - } - } -} - -impl ::std::marker::Copy for ConsumptionOrder { -} - -// Note, `Default` is implemented although default value is not 0 -impl ::std::default::Default for ConsumptionOrder { - fn default() -> Self { - ConsumptionOrder::SEQUENTIAL - } -} - -impl ::protobuf::reflect::ProtobufValue for ConsumptionOrder { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Enum(self.descriptor()) - } -} - -#[derive(Clone,PartialEq,Eq,Debug,Hash)] -pub enum MediaType { - MIXED = 0, - AUDIO = 1, - VIDEO = 2, -} - -impl ::protobuf::ProtobufEnum for MediaType { - fn value(&self) -> i32 { - *self as i32 - } - - fn from_i32(value: i32) -> ::std::option::Option { - match value { - 0 => ::std::option::Option::Some(MediaType::MIXED), - 1 => ::std::option::Option::Some(MediaType::AUDIO), - 2 => ::std::option::Option::Some(MediaType::VIDEO), - _ => ::std::option::Option::None - } - } - - fn values() -> &'static [Self] { - static values: &'static [MediaType] = &[ - MediaType::MIXED, - MediaType::AUDIO, - MediaType::VIDEO, - ]; - values - } - - fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::EnumDescriptor, - }; - unsafe { - descriptor.get(|| { - ::protobuf::reflect::EnumDescriptor::new("MediaType", file_descriptor_proto()) - }) - } - } -} - -impl ::std::marker::Copy for MediaType { -} - -impl ::std::default::Default for MediaType { - fn default() -> Self { - MediaType::MIXED - } -} - -impl ::protobuf::reflect::ProtobufValue for MediaType { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Enum(self.descriptor()) - } -} - -#[derive(Clone,PartialEq,Eq,Debug,Hash)] -pub enum PassthroughEnum { - UNKNOWN = 0, - NONE = 1, - ALLOWED = 2, -} - -impl ::protobuf::ProtobufEnum for PassthroughEnum { - fn value(&self) -> i32 { - *self as i32 - } - - fn from_i32(value: i32) -> ::std::option::Option { - match value { - 0 => ::std::option::Option::Some(PassthroughEnum::UNKNOWN), - 1 => ::std::option::Option::Some(PassthroughEnum::NONE), - 2 => ::std::option::Option::Some(PassthroughEnum::ALLOWED), - _ => ::std::option::Option::None - } - } - - fn values() -> &'static [Self] { - static values: &'static [PassthroughEnum] = &[ - PassthroughEnum::UNKNOWN, - PassthroughEnum::NONE, - PassthroughEnum::ALLOWED, - ]; - values - } - - fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::EnumDescriptor, - }; - unsafe { - descriptor.get(|| { - ::protobuf::reflect::EnumDescriptor::new("PassthroughEnum", file_descriptor_proto()) - }) - } - } -} - -impl ::std::marker::Copy for PassthroughEnum { -} - -impl ::std::default::Default for PassthroughEnum { - fn default() -> Self { - PassthroughEnum::UNKNOWN - } -} - -impl ::protobuf::reflect::ProtobufValue for PassthroughEnum { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Enum(self.descriptor()) - } -} - static file_descriptor_proto_data: &'static [u8] = b"\ \n\x0emetadata.proto\x12\0\"9\n\tTopTracks\x12\x11\n\x07country\x18\x01\ \x20\x01(\tB\0\x12\x17\n\x05track\x18\x02\x20\x03(\x0b2\x06.TrackB\0:\0\ @@ -8970,32 +9736,33 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x18\x0f\x20\x03(\x0b2\x07.ArtistB\0\x12!\n\x17is_portrait_album_cover\ \x18\x10\x20\x01(\x08B\0\x12%\n\x0eportrait_group\x18\x11\x20\x01(\x0b2\ \x0b.ImageGroupB\0:\0\"'\n\nAlbumGroup\x12\x17\n\x05album\x18\x01\x20\ - \x03(\x0b2\x06.AlbumB\0:\0\"8\n\x04Date\x12\x0e\n\x04year\x18\x01\x20\ + \x03(\x0b2\x06.AlbumB\0:\0\"Z\n\x04Date\x12\x0e\n\x04year\x18\x01\x20\ \x01(\x11B\0\x12\x0f\n\x05month\x18\x02\x20\x01(\x11B\0\x12\r\n\x03day\ - \x18\x03\x20\x01(\x11B\0:\0\"\xf7\x03\n\x05Album\x12\r\n\x03gid\x18\x01\ - \x20\x01(\x0cB\0\x12\x0e\n\x04name\x18\x02\x20\x01(\tB\0\x12\x19\n\x06ar\ - tist\x18\x03\x20\x03(\x0b2\x07.ArtistB\0\x12\x1a\n\x03typ\x18\x04\x20\ - \x01(\x0e2\x0b.Album.TypeB\0\x12\x0f\n\x05label\x18\x05\x20\x01(\tB\0\ - \x12\x15\n\x04date\x18\x06\x20\x01(\x0b2\x05.DateB\0\x12\x14\n\npopulari\ - ty\x18\x07\x20\x01(\x11B\0\x12\x0f\n\x05genre\x18\x08\x20\x03(\tB\0\x12\ - \x17\n\x05cover\x18\t\x20\x03(\x0b2\x06.ImageB\0\x12\"\n\x0bexternal_id\ - \x18\n\x20\x03(\x0b2\x0b.ExternalIdB\0\x12\x15\n\x04disc\x18\x0b\x20\x03\ - (\x0b2\x05.DiscB\0\x12\x10\n\x06review\x18\x0c\x20\x03(\tB\0\x12\x1f\n\t\ - copyright\x18\r\x20\x03(\x0b2\n.CopyrightB\0\x12#\n\x0brestriction\x18\ - \x0e\x20\x03(\x0b2\x0c.RestrictionB\0\x12\x19\n\x07related\x18\x0f\x20\ - \x03(\x0b2\x06.AlbumB\0\x12\"\n\x0bsale_period\x18\x10\x20\x03(\x0b2\x0b\ - .SalePeriodB\0\x12\"\n\x0bcover_group\x18\x11\x20\x01(\x0b2\x0b.ImageGro\ - upB\0\"8\n\x04Type\x12\t\n\x05ALBUM\x10\x01\x12\n\n\x06SINGLE\x10\x02\ - \x12\x0f\n\x0bCOMPILATION\x10\x03\x12\x06\n\x02EP\x10\x04\x1a\0:\0\"\x8a\ - \x03\n\x05Track\x12\r\n\x03gid\x18\x01\x20\x01(\x0cB\0\x12\x0e\n\x04name\ - \x18\x02\x20\x01(\tB\0\x12\x17\n\x05album\x18\x03\x20\x01(\x0b2\x06.Albu\ - mB\0\x12\x19\n\x06artist\x18\x04\x20\x03(\x0b2\x07.ArtistB\0\x12\x10\n\ - \x06number\x18\x05\x20\x01(\x11B\0\x12\x15\n\x0bdisc_number\x18\x06\x20\ - \x01(\x11B\0\x12\x12\n\x08duration\x18\x07\x20\x01(\x11B\0\x12\x14\n\npo\ - pularity\x18\x08\x20\x01(\x11B\0\x12\x12\n\x08explicit\x18\t\x20\x01(\ - \x08B\0\x12\"\n\x0bexternal_id\x18\n\x20\x03(\x0b2\x0b.ExternalIdB\0\x12\ - #\n\x0brestriction\x18\x0b\x20\x03(\x0b2\x0c.RestrictionB\0\x12\x1a\n\ - \x04file\x18\x0c\x20\x03(\x0b2\n.AudioFileB\0\x12\x1d\n\x0balternative\ + \x18\x03\x20\x01(\x11B\0\x12\x0e\n\x04hour\x18\x04\x20\x01(\x11B\0\x12\ + \x10\n\x06minute\x18\x05\x20\x01(\x11B\0:\0\"\xf7\x03\n\x05Album\x12\r\n\ + \x03gid\x18\x01\x20\x01(\x0cB\0\x12\x0e\n\x04name\x18\x02\x20\x01(\tB\0\ + \x12\x19\n\x06artist\x18\x03\x20\x03(\x0b2\x07.ArtistB\0\x12\x1a\n\x03ty\ + p\x18\x04\x20\x01(\x0e2\x0b.Album.TypeB\0\x12\x0f\n\x05label\x18\x05\x20\ + \x01(\tB\0\x12\x15\n\x04date\x18\x06\x20\x01(\x0b2\x05.DateB\0\x12\x14\n\ + \npopularity\x18\x07\x20\x01(\x11B\0\x12\x0f\n\x05genre\x18\x08\x20\x03(\ + \tB\0\x12\x17\n\x05cover\x18\t\x20\x03(\x0b2\x06.ImageB\0\x12\"\n\x0bext\ + ernal_id\x18\n\x20\x03(\x0b2\x0b.ExternalIdB\0\x12\x15\n\x04disc\x18\x0b\ + \x20\x03(\x0b2\x05.DiscB\0\x12\x10\n\x06review\x18\x0c\x20\x03(\tB\0\x12\ + \x1f\n\tcopyright\x18\r\x20\x03(\x0b2\n.CopyrightB\0\x12#\n\x0brestricti\ + on\x18\x0e\x20\x03(\x0b2\x0c.RestrictionB\0\x12\x19\n\x07related\x18\x0f\ + \x20\x03(\x0b2\x06.AlbumB\0\x12\"\n\x0bsale_period\x18\x10\x20\x03(\x0b2\ + \x0b.SalePeriodB\0\x12\"\n\x0bcover_group\x18\x11\x20\x01(\x0b2\x0b.Imag\ + eGroupB\0\"8\n\x04Type\x12\t\n\x05ALBUM\x10\x01\x12\n\n\x06SINGLE\x10\ + \x02\x12\x0f\n\x0bCOMPILATION\x10\x03\x12\x06\n\x02EP\x10\x04\x1a\0:\0\"\ + \x8a\x03\n\x05Track\x12\r\n\x03gid\x18\x01\x20\x01(\x0cB\0\x12\x0e\n\x04\ + name\x18\x02\x20\x01(\tB\0\x12\x17\n\x05album\x18\x03\x20\x01(\x0b2\x06.\ + AlbumB\0\x12\x19\n\x06artist\x18\x04\x20\x03(\x0b2\x07.ArtistB\0\x12\x10\ + \n\x06number\x18\x05\x20\x01(\x11B\0\x12\x15\n\x0bdisc_number\x18\x06\ + \x20\x01(\x11B\0\x12\x12\n\x08duration\x18\x07\x20\x01(\x11B\0\x12\x14\n\ + \npopularity\x18\x08\x20\x01(\x11B\0\x12\x12\n\x08explicit\x18\t\x20\x01\ + (\x08B\0\x12\"\n\x0bexternal_id\x18\n\x20\x03(\x0b2\x0b.ExternalIdB\0\ + \x12#\n\x0brestriction\x18\x0b\x20\x03(\x0b2\x0c.RestrictionB\0\x12\x1a\ + \n\x04file\x18\x0c\x20\x03(\x0b2\n.AudioFileB\0\x12\x1d\n\x0balternative\ \x18\r\x20\x03(\x0b2\x06.TrackB\0\x12\"\n\x0bsale_period\x18\x0e\x20\x03\ (\x0b2\x0b.SalePeriodB\0\x12\x1d\n\x07preview\x18\x0f\x20\x03(\x0b2\n.Au\ dioFileB\0:\0\"\x95\x01\n\x05Image\x12\x11\n\x07file_id\x18\x01\x20\x01(\ @@ -9011,14 +9778,19 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \n\x05track\x18\x03\x20\x03(\x0b2\x06.TrackB\0:\0\"U\n\tCopyright\x12\ \x1e\n\x03typ\x18\x01\x20\x01(\x0e2\x0f.Copyright.TypeB\0\x12\x0e\n\x04t\ ext\x18\x02\x20\x01(\tB\0\"\x16\n\x04Type\x12\x05\n\x01P\x10\0\x12\x05\n\ - \x01C\x10\x01\x1a\0:\0\"\x9f\x01\n\x0bRestriction\x12\x1b\n\x11countries\ - _allowed\x18\x02\x20\x01(\tB\0\x12\x1d\n\x13countries_forbidden\x18\x03\ + \x01C\x10\x01\x1a\0:\0\"\xa5\x02\n\x0bRestriction\x12+\n\tcatalogue\x18\ + \x01\x20\x03(\x0e2\x16.Restriction.CatalogueB\0\x12\x1b\n\x11countries_a\ + llowed\x18\x02\x20\x01(\tB\0\x12\x1d\n\x13countries_forbidden\x18\x03\ \x20\x01(\tB\0\x12\x20\n\x03typ\x18\x04\x20\x01(\x0e2\x11.Restriction.Ty\ - peB\0\x12\x17\n\rcatalogue_str\x18\x05\x20\x03(\tB\0\"\x17\n\x04Type\x12\ - \r\n\tSTREAMING\x10\0\x1a\0:\0\"a\n\nSalePeriod\x12#\n\x0brestriction\ - \x18\x01\x20\x03(\x0b2\x0c.RestrictionB\0\x12\x16\n\x05start\x18\x02\x20\ - \x01(\x0b2\x05.DateB\0\x12\x14\n\x03end\x18\x03\x20\x01(\x0b2\x05.DateB\ - \0:\0\"+\n\nExternalId\x12\r\n\x03typ\x18\x01\x20\x01(\tB\0\x12\x0c\n\ + peB\0\x12\x17\n\rcatalogue_str\x18\x05\x20\x03(\tB\0\"W\n\tCatalogue\x12\ + \x06\n\x02AD\x10\0\x12\x10\n\x0cSUBSCRIPTION\x10\x01\x12\x11\n\rCATALOGU\ + E_ALL\x10\x02\x12\x0b\n\x07SHUFFLE\x10\x03\x12\x0e\n\nCOMMERCIAL\x10\x04\ + \x1a\0\"\x17\n\x04Type\x12\r\n\tSTREAMING\x10\0\x1a\0:\0\"A\n\x0cAvailab\ + ility\x12\x17\n\rcatalogue_str\x18\x01\x20\x03(\tB\0\x12\x16\n\x05start\ + \x18\x02\x20\x01(\x0b2\x05.DateB\0:\0\"a\n\nSalePeriod\x12#\n\x0brestric\ + tion\x18\x01\x20\x03(\x0b2\x0c.RestrictionB\0\x12\x16\n\x05start\x18\x02\ + \x20\x01(\x0b2\x05.DateB\0\x12\x14\n\x03end\x18\x03\x20\x01(\x0b2\x05.Da\ + teB\0:\0\"+\n\nExternalId\x12\r\n\x03typ\x18\x01\x20\x01(\tB\0\x12\x0c\n\ \x02id\x18\x02\x20\x01(\tB\0:\0\"\xa2\x02\n\tAudioFile\x12\x11\n\x07file\ _id\x18\x01\x20\x01(\x0cB\0\x12#\n\x06format\x18\x02\x20\x01(\x0e2\x11.A\ udioFile.FormatB\0\"\xda\x01\n\x06Format\x12\x11\n\rOGG_VORBIS_96\x10\0\ @@ -9027,42 +9799,48 @@ static file_descriptor_proto_data: &'static [u8] = b"\ MP3_160\x10\x05\x12\n\n\x06MP3_96\x10\x06\x12\x0f\n\x0bMP3_160_ENC\x10\ \x07\x12\x10\n\x0cMP4_128_DUAL\x10\x08\x12\n\n\x06OTHER3\x10\t\x12\x0b\n\ \x07AAC_160\x10\n\x12\x0b\n\x07AAC_320\x10\x0b\x12\x0b\n\x07MP4_128\x10\ - \x0c\x12\n\n\x06OTHER5\x10\r\x1a\0:\0\"a\n\x0bPublishTime\x12\x0e\n\x04y\ - ear\x18\x01\x20\x01(\x11B\0\x12\x0f\n\x05month\x18\x02\x20\x01(\x11B\0\ - \x12\r\n\x03day\x18\x03\x20\x01(\x11B\0\x12\x10\n\x06minute\x18\x05\x20\ - \x01(\x11B\0\x12\x0e\n\x04hour\x18\x04\x20\x01(\x11B\0:\0\"\xc2\x03\n\ - \x04Show\x12\r\n\x03gid\x18\x01\x20\x01(\x0cB\0\x12\x0e\n\x04name\x18\ - \x02\x20\x01(\tB\0\x12\x1b\n\x07episode\x18F\x20\x03(\x0b2\x08.EpisodeB\ - \0\x12\x15\n\x0bdescription\x18@\x20\x01(\tB\0\x12\x13\n\tpublisher\x18B\ - \x20\x01(\tB\0\x12\x12\n\x08language\x18C\x20\x01(\tB\0\x12\x12\n\x08exp\ - licit\x18D\x20\x01(\x08B\0\x12\x1d\n\x06covers\x18E\x20\x01(\x0b2\x0b.Im\ - ageGroupB\0\x12#\n\x0brestriction\x18H\x20\x03(\x0b2\x0c.RestrictionB\0\ - \x12\x20\n\nmedia_type\x18J\x20\x01(\x0e2\n.MediaTypeB\0\x12.\n\x11consu\ - mption_order\x18K\x20\x01(\x0e2\x11.ConsumptionOrderB\0\x12+\n!interpret\ - _restriction_using_geoip\x18L\x20\x01(\x08B\0\x12\x1b\n\x11country_of_or\ - igin\x18O\x20\x01(\tB\0\x12\x1f\n\ncategories\x18P\x20\x03(\x0b2\t.Categ\ - oryB\0\x12'\n\x0bpassthrough\x18Q\x20\x01(\x0e2\x10.PassthroughEnumB\0:\ - \0\"\xfd\x03\n\x07Episode\x12\r\n\x03gid\x18\x01\x20\x01(\x0cB\0\x12\x0e\ - \n\x04name\x18\x02\x20\x01(\tB\0\x12\x12\n\x08duration\x18\x07\x20\x01(\ - \x11B\0\x12\x14\n\npopularity\x18\x08\x20\x01(\x11B\0\x12\x1a\n\x04file\ - \x18\x0c\x20\x03(\x0b2\n.AudioFileB\0\x12\x15\n\x0bdescription\x18@\x20\ - \x01(\tB\0\x12\x1d\n\x0cpublish_time\x18B\x20\x01(\x0b2\x05.DateB\0\x12\ - \x1d\n\x06covers\x18D\x20\x01(\x0b2\x0b.ImageGroupB\0\x12\x12\n\x08langu\ - age\x18E\x20\x01(\tB\0\x12\x12\n\x08explicit\x18F\x20\x01(\x08B\0\x12\ - \x15\n\x04show\x18G\x20\x01(\x0b2\x05.ShowB\0\x12\x1d\n\x07preview\x18J\ - \x20\x03(\x0b2\n.AudioFileB\0\x12#\n\x0brestriction\x18K\x20\x03(\x0b2\ - \x0c.RestrictionB\0\x12\x1f\n\x15suppress_monetization\x18N\x20\x01(\x08\ - B\0\x12#\n\x19allow_background_playback\x18O\x20\x01(\x08B\0\x12+\n!inte\ - rpret_restriction_using_geoip\x18Q\x20\x01(\x08B\0\x12\x16\n\x0cexternal\ - _url\x18S\x20\x01(\tB\0\x12(\n\x0eoriginal_audio\x18T\x20\x01(\x0b2\x0e.\ - OriginalAudioB\0:\0\"@\n\x08Category\x12\x0e\n\x04name\x18\x01\x20\x01(\ - \tB\0\x12\"\n\rsubcategories\x18\x02\x20\x03(\x0b2\t.CategoryB\0:\0\"!\n\ - \rOriginalAudio\x12\x0e\n\x04uuid\x18\x01\x20\x01(\x0cB\0:\0*>\n\x10Cons\ - umptionOrder\x12\x0e\n\nSEQUENTIAL\x10\x01\x12\x0c\n\x08EPISODIC\x10\x02\ - \x12\n\n\x06RECENT\x10\x03\x1a\0*.\n\tMediaType\x12\t\n\x05MIXED\x10\0\ - \x12\t\n\x05AUDIO\x10\x01\x12\t\n\x05VIDEO\x10\x02\x1a\0*7\n\x0fPassthro\ - ughEnum\x12\x0b\n\x07UNKNOWN\x10\0\x12\x08\n\x04NONE\x10\x01\x12\x0b\n\ - \x07ALLOWED\x10\x02\x1a\0B\0b\x06proto2\ + \x0c\x12\n\n\x06OTHER5\x10\r\x1a\0:\0\"\x20\n\tVideoFile\x12\x11\n\x07fi\ + le_id\x18\x01\x20\x01(\x0cB\0:\0\"\xf6\x05\n\x04Show\x12\r\n\x03gid\x18\ + \x01\x20\x01(\x0cB\0\x12\x0e\n\x04name\x18\x02\x20\x01(\tB\0\x12\x15\n\ + \x0bdescription\x18@\x20\x01(\tB\0\x12\x1f\n\x15deprecated_popularity\ + \x18A\x20\x01(\x11B\0\x12\x13\n\tpublisher\x18B\x20\x01(\tB\0\x12\x12\n\ + \x08language\x18C\x20\x01(\tB\0\x12\x12\n\x08explicit\x18D\x20\x01(\x08B\ + \0\x12\x1d\n\x06covers\x18E\x20\x01(\x0b2\x0b.ImageGroupB\0\x12\x1b\n\ + \x07episode\x18F\x20\x03(\x0b2\x08.EpisodeB\0\x12\x1f\n\tcopyright\x18G\ + \x20\x03(\x0b2\n.CopyrightB\0\x12#\n\x0brestriction\x18H\x20\x03(\x0b2\ + \x0c.RestrictionB\0\x12\x11\n\x07keyword\x18I\x20\x03(\tB\0\x12%\n\nmedi\ + a_type\x18J\x20\x01(\x0e2\x0f.Show.MediaTypeB\0\x123\n\x11consumption_or\ + der\x18K\x20\x01(\x0e2\x16.Show.ConsumptionOrderB\0\x12+\n!interpret_res\ + triction_using_geoip\x18L\x20\x01(\x08B\0\x12%\n\x0cavailability\x18N\ + \x20\x03(\x0b2\r.AvailabilityB\0\x12\x1b\n\x11country_of_origin\x18O\x20\ + \x01(\tB\0\x12\x1f\n\ncategories\x18P\x20\x03(\x0b2\t.CategoryB\0\x12,\n\ + \x0bpassthrough\x18Q\x20\x01(\x0e2\x15.Show.PassthroughEnumB\0\".\n\tMed\ + iaType\x12\t\n\x05MIXED\x10\0\x12\t\n\x05AUDIO\x10\x01\x12\t\n\x05VIDEO\ + \x10\x02\x1a\0\">\n\x10ConsumptionOrder\x12\x0e\n\nSEQUENTIAL\x10\x01\ + \x12\x0c\n\x08EPISODIC\x10\x02\x12\n\n\x06RECENT\x10\x03\x1a\0\"7\n\x0fP\ + assthroughEnum\x12\x0b\n\x07UNKNOWN\x10\0\x12\x08\n\x04NONE\x10\x01\x12\ + \x0b\n\x07ALLOWED\x10\x02\x1a\0:\0\"\xd7\x05\n\x07Episode\x12\r\n\x03gid\ + \x18\x01\x20\x01(\x0cB\0\x12\x0e\n\x04name\x18\x02\x20\x01(\tB\0\x12\x12\ + \n\x08duration\x18\x07\x20\x01(\x11B\0\x12\x14\n\npopularity\x18\x08\x20\ + \x01(\x11B\0\x12\x1a\n\x04file\x18\x0c\x20\x03(\x0b2\n.AudioFileB\0\x12\ + \x15\n\x0bdescription\x18@\x20\x01(\tB\0\x12\x10\n\x06number\x18A\x20\ + \x01(\x11B\0\x12\x1d\n\x0cpublish_time\x18B\x20\x01(\x0b2\x05.DateB\0\ + \x12\x1f\n\x15deprecated_popularity\x18C\x20\x01(\x11B\0\x12\x1d\n\x06co\ + vers\x18D\x20\x01(\x0b2\x0b.ImageGroupB\0\x12\x12\n\x08language\x18E\x20\ + \x01(\tB\0\x12\x12\n\x08explicit\x18F\x20\x01(\x08B\0\x12\x15\n\x04show\ + \x18G\x20\x01(\x0b2\x05.ShowB\0\x12\x1b\n\x05video\x18H\x20\x03(\x0b2\n.\ + VideoFileB\0\x12#\n\rvideo_preview\x18I\x20\x03(\x0b2\n.VideoFileB\0\x12\ + #\n\raudio_preview\x18J\x20\x03(\x0b2\n.AudioFileB\0\x12#\n\x0brestricti\ + on\x18K\x20\x03(\x0b2\x0c.RestrictionB\0\x12#\n\x0cfreeze_frame\x18L\x20\ + \x01(\x0b2\x0b.ImageGroupB\0\x12\x11\n\x07keyword\x18M\x20\x03(\tB\0\x12\ + \x1f\n\x15suppress_monetization\x18N\x20\x01(\x08B\0\x12+\n!interpret_re\ + striction_using_geoip\x18O\x20\x01(\x08B\0\x12#\n\x19allow_background_pl\ + ayback\x18Q\x20\x01(\x08B\0\x12%\n\x0cavailability\x18R\x20\x03(\x0b2\r.\ + AvailabilityB\0\x12\x16\n\x0cexternal_url\x18S\x20\x01(\tB\0\x12(\n\x0eo\ + riginal_audio\x18T\x20\x01(\x0b2\x0e.OriginalAudioB\0:\0\"@\n\x08Categor\ + y\x12\x0e\n\x04name\x18\x01\x20\x01(\tB\0\x12\"\n\rsubcategories\x18\x02\ + \x20\x03(\x0b2\t.CategoryB\0:\0\"!\n\rOriginalAudio\x12\x0e\n\x04uuid\ + \x18\x01\x20\x01(\x0cB\0:\0B\0b\x06proto2\ "; static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { From b96405af8262fc5b0e0567440f969d110492a836 Mon Sep 17 00:00:00 2001 From: ashthespy Date: Wed, 9 Oct 2019 19:49:13 +0200 Subject: [PATCH 05/43] Make `SpotifyId` understand more URI formats --- connect/src/spirc.rs | 44 +++++++++++++++++++++++++++--------------- core/src/spotify_id.rs | 13 ++++++++++--- metadata/src/lib.rs | 4 ++++ 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/connect/src/spirc.rs b/connect/src/spirc.rs index 92e26ce0..5e00ebb0 100644 --- a/connect/src/spirc.rs +++ b/connect/src/spirc.rs @@ -13,14 +13,14 @@ use context::StationContext; use librespot_core::config::ConnectConfig; use librespot_core::mercury::MercuryError; use librespot_core::session::Session; -use librespot_core::spotify_id::SpotifyId; +use librespot_core::spotify_id::{SpotifyId, SpotifyIdError}; use librespot_core::util::SeqGenerator; use librespot_core::version; use librespot_core::volume::Volume; use playback::mixer::Mixer; use playback::player::Player; use protocol; -use protocol::spirc::{DeviceState, Frame, MessageType, PlayStatus, State}; +use protocol::spirc::{DeviceState, Frame, MessageType, PlayStatus, State, TrackRef}; pub struct SpircTask { player: Player, @@ -797,7 +797,7 @@ impl SpircTask { } fn update_tracks(&mut self, frame: &protocol::spirc::Frame) { - // debug!("State: {:?}", frame.get_state()); + debug!("State: {:?}", frame.get_state()); let index = frame.get_state().get_playing_track_index(); let context_uri = frame.get_state().get_context_uri().to_owned(); let tracks = frame.get_state().get_track(); @@ -813,31 +813,43 @@ impl SpircTask { self.state.set_shuffle(frame.get_state().get_shuffle()); } + // should this be a method of SpotifyId directly? + fn get_spotify_id_for_track(&self, track_ref: &TrackRef) -> Result { + SpotifyId::from_raw(track_ref.get_gid()).or_else(|_| { + let uri = track_ref.get_uri(); + debug!("Malformed or no gid, attempting to parse URI <{}>", uri); + SpotifyId::from_uri(uri) + }) + } + fn load_track(&mut self, play: bool) { let context_uri = self.state.get_context_uri().to_owned(); - let index = self.state.get_playing_track_index(); - info!("context: {}", context_uri); - // Redundant check here - let track = if context_uri.contains(":show:") || context_uri.contains(":episode:") { - let uri = self.state.get_track()[index as usize].get_uri(); - SpotifyId::from_uri(uri).expect("Unable to parse uri") - } else { - let mut index = self.state.get_playing_track_index(); - // Check for malformed gid - let tracks_len = self.state.get_track().len() as u32; + let mut index = self.state.get_playing_track_index(); + let tracks_len = self.state.get_track().len() as u32; + debug!( + "Loading context: {} index: [{}] of {}", + context_uri, index, tracks_len + ); + // Tracks either have a gid or uri. + // Context based frames sometimes use spotify:meta:page: that needs to be ignored. + let track = { let mut track_ref = &self.state.get_track()[index as usize]; - while track_ref.get_gid().len() != 16 { + let mut track_id = self.get_spotify_id_for_track(track_ref); + while track_id.is_err() { warn!( "Skipping track {:?} at position [{}] of {}", track_ref.get_uri(), index, tracks_len ); + // This will keep looping over, instead we should cylce tracks only once index = if index + 1 < tracks_len { index + 1 } else { 0 }; track_ref = &self.state.get_track()[index as usize]; + track_id = self.get_spotify_id_for_track(track_ref); } - SpotifyId::from_raw(track_ref.get_gid()).unwrap() - }; + track_id + } + .unwrap(); let position = self.state.get_position_ms(); let end_of_track = self.player.load(track, play, position); diff --git a/core/src/spotify_id.rs b/core/src/spotify_id.rs index c8f01674..e6f0cdd8 100644 --- a/core/src/spotify_id.rs +++ b/core/src/spotify_id.rs @@ -5,6 +5,7 @@ use std::fmt; pub enum SpotifyAudioType { Track, Podcast, + NonPlayable, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -71,12 +72,18 @@ impl SpotifyId { pub fn from_uri(uri: &str) -> Result { let parts = uri.split(":").collect::>(); - if uri.contains(":show:") || uri.contains(":episode:") { - let mut spotify_id = SpotifyId::from_base62(parts[2]).unwrap(); + let gid = parts.last().unwrap(); + if uri.contains(":episode:") { + let mut spotify_id = SpotifyId::from_base62(gid).unwrap(); let _ = std::mem::replace(&mut spotify_id.audio_type, SpotifyAudioType::Podcast); Ok(spotify_id) + } else if uri.contains(":track:") { + SpotifyId::from_base62(gid) } else { - SpotifyId::from_base62(parts[2]) + // show/playlist/artist/album/?? + let mut spotify_id = SpotifyId::from_base62(gid).unwrap(); + let _ = std::mem::replace(&mut spotify_id.audio_type, SpotifyAudioType::NonPlayable); + Ok(spotify_id) } } diff --git a/metadata/src/lib.rs b/metadata/src/lib.rs index 75a42e2f..344a3a54 100644 --- a/metadata/src/lib.rs +++ b/metadata/src/lib.rs @@ -8,6 +8,7 @@ extern crate librespot_protocol as protocol; pub mod cover; +use futures::future; use futures::Future; use linear_map::LinearMap; @@ -71,6 +72,9 @@ impl AudioItem { match id.audio_type { SpotifyAudioType::Track => Track::get_audio_item(session, id), SpotifyAudioType::Podcast => Episode::get_audio_item(session, id), + SpotifyAudioType::NonPlayable => { + Box::new(future::err::(MercuryError)) + } } } } From 508c7e2b260c041048373f12b33fca7702c4fe13 Mon Sep 17 00:00:00 2001 From: ashthespy Date: Tue, 22 Oct 2019 11:05:35 +0100 Subject: [PATCH 06/43] Tweak track loading --- connect/src/spirc.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/connect/src/spirc.rs b/connect/src/spirc.rs index 5e00ebb0..041bc88e 100644 --- a/connect/src/spirc.rs +++ b/connect/src/spirc.rs @@ -13,7 +13,7 @@ use context::StationContext; use librespot_core::config::ConnectConfig; use librespot_core::mercury::MercuryError; use librespot_core::session::Session; -use librespot_core::spotify_id::{SpotifyId, SpotifyIdError}; +use librespot_core::spotify_id::{SpotifyAudioType, SpotifyId, SpotifyIdError}; use librespot_core::util::SeqGenerator; use librespot_core::version; use librespot_core::volume::Volume; @@ -825,31 +825,38 @@ impl SpircTask { fn load_track(&mut self, play: bool) { let context_uri = self.state.get_context_uri().to_owned(); let mut index = self.state.get_playing_track_index(); + let start_index = index; let tracks_len = self.state.get_track().len() as u32; debug!( - "Loading context: {} index: [{}] of {}", + "Loading context: <{}> index: [{}] of {}", context_uri, index, tracks_len ); - // Tracks either have a gid or uri. - // Context based frames sometimes use spotify:meta:page: that needs to be ignored. + // Cycle through all tracks, break if we don't find any playable tracks + // TODO: This will panic if no playable tracks are found! + // tracks in each frame either have a gid or uri (that may or may not be a valid track) + // E.g - context based frames sometimes contain tracks with let track = { let mut track_ref = &self.state.get_track()[index as usize]; let mut track_id = self.get_spotify_id_for_track(track_ref); - while track_id.is_err() { + while track_id.is_err() || track_id.unwrap().audio_type == SpotifyAudioType::NonPlayable { warn!( - "Skipping track {:?} at position [{}] of {}", + "Skipping track <{:?}> at position [{}] of {}", track_ref.get_uri(), index, tracks_len ); - // This will keep looping over, instead we should cylce tracks only once index = if index + 1 < tracks_len { index + 1 } else { 0 }; + if index == start_index { + warn!("No playable track found in state: {:?}", self.state); + break; + } + self.state.set_playing_track_index(index); track_ref = &self.state.get_track()[index as usize]; track_id = self.get_spotify_id_for_track(track_ref); } track_id } - .unwrap(); + .expect("Invalid SpotifyId"); let position = self.state.get_position_ms(); let end_of_track = self.player.load(track, play, position); From ee3a756a6edf8748e90d500430f317c57587e819 Mon Sep 17 00:00:00 2001 From: ashthespy Date: Wed, 30 Oct 2019 13:53:11 +0100 Subject: [PATCH 07/43] Fix borrow for Rust 1.32.0 --- connect/src/spirc.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/connect/src/spirc.rs b/connect/src/spirc.rs index 041bc88e..299bae02 100644 --- a/connect/src/spirc.rs +++ b/connect/src/spirc.rs @@ -836,8 +836,8 @@ impl SpircTask { // tracks in each frame either have a gid or uri (that may or may not be a valid track) // E.g - context based frames sometimes contain tracks with let track = { - let mut track_ref = &self.state.get_track()[index as usize]; - let mut track_id = self.get_spotify_id_for_track(track_ref); + let mut track_ref = self.state.get_track()[index as usize].clone(); + let mut track_id = self.get_spotify_id_for_track(&track_ref); while track_id.is_err() || track_id.unwrap().audio_type == SpotifyAudioType::NonPlayable { warn!( "Skipping track <{:?}> at position [{}] of {}", @@ -846,13 +846,13 @@ impl SpircTask { tracks_len ); index = if index + 1 < tracks_len { index + 1 } else { 0 }; + self.state.set_playing_track_index(index); if index == start_index { warn!("No playable track found in state: {:?}", self.state); break; } - self.state.set_playing_track_index(index); - track_ref = &self.state.get_track()[index as usize]; - track_id = self.get_spotify_id_for_track(track_ref); + track_ref = self.state.get_track()[index as usize].clone(); + track_id = self.get_spotify_id_for_track(&track_ref); } track_id } From 939fc583e7e8221a457085f8e63918caa224778e Mon Sep 17 00:00:00 2001 From: ashthespy Date: Fri, 1 Nov 2019 17:01:58 +0100 Subject: [PATCH 08/43] Help `pkg-config` with explicit paths --- contrib/Dockerfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contrib/Dockerfile b/contrib/Dockerfile index 9cf2d134..74b83d31 100644 --- a/contrib/Dockerfile +++ b/contrib/Dockerfile @@ -44,6 +44,10 @@ RUN mkdir /build && \ ENV CARGO_TARGET_DIR /build ENV CARGO_HOME /build/cache ENV PKG_CONFIG_ALLOW_CROSS=1 +ENV PKG_CONFIG_PATH_aarch64-unknown-linux-gnu=/usr/lib/aarch64-linux-gnu/pkgconfig/ +ENV PKG_CONFIG_PATH_arm-unknown-linux-gnueabihf=/usr/lib/arm-linux-gnueabihf/pkgconfig/ +ENV PKG_CONFIG_PATH_arm-unknown-linux-gnueabi=/usr/lib/arm-linux-gnueabi/pkgconfig/ +ENV PKG_CONFIG_PATH_mipsel-unknown-linux-gnu=/usr/lib/mipsel-linux-gnu/pkgconfig/ ADD . /src WORKDIR /src From 333fc5010c05b843fea62e7d85def603414d4e6c Mon Sep 17 00:00:00 2001 From: Konstantin Seiler Date: Sat, 2 Nov 2019 06:46:28 +1100 Subject: [PATCH 09/43] New file downloading mechanism --- Cargo.lock | 2 + audio/Cargo.toml | 2 + audio/src/fetch.rs | 744 ++++++++++++++++++++++++++++++++++------- audio/src/lib.rs | 7 +- audio/src/range_set.rs | 241 +++++++++++++ core/src/channel.rs | 2 + playback/src/player.rs | 65 +++- 7 files changed, 944 insertions(+), 119 deletions(-) create mode 100644 audio/src/range_set.rs diff --git a/Cargo.lock b/Cargo.lock index 1f4824f5..67573c29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -467,6 +467,7 @@ version = "0.1.0" dependencies = [ "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "lewton 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", "librespot-core 0.1.0", @@ -475,6 +476,7 @@ dependencies = [ "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tremor 0.1.0 (git+https://github.com/plietar/rust-tremor)", "vorbis 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/audio/Cargo.toml b/audio/Cargo.toml index 5c61b694..59ebfe84 100644 --- a/audio/Cargo.toml +++ b/audio/Cargo.toml @@ -9,6 +9,7 @@ path = "../core" [dependencies] bit-set = "0.4.0" byteorder = "1.0" +bytes = "0.4" futures = "0.1.8" lewton = "0.9.3" log = "0.3.5" @@ -16,6 +17,7 @@ num-bigint = "0.1.35" num-traits = "0.1.36" rust-crypto = "0.2.36" tempfile = "2.1" +tokio = "0.1.2" tremor = { git = "https://github.com/plietar/rust-tremor", optional = true } vorbis = { version ="0.1.0", optional = true } diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index 1aa0c0c0..ffdbe4b1 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -1,5 +1,5 @@ -use bit_set::BitSet; use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; +use bytes::Bytes; use futures::sync::{mpsc, oneshot}; use futures::Stream; use futures::{Async, Future, Poll}; @@ -7,13 +7,20 @@ use std::cmp::min; use std::fs; use std::io::{self, Read, Seek, SeekFrom, Write}; use std::sync::{Arc, Condvar, Mutex}; +use std::time::{Duration, Instant}; use tempfile::NamedTempFile; +use range_set::{Range, RangeSet}; use core::channel::{Channel, ChannelData, ChannelError, ChannelHeaders}; use core::session::Session; use core::spotify_id::FileId; +use futures::sync::mpsc::unbounded; +use std::sync::atomic; +use std::sync::atomic::AtomicUsize; -const CHUNK_SIZE: usize = 0x20000; +const MINIMUM_CHUNK_SIZE: usize = 1024 * 16; +const MAXIMUM_CHUNK_SIZE: usize = 1024 * 128; +const MAXIMUM_ASSUMED_PING_TIME_SECONDS: u64 = 5; pub enum AudioFile { Cached(fs::File), @@ -27,37 +34,187 @@ pub enum AudioFileOpen { pub struct AudioFileOpenStreaming { session: Session, - data_rx: Option, + initial_data_rx: Option, + initial_data_length: Option, + initial_request_sent_time: Instant, headers: ChannelHeaders, file_id: FileId, complete_tx: Option>, } + +enum StreamLoaderCommand{ + Fetch(Range), // signal the stream loader to fetch a range of the file + RandomAccessMode(), // optimise download strategy for random access + StreamMode(), // optimise download strategy for streaming + StreamDataRate(usize), // when optimising for streaming, assume a streaming rate of this many bytes per second. + Close(), // terminate and don't load any more data +} + + +#[derive(Clone)] +pub struct StreamLoaderController { + channel_tx: Option>, + stream_shared: Option>, + file_size: usize, +} + + +impl StreamLoaderController { + pub fn len(&self) -> usize { + return self.file_size; + } + + pub fn range_available(&self, range: Range) -> bool { + if let Some(ref shared) = self.stream_shared { + let mut download_status = shared.download_status.lock().unwrap(); + if range.length <= download_status.downloaded.contained_length_from_value(range.start) { + return true; + } else { + return false; + } + } else { + if range.length <= self.len() - range.start { + return true; + } else { + return false; + } + } + } + + pub fn ping_time_ms(&self) -> usize { + if let Some(ref shared) = self.stream_shared { + return shared.ping_time_ms.load(atomic::Ordering::Relaxed); + } else { + return 0; + } + } + + fn send_stream_loader_command(&mut self, command: StreamLoaderCommand) { + if let Some(ref mut channel) = self.channel_tx { + // ignore the error in case the channel has been closed already. + let _ = channel.unbounded_send(command); + } + } + + pub fn fetch(&mut self, range: Range) { + // signal the stream loader to fetch a range of the file + self.send_stream_loader_command(StreamLoaderCommand::Fetch(range)); + } + + pub fn fetch_blocking(&mut self, mut range: Range) { + // signal the stream loader to tech a range of the file and block until it is loaded. + + // ensure the range is within the file's bounds. + if range.start >= self.len() { + range.length = 0; + } else if range.end() > self.len() { + range.length = self.len() - range.start; + } + + self.fetch(range); + + if let Some(ref shared) = self.stream_shared { + let mut download_status = shared.download_status.lock().unwrap(); + while range.length > download_status.downloaded.contained_length_from_value(range.start) { + download_status = shared.cond.wait_timeout(download_status, Duration::from_millis(1000)).unwrap().0; + if range.length > (download_status.downloaded.union(&download_status.requested).contained_length_from_value(range.start)) { + // For some reason, the requested range is neither downloaded nor requested. + // This could be due to a network error. Request it again. + // We can't use self.fetch here because self can't borrowed mutably, so we access the channel directly. + if let Some(ref mut channel) = self.channel_tx { + // ignore the error in case the channel has been closed already. + let _ = channel.unbounded_send(StreamLoaderCommand::Fetch(range)); + } + } + } + } + + } + + pub fn fetch_next(&mut self, length: usize) { + let range:Range = if let Some(ref shared) = self.stream_shared { + Range { + start: shared.read_position.load(atomic::Ordering::Relaxed), + length: length, + } + } else { + return; + }; + self.fetch(range); + } + + pub fn fetch_next_blocking(&mut self, length: usize) { + let range:Range = if let Some(ref shared) = self.stream_shared { + Range { + start: shared.read_position.load(atomic::Ordering::Relaxed), + length: length, + } + } else { + return; + }; + self.fetch_blocking(range); + } + + pub fn set_random_access_mode(&mut self) { + // optimise download strategy for random access + self.send_stream_loader_command(StreamLoaderCommand::RandomAccessMode()); + } + + pub fn set_stream_mode(&mut self) { + // optimise download strategy for streaming + self.send_stream_loader_command(StreamLoaderCommand::StreamMode()); + } + + pub fn set_stream_data_rate(&mut self, bytes_per_second: usize) { + // when optimising for streaming, assume a streaming rate of this many bytes per second. + self.send_stream_loader_command(StreamLoaderCommand::StreamDataRate(bytes_per_second)); + } + + pub fn close(&mut self) { + // terminate stream loading and don't load any more data for this file. + self.send_stream_loader_command(StreamLoaderCommand::Close()); + } + + +} + + pub struct AudioFileStreaming { read_file: fs::File, position: u64, - seek: mpsc::UnboundedSender, + + stream_loader_command_tx: mpsc::UnboundedSender, shared: Arc, } + +struct AudioFileDownloadStatus { + requested: RangeSet, + downloaded: RangeSet, +} + struct AudioFileShared { file_id: FileId, - chunk_count: usize, + file_size: usize, cond: Condvar, - bitmap: Mutex, + download_status: Mutex, + ping_time_ms: AtomicUsize, + read_position: AtomicUsize, } impl AudioFileOpenStreaming { fn finish(&mut self, size: usize) -> AudioFileStreaming { - let chunk_count = (size + CHUNK_SIZE - 1) / CHUNK_SIZE; let shared = Arc::new(AudioFileShared { file_id: self.file_id, - chunk_count: chunk_count, + file_size: size, cond: Condvar::new(), - bitmap: Mutex::new(BitSet::with_capacity(chunk_count)), + download_status: Mutex::new(AudioFileDownloadStatus {requested: RangeSet::new(), downloaded: RangeSet::new()}), + ping_time_ms: AtomicUsize::new(0), + read_position: AtomicUsize::new(0), }); let mut write_file = NamedTempFile::new().unwrap(); @@ -66,16 +223,20 @@ impl AudioFileOpenStreaming { let read_file = write_file.reopen().unwrap(); - let data_rx = self.data_rx.take().unwrap(); + let initial_data_rx = self.initial_data_rx.take().unwrap(); + let initial_data_length = self.initial_data_length.take().unwrap(); let complete_tx = self.complete_tx.take().unwrap(); - let (seek_tx, seek_rx) = mpsc::unbounded(); + //let (seek_tx, seek_rx) = mpsc::unbounded(); + let (stream_loader_command_tx, stream_loader_command_rx) = mpsc::unbounded::(); let fetcher = AudioFileFetch::new( self.session.clone(), shared.clone(), - data_rx, + initial_data_rx, + self.initial_request_sent_time, + initial_data_length, write_file, - seek_rx, + stream_loader_command_rx, complete_tx, ); self.session.spawn(move |_| fetcher); @@ -84,7 +245,8 @@ impl AudioFileOpenStreaming { read_file: read_file, position: 0, - seek: seek_tx, + //seek: seek_tx, + stream_loader_command_tx: stream_loader_command_tx, shared: shared, } @@ -139,14 +301,17 @@ impl AudioFile { debug!("Downloading file {}", file_id); let (complete_tx, complete_rx) = oneshot::channel(); - let (headers, data) = request_chunk(session, file_id, 0).split(); + let initial_data_length = MINIMUM_CHUNK_SIZE; + let (headers, data) = request_range(session, file_id, 0, initial_data_length).split(); let open = AudioFileOpenStreaming { session: session.clone(), file_id: file_id, headers: headers, - data_rx: Some(data), + initial_data_rx: Some(data), + initial_data_length: Some(initial_data_length), + initial_request_sent_time: Instant::now(), complete_tx: Some(complete_tx), }; @@ -167,13 +332,36 @@ impl AudioFile { AudioFileOpen::Streaming(open) } + + pub fn get_stream_loader_controller(&self) -> StreamLoaderController { + match self { + AudioFile::Streaming(stream) => { + return StreamLoaderController { + channel_tx: Some(stream.stream_loader_command_tx.clone()), + stream_shared: Some(stream.shared.clone()), + file_size: stream.shared.file_size, + } + } + AudioFile::Cached(ref file) => { + return StreamLoaderController { + channel_tx: None, + stream_shared: None, + file_size: file.metadata().unwrap().len() as usize, + } + } + } + } } -fn request_chunk(session: &Session, file: FileId, index: usize) -> Channel { - trace!("requesting chunk {}", index); - let start = (index * CHUNK_SIZE / 4) as u32; - let end = ((index + 1) * CHUNK_SIZE / 4) as u32; +fn request_range(session: &Session, file: FileId, offset: usize, length: usize) -> Channel { + trace!("requesting range starting at {} of length {}", offset, length); + + let start = offset / 4; + let mut end = (offset+length) / 4; + if (offset+length) % 4 != 0 { + end += 1; + } let (id, channel) = session.channel().allocate(); @@ -186,81 +374,405 @@ fn request_chunk(session: &Session, file: FileId, index: usize) -> Channel { data.write_u32::(0x00009C40).unwrap(); data.write_u32::(0x00020000).unwrap(); data.write(&file.0).unwrap(); - data.write_u32::(start).unwrap(); - data.write_u32::(end).unwrap(); + data.write_u32::(start as u32).unwrap(); + data.write_u32::(end as u32).unwrap(); session.send_packet(0x8, data); channel } + + +struct PartialFileData { + offset: usize, + data: Bytes, +} + +enum ReceivedData { + ResponseTimeMs(usize), + Data(PartialFileData), +} + +struct AudioFileFetchDataReceiver { + shared: Arc, + file_data_tx: mpsc::UnboundedSender, + data_rx: ChannelData, + data_offset: usize, + request_length: usize, + request_sent_time: Option, +} + +impl AudioFileFetchDataReceiver { + fn new( + shared: Arc, + file_data_tx: mpsc::UnboundedSender, + data_rx: ChannelData, + data_offset: usize, + request_length: usize, + request_sent_time: Instant, + ) -> AudioFileFetchDataReceiver { + + AudioFileFetchDataReceiver { + shared: shared, + data_rx: data_rx, + file_data_tx: file_data_tx, + data_offset: data_offset, + request_length: request_length, + request_sent_time: Some(request_sent_time), + } + } +} + + + +impl AudioFileFetchDataReceiver { + fn finish(&mut self) { + if self.request_length > 0 { + + let missing_range = Range::new(self.data_offset, self.request_length); + + let mut download_status = self.shared.download_status.lock().unwrap(); + download_status.requested.subtract_range(&missing_range); + self.shared.cond.notify_all(); + } + } +} + +impl Future for AudioFileFetchDataReceiver { + type Item = (); + type Error = (); + + fn poll(&mut self) -> Poll<(), ()> { + loop { + trace!("Looping data_receiver for offset {} and length {}", self.data_offset, self.request_length); + match self.data_rx.poll() { + Ok(Async::Ready(Some(data))) => { + if let Some(request_sent_time) = self.request_sent_time { + let duration = Instant::now() - request_sent_time; + let mut duration_ms: u64; + if duration.as_secs() > MAXIMUM_ASSUMED_PING_TIME_SECONDS { + duration_ms = MAXIMUM_ASSUMED_PING_TIME_SECONDS * 1000; + }else { + duration_ms = duration.as_secs() *1000 + duration.subsec_millis() as u64; + } + let _ = self.file_data_tx.unbounded_send(ReceivedData::ResponseTimeMs(duration_ms as usize)); + } + let data_size = data.len(); + trace!("data_receiver got {} bytes of data", data_size); + let _ = self.file_data_tx.unbounded_send(ReceivedData::Data(PartialFileData { offset: self.data_offset, data: data, })); + self.data_offset += data_size; + if self.request_length < data_size { + warn!("Received more data from server than requested."); + self.request_length = 0; + } else { + self.request_length -= data_size; + } + if self.request_length == 0 { + trace!("Data receiver completed at position {}", self.data_offset); + return Ok(Async::Ready(())); + } + } + Ok(Async::Ready(None)) => { + if self.request_length > 0 { + warn!("Received less data from server than requested."); + self.finish(); + } + return Ok(Async::Ready(())); + } + Ok(Async::NotReady) => { + //trace!("No more data for data_receiver at the moment."); + return Ok(Async::NotReady); + } + Err(ChannelError) => { + warn!("error from channel"); + self.finish(); + return Ok(Async::Ready(())); + } + } + } + } +} + + +enum DownloadStrategy { + RandomAccess(), + Streaming(), +} + struct AudioFileFetch { session: Session, shared: Arc, output: Option, - index: usize, - data_rx: ChannelData, + file_data_tx: mpsc::UnboundedSender, + file_data_rx: mpsc::UnboundedReceiver, - seek_rx: mpsc::UnboundedReceiver, + stream_loader_command_rx: mpsc::UnboundedReceiver, complete_tx: Option>, + download_strategy: DownloadStrategy, + streaming_data_rate: usize, + network_response_times_ms: Vec, } impl AudioFileFetch { fn new( session: Session, shared: Arc, - data_rx: ChannelData, + initial_data_rx: ChannelData, + initial_request_sent_time: Instant, + initial_data_length: usize, + output: NamedTempFile, - seek_rx: mpsc::UnboundedReceiver, + stream_loader_command_rx: mpsc::UnboundedReceiver, complete_tx: oneshot::Sender, ) -> AudioFileFetch { + + let (file_data_tx, file_data_rx) = unbounded::(); + + { + let requested_range = Range::new(0, initial_data_length); + let mut download_status = shared.download_status.lock().unwrap(); + download_status.requested.add_range(&requested_range); + } + + + let initial_data_receiver = AudioFileFetchDataReceiver::new( + shared.clone(), + file_data_tx.clone(), + initial_data_rx, + 0, + initial_data_length, + initial_request_sent_time, + ); + + session.spawn(move |_| initial_data_receiver); + AudioFileFetch { session: session, shared: shared, output: Some(output), - index: 0, - data_rx: data_rx, + file_data_tx: file_data_tx, + file_data_rx: file_data_rx, - seek_rx: seek_rx, + stream_loader_command_rx: stream_loader_command_rx, complete_tx: Some(complete_tx), + download_strategy: DownloadStrategy::RandomAccess(), // start with random access mode until someone tells us otherwise + streaming_data_rate: 40, // assume 360 kbit per second unless someone tells us otherwise. + network_response_times_ms: Vec::new(), } } - fn download(&mut self, mut new_index: usize) { - assert!(new_index < self.shared.chunk_count); + fn download_range(&mut self, mut offset: usize, mut length: usize) { + if length < MINIMUM_CHUNK_SIZE { + length = MINIMUM_CHUNK_SIZE; + } + + // ensure the values are within the bounds and align them by 4 for the spotify protocol. + if offset >= self.shared.file_size { + return; + } + + if length <= 0 { + return; + } + + if offset + length > self.shared.file_size { + length = self.shared.file_size - offset; + } + + if offset % 4 != 0 { + length += offset % 4; + offset -= offset % 4; + } + + if length % 4 != 0 { + length += 4 - (length % 4); + } + + let mut ranges_to_request = RangeSet::new(); + ranges_to_request.add_range(&Range::new(offset, length)); + + let mut download_status = self.shared.download_status.lock().unwrap(); + + ranges_to_request.subtract_range_set(&download_status.downloaded); + ranges_to_request.subtract_range_set(&download_status.requested); + + + for range in ranges_to_request.iter() { + let (_headers, data) = request_range(&self.session, self.shared.file_id, range.start, range.length).split(); + + download_status.requested.add_range(range); + + + let receiver = AudioFileFetchDataReceiver::new( + self.shared.clone(), + self.file_data_tx.clone(), + data, + range.start, + range.length, + Instant::now(), + ); + + self.session.spawn(move |_| receiver); + } + + } + + fn pre_fetch_more_data(&mut self) { + + // determine what is still missing + let mut missing_data = RangeSet::new(); + missing_data.add_range(&Range::new(0,self.shared.file_size)); { - let bitmap = self.shared.bitmap.lock().unwrap(); - while bitmap.contains(new_index) { - new_index = (new_index + 1) % self.shared.chunk_count; + let download_status = self.shared.download_status.lock().unwrap(); + missing_data.subtract_range_set(&download_status.downloaded); + missing_data.subtract_range_set(&download_status.requested); + } + + // download data from after the current read position first + let mut tail_end = RangeSet::new(); + let read_position = self.shared.read_position.load(atomic::Ordering::Relaxed); + tail_end.add_range(&Range::new(read_position, self.shared.file_size - read_position)); + let tail_end = tail_end.intersection(&missing_data); + + if ! tail_end.is_empty() { + let range = tail_end.get_range(0); + let offset = range.start; + let length = min(range.length, MAXIMUM_CHUNK_SIZE); + self.download_range(offset, length); + + } else if ! missing_data.is_empty() { + // ok, the tail is downloaded, download something fom the beginning. + let range = missing_data.get_range(0); + let offset = range.start; + let length = min(range.length, MAXIMUM_CHUNK_SIZE); + self.download_range(offset, length); + } + + } + + fn poll_file_data_rx(&mut self) -> Poll<(), ()> { + + loop { + match self.file_data_rx.poll() { + Ok(Async::Ready(None)) => { + trace!("File data channel closed."); + return Ok(Async::Ready(())); + } + Ok(Async::Ready(Some(ReceivedData::ResponseTimeMs(response_time_ms)))) => { + trace!("Received ping time information: {} ms.", response_time_ms); + + // record the response time + self.network_response_times_ms.push(response_time_ms); + + // prone old response times. Keep at most three. + while self.network_response_times_ms.len() > 3 { + self.network_response_times_ms.remove(0); + } + + // stats::median is experimental. So we calculate the median of up to three ourselves. + let ping_time_ms: usize = match self.network_response_times_ms.len() { + 1 => self.network_response_times_ms[0] as usize, + 2 => ((self.network_response_times_ms[0] + self.network_response_times_ms[1]) / 2) as usize, + 3 => { + let mut times = self.network_response_times_ms.clone(); + times.sort(); + times[1] + } + _ => unreachable!(), + }; + + // store our new estimate for everyone to see + self.shared.ping_time_ms.store(ping_time_ms, atomic::Ordering::Relaxed); + + }, + Ok(Async::Ready(Some(ReceivedData::Data(data)))) => { + + trace!("Writing data to file: offset {}, length {}", data.offset, data.data.len()); + + self.output + .as_mut() + .unwrap() + .seek(SeekFrom::Start(data.offset as u64)) + .unwrap(); + self.output.as_mut().unwrap().write_all(data.data.as_ref()).unwrap(); + + + + let mut full = false; + + { + let mut download_status = self.shared.download_status.lock().unwrap(); + + let received_range = Range::new(data.offset, data.data.len()); + download_status.downloaded.add_range(&received_range); + self.shared.cond.notify_all(); + + if download_status.downloaded.contained_length_from_value(0) >= self.shared.file_size { + full = true; + } + drop(download_status); + } + + if full { + self.finish(); + return Ok(Async::Ready(())); + } + + + } + Ok(Async::NotReady) => { + return Ok(Async::NotReady); + }, + Err(()) => unreachable!(), + } + + } + + } + + + fn poll_stream_loader_command_rx(&mut self) -> Poll<(), ()> { + + loop { + match self.stream_loader_command_rx.poll() { + Ok(Async::Ready(None)) => {} + Ok(Async::Ready(Some(StreamLoaderCommand::Fetch(request)))) => { + self.download_range(request.start, request.length); + } + Ok(Async::Ready(Some(StreamLoaderCommand::RandomAccessMode()))) => { + self.download_strategy = DownloadStrategy::RandomAccess(); + } + Ok(Async::Ready(Some(StreamLoaderCommand::StreamMode()))) => { + self.download_strategy = DownloadStrategy::Streaming(); + } + Ok(Async::Ready(Some(StreamLoaderCommand::StreamDataRate(rate)))) => { + self.streaming_data_rate = rate; + } + Ok(Async::Ready(Some(StreamLoaderCommand::Close()))) => { + return Ok(Async::Ready(())); + } + Ok(Async::NotReady) => { + return Ok(Async::NotReady) + }, + Err(()) => unreachable!(), } } - if self.index != new_index { - self.index = new_index; - - let offset = self.index * CHUNK_SIZE; - - self.output - .as_mut() - .unwrap() - .seek(SeekFrom::Start(offset as u64)) - .unwrap(); - - let (_headers, data) = request_chunk(&self.session, self.shared.file_id, self.index).split(); - self.data_rx = data; - } } fn finish(&mut self) { + trace!("====== FINISHED DOWNLOADING FILE! ======"); let mut output = self.output.take().unwrap(); let complete_tx = self.complete_tx.take().unwrap(); output.seek(SeekFrom::Start(0)).unwrap(); let _ = complete_tx.send(output); } + } impl Future for AudioFileFetch { @@ -268,80 +780,92 @@ impl Future for AudioFileFetch { type Error = (); fn poll(&mut self) -> Poll<(), ()> { - loop { - let mut progress = false; - match self.seek_rx.poll() { - Ok(Async::Ready(None)) => { - return Ok(Async::Ready(())); - } - Ok(Async::Ready(Some(offset))) => { - progress = true; - let index = offset as usize / CHUNK_SIZE; - self.download(index); - } - Ok(Async::NotReady) => (), - Err(()) => unreachable!(), + trace!("Polling AudioFileFetch"); + + match self.poll_stream_loader_command_rx() { + Ok(Async::NotReady) => (), + Ok(Async::Ready(_)) => { + return Ok(Async::Ready(())); } + Err(()) => unreachable!(), + } - match self.data_rx.poll() { - Ok(Async::Ready(Some(data))) => { - progress = true; - - self.output.as_mut().unwrap().write_all(data.as_ref()).unwrap(); - } - Ok(Async::Ready(None)) => { - progress = true; - - trace!("chunk {} / {} complete", self.index, self.shared.chunk_count); - - let full = { - let mut bitmap = self.shared.bitmap.lock().unwrap(); - bitmap.insert(self.index as usize); - self.shared.cond.notify_all(); - - bitmap.len() >= self.shared.chunk_count - }; - - if full { - self.finish(); - return Ok(Async::Ready(())); - } - - let new_index = (self.index + 1) % self.shared.chunk_count; - self.download(new_index); - } - Ok(Async::NotReady) => (), - Err(ChannelError) => { - warn!("error from channel"); - return Ok(Async::Ready(())); - } + match self.poll_file_data_rx() { + Ok(Async::NotReady) => (), + Ok(Async::Ready(_)) => { + return Ok(Async::Ready(())); } + Err(()) => unreachable!(), + } - if !progress { - return Ok(Async::NotReady); + + if let DownloadStrategy::Streaming() = self.download_strategy { + let bytes_pending: usize = { + let download_status = self.shared.download_status.lock().unwrap(); + download_status.requested.minus(&download_status.downloaded).len() + }; + + let ping_time = self.shared.ping_time_ms.load(atomic::Ordering::Relaxed); + + if bytes_pending < 2 * ping_time * self.streaming_data_rate { + self.pre_fetch_more_data(); } } + + + return Ok(Async::NotReady) } } impl Read for AudioFileStreaming { fn read(&mut self, output: &mut [u8]) -> io::Result { - let index = self.position as usize / CHUNK_SIZE; - let offset = self.position as usize % CHUNK_SIZE; - let len = min(output.len(), CHUNK_SIZE - offset); + let offset = self.position as usize; - let mut bitmap = self.shared.bitmap.lock().unwrap(); - while !bitmap.contains(index) { - bitmap = self.shared.cond.wait(bitmap).unwrap(); + if offset >= self.shared.file_size { + return Ok(0); } - drop(bitmap); - let read_len = try!(self.read_file.read(&mut output[..len])); + let length = min(output.len(), self.shared.file_size - offset); + + if length == 0 { + return Ok(0); + } + + + + let mut ranges_to_request = RangeSet::new(); + ranges_to_request.add_range(&Range::new(offset, length)); + + + let mut download_status = self.shared.download_status.lock().unwrap(); + ranges_to_request.subtract_range_set(&download_status.downloaded); + ranges_to_request.subtract_range_set(&download_status.requested); + + + for range in ranges_to_request.iter() { + debug!("requesting data at position {} (length : {})", range.start, range.length); + self.stream_loader_command_tx.unbounded_send(StreamLoaderCommand::Fetch(range.clone())).unwrap(); + } + + while !download_status.downloaded.contains(offset) { + download_status = self.shared.cond.wait_timeout(download_status, Duration::from_millis(1000)).unwrap().0; + } + let available_length = download_status.downloaded.contained_length_from_value(offset); + assert!(available_length > 0); + drop(download_status); + + + self.position = self.read_file.seek(SeekFrom::Start(offset as u64)).unwrap(); + let read_len = min(length, available_length); + let read_len = try!(self.read_file.read(&mut output[..read_len])); + self.position += read_len as u64; + self.shared.read_position.store(self.position as usize, atomic::Ordering::Relaxed); - Ok(read_len) + + return Ok(read_len); } } @@ -349,15 +873,7 @@ impl Seek for AudioFileStreaming { fn seek(&mut self, pos: SeekFrom) -> io::Result { self.position = try!(self.read_file.seek(pos)); // Do not seek past EOF - if (self.position as usize % CHUNK_SIZE) != 0 { - // Notify the fetch thread to get the correct block - // This can fail if fetch thread has completed, in which case the - // block is ready. Just ignore the error. - let _ = self.seek.unbounded_send(self.position); - } else { - warn!("Trying to seek past EOF"); - } - + self.shared.read_position.store(self.position as usize, atomic::Ordering::Relaxed); Ok(self.position) } } diff --git a/audio/src/lib.rs b/audio/src/lib.rs index 5b582dc0..f316e143 100644 --- a/audio/src/lib.rs +++ b/audio/src/lib.rs @@ -5,10 +5,12 @@ extern crate log; extern crate bit_set; extern crate byteorder; +extern crate bytes; extern crate crypto; extern crate num_bigint; extern crate num_traits; extern crate tempfile; +extern crate tokio; extern crate librespot_core as core; @@ -20,10 +22,13 @@ mod lewton_decoder; #[cfg(any(feature = "with-tremor", feature = "with-vorbis"))] mod libvorbis_decoder; +mod range_set; + pub use decrypt::AudioDecrypt; -pub use fetch::{AudioFile, AudioFileOpen}; +pub use fetch::{AudioFile, AudioFileOpen, StreamLoaderController}; #[cfg(not(any(feature = "with-tremor", feature = "with-vorbis")))] pub use lewton_decoder::{VorbisDecoder, VorbisError, VorbisPacket}; #[cfg(any(feature = "with-tremor", feature = "with-vorbis"))] pub use libvorbis_decoder::{VorbisDecoder, VorbisError, VorbisPacket}; + diff --git a/audio/src/range_set.rs b/audio/src/range_set.rs new file mode 100644 index 00000000..378725f6 --- /dev/null +++ b/audio/src/range_set.rs @@ -0,0 +1,241 @@ + +use std::cmp::{max,min}; +use std::slice::Iter; + + + +#[derive(Copy, Clone)] +pub struct Range { + pub start: usize, + pub length: usize, +} + +impl Range { + + pub fn new(start: usize, length: usize) -> Range { + return Range { + start: start, + length: length, + } + } + + pub fn end(&self) -> usize { + return self.start + self.length; + } + +} + +#[derive(Clone)] +pub struct RangeSet { + ranges: Vec, +} + + +impl RangeSet { + pub fn new() -> RangeSet { + RangeSet{ + ranges: Vec::::new(), + } + } + + pub fn is_empty(&self) -> bool { + return self.ranges.is_empty(); + } + + pub fn len(&self) -> usize { + let mut result = 0; + for range in self.ranges.iter() { + result += range.length; + } + return result; + } + + pub fn get_range(&self, index: usize) -> Range { + return self.ranges[index].clone(); + } + + pub fn iter(&self) -> Iter { + return self.ranges.iter(); + } + + pub fn contains(&self, value: usize) -> bool { + for range in self.ranges.iter() { + if value < range.start { + return false; + } else if range.start <= value && value < range.end() { + return true; + } + } + return false; + } + + pub fn contained_length_from_value(&self, value: usize) -> usize { + for range in self.ranges.iter() { + if value < range.start { + return 0; + } else if range.start <= value && value < range.end() { + return range.end() - value; + } + } + return 0; + + } + + #[allow(dead_code)] + pub fn contains_range_set(&self, other: &RangeSet) -> bool { + for range in other.ranges.iter() { + if self.contained_length_from_value(range.start) < range.length { + return false; + } + } + return true; + } + + + pub fn add_range(&mut self, range:&Range) { + + if range.length <= 0 { + // the interval is empty or invalid -> nothing to do. + return; + } + + + for index in 0..self.ranges.len() { + // the new range is clear of any ranges we already iterated over. + if range.end() < self.ranges[index].start{ + // the new range starts after anything we already passed and ends before the next range starts (they don't touch) -> insert it. + self.ranges.insert(index, range.clone()); + return; + + } else if range.start <= self.ranges[index].end() && self.ranges[index].start <= range.end() { + // the new range overlaps (or touches) the first range. They are to be merged. + // In addition we might have to merge further ranges in as well. + + let mut new_range = range.clone(); + + while index < self.ranges.len() && self.ranges[index].start <= new_range.end() { + let new_end = max(new_range.end(), self.ranges[index].end()); + new_range.start = min(new_range.start, self.ranges[index].start); + new_range.length = new_end - new_range.start; + self.ranges.remove(index); + } + + self.ranges.insert(index, new_range); + return; + + } + } + + // the new range is after everything else -> just add it + self.ranges.push(range.clone()); + } + + #[allow(dead_code)] + pub fn add_range_set(&mut self, other: &RangeSet) { + for range in other.ranges.iter() { + self.add_range(range); + } + } + + #[allow(dead_code)] + pub fn union(&self, other: &RangeSet) -> RangeSet { + let mut result = self.clone(); + result.add_range_set(other); + return result; + } + + pub fn subtract_range(&mut self, range: &Range) { + + if range.length <= 0 { + return; + } + + for index in 0..self.ranges.len() { + // the ranges we already passed don't overlap with the range to remove + + if range.end() <= self.ranges[index].start { + // the remaining ranges are past the one to subtract. -> we're done. + return + + } else if range.start <= self.ranges[index].start && self.ranges[index].start < range.end() { + // the range to subtract started before the current range and reaches into the current range + // -> we have to remove the beginning of the range or the entire range and do the same for following ranges. + + while index < self.ranges.len() && self.ranges[index].end() <= range.end() { + self.ranges.remove(index); + } + + if index < self.ranges.len() && self.ranges[index].start < range.end() { + self.ranges[index].start = range.end(); + } + + return; + + } else if range.end() < self.ranges[index].end() { + // the range to subtract punches a hole into the current range -> we need to create two smaller ranges. + + let first_range = Range { + start: self.ranges[index].start, + length: range.start - self.ranges[index].start, + }; + + self.ranges[index].start = range.end(); + + self.ranges.insert(index, first_range); + + return; + + } else if range.start < self.ranges[index].end() { + // the range truncates the existing range -> truncate the range. Let the for loop take care of overlaps with other ranges. + self.ranges[index].length = range.start - self.ranges[index].start; + + } + } + } + + pub fn subtract_range_set(&mut self, other: &RangeSet) { + for range in other.ranges.iter() { + self.subtract_range(range); + } + } + + pub fn minus(&self, other: &RangeSet) -> RangeSet { + let mut result = self.clone(); + result.subtract_range_set(other); + return result; + } + + pub fn intersection(&self, other: &RangeSet) -> RangeSet { + let mut result = RangeSet::new(); + + let mut self_index: usize = 0; + let mut other_index: usize = 0; + + while self_index < self.ranges.len() && other_index < other.ranges.len() { + if self.ranges[self_index].end() <= other.ranges[other_index].start { + // skip the interval + self_index += 1; + } else if other.ranges[other_index].end() <= self.ranges[self_index].start { + // skip the interval + other_index += 1; + } else { + // the two intervals overlap. Add the union and advance the index of the one that ends first. + let new_start = max(self.ranges[self_index].start, other.ranges[other_index].start); + let new_end = min(self.ranges[self_index].end(), other.ranges[other_index].end()); + assert!(new_start <= new_end); + result.add_range(&Range::new(new_start, new_end-new_start)); + if self.ranges[self_index].end() <= other.ranges[other_index].end() { + self_index += 1; + } else { + other_index += 1; + } + + } + + } + + return result; + } + +} + diff --git a/core/src/channel.rs b/core/src/channel.rs index 57655feb..3238a0a6 100644 --- a/core/src/channel.rs +++ b/core/src/channel.rs @@ -59,6 +59,8 @@ impl ChannelManager { let id: u16 = BigEndian::read_u16(data.split_to(2).as_ref()); + trace!("Received data for channel {}: {} bytes.", id, data.len()); + self.lock(|inner| { if let Entry::Occupied(entry) = inner.channels.entry(id) { let _ = entry.get().unbounded_send((cmd, data)); diff --git a/playback/src/player.rs b/playback/src/player.rs index a421c9ab..5d0e58ab 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -14,12 +14,14 @@ use config::{Bitrate, PlayerConfig}; use core::session::Session; use core::spotify_id::SpotifyId; -use audio::{AudioDecrypt, AudioFile}; +use audio::{AudioDecrypt, AudioFile, StreamLoaderController}; use audio::{VorbisDecoder, VorbisPacket}; use audio_backend::Sink; use metadata::{FileFormat, Metadata, Track}; use mixer::AudioFilter; + + pub struct Player { commands: Option>, thread_handle: Option>, @@ -202,12 +204,14 @@ enum PlayerState { decoder: Decoder, end_of_track: oneshot::Sender<()>, normalisation_factor: f32, + stream_loader_controller: StreamLoaderController, }, Playing { track_id: SpotifyId, decoder: Decoder, end_of_track: oneshot::Sender<()>, normalisation_factor: f32, + stream_loader_controller: StreamLoaderController, }, EndOfTrack { track_id: SpotifyId, @@ -234,6 +238,15 @@ impl PlayerState { } } + fn stream_loader_controller(&mut self) -> Option<&mut StreamLoaderController> { + use self::PlayerState::*; + match *self { + Stopped | EndOfTrack { .. } => None, + Paused { ref mut stream_loader_controller, .. } | Playing { ref mut stream_loader_controller, .. } => Some(stream_loader_controller), + Invalid => panic!("invalid state"), + } + } + fn playing_to_end_of_track(&mut self) { use self::PlayerState::*; match mem::replace(self, Invalid) { @@ -257,12 +270,14 @@ impl PlayerState { decoder, end_of_track, normalisation_factor, + stream_loader_controller, } => { *self = Playing { track_id: track_id, decoder: decoder, end_of_track: end_of_track, normalisation_factor: normalisation_factor, + stream_loader_controller: stream_loader_controller, }; } _ => panic!("invalid state"), @@ -277,12 +292,14 @@ impl PlayerState { decoder, end_of_track, normalisation_factor, + stream_loader_controller, } => { *self = Paused { track_id: track_id, decoder: decoder, end_of_track: end_of_track, normalisation_factor: normalisation_factor, + stream_loader_controller: stream_loader_controller, }; } _ => panic!("invalid state"), @@ -403,7 +420,7 @@ impl PlayerInternal { } match self.load_track(track_id, position as i64) { - Some((decoder, normalisation_factor)) => { + Some((decoder, normalisation_factor, stream_loader_controller)) => { if play { match self.state { PlayerState::Playing { @@ -427,6 +444,7 @@ impl PlayerInternal { decoder: decoder, end_of_track: end_of_track, normalisation_factor: normalisation_factor, + stream_loader_controller: stream_loader_controller, }; } else { self.state = PlayerState::Paused { @@ -434,6 +452,7 @@ impl PlayerInternal { decoder: decoder, end_of_track: end_of_track, normalisation_factor: normalisation_factor, + stream_loader_controller: stream_loader_controller, }; match self.state { PlayerState::Playing { @@ -460,6 +479,9 @@ impl PlayerInternal { } PlayerCommand::Seek(position) => { + if let Some(stream_loader_controller) = self.state.stream_loader_controller() { + stream_loader_controller.set_random_access_mode(); + } if let Some(decoder) = self.state.decoder() { match decoder.seek(position as i64) { Ok(_) => (), @@ -468,6 +490,17 @@ impl PlayerInternal { } else { warn!("Player::seek called from invalid state"); } + + // If we're playing, ensure, that we have enough data leaded to avoid a buffer underrun. + let stream_data_rate = self.stream_data_rate(); + if let Some(stream_loader_controller) = self.state.stream_loader_controller() { + stream_loader_controller.set_stream_mode(); + if let PlayerState::Playing{..} = self.state { + let wait_for_data_length = (2 * stream_loader_controller.ping_time_ms() * stream_data_rate) / 1000; + stream_loader_controller.fetch_next_blocking(wait_for_data_length); + } + } + } PlayerCommand::Play => { @@ -526,7 +559,15 @@ impl PlayerInternal { } } - fn load_track(&self, track_id: SpotifyId, position: i64) -> Option<(Decoder, f32)> { + fn stream_data_rate(&self) -> usize { + match self.config.bitrate { + Bitrate::Bitrate96 => 12 * 1024, + Bitrate::Bitrate160 => 20 * 1024, + Bitrate::Bitrate320 => 40 * 1024, + } + } + + fn load_track(&self, track_id: SpotifyId, position: i64) -> Option<(Decoder, f32, StreamLoaderController)> { let track = Track::get(&self.session, track_id).wait().unwrap(); info!( @@ -565,6 +606,21 @@ impl PlayerInternal { let encrypted_file = encrypted_file.wait().unwrap(); + + let mut stream_loader_controller = encrypted_file.get_stream_loader_controller(); + + // tell the stream loader how to optimise its strategy. + stream_loader_controller.set_stream_data_rate(self.stream_data_rate()); + + if position == 0 { + // No need to seek -> we stream from the beginning + stream_loader_controller.set_stream_mode(); + } else { + // we need to seek -> we set stream mode after the initial seek. + stream_loader_controller.set_random_access_mode(); + } + + let key = key.wait().unwrap(); let mut decrypted_file = AudioDecrypt::new(key, encrypted_file); @@ -585,11 +641,12 @@ impl PlayerInternal { Ok(_) => (), Err(err) => error!("Vorbis error: {:?}", err), } + stream_loader_controller.set_stream_mode(); } info!("Track \"{}\" loaded", track.name); - Some((decoder, normalisation_factor)) + Some((decoder, normalisation_factor, stream_loader_controller)) } } From bf47ca70332fb2853f949566afdacb6f6476fcde Mon Sep 17 00:00:00 2001 From: Konstantin Seiler Date: Sat, 2 Nov 2019 06:48:18 +1100 Subject: [PATCH 10/43] some debug messages --- audio/src/fetch.rs | 67 ++++++++++++++++++++++++++++++++++++++++++ playback/src/player.rs | 27 +++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index ffdbe4b1..d36df090 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -1,3 +1,4 @@ +//use bit_set::BitSet; use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; use bytes::Bytes; use futures::sync::{mpsc, oneshot}; @@ -301,8 +302,10 @@ impl AudioFile { debug!("Downloading file {}", file_id); let (complete_tx, complete_rx) = oneshot::channel(); + debug!("calling request_chunk"); let initial_data_length = MINIMUM_CHUNK_SIZE; let (headers, data) = request_range(session, file_id, 0, initial_data_length).split(); + debug!("returned from request_chunk"); let open = AudioFileOpenStreaming { session: session.clone(), @@ -316,6 +319,7 @@ impl AudioFile { complete_tx: Some(complete_tx), }; + debug!("cloning into cache session"); let session_ = session.clone(); session.spawn(move |_| { complete_rx @@ -330,6 +334,7 @@ impl AudioFile { .or_else(|oneshot::Canceled| Ok(())) }); + debug!("returning open stream"); AudioFileOpen::Streaming(open) } @@ -365,6 +370,8 @@ fn request_range(session: &Session, file: FileId, offset: usize, length: usize) let (id, channel) = session.channel().allocate(); + trace!("allocated channel {}", id); + let mut data: Vec = Vec::new(); data.write_u16::(id).unwrap(); data.write_u8(0).unwrap(); @@ -382,6 +389,32 @@ fn request_range(session: &Session, file: FileId, offset: usize, length: usize) channel } +//fn request_chunk(session: &Session, file: FileId, index: usize) -> Channel { +// trace!("requesting chunk {}", index); +// +// let start = (index * CHUNK_SIZE / 4) as u32; +// let end = ((index + 1) * CHUNK_SIZE / 4) as u32; +// +// let (id, channel) = session.channel().allocate(); +// +// trace!("allocated channel {}", id); +// +// let mut data: Vec = Vec::new(); +// data.write_u16::(id).unwrap(); +// data.write_u8(0).unwrap(); +// data.write_u8(1).unwrap(); +// data.write_u16::(0x0000).unwrap(); +// data.write_u32::(0x00000000).unwrap(); +// data.write_u32::(0x00009C40).unwrap(); +// data.write_u32::(0x00020000).unwrap(); +// data.write(&file.0).unwrap(); +// data.write_u32::(start).unwrap(); +// data.write_u32::(end).unwrap(); +// +// session.send_packet(0x8, data); +// +// channel +//} struct PartialFileData { @@ -508,6 +541,7 @@ struct AudioFileFetch { file_data_tx: mpsc::UnboundedSender, file_data_rx: mpsc::UnboundedReceiver, + //seek_rx: mpsc::UnboundedReceiver, stream_loader_command_rx: mpsc::UnboundedReceiver, complete_tx: Option>, download_strategy: DownloadStrategy, @@ -654,6 +688,35 @@ impl AudioFileFetch { } +// fn download(&mut self, mut new_index: usize) { +// assert!(new_index < self.shared.chunk_count); +// +// { +// let download_status = self.shared.download_status.lock().unwrap(); +// while download_status.downloaded.contains(new_index) { +// new_index = (new_index + 1) % self.shared.chunk_count; +// debug!("Download iterated to new_index {}", new_index); +// } +// } +// +// trace!("== download called for chunk {} of {}", new_index, self.shared.chunk_count); +// +// if self.index != new_index { +// self.index = new_index; +// +// let offset = self.index * CHUNK_SIZE; +// +// self.output +// .as_mut() +// .unwrap() +// .seek(SeekFrom::Start(offset as u64)) +// .unwrap(); +// +// let (_headers, data) = request_chunk(&self.session, self.shared.file_id, self.index).split(); +// self.data_rx = data; +// } +// } + fn poll_file_data_rx(&mut self) -> Poll<(), ()> { loop { @@ -837,6 +900,7 @@ impl Read for AudioFileStreaming { let mut ranges_to_request = RangeSet::new(); ranges_to_request.add_range(&Range::new(offset, length)); + debug!("reading at postion {} (length : {})", offset, length); let mut download_status = self.shared.download_status.lock().unwrap(); ranges_to_request.subtract_range_set(&download_status.downloaded); @@ -849,7 +913,9 @@ impl Read for AudioFileStreaming { } while !download_status.downloaded.contains(offset) { + debug!("waiting for download"); download_status = self.shared.cond.wait_timeout(download_status, Duration::from_millis(1000)).unwrap().0; + debug!("re-checking data availability at offset {}.", offset); } let available_length = download_status.downloaded.contained_length_from_value(offset); assert!(available_length > 0); @@ -860,6 +926,7 @@ impl Read for AudioFileStreaming { let read_len = min(length, available_length); let read_len = try!(self.read_file.read(&mut output[..read_len])); + debug!("read at postion {} (length : {})", offset, read_len); self.position += read_len as u64; self.shared.read_position.store(self.position as usize, atomic::Ordering::Relaxed); diff --git a/playback/src/player.rs b/playback/src/player.rs index 5d0e58ab..1e6db128 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -576,6 +576,8 @@ impl PlayerInternal { track_id.to_base62() ); + info!("find_available_alternative"); + let track = match self.find_available_alternative(&track) { Some(track) => track, None => { @@ -584,12 +586,17 @@ impl PlayerInternal { } }; + info!("config.bitrate"); + + let format = match self.config.bitrate { Bitrate::Bitrate96 => FileFormat::OGG_VORBIS_96, Bitrate::Bitrate160 => FileFormat::OGG_VORBIS_160, Bitrate::Bitrate320 => FileFormat::OGG_VORBIS_320, }; + info!("file_id"); + let file_id = match track.files.get(&format) { Some(&file_id) => file_id, None => { @@ -598,13 +605,22 @@ impl PlayerInternal { } }; + info!("key"); + let key = self .session .audio_key() .request(track.id, file_id); + //.wait() + //.unwrap() + + info!("encrypted_file"); + let encrypted_file = AudioFile::open(&self.session, file_id); + info!("waiting for encrypted_file"); + let encrypted_file = encrypted_file.wait().unwrap(); let mut stream_loader_controller = encrypted_file.get_stream_loader_controller(); @@ -621,9 +637,16 @@ impl PlayerInternal { } + + info!("wait for key"); let key = key.wait().unwrap(); + + info!("decrypted_file"); + let mut decrypted_file = AudioDecrypt::new(key, encrypted_file); + info!("normalisation_factor"); + let normalisation_factor = match NormalisationData::parse_from_file(&mut decrypted_file) { Ok(normalisation_data) => NormalisationData::get_factor(&self.config, normalisation_data), Err(_) => { @@ -632,8 +655,12 @@ impl PlayerInternal { } }; + info!("new Subfile"); + let audio_file = Subfile::new(decrypted_file, 0xa7); + info!("new VorbisDecoder"); + let mut decoder = VorbisDecoder::new(audio_file).unwrap(); if position != 0 { From 971b2a9b9fdd91d3e9e68c2d51ae1190e7b67f2b Mon Sep 17 00:00:00 2001 From: Konstantin Seiler Date: Sat, 2 Nov 2019 08:38:46 +1100 Subject: [PATCH 11/43] Fix compile issues after merge --- Cargo.lock | 1 + audio/Cargo.toml | 1 + audio/src/fetch.rs | 6 +++--- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 602b6abb..0f84b3a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -843,6 +843,7 @@ dependencies = [ "aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "lewton 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", "librespot-core 0.1.0", diff --git a/audio/Cargo.toml b/audio/Cargo.toml index 49902c50..a7237daf 100644 --- a/audio/Cargo.toml +++ b/audio/Cargo.toml @@ -9,6 +9,7 @@ path = "../core" [dependencies] bit-set = "0.5" byteorder = "1.3" +bytes = "0.4" futures = "0.1" lewton = "0.9" log = "0.4" diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index c464a9a3..9bde9c3a 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -67,7 +67,7 @@ impl StreamLoaderController { pub fn range_available(&self, range: Range) -> bool { if let Some(ref shared) = self.stream_shared { - let mut download_status = shared.download_status.lock().unwrap(); + let download_status = shared.download_status.lock().unwrap(); if range.length <= download_status.downloaded.contained_length_from_value(range.start) { return true; } else { @@ -218,7 +218,7 @@ impl AudioFileOpenStreaming { }); let mut write_file = NamedTempFile::new().unwrap(); - write_file.set_len(size as u64).unwrap(); + write_file.as_file().set_len(size as u64).unwrap(); write_file.seek(SeekFrom::Start(0)).unwrap(); let read_file = write_file.reopen().unwrap(); @@ -450,7 +450,7 @@ impl Future for AudioFileFetchDataReceiver { Ok(Async::Ready(Some(data))) => { if let Some(request_sent_time) = self.request_sent_time { let duration = Instant::now() - request_sent_time; - let mut duration_ms: u64; + let duration_ms: u64; if duration.as_secs() > MAXIMUM_ASSUMED_PING_TIME_SECONDS { duration_ms = MAXIMUM_ASSUMED_PING_TIME_SECONDS * 1000; }else { From 5ad6446616d203993ec3d4a0715418f170826f84 Mon Sep 17 00:00:00 2001 From: Konstantin Seiler Date: Sat, 2 Nov 2019 09:22:07 +1100 Subject: [PATCH 12/43] remove compiler warning --- playback/src/player.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/playback/src/player.rs b/playback/src/player.rs index 2e47c84c..7d26ecf1 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -495,7 +495,9 @@ impl PlayerInternal { let stream_data_rate = self.stream_data_rate(); if let Some(stream_loader_controller) = self.state.stream_loader_controller() { stream_loader_controller.set_stream_mode(); - if let PlayerState::Playing{..} = self.state { + } + if let PlayerState::Playing{..} = self.state { + if let Some(stream_loader_controller) = self.state.stream_loader_controller() { let wait_for_data_length = (2 * stream_loader_controller.ping_time_ms() * stream_data_rate) / 1000; stream_loader_controller.fetch_next_blocking(wait_for_data_length); } From 216bdc0f6fe8c38fc328a5715837cc4c6bd41e30 Mon Sep 17 00:00:00 2001 From: Konstantin Seiler Date: Sat, 2 Nov 2019 10:00:08 +1100 Subject: [PATCH 13/43] Fix typo --- audio/src/fetch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index e24b2ff4..0ff8a5ab 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -731,7 +731,7 @@ impl AudioFileFetch { // record the response time self.network_response_times_ms.push(response_time_ms); - // prone old response times. Keep at most three. + // prune old response times. Keep at most three. while self.network_response_times_ms.len() > 3 { self.network_response_times_ms.remove(0); } From 9f3e3d09d982667cf8e6439ffe3973706534a59e Mon Sep 17 00:00:00 2001 From: Konstantin Seiler Date: Sat, 2 Nov 2019 11:04:46 +1100 Subject: [PATCH 14/43] Fix infinite loop bug --- audio/src/fetch.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index 0ff8a5ab..67ccdbbc 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -302,10 +302,10 @@ impl AudioFile { debug!("Downloading file {}", file_id); let (complete_tx, complete_rx) = oneshot::channel(); - debug!("calling request_chunk"); + trace!("calling request_chunk"); let initial_data_length = MINIMUM_CHUNK_SIZE; let (headers, data) = request_range(session, file_id, 0, initial_data_length).split(); - debug!("returned from request_chunk"); + trace!("returned from request_chunk"); let open = AudioFileOpenStreaming { session: session.clone(), @@ -319,7 +319,7 @@ impl AudioFile { complete_tx: Some(complete_tx), }; - debug!("cloning into cache session"); + trace!("cloning into cache session"); let session_ = session.clone(); session.spawn(move |_| { complete_rx @@ -334,7 +334,7 @@ impl AudioFile { .or_else(|oneshot::Canceled| Ok(())) }); - debug!("returning open stream"); + trace!("returning open stream"); AudioFileOpen::Streaming(open) } @@ -802,7 +802,9 @@ impl AudioFileFetch { loop { match self.stream_loader_command_rx.poll() { - Ok(Async::Ready(None)) => {} + Ok(Async::Ready(None)) => { + return Ok(Async::Ready(())); + } Ok(Async::Ready(Some(StreamLoaderCommand::Fetch(request)))) => { self.download_range(request.start, request.length); } @@ -900,7 +902,7 @@ impl Read for AudioFileStreaming { let mut ranges_to_request = RangeSet::new(); ranges_to_request.add_range(&Range::new(offset, length)); - debug!("reading at postion {} (length : {})", offset, length); + trace!("reading at postion {} (length : {})", offset, length); let mut download_status = self.shared.download_status.lock().unwrap(); ranges_to_request.subtract_range_set(&download_status.downloaded); @@ -908,14 +910,14 @@ impl Read for AudioFileStreaming { for range in ranges_to_request.iter() { - debug!("requesting data at position {} (length : {})", range.start, range.length); + trace!("requesting data at position {} (length : {})", range.start, range.length); self.stream_loader_command_tx.unbounded_send(StreamLoaderCommand::Fetch(range.clone())).unwrap(); } while !download_status.downloaded.contains(offset) { - debug!("waiting for download"); + trace!("waiting for download"); download_status = self.shared.cond.wait_timeout(download_status, Duration::from_millis(1000)).unwrap().0; - debug!("re-checking data availability at offset {}.", offset); + trace!("re-checking data availability at offset {}.", offset); } let available_length = download_status.downloaded.contained_length_from_value(offset); assert!(available_length > 0); @@ -926,7 +928,7 @@ impl Read for AudioFileStreaming { let read_len = min(length, available_length); let read_len = try!(self.read_file.read(&mut output[..read_len])); - debug!("read at postion {} (length : {})", offset, read_len); + trace!("read at postion {} (length : {})", offset, read_len); self.position += read_len as u64; self.shared.read_position.store(self.position as usize, atomic::Ordering::Relaxed); From af6e33bfa012835077b066cb5bcab91658deb44c Mon Sep 17 00:00:00 2001 From: Konstantin Seiler Date: Sat, 2 Nov 2019 11:11:24 +1100 Subject: [PATCH 15/43] Remove commented line --- audio/src/fetch.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index 67ccdbbc..dd7ae51a 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -1,4 +1,3 @@ -//use bit_set::BitSet; use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; use bytes::Bytes; use futures::sync::{mpsc, oneshot}; From c991974f821bbe08754485cb4308ffbc13342079 Mon Sep 17 00:00:00 2001 From: Konstantin Seiler Date: Sat, 2 Nov 2019 17:19:31 +1100 Subject: [PATCH 16/43] Improve ping time measurements. Don't measure response times if other requests are pending. --- audio/src/fetch.rs | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index dd7ae51a..8ca37c64 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -201,6 +201,7 @@ struct AudioFileShared { file_size: usize, cond: Condvar, download_status: Mutex, + number_of_open_requests: AtomicUsize, ping_time_ms: AtomicUsize, read_position: AtomicUsize, } @@ -213,6 +214,7 @@ impl AudioFileOpenStreaming { file_size: size, cond: Condvar::new(), download_status: Mutex::new(AudioFileDownloadStatus {requested: RangeSet::new(), downloaded: RangeSet::new()}), + number_of_open_requests: AtomicUsize::new(0), ping_time_ms: AtomicUsize::new(0), read_position: AtomicUsize::new(0), }); @@ -433,6 +435,7 @@ struct AudioFileFetchDataReceiver { data_offset: usize, request_length: usize, request_sent_time: Option, + measure_ping_time: bool, } impl AudioFileFetchDataReceiver { @@ -445,6 +448,10 @@ impl AudioFileFetchDataReceiver { request_sent_time: Instant, ) -> AudioFileFetchDataReceiver { + let measure_ping_time = shared.number_of_open_requests.load(atomic::Ordering::SeqCst) == 0; + + shared.number_of_open_requests.fetch_add(1, atomic::Ordering::SeqCst); + AudioFileFetchDataReceiver { shared: shared, data_rx: data_rx, @@ -452,6 +459,7 @@ impl AudioFileFetchDataReceiver { data_offset: data_offset, request_length: request_length, request_sent_time: Some(request_sent_time), + measure_ping_time: measure_ping_time, } } } @@ -468,6 +476,9 @@ impl AudioFileFetchDataReceiver { download_status.requested.subtract_range(&missing_range); self.shared.cond.notify_all(); } + + self.shared.number_of_open_requests.fetch_sub(1, atomic::Ordering::SeqCst); + } } @@ -480,15 +491,18 @@ impl Future for AudioFileFetchDataReceiver { trace!("Looping data_receiver for offset {} and length {}", self.data_offset, self.request_length); match self.data_rx.poll() { Ok(Async::Ready(Some(data))) => { - if let Some(request_sent_time) = self.request_sent_time { - let duration = Instant::now() - request_sent_time; - let duration_ms: u64; - if duration.as_secs() > MAXIMUM_ASSUMED_PING_TIME_SECONDS { - duration_ms = MAXIMUM_ASSUMED_PING_TIME_SECONDS * 1000; - }else { - duration_ms = duration.as_secs() *1000 + duration.subsec_millis() as u64; + if self.measure_ping_time { + if let Some(request_sent_time) = self.request_sent_time { + let duration = Instant::now() - request_sent_time; + let duration_ms: u64; + if duration.as_secs() > MAXIMUM_ASSUMED_PING_TIME_SECONDS { + duration_ms = MAXIMUM_ASSUMED_PING_TIME_SECONDS * 1000; + } else { + duration_ms = duration.as_secs() * 1000 + duration.subsec_millis() as u64; + } + let _ = self.file_data_tx.unbounded_send(ReceivedData::ResponseTimeMs(duration_ms as usize)); + self.measure_ping_time = false; } - let _ = self.file_data_tx.unbounded_send(ReceivedData::ResponseTimeMs(duration_ms as usize)); } let data_size = data.len(); trace!("data_receiver got {} bytes of data", data_size); @@ -502,14 +516,15 @@ impl Future for AudioFileFetchDataReceiver { } if self.request_length == 0 { trace!("Data receiver completed at position {}", self.data_offset); + self.finish(); return Ok(Async::Ready(())); } } Ok(Async::Ready(None)) => { if self.request_length > 0 { warn!("Received less data from server than requested."); - self.finish(); } + self.finish(); return Ok(Async::Ready(())); } Ok(Async::NotReady) => { From 393df6475e7b2731f777cd9df7cca06b0f8859e0 Mon Sep 17 00:00:00 2001 From: Konstantin Seiler Date: Tue, 5 Nov 2019 22:58:00 +1100 Subject: [PATCH 17/43] Set better log messages. --- audio/src/fetch.rs | 94 ++++++++---------------------------------- audio/src/range_set.rs | 20 +++++++++ 2 files changed, 38 insertions(+), 76 deletions(-) diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index 8ca37c64..b15033b3 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -303,10 +303,8 @@ impl AudioFile { debug!("Downloading file {}", file_id); let (complete_tx, complete_rx) = oneshot::channel(); - trace!("calling request_chunk"); let initial_data_length = MINIMUM_CHUNK_SIZE; let (headers, data) = request_range(session, file_id, 0, initial_data_length).split(); - trace!("returned from request_chunk"); let open = AudioFileOpenStreaming { session: session.clone(), @@ -320,7 +318,6 @@ impl AudioFile { complete_tx: Some(complete_tx), }; - trace!("cloning into cache session"); let session_ = session.clone(); session.spawn(move |_| { complete_rx @@ -335,7 +332,6 @@ impl AudioFile { .or_else(|oneshot::Canceled| Ok(())) }); - trace!("returning open stream"); AudioFileOpen::Streaming(open) } @@ -361,17 +357,15 @@ impl AudioFile { fn request_range(session: &Session, file: FileId, offset: usize, length: usize) -> Channel { - trace!("requesting range starting at {} of length {}", offset, length); + assert!(offset % 4 == 0, "Range request start positions must be aligned by 4 bytes."); + assert!(length % 4 == 0, "Range request range lengths must be aligned by 4 bytes."); let start = offset / 4; - let mut end = (offset+length) / 4; - if (offset+length) % 4 != 0 { - end += 1; - } + let end = (offset+length) / 4; let (id, channel) = session.channel().allocate(); - trace!("allocated channel {}", id); + trace!("requesting range starting at {} of length {} on channel {}.", offset, length, id); let mut data: Vec = Vec::new(); data.write_u16::(id).unwrap(); @@ -390,32 +384,6 @@ fn request_range(session: &Session, file: FileId, offset: usize, length: usize) channel } -//fn request_chunk(session: &Session, file: FileId, index: usize) -> Channel { -// trace!("requesting chunk {}", index); -// -// let start = (index * CHUNK_SIZE / 4) as u32; -// let end = ((index + 1) * CHUNK_SIZE / 4) as u32; -// -// let (id, channel) = session.channel().allocate(); -// -// trace!("allocated channel {}", id); -// -// let mut data: Vec = Vec::new(); -// data.write_u16::(id).unwrap(); -// data.write_u8(0).unwrap(); -// data.write_u8(1).unwrap(); -// data.write_u16::(0x0000).unwrap(); -// data.write_u32::(0x00000000).unwrap(); -// data.write_u32::(0x00009C40).unwrap(); -// data.write_u32::(0x00020000).unwrap(); -// data.write(&file.0).unwrap(); -// data.write_u32::(start).unwrap(); -// data.write_u32::(end).unwrap(); -// -// session.send_packet(0x8, data); -// -// channel -//} struct PartialFileData { @@ -432,6 +400,8 @@ struct AudioFileFetchDataReceiver { shared: Arc, file_data_tx: mpsc::UnboundedSender, data_rx: ChannelData, + initial_data_offset: usize, + initial_request_length: usize, data_offset: usize, request_length: usize, request_sent_time: Option, @@ -456,6 +426,8 @@ impl AudioFileFetchDataReceiver { shared: shared, data_rx: data_rx, file_data_tx: file_data_tx, + initial_data_offset: data_offset, + initial_request_length: request_length, data_offset: data_offset, request_length: request_length, request_sent_time: Some(request_sent_time), @@ -505,34 +477,33 @@ impl Future for AudioFileFetchDataReceiver { } } let data_size = data.len(); - trace!("data_receiver got {} bytes of data", data_size); + trace!("data_receiver for range {} (+{}) got {} bytes of data starting at {}. ({} bytes pending).", self.initial_data_offset, self.initial_request_length, data_size, self.data_offset, self.request_length - data_size); let _ = self.file_data_tx.unbounded_send(ReceivedData::Data(PartialFileData { offset: self.data_offset, data: data, })); self.data_offset += data_size; if self.request_length < data_size { - warn!("Received more data from server than requested."); + warn!("Data receiver for range {} (+{}) received more data from server than requested.", self.initial_data_offset, self.initial_request_length); self.request_length = 0; } else { self.request_length -= data_size; } if self.request_length == 0 { - trace!("Data receiver completed at position {}", self.data_offset); + trace!("Data receiver for range {} (+{}) completed.", self.initial_data_offset, self.initial_request_length); self.finish(); return Ok(Async::Ready(())); } } Ok(Async::Ready(None)) => { if self.request_length > 0 { - warn!("Received less data from server than requested."); + warn!("Data receiver for range {} (+{}) received less data from server than requested.", self.initial_data_offset, self.initial_request_length); } self.finish(); return Ok(Async::Ready(())); } Ok(Async::NotReady) => { - //trace!("No more data for data_receiver at the moment."); return Ok(Async::NotReady); } Err(ChannelError) => { - warn!("error from channel"); + warn!("Error from channel for data receiver for range {} (+{}).", self.initial_data_offset, self.initial_request_length); self.finish(); return Ok(Async::Ready(())); } @@ -702,45 +673,16 @@ impl AudioFileFetch { } -// fn download(&mut self, mut new_index: usize) { -// assert!(new_index < self.shared.chunk_count); -// -// { -// let download_status = self.shared.download_status.lock().unwrap(); -// while download_status.downloaded.contains(new_index) { -// new_index = (new_index + 1) % self.shared.chunk_count; -// debug!("Download iterated to new_index {}", new_index); -// } -// } -// -// trace!("== download called for chunk {} of {}", new_index, self.shared.chunk_count); -// -// if self.index != new_index { -// self.index = new_index; -// -// let offset = self.index * CHUNK_SIZE; -// -// self.output -// .as_mut() -// .unwrap() -// .seek(SeekFrom::Start(offset as u64)) -// .unwrap(); -// -// let (_headers, data) = request_chunk(&self.session, self.shared.file_id, self.index).split(); -// self.data_rx = data; -// } -// } fn poll_file_data_rx(&mut self) -> Poll<(), ()> { loop { match self.file_data_rx.poll() { Ok(Async::Ready(None)) => { - trace!("File data channel closed."); return Ok(Async::Ready(())); } Ok(Async::Ready(Some(ReceivedData::ResponseTimeMs(response_time_ms)))) => { - trace!("Received ping time information: {} ms.", response_time_ms); + trace!("Received ping time estimate: {} ms.", response_time_ms); // record the response time self.network_response_times_ms.push(response_time_ms); @@ -768,7 +710,6 @@ impl AudioFileFetch { }, Ok(Async::Ready(Some(ReceivedData::Data(data)))) => { - trace!("Writing data to file: offset {}, length {}", data.offset, data.data.len()); self.output .as_mut() @@ -791,6 +732,9 @@ impl AudioFileFetch { if download_status.downloaded.contained_length_from_value(0) >= self.shared.file_size { full = true; } + + trace!("Downloaded: {} Requested: {}", download_status.downloaded, download_status.requested); + drop(download_status); } @@ -860,8 +804,6 @@ impl Future for AudioFileFetch { fn poll(&mut self) -> Poll<(), ()> { - trace!("Polling AudioFileFetch"); - match self.poll_stream_loader_command_rx() { Ok(Async::NotReady) => (), Ok(Async::Ready(_)) => { @@ -942,7 +884,7 @@ impl Read for AudioFileStreaming { let read_len = min(length, available_length); let read_len = try!(self.read_file.read(&mut output[..read_len])); - trace!("read at postion {} (length : {})", offset, read_len); + trace!("read successfully at postion {} (length : {})", offset, read_len); self.position += read_len as u64; self.shared.read_position.store(self.position as usize, atomic::Ordering::Relaxed); diff --git a/audio/src/range_set.rs b/audio/src/range_set.rs index 378725f6..12b82997 100644 --- a/audio/src/range_set.rs +++ b/audio/src/range_set.rs @@ -1,6 +1,7 @@ use std::cmp::{max,min}; use std::slice::Iter; +use std::fmt; @@ -10,6 +11,13 @@ pub struct Range { pub length: usize, } +impl fmt::Display for Range { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + return write!(f, "[{}, {}]", self.start, self.start+self.length-1); + } +} + + impl Range { pub fn new(start: usize, length: usize) -> Range { @@ -25,11 +33,23 @@ impl Range { } + #[derive(Clone)] pub struct RangeSet { ranges: Vec, } +impl fmt::Display for RangeSet { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(").unwrap(); + for range in self.ranges.iter() { + write!(f, "{}", range).unwrap(); + } + write!(f, ")") + } +} + + impl RangeSet { pub fn new() -> RangeSet { From 4a611d9af33b1858b47aa372b55a90dd4b3625f6 Mon Sep 17 00:00:00 2001 From: Konstantin Seiler Date: Tue, 5 Nov 2019 23:58:35 +1100 Subject: [PATCH 18/43] Fix pre-fetch heuristic. --- audio/src/fetch.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index b15033b3..e17473ed 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -460,7 +460,6 @@ impl Future for AudioFileFetchDataReceiver { fn poll(&mut self) -> Poll<(), ()> { loop { - trace!("Looping data_receiver for offset {} and length {}", self.data_offset, self.request_length); match self.data_rx.poll() { Ok(Async::Ready(Some(data))) => { if self.measure_ping_time { @@ -733,7 +732,7 @@ impl AudioFileFetch { full = true; } - trace!("Downloaded: {} Requested: {}", download_status.downloaded, download_status.requested); + trace!("Downloaded: {} Requested: {}", download_status.downloaded, download_status.requested.minus(&download_status.downloaded)); drop(download_status); } @@ -829,7 +828,8 @@ impl Future for AudioFileFetch { let ping_time = self.shared.ping_time_ms.load(atomic::Ordering::Relaxed); - if bytes_pending < 2 * ping_time * self.streaming_data_rate { + if bytes_pending < 2 * ping_time * self.streaming_data_rate / 1000 { + trace!("Prefetching more data. pending bytes({}) < 2 * ping time ({}) * data rate({}) / 1000.",bytes_pending, ping_time, self.streaming_data_rate); self.pre_fetch_more_data(); } } From c50fc9885ac296799416895f851f3c715863aaba Mon Sep 17 00:00:00 2001 From: Konstantin Seiler Date: Wed, 6 Nov 2019 08:16:01 +1100 Subject: [PATCH 19/43] Adapt code for the new bitrate selection via alternatives. --- audio/src/fetch.rs | 14 +++++++++++--- playback/src/player.rs | 28 ++++++++++++++++++---------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index e17473ed..e3d63dfb 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -57,6 +57,7 @@ pub struct StreamLoaderController { channel_tx: Option>, stream_shared: Option>, file_size: usize, + bytes_per_second: usize, } @@ -65,6 +66,8 @@ impl StreamLoaderController { return self.file_size; } + pub fn data_rate(&self) -> usize { return self.bytes_per_second; } + pub fn range_available(&self, range: Range) -> bool { if let Some(ref shared) = self.stream_shared { let download_status = shared.download_status.lock().unwrap(); @@ -168,6 +171,7 @@ impl StreamLoaderController { pub fn set_stream_data_rate(&mut self, bytes_per_second: usize) { // when optimising for streaming, assume a streaming rate of this many bytes per second. + self.bytes_per_second = bytes_per_second; self.send_stream_loader_command(StreamLoaderCommand::StreamDataRate(bytes_per_second)); } @@ -335,20 +339,24 @@ impl AudioFile { AudioFileOpen::Streaming(open) } - pub fn get_stream_loader_controller(&self) -> StreamLoaderController { + pub fn get_stream_loader_controller(&self, bytes_per_second: usize) -> StreamLoaderController { match self { AudioFile::Streaming(stream) => { - return StreamLoaderController { + let mut result = StreamLoaderController { channel_tx: Some(stream.stream_loader_command_tx.clone()), stream_shared: Some(stream.shared.clone()), file_size: stream.shared.file_size, - } + bytes_per_second: bytes_per_second, + }; + result.set_stream_data_rate(bytes_per_second); + return result; } AudioFile::Cached(ref file) => { return StreamLoaderController { channel_tx: None, stream_shared: None, file_size: file.metadata().unwrap().len() as usize, + bytes_per_second: bytes_per_second, } } } diff --git a/playback/src/player.rs b/playback/src/player.rs index 23121785..32500e30 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -490,12 +490,12 @@ impl PlayerInternal { } // If we're playing, ensure, that we have enough data leaded to avoid a buffer underrun. - let stream_data_rate = self.stream_data_rate(); if let Some(stream_loader_controller) = self.state.stream_loader_controller() { stream_loader_controller.set_stream_mode(); } if let PlayerState::Playing{..} = self.state { if let Some(stream_loader_controller) = self.state.stream_loader_controller() { + let stream_data_rate = stream_loader_controller.data_rate(); let wait_for_data_length = (2 * stream_loader_controller.ping_time_ms() * stream_data_rate) / 1000; stream_loader_controller.fetch_next_blocking(wait_for_data_length); } @@ -561,11 +561,22 @@ impl PlayerInternal { } } - fn stream_data_rate(&self) -> usize { - match self.config.bitrate { - Bitrate::Bitrate96 => 12 * 1024, - Bitrate::Bitrate160 => 20 * 1024, - Bitrate::Bitrate320 => 40 * 1024, + fn stream_data_rate(&self, format: FileFormat) -> usize { + match format { + FileFormat::OGG_VORBIS_96 => 12 * 1024, + FileFormat::OGG_VORBIS_160 => 20 * 1024, + FileFormat::OGG_VORBIS_320=> 40 * 1024, + FileFormat::MP3_256 => 32 * 1024, + FileFormat::MP3_320 => 40 * 1024, + FileFormat::MP3_160 => 20 * 1024, + FileFormat::MP3_96 => 12 * 1024, + FileFormat::MP3_160_ENC => 20 * 1024, + FileFormat::MP4_128_DUAL => 16 * 1024, + FileFormat::OTHER3 => 40 * 1024, // better some high guess than nothing + FileFormat::AAC_160 => 20 * 1024, + FileFormat::AAC_320 => 40 * 1024, + FileFormat::MP4_128 => 16 * 1024, + FileFormat::OTHER5 => 40 * 1024, // better some high guess than nothing } } @@ -618,10 +629,7 @@ impl PlayerInternal { let encrypted_file = encrypted_file.wait().unwrap(); - let mut stream_loader_controller = encrypted_file.get_stream_loader_controller(); - - // tell the stream loader how to optimise its strategy. - stream_loader_controller.set_stream_data_rate(self.stream_data_rate()); + let mut stream_loader_controller = encrypted_file.get_stream_loader_controller(self.stream_data_rate(*format)); if position == 0 { // No need to seek -> we stream from the beginning From 224ec0a04e0ff1f4a58f81d34c2f8d5607e2b76b Mon Sep 17 00:00:00 2001 From: Konstantin Seiler Date: Wed, 6 Nov 2019 14:38:28 +1100 Subject: [PATCH 20/43] Remove log message --- core/src/channel.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/src/channel.rs b/core/src/channel.rs index 3238a0a6..57655feb 100644 --- a/core/src/channel.rs +++ b/core/src/channel.rs @@ -59,8 +59,6 @@ impl ChannelManager { let id: u16 = BigEndian::read_u16(data.split_to(2).as_ref()); - trace!("Received data for channel {}: {} bytes.", id, data.len()); - self.lock(|inner| { if let Entry::Occupied(entry) = inner.channels.entry(id) { let _ = entry.get().unbounded_send((cmd, data)); From 395d29ad473d6bc15554163e26f6e93a896dc572 Mon Sep 17 00:00:00 2001 From: Konstantin Seiler Date: Wed, 6 Nov 2019 17:15:32 +1100 Subject: [PATCH 21/43] Add warning in source code. --- audio/src/fetch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index e3d63dfb..8e39e5ac 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -18,7 +18,7 @@ use futures::sync::mpsc::unbounded; use std::sync::atomic; use std::sync::atomic::AtomicUsize; -const MINIMUM_CHUNK_SIZE: usize = 1024 * 16; +const MINIMUM_CHUNK_SIZE: usize = 1024 * 16; // This number MUST be divisible by 4. const MAXIMUM_CHUNK_SIZE: usize = 1024 * 128; const MAXIMUM_ASSUMED_PING_TIME_SECONDS: u64 = 5; From a1763b75c0eaaee86767baa1d9809062033c0423 Mon Sep 17 00:00:00 2001 From: ashthespy Date: Wed, 6 Nov 2019 14:48:21 +0100 Subject: [PATCH 22/43] Disable `regex` feature of `env_logger` --- Cargo.lock | 32 -------------------------------- Cargo.toml | 2 +- 2 files changed, 1 insertion(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 888ef466..95543bc1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,14 +49,6 @@ dependencies = [ "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "aho-corasick" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "alga" version = "0.9.1" @@ -495,7 +487,6 @@ dependencies = [ "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1589,18 +1580,6 @@ dependencies = [ "utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "regex" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "regex-syntax" version = "0.5.6" @@ -1609,14 +1588,6 @@ dependencies = [ "ucd-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "regex-syntax" -version = "0.6.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ucd-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "relay" version = "0.1.1" @@ -2438,7 +2409,6 @@ dependencies = [ "checksum aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d" "checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" "checksum aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5" -"checksum aho-corasick 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "36b7aa1ccb7d7ea3f437cf025a2ab1c47cc6c1bc9fc84918ff449def12f5e282" "checksum alga 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d708cb68c7106ed1844de68f50f0157a7788c2909a6926fad5a87546ef6a4ff8" "checksum alsa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b4a0d4ebc8b23041c5de9bc9aee13b4bad844a589479701f31a5934cfe4aeb32" "checksum alsa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b0edcbbf9ef68f15ae1b620f722180b82a98b6f0628d30baa6b8d2a5abc87d58" @@ -2599,9 +2569,7 @@ dependencies = [ "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384" -"checksum regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b23da8dfd98a84bd7e08700190a5d9f7d2d38abd4369dd1dae651bc40bfd2cc" "checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7" -"checksum regex-syntax 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5485bf1523a9ed51c4964273f22f63f24e31632adb5dad134f488f86a3875c" "checksum relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1576e382688d7e9deecea24417e350d3062d97e32e45d70b1cde65994ff1489a" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" "checksum rodio 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d0f961b254e66d147a7b550c78b01308934c97d807a34b417fd0f5a0a0f3a2d" diff --git a/Cargo.toml b/Cargo.toml index 69582a59..3fa60490 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ path = "protocol" [dependencies] base64 = "0.10" -env_logger = "0.6" +env_logger = {version = "0.6", default-features = false, features = ["termcolor","humantime","atty"]} futures = "0.1" getopts = "0.2" hyper = "0.11" From 267c182ff4ca5e76a208ee05e0127a6feed8d60f Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Wed, 6 Nov 2019 16:38:30 +0100 Subject: [PATCH 23/43] Set exact protobuf dependencies required by crates.io --- protocol/Cargo.toml | 6 +- protocol/src/authentication.rs | 100 ++++++++++---------- protocol/src/keyexchange.rs | 166 ++++++++++++++++----------------- protocol/src/mercury.rs | 40 ++++---- protocol/src/metadata.rs | 136 +++++++++++++-------------- protocol/src/pubsub.rs | 10 +- protocol/src/spirc.rs | 52 +++++------ 7 files changed, 255 insertions(+), 255 deletions(-) diff --git a/protocol/Cargo.toml b/protocol/Cargo.toml index a0d30ad0..e81d4d92 100644 --- a/protocol/Cargo.toml +++ b/protocol/Cargo.toml @@ -5,8 +5,8 @@ authors = ["Paul Liétar "] build = "build.rs" [dependencies] -protobuf = "2.8.*" +protobuf = "2.8.1" [build-dependencies] -protobuf-codegen-pure = "2.8.*" -protobuf-codegen = "*" +protobuf-codegen-pure = "2.8.1" +protobuf-codegen = "2.8.1" diff --git a/protocol/src/authentication.rs b/protocol/src/authentication.rs index a6c85990..ca282991 100644 --- a/protocol/src/authentication.rs +++ b/protocol/src/authentication.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 2.8.0. Do not edit +// This file is generated by rust-protobuf 2.8.1. Do not edit // @generated // https://github.com/Manishearth/rust-clippy/issues/702 @@ -24,7 +24,7 @@ use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; /// Generated files are compatible only with the same version /// of protobuf runtime. -const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_8_0; +const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_8_1; #[derive(PartialEq,Clone,Default)] pub struct ClientResponseEncrypted { @@ -385,7 +385,7 @@ impl ::protobuf::Message for ClientResponseEncrypted { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -466,7 +466,7 @@ impl ::protobuf::Message for ClientResponseEncrypted { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.login_credentials.as_ref() { os.write_tag(10, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -629,7 +629,7 @@ impl ::protobuf::Clear for ClientResponseEncrypted { } impl ::std::fmt::Debug for ClientResponseEncrypted { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -762,7 +762,7 @@ impl ::protobuf::Message for LoginCredentials { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -801,7 +801,7 @@ impl ::protobuf::Message for LoginCredentials { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.username.as_ref() { os.write_string(10, &v)?; } @@ -898,7 +898,7 @@ impl ::protobuf::Clear for LoginCredentials { } impl ::std::fmt::Debug for LoginCredentials { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -1012,7 +1012,7 @@ impl ::protobuf::Message for FingerprintResponseUnion { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -1047,7 +1047,7 @@ impl ::protobuf::Message for FingerprintResponseUnion { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.grain.as_ref() { os.write_tag(10, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -1139,7 +1139,7 @@ impl ::protobuf::Clear for FingerprintResponseUnion { } impl ::std::fmt::Debug for FingerprintResponseUnion { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -1215,7 +1215,7 @@ impl ::protobuf::Message for FingerprintGrainResponse { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -1242,7 +1242,7 @@ impl ::protobuf::Message for FingerprintGrainResponse { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.encrypted_key.as_ref() { os.write_bytes(10, &v)?; } @@ -1321,7 +1321,7 @@ impl ::protobuf::Clear for FingerprintGrainResponse { } impl ::std::fmt::Debug for FingerprintGrainResponse { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -1397,7 +1397,7 @@ impl ::protobuf::Message for FingerprintHmacRipemdResponse { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -1424,7 +1424,7 @@ impl ::protobuf::Message for FingerprintHmacRipemdResponse { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.hmac.as_ref() { os.write_bytes(10, &v)?; } @@ -1503,7 +1503,7 @@ impl ::protobuf::Clear for FingerprintHmacRipemdResponse { } impl ::std::fmt::Debug for FingerprintHmacRipemdResponse { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -1617,7 +1617,7 @@ impl ::protobuf::Message for PeerTicketUnion { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -1652,7 +1652,7 @@ impl ::protobuf::Message for PeerTicketUnion { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.public_key.as_ref() { os.write_tag(10, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -1744,7 +1744,7 @@ impl ::protobuf::Clear for PeerTicketUnion { } impl ::std::fmt::Debug for PeerTicketUnion { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -1820,7 +1820,7 @@ impl ::protobuf::Message for PeerTicketPublicKey { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -1847,7 +1847,7 @@ impl ::protobuf::Message for PeerTicketPublicKey { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.public_key.as_ref() { os.write_bytes(10, &v)?; } @@ -1926,7 +1926,7 @@ impl ::protobuf::Clear for PeerTicketPublicKey { } impl ::std::fmt::Debug for PeerTicketPublicKey { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -2042,7 +2042,7 @@ impl ::protobuf::Message for PeerTicketOld { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -2075,7 +2075,7 @@ impl ::protobuf::Message for PeerTicketOld { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.peer_ticket.as_ref() { os.write_bytes(10, &v)?; } @@ -2163,7 +2163,7 @@ impl ::protobuf::Clear for PeerTicketOld { } impl ::std::fmt::Debug for PeerTicketOld { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -2439,7 +2439,7 @@ impl ::protobuf::Message for SystemInfo { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -2540,7 +2540,7 @@ impl ::protobuf::Message for SystemInfo { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.cpu_family { os.write_enum(10, v.value())?; } @@ -2700,7 +2700,7 @@ impl ::protobuf::Clear for SystemInfo { } impl ::std::fmt::Debug for SystemInfo { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -2919,7 +2919,7 @@ impl ::protobuf::Message for LibspotifyAppKey { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -2974,7 +2974,7 @@ impl ::protobuf::Message for LibspotifyAppKey { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.version { os.write_uint32(1, v)?; } @@ -3089,7 +3089,7 @@ impl ::protobuf::Clear for LibspotifyAppKey { } impl ::std::fmt::Debug for LibspotifyAppKey { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -3221,7 +3221,7 @@ impl ::protobuf::Message for ClientInfo { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -3265,7 +3265,7 @@ impl ::protobuf::Message for ClientInfo { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.limited { os.write_bool(1, v)?; } @@ -3364,7 +3364,7 @@ impl ::protobuf::Clear for ClientInfo { } impl ::std::fmt::Debug for ClientInfo { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -3437,7 +3437,7 @@ impl ::protobuf::Message for ClientInfoFacebook { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -3464,7 +3464,7 @@ impl ::protobuf::Message for ClientInfoFacebook { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.machine_id.as_ref() { os.write_string(1, &v)?; } @@ -3543,7 +3543,7 @@ impl ::protobuf::Clear for ClientInfoFacebook { } impl ::std::fmt::Debug for ClientInfoFacebook { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -3843,7 +3843,7 @@ impl ::protobuf::Message for APWelcome { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -3914,7 +3914,7 @@ impl ::protobuf::Message for APWelcome { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.canonical_username.as_ref() { os.write_string(10, &v)?; } @@ -4060,7 +4060,7 @@ impl ::protobuf::Clear for APWelcome { } impl ::std::fmt::Debug for APWelcome { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -4174,7 +4174,7 @@ impl ::protobuf::Message for AccountInfo { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -4209,7 +4209,7 @@ impl ::protobuf::Message for AccountInfo { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.spotify.as_ref() { os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -4301,7 +4301,7 @@ impl ::protobuf::Clear for AccountInfo { } impl ::std::fmt::Debug for AccountInfo { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -4336,7 +4336,7 @@ impl ::protobuf::Message for AccountInfoSpotify { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -4357,7 +4357,7 @@ impl ::protobuf::Message for AccountInfoSpotify { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) } @@ -4427,7 +4427,7 @@ impl ::protobuf::Clear for AccountInfoSpotify { } impl ::std::fmt::Debug for AccountInfoSpotify { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -4537,7 +4537,7 @@ impl ::protobuf::Message for AccountInfoFacebook { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -4570,7 +4570,7 @@ impl ::protobuf::Message for AccountInfoFacebook { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.access_token.as_ref() { os.write_string(1, &v)?; } @@ -4658,7 +4658,7 @@ impl ::protobuf::Clear for AccountInfoFacebook { } impl ::std::fmt::Debug for AccountInfoFacebook { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } diff --git a/protocol/src/keyexchange.rs b/protocol/src/keyexchange.rs index b026ec87..f6cec4dd 100644 --- a/protocol/src/keyexchange.rs +++ b/protocol/src/keyexchange.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 2.8.0. Do not edit +// This file is generated by rust-protobuf 2.8.1. Do not edit // @generated // https://github.com/Manishearth/rust-clippy/issues/702 @@ -24,7 +24,7 @@ use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; /// Generated files are compatible only with the same version /// of protobuf runtime. -const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_8_0; +const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_8_1; #[derive(PartialEq,Clone,Default)] pub struct ClientHello { @@ -329,7 +329,7 @@ impl ::protobuf::Message for ClientHello { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -401,7 +401,7 @@ impl ::protobuf::Message for ClientHello { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.build_info.as_ref() { os.write_tag(10, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -549,7 +549,7 @@ impl ::protobuf::Clear for ClientHello { } impl ::std::fmt::Debug for ClientHello { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -680,7 +680,7 @@ impl ::protobuf::Message for BuildInfo { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -729,7 +729,7 @@ impl ::protobuf::Message for BuildInfo { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.product { os.write_enum(10, v.value())?; } @@ -835,7 +835,7 @@ impl ::protobuf::Clear for BuildInfo { } impl ::std::fmt::Debug for BuildInfo { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -910,7 +910,7 @@ impl ::protobuf::Message for LoginCryptoHelloUnion { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -938,7 +938,7 @@ impl ::protobuf::Message for LoginCryptoHelloUnion { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.diffie_hellman.as_ref() { os.write_tag(10, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -1019,7 +1019,7 @@ impl ::protobuf::Clear for LoginCryptoHelloUnion { } impl ::std::fmt::Debug for LoginCryptoHelloUnion { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -1118,7 +1118,7 @@ impl ::protobuf::Message for LoginCryptoDiffieHellmanHello { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -1155,7 +1155,7 @@ impl ::protobuf::Message for LoginCryptoDiffieHellmanHello { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.gc.as_ref() { os.write_bytes(10, &v)?; } @@ -1243,7 +1243,7 @@ impl ::protobuf::Clear for LoginCryptoDiffieHellmanHello { } impl ::std::fmt::Debug for LoginCryptoDiffieHellmanHello { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -1319,7 +1319,7 @@ impl ::protobuf::Message for FeatureSet { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -1360,7 +1360,7 @@ impl ::protobuf::Message for FeatureSet { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.autoupdate2 { os.write_bool(1, v)?; } @@ -1448,7 +1448,7 @@ impl ::protobuf::Clear for FeatureSet { } impl ::std::fmt::Debug for FeatureSet { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -1601,7 +1601,7 @@ impl ::protobuf::Message for APResponseMessage { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -1643,7 +1643,7 @@ impl ::protobuf::Message for APResponseMessage { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.challenge.as_ref() { os.write_tag(10, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -1746,7 +1746,7 @@ impl ::protobuf::Clear for APResponseMessage { } impl ::std::fmt::Debug for APResponseMessage { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -2027,7 +2027,7 @@ impl ::protobuf::Message for APChallenge { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -2088,7 +2088,7 @@ impl ::protobuf::Message for APChallenge { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.login_crypto_challenge.as_ref() { os.write_tag(10, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -2220,7 +2220,7 @@ impl ::protobuf::Clear for APChallenge { } impl ::std::fmt::Debug for APChallenge { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -2295,7 +2295,7 @@ impl ::protobuf::Message for LoginCryptoChallengeUnion { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -2323,7 +2323,7 @@ impl ::protobuf::Message for LoginCryptoChallengeUnion { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.diffie_hellman.as_ref() { os.write_tag(10, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -2404,7 +2404,7 @@ impl ::protobuf::Clear for LoginCryptoChallengeUnion { } impl ::std::fmt::Debug for LoginCryptoChallengeUnion { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -2543,7 +2543,7 @@ impl ::protobuf::Message for LoginCryptoDiffieHellmanChallenge { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -2586,7 +2586,7 @@ impl ::protobuf::Message for LoginCryptoDiffieHellmanChallenge { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.gs.as_ref() { os.write_bytes(10, &v)?; } @@ -2683,7 +2683,7 @@ impl ::protobuf::Clear for LoginCryptoDiffieHellmanChallenge { } impl ::std::fmt::Debug for LoginCryptoDiffieHellmanChallenge { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -2797,7 +2797,7 @@ impl ::protobuf::Message for FingerprintChallengeUnion { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -2832,7 +2832,7 @@ impl ::protobuf::Message for FingerprintChallengeUnion { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.grain.as_ref() { os.write_tag(10, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -2924,7 +2924,7 @@ impl ::protobuf::Clear for FingerprintChallengeUnion { } impl ::std::fmt::Debug for FingerprintChallengeUnion { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -3000,7 +3000,7 @@ impl ::protobuf::Message for FingerprintGrainChallenge { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -3027,7 +3027,7 @@ impl ::protobuf::Message for FingerprintGrainChallenge { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.kek.as_ref() { os.write_bytes(10, &v)?; } @@ -3106,7 +3106,7 @@ impl ::protobuf::Clear for FingerprintGrainChallenge { } impl ::std::fmt::Debug for FingerprintGrainChallenge { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -3182,7 +3182,7 @@ impl ::protobuf::Message for FingerprintHmacRipemdChallenge { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -3209,7 +3209,7 @@ impl ::protobuf::Message for FingerprintHmacRipemdChallenge { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.challenge.as_ref() { os.write_bytes(10, &v)?; } @@ -3288,7 +3288,7 @@ impl ::protobuf::Clear for FingerprintHmacRipemdChallenge { } impl ::std::fmt::Debug for FingerprintHmacRipemdChallenge { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -3363,7 +3363,7 @@ impl ::protobuf::Message for PoWChallengeUnion { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -3391,7 +3391,7 @@ impl ::protobuf::Message for PoWChallengeUnion { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.hash_cash.as_ref() { os.write_tag(10, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -3472,7 +3472,7 @@ impl ::protobuf::Clear for PoWChallengeUnion { } impl ::std::fmt::Debug for PoWChallengeUnion { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -3585,7 +3585,7 @@ impl ::protobuf::Message for PoWHashCashChallenge { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -3632,7 +3632,7 @@ impl ::protobuf::Message for PoWHashCashChallenge { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.prefix.as_ref() { os.write_bytes(10, &v)?; } @@ -3729,7 +3729,7 @@ impl ::protobuf::Clear for PoWHashCashChallenge { } impl ::std::fmt::Debug for PoWHashCashChallenge { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -3843,7 +3843,7 @@ impl ::protobuf::Message for CryptoChallengeUnion { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -3878,7 +3878,7 @@ impl ::protobuf::Message for CryptoChallengeUnion { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.shannon.as_ref() { os.write_tag(10, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -3970,7 +3970,7 @@ impl ::protobuf::Clear for CryptoChallengeUnion { } impl ::std::fmt::Debug for CryptoChallengeUnion { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -4005,7 +4005,7 @@ impl ::protobuf::Message for CryptoShannonChallenge { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -4026,7 +4026,7 @@ impl ::protobuf::Message for CryptoShannonChallenge { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) } @@ -4096,7 +4096,7 @@ impl ::protobuf::Clear for CryptoShannonChallenge { } impl ::std::fmt::Debug for CryptoShannonChallenge { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -4131,7 +4131,7 @@ impl ::protobuf::Message for CryptoRc4Sha1HmacChallenge { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -4152,7 +4152,7 @@ impl ::protobuf::Message for CryptoRc4Sha1HmacChallenge { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) } @@ -4222,7 +4222,7 @@ impl ::protobuf::Clear for CryptoRc4Sha1HmacChallenge { } impl ::std::fmt::Debug for CryptoRc4Sha1HmacChallenge { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -4375,7 +4375,7 @@ impl ::protobuf::Message for UpgradeRequiredMessage { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -4414,7 +4414,7 @@ impl ::protobuf::Message for UpgradeRequiredMessage { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.upgrade_signed_part.as_ref() { os.write_bytes(10, &v)?; } @@ -4511,7 +4511,7 @@ impl ::protobuf::Clear for UpgradeRequiredMessage { } impl ::std::fmt::Debug for UpgradeRequiredMessage { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -4647,7 +4647,7 @@ impl ::protobuf::Message for APLoginFailed { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -4700,7 +4700,7 @@ impl ::protobuf::Message for APLoginFailed { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.error_code { os.write_enum(10, v.value())?; } @@ -4806,7 +4806,7 @@ impl ::protobuf::Clear for APLoginFailed { } impl ::std::fmt::Debug for APLoginFailed { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -4968,7 +4968,7 @@ impl ::protobuf::Message for ClientResponsePlaintext { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -5010,7 +5010,7 @@ impl ::protobuf::Message for ClientResponsePlaintext { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.login_crypto_response.as_ref() { os.write_tag(10, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -5113,7 +5113,7 @@ impl ::protobuf::Clear for ClientResponsePlaintext { } impl ::std::fmt::Debug for ClientResponsePlaintext { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -5188,7 +5188,7 @@ impl ::protobuf::Message for LoginCryptoResponseUnion { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -5216,7 +5216,7 @@ impl ::protobuf::Message for LoginCryptoResponseUnion { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.diffie_hellman.as_ref() { os.write_tag(10, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -5297,7 +5297,7 @@ impl ::protobuf::Clear for LoginCryptoResponseUnion { } impl ::std::fmt::Debug for LoginCryptoResponseUnion { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -5373,7 +5373,7 @@ impl ::protobuf::Message for LoginCryptoDiffieHellmanResponse { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -5400,7 +5400,7 @@ impl ::protobuf::Message for LoginCryptoDiffieHellmanResponse { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.hmac.as_ref() { os.write_bytes(10, &v)?; } @@ -5479,7 +5479,7 @@ impl ::protobuf::Clear for LoginCryptoDiffieHellmanResponse { } impl ::std::fmt::Debug for LoginCryptoDiffieHellmanResponse { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -5554,7 +5554,7 @@ impl ::protobuf::Message for PoWResponseUnion { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -5582,7 +5582,7 @@ impl ::protobuf::Message for PoWResponseUnion { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.hash_cash.as_ref() { os.write_tag(10, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -5663,7 +5663,7 @@ impl ::protobuf::Clear for PoWResponseUnion { } impl ::std::fmt::Debug for PoWResponseUnion { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -5739,7 +5739,7 @@ impl ::protobuf::Message for PoWHashCashResponse { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -5766,7 +5766,7 @@ impl ::protobuf::Message for PoWHashCashResponse { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.hash_suffix.as_ref() { os.write_bytes(10, &v)?; } @@ -5845,7 +5845,7 @@ impl ::protobuf::Clear for PoWHashCashResponse { } impl ::std::fmt::Debug for PoWHashCashResponse { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -5959,7 +5959,7 @@ impl ::protobuf::Message for CryptoResponseUnion { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -5994,7 +5994,7 @@ impl ::protobuf::Message for CryptoResponseUnion { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.shannon.as_ref() { os.write_tag(10, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -6086,7 +6086,7 @@ impl ::protobuf::Clear for CryptoResponseUnion { } impl ::std::fmt::Debug for CryptoResponseUnion { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -6142,7 +6142,7 @@ impl ::protobuf::Message for CryptoShannonResponse { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -6173,7 +6173,7 @@ impl ::protobuf::Message for CryptoShannonResponse { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.dummy { os.write_int32(1, v)?; } @@ -6252,7 +6252,7 @@ impl ::protobuf::Clear for CryptoShannonResponse { } impl ::std::fmt::Debug for CryptoShannonResponse { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -6308,7 +6308,7 @@ impl ::protobuf::Message for CryptoRc4Sha1HmacResponse { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -6339,7 +6339,7 @@ impl ::protobuf::Message for CryptoRc4Sha1HmacResponse { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.dummy { os.write_int32(1, v)?; } @@ -6418,7 +6418,7 @@ impl ::protobuf::Clear for CryptoRc4Sha1HmacResponse { } impl ::std::fmt::Debug for CryptoRc4Sha1HmacResponse { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } diff --git a/protocol/src/mercury.rs b/protocol/src/mercury.rs index 0913c5c7..3b371f7a 100644 --- a/protocol/src/mercury.rs +++ b/protocol/src/mercury.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 2.8.0. Do not edit +// This file is generated by rust-protobuf 2.8.1. Do not edit // @generated // https://github.com/Manishearth/rust-clippy/issues/702 @@ -24,7 +24,7 @@ use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; /// Generated files are compatible only with the same version /// of protobuf runtime. -const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_8_0; +const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_8_1; #[derive(PartialEq,Clone,Default)] pub struct MercuryMultiGetRequest { @@ -82,7 +82,7 @@ impl ::protobuf::Message for MercuryMultiGetRequest { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -110,7 +110,7 @@ impl ::protobuf::Message for MercuryMultiGetRequest { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { for v in &self.request { os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -191,7 +191,7 @@ impl ::protobuf::Clear for MercuryMultiGetRequest { } impl ::std::fmt::Debug for MercuryMultiGetRequest { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -258,7 +258,7 @@ impl ::protobuf::Message for MercuryMultiGetReply { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -286,7 +286,7 @@ impl ::protobuf::Message for MercuryMultiGetReply { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { for v in &self.reply { os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -367,7 +367,7 @@ impl ::protobuf::Clear for MercuryMultiGetReply { } impl ::std::fmt::Debug for MercuryMultiGetReply { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -551,7 +551,7 @@ impl ::protobuf::Message for MercuryRequest { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -596,7 +596,7 @@ impl ::protobuf::Message for MercuryRequest { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.uri.as_ref() { os.write_string(1, &v)?; } @@ -702,7 +702,7 @@ impl ::protobuf::Clear for MercuryRequest { } impl ::std::fmt::Debug for MercuryRequest { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -946,7 +946,7 @@ impl ::protobuf::Message for MercuryReply { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -1017,7 +1017,7 @@ impl ::protobuf::Message for MercuryReply { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.status_code { os.write_sint32(1, v)?; } @@ -1150,7 +1150,7 @@ impl ::protobuf::Clear for MercuryReply { } impl ::std::fmt::Debug for MercuryReply { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -1407,7 +1407,7 @@ impl ::protobuf::Message for Header { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -1463,7 +1463,7 @@ impl ::protobuf::Message for Header { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.uri.as_ref() { os.write_string(1, &v)?; } @@ -1580,7 +1580,7 @@ impl ::protobuf::Clear for Header { } impl ::std::fmt::Debug for Header { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -1690,7 +1690,7 @@ impl ::protobuf::Message for UserField { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -1723,7 +1723,7 @@ impl ::protobuf::Message for UserField { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.key.as_ref() { os.write_string(1, &v)?; } @@ -1811,7 +1811,7 @@ impl ::protobuf::Clear for UserField { } impl ::std::fmt::Debug for UserField { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } diff --git a/protocol/src/metadata.rs b/protocol/src/metadata.rs index 386213ab..571cd7d2 100644 --- a/protocol/src/metadata.rs +++ b/protocol/src/metadata.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 2.8.0. Do not edit +// This file is generated by rust-protobuf 2.8.1. Do not edit // @generated // https://github.com/Manishearth/rust-clippy/issues/702 @@ -24,7 +24,7 @@ use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; /// Generated files are compatible only with the same version /// of protobuf runtime. -const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_8_0; +const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_8_1; #[derive(PartialEq,Clone,Default)] pub struct TopTracks { @@ -119,7 +119,7 @@ impl ::protobuf::Message for TopTracks { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -153,7 +153,7 @@ impl ::protobuf::Message for TopTracks { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.country.as_ref() { os.write_string(1, &v)?; } @@ -243,7 +243,7 @@ impl ::protobuf::Clear for TopTracks { } impl ::std::fmt::Debug for TopTracks { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -339,7 +339,7 @@ impl ::protobuf::Message for ActivityPeriod { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -390,7 +390,7 @@ impl ::protobuf::Message for ActivityPeriod { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.start_year { os.write_sint32(1, v)?; } @@ -487,7 +487,7 @@ impl ::protobuf::Clear for ActivityPeriod { } impl ::std::fmt::Debug for ActivityPeriod { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -1043,7 +1043,7 @@ impl ::protobuf::Message for Artist { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -1186,7 +1186,7 @@ impl ::protobuf::Message for Artist { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.gid.as_ref() { os.write_bytes(1, &v)?; } @@ -1433,7 +1433,7 @@ impl ::protobuf::Clear for Artist { } impl ::std::fmt::Debug for Artist { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -1500,7 +1500,7 @@ impl ::protobuf::Message for AlbumGroup { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -1528,7 +1528,7 @@ impl ::protobuf::Message for AlbumGroup { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { for v in &self.album { os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -1609,7 +1609,7 @@ impl ::protobuf::Clear for AlbumGroup { } impl ::std::fmt::Debug for AlbumGroup { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -1745,7 +1745,7 @@ impl ::protobuf::Message for Date { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -1816,7 +1816,7 @@ impl ::protobuf::Message for Date { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.year { os.write_sint32(1, v)?; } @@ -1931,7 +1931,7 @@ impl ::protobuf::Clear for Date { } impl ::std::fmt::Debug for Date { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -2496,7 +2496,7 @@ impl ::protobuf::Message for Album { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -2633,7 +2633,7 @@ impl ::protobuf::Message for Album { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.gid.as_ref() { os.write_bytes(1, &v)?; } @@ -2876,7 +2876,7 @@ impl ::protobuf::Clear for Album { } impl ::std::fmt::Debug for Album { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -3404,7 +3404,7 @@ impl ::protobuf::Message for Track { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -3543,7 +3543,7 @@ impl ::protobuf::Message for Track { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.gid.as_ref() { os.write_bytes(1, &v)?; } @@ -3764,7 +3764,7 @@ impl ::protobuf::Clear for Track { } impl ::std::fmt::Debug for Track { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -3897,7 +3897,7 @@ impl ::protobuf::Message for Image { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -3950,7 +3950,7 @@ impl ::protobuf::Message for Image { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.file_id.as_ref() { os.write_bytes(1, &v)?; } @@ -4056,7 +4056,7 @@ impl ::protobuf::Clear for Image { } impl ::std::fmt::Debug for Image { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -4184,7 +4184,7 @@ impl ::protobuf::Message for ImageGroup { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -4212,7 +4212,7 @@ impl ::protobuf::Message for ImageGroup { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { for v in &self.image { os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -4293,7 +4293,7 @@ impl ::protobuf::Clear for ImageGroup { } impl ::std::fmt::Debug for ImageGroup { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -4428,7 +4428,7 @@ impl ::protobuf::Message for Biography { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -4469,7 +4469,7 @@ impl ::protobuf::Message for Biography { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.text.as_ref() { os.write_string(1, &v)?; } @@ -4570,7 +4570,7 @@ impl ::protobuf::Clear for Biography { } impl ::std::fmt::Debug for Biography { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -4694,7 +4694,7 @@ impl ::protobuf::Message for Disc { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -4738,7 +4738,7 @@ impl ::protobuf::Message for Disc { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.number { os.write_sint32(1, v)?; } @@ -4837,7 +4837,7 @@ impl ::protobuf::Clear for Disc { } impl ::std::fmt::Debug for Disc { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -4930,7 +4930,7 @@ impl ::protobuf::Message for Copyright { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -4963,7 +4963,7 @@ impl ::protobuf::Message for Copyright { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.typ { os.write_enum(1, v.value())?; } @@ -5051,7 +5051,7 @@ impl ::protobuf::Clear for Copyright { } impl ::std::fmt::Debug for Copyright { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -5288,7 +5288,7 @@ impl ::protobuf::Message for Restriction { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -5339,7 +5339,7 @@ impl ::protobuf::Message for Restriction { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { for v in &self.catalogue { os.write_enum(1, v.value())?; }; @@ -5454,7 +5454,7 @@ impl ::protobuf::Clear for Restriction { } impl ::std::fmt::Debug for Restriction { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -5671,7 +5671,7 @@ impl ::protobuf::Message for Availability { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -5705,7 +5705,7 @@ impl ::protobuf::Message for Availability { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { for v in &self.catalogue_str { os.write_string(1, &v)?; }; @@ -5795,7 +5795,7 @@ impl ::protobuf::Clear for Availability { } impl ::std::fmt::Debug for Availability { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -5940,7 +5940,7 @@ impl ::protobuf::Message for SalePeriod { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -5982,7 +5982,7 @@ impl ::protobuf::Message for SalePeriod { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { for v in &self.restriction { os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -6085,7 +6085,7 @@ impl ::protobuf::Clear for SalePeriod { } impl ::std::fmt::Debug for SalePeriod { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -6195,7 +6195,7 @@ impl ::protobuf::Message for ExternalId { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -6228,7 +6228,7 @@ impl ::protobuf::Message for ExternalId { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.typ.as_ref() { os.write_string(1, &v)?; } @@ -6316,7 +6316,7 @@ impl ::protobuf::Clear for ExternalId { } impl ::std::fmt::Debug for ExternalId { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -6409,7 +6409,7 @@ impl ::protobuf::Message for AudioFile { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -6442,7 +6442,7 @@ impl ::protobuf::Message for AudioFile { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.file_id.as_ref() { os.write_bytes(1, &v)?; } @@ -6530,7 +6530,7 @@ impl ::protobuf::Clear for AudioFile { } impl ::std::fmt::Debug for AudioFile { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -6694,7 +6694,7 @@ impl ::protobuf::Message for VideoFile { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -6721,7 +6721,7 @@ impl ::protobuf::Message for VideoFile { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.file_id.as_ref() { os.write_bytes(1, &v)?; } @@ -6800,7 +6800,7 @@ impl ::protobuf::Clear for VideoFile { } impl ::std::fmt::Debug for VideoFile { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -7398,7 +7398,7 @@ impl ::protobuf::Message for Show { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -7551,7 +7551,7 @@ impl ::protobuf::Message for Show { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.gid.as_ref() { os.write_bytes(1, &v)?; } @@ -7804,7 +7804,7 @@ impl ::protobuf::Clear for Show { } impl ::std::fmt::Debug for Show { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -8767,7 +8767,7 @@ impl ::protobuf::Message for Episode { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -8981,7 +8981,7 @@ impl ::protobuf::Message for Episode { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.gid.as_ref() { os.write_bytes(1, &v)?; } @@ -9298,7 +9298,7 @@ impl ::protobuf::Clear for Episode { } impl ::std::fmt::Debug for Episode { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -9402,7 +9402,7 @@ impl ::protobuf::Message for Category { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -9436,7 +9436,7 @@ impl ::protobuf::Message for Category { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.name.as_ref() { os.write_string(1, &v)?; } @@ -9526,7 +9526,7 @@ impl ::protobuf::Clear for Category { } impl ::std::fmt::Debug for Category { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -9599,7 +9599,7 @@ impl ::protobuf::Message for OriginalAudio { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -9626,7 +9626,7 @@ impl ::protobuf::Message for OriginalAudio { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.uuid.as_ref() { os.write_bytes(1, &v)?; } @@ -9705,7 +9705,7 @@ impl ::protobuf::Clear for OriginalAudio { } impl ::std::fmt::Debug for OriginalAudio { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } diff --git a/protocol/src/pubsub.rs b/protocol/src/pubsub.rs index 31871a2d..a0daca49 100644 --- a/protocol/src/pubsub.rs +++ b/protocol/src/pubsub.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 2.8.0. Do not edit +// This file is generated by rust-protobuf 2.8.1. Do not edit // @generated // https://github.com/Manishearth/rust-clippy/issues/702 @@ -24,7 +24,7 @@ use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; /// Generated files are compatible only with the same version /// of protobuf runtime. -const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_8_0; +const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_8_1; #[derive(PartialEq,Clone,Default)] pub struct Subscription { @@ -128,7 +128,7 @@ impl ::protobuf::Message for Subscription { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -175,7 +175,7 @@ impl ::protobuf::Message for Subscription { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.uri.as_ref() { os.write_string(1, &v)?; } @@ -272,7 +272,7 @@ impl ::protobuf::Clear for Subscription { } impl ::std::fmt::Debug for Subscription { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } diff --git a/protocol/src/spirc.rs b/protocol/src/spirc.rs index 80b92d24..e68f8110 100644 --- a/protocol/src/spirc.rs +++ b/protocol/src/spirc.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 2.8.0. Do not edit +// This file is generated by rust-protobuf 2.8.1. Do not edit // @generated // https://github.com/Manishearth/rust-clippy/issues/702 @@ -24,7 +24,7 @@ use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; /// Generated files are compatible only with the same version /// of protobuf runtime. -const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_8_0; +const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_8_1; #[derive(PartialEq,Clone,Default)] pub struct Frame { @@ -501,7 +501,7 @@ impl ::protobuf::Message for Frame { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -636,7 +636,7 @@ impl ::protobuf::Message for Frame { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.version { os.write_uint32(1, v)?; } @@ -849,7 +849,7 @@ impl ::protobuf::Clear for Frame { } impl ::std::fmt::Debug for Frame { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -1195,7 +1195,7 @@ impl ::protobuf::Message for DeviceState { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -1304,7 +1304,7 @@ impl ::protobuf::Message for DeviceState { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.sw_version.as_ref() { os.write_string(1, &v)?; } @@ -1477,7 +1477,7 @@ impl ::protobuf::Clear for DeviceState { } impl ::std::fmt::Debug for DeviceState { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -1585,7 +1585,7 @@ impl ::protobuf::Message for Capability { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -1624,7 +1624,7 @@ impl ::protobuf::Message for Capability { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.typ { os.write_enum(1, v.value())?; } @@ -1721,7 +1721,7 @@ impl ::protobuf::Clear for Capability { } impl ::std::fmt::Debug for Capability { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -1794,7 +1794,7 @@ impl ::protobuf::Message for Goodbye { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -1821,7 +1821,7 @@ impl ::protobuf::Message for Goodbye { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.reason.as_ref() { os.write_string(1, &v)?; } @@ -1900,7 +1900,7 @@ impl ::protobuf::Clear for Goodbye { } impl ::std::fmt::Debug for Goodbye { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -2317,7 +2317,7 @@ impl ::protobuf::Message for State { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -2466,7 +2466,7 @@ impl ::protobuf::Message for State { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.context_uri.as_ref() { os.write_string(2, &v)?; } @@ -2675,7 +2675,7 @@ impl ::protobuf::Clear for State { } impl ::std::fmt::Debug for State { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -2842,7 +2842,7 @@ impl ::protobuf::Message for TrackRef { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -2891,7 +2891,7 @@ impl ::protobuf::Message for TrackRef { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.gid.as_ref() { os.write_bytes(1, &v)?; } @@ -2997,7 +2997,7 @@ impl ::protobuf::Clear for TrackRef { } impl ::std::fmt::Debug for TrackRef { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -3332,7 +3332,7 @@ impl ::protobuf::Message for Ad { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -3415,7 +3415,7 @@ impl ::protobuf::Message for Ad { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.next { os.write_int32(1, v)?; } @@ -3566,7 +3566,7 @@ impl ::protobuf::Clear for Ad { } impl ::std::fmt::Debug for Ad { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } @@ -3676,7 +3676,7 @@ impl ::protobuf::Message for Metadata { true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -3709,7 +3709,7 @@ impl ::protobuf::Message for Metadata { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.field_type.as_ref() { os.write_string(1, &v)?; } @@ -3797,7 +3797,7 @@ impl ::protobuf::Clear for Metadata { } impl ::std::fmt::Debug for Metadata { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } From d91bf573a460045a08d3d41c5493f64ce2ee1950 Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Wed, 6 Nov 2019 16:39:31 +0100 Subject: [PATCH 24/43] Switch to libmdns for discovery --- connect/Cargo.toml | 4 ++-- connect/src/discovery.rs | 6 +++--- connect/src/lib.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/connect/Cargo.toml b/connect/Cargo.toml index 9c0f5b0a..f015fa30 100644 --- a/connect/Cargo.toml +++ b/connect/Cargo.toml @@ -29,8 +29,8 @@ aes-ctr = "0.3" block-modes = "0.3" dns-sd = { version = "0.1.3", optional = true } -mdns = { git = "https://github.com/plietar/rust-mdns", optional = true } +libmdns = { version = "0.2", optional = true } [features] -default = ["mdns"] +default = ["libmdns"] with-dns-sd = ["dns-sd"] diff --git a/connect/src/discovery.rs b/connect/src/discovery.rs index 53d5a6ec..de575b15 100644 --- a/connect/src/discovery.rs +++ b/connect/src/discovery.rs @@ -13,7 +13,7 @@ use hyper::{self, Get, Post, StatusCode}; use dns_sd::DNSService; #[cfg(not(feature = "with-dns-sd"))] -use mdns; +use libmdns; use num_bigint::BigUint; use rand; @@ -218,7 +218,7 @@ pub struct DiscoveryStream { #[cfg(not(feature = "with-dns-sd"))] pub struct DiscoveryStream { credentials: mpsc::UnboundedReceiver, - _svc: mdns::Service, + _svc: libmdns::Service, } pub fn discovery( @@ -263,7 +263,7 @@ pub fn discovery( ).unwrap(); #[cfg(not(feature = "with-dns-sd"))] - let responder = mdns::Responder::spawn(&handle)?; + let responder = libmdns::Responder::spawn(&handle)?; #[cfg(not(feature = "with-dns-sd"))] let svc = responder.register( diff --git a/connect/src/lib.rs b/connect/src/lib.rs index cd3d5e0b..d0290585 100644 --- a/connect/src/lib.rs +++ b/connect/src/lib.rs @@ -24,7 +24,7 @@ extern crate block_modes; extern crate dns_sd; #[cfg(not(feature = "with-dns-sd"))] -extern crate mdns; +extern crate libmdns; extern crate librespot_core; extern crate librespot_playback as playback; From 6093d8f2992311d8abd0e30b8e0e850682c7bc8f Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Wed, 6 Nov 2019 16:40:13 +0100 Subject: [PATCH 25/43] Move to librespot-tremor for crates.io compatability. --- audio/Cargo.toml | 4 ++-- audio/src/libvorbis_decoder.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/audio/Cargo.toml b/audio/Cargo.toml index 49902c50..3584f0ad 100644 --- a/audio/Cargo.toml +++ b/audio/Cargo.toml @@ -17,9 +17,9 @@ num-traits = "0.2" tempfile = "3.1" aes-ctr = "0.3" -tremor = { git = "https://github.com/plietar/rust-tremor", optional = true } +librespot-tremor = { version = "0.1.0", optional = true } vorbis = { version ="0.1.0", optional = true } [features] -with-tremor = ["tremor"] +with-tremor = ["librespot-tremor"] with-vorbis = ["vorbis"] diff --git a/audio/src/libvorbis_decoder.rs b/audio/src/libvorbis_decoder.rs index b2045393..eef1708d 100644 --- a/audio/src/libvorbis_decoder.rs +++ b/audio/src/libvorbis_decoder.rs @@ -1,5 +1,5 @@ #[cfg(feature = "with-tremor")] -extern crate tremor as vorbis; +extern crate librespot_tremor as vorbis; #[cfg(not(feature = "with-tremor"))] extern crate vorbis; From 03b62052baad8f669b7c74c05f2067157eccaef9 Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Wed, 6 Nov 2019 16:44:11 +0100 Subject: [PATCH 26/43] More exact dependencies for crates.io --- Cargo.lock | 277 ++++++++++++++++++--------------------------- Cargo.toml | 2 +- connect/Cargo.toml | 2 +- 3 files changed, 113 insertions(+), 168 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 888ef466..be3d3a49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,7 +75,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "alsa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -84,7 +84,7 @@ name = "alsa-sys" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -122,7 +122,7 @@ name = "atty" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -138,7 +138,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -147,8 +147,8 @@ name = "backtrace-sys" version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -261,11 +261,6 @@ name = "byte-tools" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "byteorder" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "byteorder" version = "1.3.2" @@ -289,14 +284,9 @@ dependencies = [ "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "c_linked_list" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "cc" -version = "1.0.38" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -317,7 +307,7 @@ name = "chrono" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -329,7 +319,7 @@ version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -360,7 +350,7 @@ name = "core-foundation-sys" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -389,7 +379,7 @@ dependencies = [ "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "coreaudio-rs 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "stdweb 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -459,22 +449,12 @@ dependencies = [ "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "dns-parser" -version = "0.3.2" -source = "git+https://github.com/plietar/dns-parser#1d3e5a5591bc72eb061c23bd426c4a25f2f73791" -dependencies = [ - "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "dns-sd" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -583,26 +563,6 @@ dependencies = [ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "get_if_addrs" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "c_linked_list 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "get_if_addrs-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "get_if_addrs-sys" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "getopts" version = "0.2.19" @@ -617,7 +577,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -705,7 +665,7 @@ name = "iovec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -722,7 +682,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "jack-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -731,7 +691,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -769,7 +729,7 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.60" +version = "0.2.65" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -787,12 +747,32 @@ name = "libm" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "libmdns" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "multimap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "libpulse-sys" version = "0.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -813,7 +793,7 @@ dependencies = [ "librespot-protocol 0.1.0", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rpassword 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -834,11 +814,11 @@ dependencies = [ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "lewton 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", "librespot-core 0.1.0", + "librespot-tremor 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tremor 0.1.0 (git+https://github.com/plietar/rust-tremor)", "vorbis 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -853,13 +833,13 @@ dependencies = [ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)", + "libmdns 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "librespot-core 0.1.0", "librespot-playback 0.1.0", "librespot-protocol 0.1.0", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "mdns 0.2.0 (git+https://github.com/plietar/rust-mdns)", "num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", @@ -890,7 +870,7 @@ dependencies = [ "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", @@ -914,7 +894,7 @@ dependencies = [ "librespot-core 0.1.0", "librespot-protocol 0.1.0", "linear-map 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -926,7 +906,7 @@ dependencies = [ "cpal 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "jack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "libpulse-sys 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "librespot-audio 0.1.0", "librespot-core 0.1.0", @@ -941,9 +921,20 @@ dependencies = [ name = "librespot-protocol" version = "0.1.0" dependencies = [ - "protobuf 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf-codegen 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf-codegen-pure 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf-codegen 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf-codegen-pure 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "librespot-tremor" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "ogg-sys 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -989,33 +980,12 @@ dependencies = [ "rawpointer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "mdns" -version = "0.2.0" -source = "git+https://github.com/plietar/rust-mdns#66a74033da6c9f1a06e7b0a29f4544fd189d6479" -dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "dns-parser 0.3.2 (git+https://github.com/plietar/dns-parser)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "get_if_addrs 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "multimap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "nix 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "socket2 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "memchr" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1048,7 +1018,7 @@ dependencies = [ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1073,7 +1043,7 @@ version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1126,7 +1096,7 @@ version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1137,19 +1107,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "nix" -version = "0.11.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1226,7 +1197,7 @@ name = "num_cpus" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1243,7 +1214,7 @@ version = "0.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1274,7 +1245,7 @@ name = "parking_lot_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1316,7 +1287,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "portaudio-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1325,7 +1296,7 @@ name = "portaudio-sys" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1352,24 +1323,24 @@ dependencies = [ [[package]] name = "protobuf" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "protobuf-codegen" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "protobuf 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "protobuf-codegen-pure" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "protobuf 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf-codegen 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf-codegen 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1398,7 +1369,7 @@ name = "rand" version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1408,7 +1379,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1421,7 +1392,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1432,7 +1403,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1450,7 +1421,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1524,7 +1495,7 @@ name = "rand_jitter" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1536,7 +1507,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1649,7 +1620,7 @@ version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1698,7 +1669,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1710,7 +1681,7 @@ version = "0.32.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1786,7 +1757,7 @@ name = "signal-hook" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "signal-hook-registry 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1796,7 +1767,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arc-swap 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1826,7 +1797,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1837,7 +1808,7 @@ version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1907,7 +1878,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1943,7 +1914,7 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2045,7 +2016,7 @@ dependencies = [ "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", "mio-named-pipes 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2104,7 +2075,7 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "signal-hook 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2185,7 +2156,7 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2194,26 +2165,6 @@ dependencies = [ "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tremor" -version = "0.1.0" -source = "git+https://github.com/plietar/rust-tremor#5958cc302e78f535dad90e9665da981ddff4000a" -dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "tremor-sys 0.1.0 (git+https://github.com/plietar/rust-tremor)", -] - -[[package]] -name = "tremor-sys" -version = "0.1.0" -source = "git+https://github.com/plietar/rust-tremor#5958cc302e78f535dad90e9665da981ddff4000a" -dependencies = [ - "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "ogg-sys 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "try-lock" version = "0.1.0" @@ -2316,7 +2267,7 @@ name = "vorbis" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "ogg-sys 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "vorbis-encoder 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2330,7 +2281,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "ogg-sys 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "vorbis-sys 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2342,7 +2293,7 @@ version = "0.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "ogg-sys 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2353,7 +2304,7 @@ version = "0.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "ogg-sys 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "vorbis-sys 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2374,7 +2325,7 @@ name = "which" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2464,12 +2415,10 @@ dependencies = [ "checksum block-modes 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "31aa8410095e39fdb732909fb5730a48d5bd7c2e3cd76bd1b07b3dbea130c529" "checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" -"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" -"checksum c_linked_list 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4964518bd3b4a8190e832886cdc0da9794f12e8e6c1613a9e90ff331c4c8724b" -"checksum cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "ce400c638d48ee0e9ab75aef7997609ec57367ccfe1463f21bf53c3eca67bf46" +"checksum cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "aa87058dce70a3ff5621797f1506cb837edd02ac4c0ae642b4542dce802908b8" "checksum cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42aac45e9567d97474a834efdee3081b3c942b2205be932092f53354ce503d6c" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe" @@ -2487,7 +2436,6 @@ dependencies = [ "checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" "checksum ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "022cd691704491df67d25d006fe8eca083098253c4d43516c2206479c58c6736" "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -"checksum dns-parser 0.3.2 (git+https://github.com/plietar/dns-parser)" = "" "checksum dns-sd 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d748509dea20228f63ba519bf142ce2593396386125b01f5b0d6412dab972087" "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" @@ -2503,8 +2451,6 @@ dependencies = [ "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -"checksum get_if_addrs 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "abddb55a898d32925f3148bd281174a68eeb68bbfd9a5938a57b18f506ee4ef7" -"checksum get_if_addrs-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0d04f9fb746cf36b191c00f3ede8bde9c8e64f9f4b05ae2694a9ccf5e3f5ab48" "checksum getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "72327b15c228bfe31f1390f93dd5e9279587f0463836393c9df719ce62a3e450" "checksum getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e65cce4e5084b14874c4e7097f38cab54f47ee554f9194673456ea379dcc4c55" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" @@ -2523,17 +2469,18 @@ dependencies = [ "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum lewton 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8d542c1a317036c45c2aa1cf10cc9d403ca91eb2d333ef1a4917e5cb10628bd0" -"checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb" +"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" "checksum libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fd38073de8f7965d0c17d30546d4bb6da311ab428d1c7a3fc71dff7f9d4979b9" "checksum libm 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" +"checksum libmdns 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "10a5de2d38a254122ddb711aa0a5d48ffc501efe7cba4be7ea531b80a274bc0d" "checksum libpulse-sys 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9bb11b06faf883500c1b625cf4453e6c7737e9df9c7ba01df3f84b22b083e4ac" +"checksum librespot-tremor 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b155a7dc4e4d272e01c37a1b85c1ee1bee7f04980ad4a7784c1a6e0f2de5929b" "checksum linear-map 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c275b6ad54070ac2d665eef9197db647b32239c9d244bfb6f041a766d00da5b3" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum matrixmultiply 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfed72d871629daa12b25af198f110e8095d7650f5f4c61c5bac28364604f9b" -"checksum mdns 0.2.0 (git+https://github.com/plietar/rust-mdns)" = "" "checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" @@ -2546,7 +2493,7 @@ dependencies = [ "checksum multimap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb04b9f127583ed176e163fb9ec6f3e793b87e21deedd5734a69386a18a0151" "checksum nalgebra 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8e12856109b5cb8e2934b5e45e4624839416e1c6c1f7d286711a7a66b79db29d" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" -"checksum nix 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "becb657d662f1cd2ef38c7ad480ec6b8cf9e96b27adb543e594f9cf0f2e6065c" +"checksum nix 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b7fd5681d13fda646462cfbd4e5f2051279a89a544d50eb98c365b507246839f" "checksum nix 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2c5afeb0198ec7be8569d666644b574345aad2e95a53baf3a532da3e0f3fb32" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b" @@ -2572,9 +2519,9 @@ dependencies = [ "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum protobuf 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8aefcec9f142b524d98fc81d07827743be89dd6586a1ba6ab21fa66a500b3fa5" -"checksum protobuf-codegen 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "31539be8028d6b9e8e1b3b7c74e2fa3555302e27b2cc20dbaee6ffba648f75e2" -"checksum protobuf-codegen-pure 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "00993dc5fbbfcf9d8a005f6b6c29fd29fd6d86deba3ae3f41fd20c624c414616" +"checksum protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40361836defdd5871ff7e84096c6f6444af7fc157f8ef1789f54f147687caa20" +"checksum protobuf-codegen 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "12c6abd78435445fc86898ebbd0521a68438063d4a73e23527b7134e6bf58b4a" +"checksum protobuf-codegen-pure 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c1646acda5319f5b28b0bff4a484324df43ddae2c0f5a3f3e63c0b26095cd600" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" @@ -2663,8 +2610,6 @@ dependencies = [ "checksum tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f2106812d500ed25a4f38235b9cae8f78a09edf43203e16e59c3b769a342a60e" "checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92" "checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" -"checksum tremor 0.1.0 (git+https://github.com/plietar/rust-tremor)" = "" -"checksum tremor-sys 0.1.0 (git+https://github.com/plietar/rust-tremor)" = "" "checksum try-lock 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2aa4715743892880f70885373966c83d73ef1b0838a664ef0c76fffd35e7c2" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum ucd-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa9b3b49edd3468c0e6565d85783f51af95212b6fa3986a5500954f00b460874" diff --git a/Cargo.toml b/Cargo.toml index 69582a59..9137df53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,7 @@ getopts = "0.2" hyper = "0.11" log = "0.4" num-bigint = "0.2" -protobuf = "2.8.*" +protobuf = "2.8.1" rand = "0.7" rpassword = "3.0" tokio-core = "0.1" diff --git a/connect/Cargo.toml b/connect/Cargo.toml index f015fa30..d4354ea1 100644 --- a/connect/Cargo.toml +++ b/connect/Cargo.toml @@ -16,7 +16,7 @@ futures = "0.1" hyper = "0.11" log = "0.4" num-bigint = "0.2" -protobuf = "2.8.*" +protobuf = "2.8.1" rand = "0.7" serde = "1.0" serde_derive = "1.0" From 394320c7b7e6b2a0bb12748818cea7056cfcb24a Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Wed, 6 Nov 2019 16:50:26 +0100 Subject: [PATCH 27/43] Add description and license to Cargo.toml for each crate --- audio/Cargo.toml | 2 ++ connect/Cargo.toml | 2 ++ core/Cargo.toml | 3 +++ metadata/Cargo.toml | 2 ++ playback/Cargo.toml | 2 ++ protocol/Cargo.toml | 2 ++ 6 files changed, 13 insertions(+) diff --git a/audio/Cargo.toml b/audio/Cargo.toml index 3584f0ad..3c1af9e0 100644 --- a/audio/Cargo.toml +++ b/audio/Cargo.toml @@ -2,6 +2,8 @@ name = "librespot-audio" version = "0.1.0" authors = ["Paul Lietar "] +description="The audio fetching and processing logic for librespot" +license="MIT" [dependencies.librespot-core] path = "../core" diff --git a/connect/Cargo.toml b/connect/Cargo.toml index d4354ea1..78cad976 100644 --- a/connect/Cargo.toml +++ b/connect/Cargo.toml @@ -2,6 +2,8 @@ name = "librespot-connect" version = "0.1.0" authors = ["Paul Lietar "] +description="The discovery and Spotify Connect logic for librespot" +license="MIT" [dependencies.librespot-core] path = "../core" diff --git a/core/Cargo.toml b/core/Cargo.toml index 162147de..da646059 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -3,9 +3,12 @@ name = "librespot-core" version = "0.1.0" authors = ["Paul Lietar "] build = "build.rs" +description="The core functionality provided by librespot" +license="MIT" [dependencies.librespot-protocol] path = "../protocol" +version = "0.1.0" [dependencies] base64 = "0.10" diff --git a/metadata/Cargo.toml b/metadata/Cargo.toml index 51e44191..49c1e0c2 100644 --- a/metadata/Cargo.toml +++ b/metadata/Cargo.toml @@ -2,6 +2,8 @@ name = "librespot-metadata" version = "0.1.0" authors = ["Paul Lietar "] +description="The metadata logic for librespot" +license="MIT" [dependencies] byteorder = "1.3" diff --git a/playback/Cargo.toml b/playback/Cargo.toml index c9ac7592..c73688bf 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -2,6 +2,8 @@ name = "librespot-playback" version = "0.1.0" authors = ["Sasha Hilton "] +description="The audio playback logic for librespot" +license="MIT" [dependencies.librespot-audio] path = "../audio" diff --git a/protocol/Cargo.toml b/protocol/Cargo.toml index e81d4d92..4c9a332b 100644 --- a/protocol/Cargo.toml +++ b/protocol/Cargo.toml @@ -3,6 +3,8 @@ name = "librespot-protocol" version = "0.1.0" authors = ["Paul Liétar "] build = "build.rs" +description="The protobuf logic for communicating with Spotify servers" +license="MIT" [dependencies] protobuf = "2.8.1" From 63049d9928cd32fc70c924024111a254341565da Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Wed, 6 Nov 2019 16:52:51 +0100 Subject: [PATCH 28/43] Protobuf exact dependency --- core/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/Cargo.toml b/core/Cargo.toml index da646059..908b9073 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -24,7 +24,7 @@ log = "0.4" num-bigint = "0.2" num-integer = "0.1" num-traits = "0.2" -protobuf = "2.8.*" +protobuf = "2.8.1" rand = "0.7" serde = "1.0" serde_derive = "1.0" From e7177da3b1460fe3c30246601b9d23ffc655d4ed Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Wed, 6 Nov 2019 16:56:51 +0100 Subject: [PATCH 29/43] Add librespot-core version number --- audio/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/audio/Cargo.toml b/audio/Cargo.toml index 3c1af9e0..2d67437d 100644 --- a/audio/Cargo.toml +++ b/audio/Cargo.toml @@ -7,6 +7,7 @@ license="MIT" [dependencies.librespot-core] path = "../core" +version = "0.1.0" [dependencies] bit-set = "0.5" From 4e1bf7a0db8bd4a6c4555af5241d1f43d566c3ed Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Wed, 6 Nov 2019 16:59:40 +0100 Subject: [PATCH 30/43] Add version numbers for all librespot crates --- Cargo.toml | 6 ++++++ connect/Cargo.toml | 3 +++ metadata/Cargo.toml | 4 +++- playback/Cargo.toml | 3 +++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 9137df53..636709d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,16 +21,22 @@ doc = false [dependencies.librespot-audio] path = "audio" +version = "0.1.0" [dependencies.librespot-connect] path = "connect" +version = "0.1.0" [dependencies.librespot-core] path = "core" +version = "0.1.0" [dependencies.librespot-metadata] path = "metadata" +version = "0.1.0" [dependencies.librespot-playback] path = "playback" +version = "0.1.0" [dependencies.librespot-protocol] path = "protocol" +version = "0.1.0" [dependencies] base64 = "0.10" diff --git a/connect/Cargo.toml b/connect/Cargo.toml index 78cad976..f4b4f534 100644 --- a/connect/Cargo.toml +++ b/connect/Cargo.toml @@ -7,10 +7,13 @@ license="MIT" [dependencies.librespot-core] path = "../core" +version = "0.1.0" [dependencies.librespot-playback] path = "../playback" +version = "0.1.0" [dependencies.librespot-protocol] path = "../protocol" +version = "0.1.0" [dependencies] base64 = "0.10" diff --git a/metadata/Cargo.toml b/metadata/Cargo.toml index 49c1e0c2..6983b4b1 100644 --- a/metadata/Cargo.toml +++ b/metadata/Cargo.toml @@ -9,9 +9,11 @@ license="MIT" byteorder = "1.3" futures = "0.1" linear-map = "1.2" -protobuf = "2.8.*" +protobuf = "2.8.1" [dependencies.librespot-core] path = "../core" +version = "0.1.0" [dependencies.librespot-protocol] path = "../protocol" +version = "0.1.0" diff --git a/playback/Cargo.toml b/playback/Cargo.toml index c73688bf..d7d1c5b5 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -7,10 +7,13 @@ license="MIT" [dependencies.librespot-audio] path = "../audio" +version = "0.1.0" [dependencies.librespot-core] path = "../core" +version = "0.1.0" [dependencies.librespot-metadata] path = "../metadata" +version = "0.1.0" [dependencies] futures = "0.1" From 295bda7e489715b9e6c27a262f9a4fcd12fb7632 Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Wed, 6 Nov 2019 17:08:22 +0100 Subject: [PATCH 31/43] Update Cargo.toml to point to Librespot Org repo --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 636709d7..1f992257 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "librespot" version = "0.1.0" -authors = ["Paul Liétar "] +authors = ["Librespot Org"] license = "MIT" description = "Open Source Spotify client library" keywords = ["spotify"] -repository = "https://github.com/plietar/librespot" +repository = "https://github.com/librespot-org/librespot" readme = "README.md" [workspace] From 9e2cfe321efeddfa580aaa21e718c6eb6e7daf09 Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Wed, 6 Nov 2019 17:25:10 +0100 Subject: [PATCH 32/43] Update readme and add publishing notes --- Cargo.toml | 2 +- PUBLISHING.md | 9 +++++++++ README.md | 6 ++++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 PUBLISHING.md diff --git a/Cargo.toml b/Cargo.toml index 1f992257..2751ac16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "librespot" version = "0.1.0" authors = ["Librespot Org"] license = "MIT" -description = "Open Source Spotify client library" +description = "An open source client library for Spotify, with support for Spotify Connect" keywords = ["spotify"] repository = "https://github.com/librespot-org/librespot" readme = "README.md" diff --git a/PUBLISHING.md b/PUBLISHING.md new file mode 100644 index 00000000..952a0b8c --- /dev/null +++ b/PUBLISHING.md @@ -0,0 +1,9 @@ +# Publishing + +Publishing librespot to crates.io is a slightly convoluted affair due to the various dependencies that each package has on other local packages. The order of publising that has been found to work is as follows: + +`protocol -> core -> audio -> metadata -> playback -> connect -> librespot` + +The `protocol` package needs to be published with `cargo publish --no-verify` due to the build script modifying the source during compile time. + +Publishing can be done using the command `cargo publish` in each of the directories of the respecive crate. \ No newline at end of file diff --git a/README.md b/README.md index e9cbf79e..62dc52e8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ [![Build Status](https://travis-ci.org/librespot-org/librespot.svg?branch=master)](https://travis-ci.org/librespot-org/librespot) [![Gitter chat](https://badges.gitter.im/librespot-org/librespot.png)](https://gitter.im/librespot-org/spotify-connect-resources) +[![Crates.io](https://img.shields.io/crates/v/librespot.svg)](https://crates.io/crates/librespot) Current maintainer is @awiouy folks. @@ -11,6 +12,11 @@ which are not available in the official library. _Note: librespot only works with Spotify Premium. This will remain the case for the forseeable future, as we are unlikely to work on implementing the features such as limited skips and adverts that would be required to make librespot compliant with free accounts._ +## Quick start +We're available on [crates.io](https://crates.io/crates/librespot) as the _librespot_ package. Simply run `cargo install librespot` to install librespot on your system. Check the wiki for more info and possible [usage options](https://github.com/librespot-org/librespot/wiki/Options). + +After installation, you can run librespot form the CLI using a command such as `librespot -n "Librespot Speaker" -b 192` to create a speaker called _Librespot Speaker_ serving 192kbps audio. + ## This fork As the origin by [plietar](https://github.com/plietar/) is no longer actively maintained, this organisation and repository have been set up so that the project may be maintained and upgraded in the future. From 09eef912cc17252b13828f9fc9ba52bdd2f63242 Mon Sep 17 00:00:00 2001 From: ashthespy Date: Thu, 7 Nov 2019 13:16:17 +0100 Subject: [PATCH 33/43] [Travis] Reduce cache bloat - don't save build artefacts --- .travis.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6a28f10a..fc3294af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,17 @@ rust: - nightly cache: cargo - +# Reduce cache bloat +before_cache: + - rm -rfv "$TRAVIS_HOME/.cargo/registry/src" + - rm -rfv target/debug/incremental/{librespot,build_script_build}-* + - rm -rfv target/debug/.fingerprint/librespot-* + - rm -rfv target/debug/build/librespot-* + - rm -rfv target/debug/deps/liblibrespot-* + - rm -rfv target/debug/deps/librespot-* + - rm -rfv target/debug/{librespot,liblibrespot}.d + - cargo clean -p librespot librespot-core librespot-connect librespot-audio librespot-metadata librespot-playback + addons: apt: packages: From 6422dcef78471583d3a282daf626f51766ad125d Mon Sep 17 00:00:00 2001 From: Konstantin Seiler Date: Fri, 8 Nov 2019 00:02:53 +1100 Subject: [PATCH 34/43] Refine file downloading heuristics to use data rates and ping times everywhere. --- audio/src/fetch.rs | 241 +++++++++++++++++++++++++++-------------- audio/src/lib.rs | 1 + core/src/channel.rs | 37 +++++++ playback/src/player.rs | 42 +++++-- 4 files changed, 233 insertions(+), 88 deletions(-) diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index e3d63dfb..46d8a88a 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -3,7 +3,7 @@ use bytes::Bytes; use futures::sync::{mpsc, oneshot}; use futures::Stream; use futures::{Async, Future, Poll}; -use std::cmp::min; +use std::cmp::{min, max}; use std::fs; use std::io::{self, Read, Seek, SeekFrom, Write}; use std::sync::{Arc, Condvar, Mutex}; @@ -18,9 +18,67 @@ use futures::sync::mpsc::unbounded; use std::sync::atomic; use std::sync::atomic::AtomicUsize; -const MINIMUM_CHUNK_SIZE: usize = 1024 * 16; -const MAXIMUM_CHUNK_SIZE: usize = 1024 * 128; -const MAXIMUM_ASSUMED_PING_TIME_SECONDS: u64 = 5; + +const MINIMUM_DOWNLOAD_SIZE: usize = 1024 * 16; +// The minimum size of a block that is requested from the Spotify servers in one request. +// This is the block size that is typically requested while doing a seek() on a file. +// Note: smaller requests can happen if part of the block is downloaded already. + +const INITIAL_DOWNLOAD_SIZE: usize = 1024 * 16; // MUST be divisible by four!!! +// The amount of data that is requested when initially opening a file. +// Note: if the file is opened to play from the beginning, the amount of data to +// read ahead is requested in addition to this amount. If the file is opened to seek to +// another position, then only this amount is requested on the first request. + +const INITIAL_PING_TIME_ESTIMATE_SECONDS: f64 = 0.5; +// The pig time that is used for calculations before a ping time was actually measured. + +const MAXIMUM_ASSUMED_PING_TIME_SECONDS: f64 = 1.5; +// If the measured ping time to the Spotify server is larger than this value, it is capped +// to avoid run-away block sizes and pre-fetching. + +pub const READ_AHEAD_BEFORE_PLAYBACK_SECONDS: f64 = 1.0; +// Before playback starts, this many seconds of data must be present. +// Note: the calculations are done using the nominal bitrate of the file. The actual amount +// of audio data may be larger or smaller. + +pub const READ_AHEAD_BEFORE_PLAYBACK_ROUNDTRIPS: f64 = 2.0; +// Same as READ_AHEAD_BEFORE_PLAYBACK_SECONDS, but the time is taken as a factor of the ping +// time to the Spotify server. +// Both, READ_AHEAD_BEFORE_PLAYBACK_SECONDS and READ_AHEAD_BEFORE_PLAYBACK_ROUNDTRIPS are +// obeyed. +// Note: the calculations are done using the nominal bitrate of the file. The actual amount +// of audio data may be larger or smaller. + +pub const READ_AHEAD_DURING_PLAYBACK_SECONDS: f64 = 1.0; +// While playing back, this many seconds of data ahead of the current read position are +// requested. +// Note: the calculations are done using the nominal bitrate of the file. The actual amount +// of audio data may be larger or smaller. + +pub const READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS: f64 = 2.0; +// Same as READ_AHEAD_DURING_PLAYBACK_SECONDS, but the time is taken as a factor of the ping +// time to the Spotify server. +// Note: the calculations are done using the nominal bitrate of the file. The actual amount +// of audio data may be larger or smaller. + +const PREFETCH_THRESHOLD_FACTOR: f64 = 4.0; +// If the amount of data that is pending (requested but not received) is less than a certain amount, +// data is pre-fetched in addition to the read ahead settings above. The threshold for requesting more +// data is calculated as +// < PREFETCH_THRESHOLD_FACTOR * * + +const FAST_PREFETCH_THRESHOLD_FACTOR: f64 = 1.5; +// Similar to PREFETCH_THRESHOLD_FACTOR, but it also takes the current download rate into account. +// The formula used is +// < FAST_PREFETCH_THRESHOLD_FACTOR * * +// This mechanism allows for fast downloading of the remainder of the file. The number should be larger +// than 1 so the download rate ramps up until the bandwidth is saturated. The larger the value, the faster +// the download rate ramps up. However, this comes at the cost that it might hurt ping-time if a seek is +// performed while downloading. Values smaller than 1 cause the download rate to collapse and effectively +// only PREFETCH_THRESHOLD_FACTOR is in effect. Thus, set to zero if bandwidth saturation is not wanted. + + pub enum AudioFile { Cached(fs::File), @@ -40,6 +98,7 @@ pub struct AudioFileOpenStreaming { headers: ChannelHeaders, file_id: FileId, complete_tx: Option>, + streaming_data_rate: usize, } @@ -47,7 +106,6 @@ enum StreamLoaderCommand{ Fetch(Range), // signal the stream loader to fetch a range of the file RandomAccessMode(), // optimise download strategy for random access StreamMode(), // optimise download strategy for streaming - StreamDataRate(usize), // when optimising for streaming, assume a streaming rate of this many bytes per second. Close(), // terminate and don't load any more data } @@ -57,7 +115,6 @@ pub struct StreamLoaderController { channel_tx: Option>, stream_shared: Option>, file_size: usize, - bytes_per_second: usize, } @@ -66,8 +123,6 @@ impl StreamLoaderController { return self.file_size; } - pub fn data_rate(&self) -> usize { return self.bytes_per_second; } - pub fn range_available(&self, range: Range) -> bool { if let Some(ref shared) = self.stream_shared { let download_status = shared.download_status.lock().unwrap(); @@ -124,7 +179,7 @@ impl StreamLoaderController { if range.length > (download_status.downloaded.union(&download_status.requested).contained_length_from_value(range.start)) { // For some reason, the requested range is neither downloaded nor requested. // This could be due to a network error. Request it again. - // We can't use self.fetch here because self can't borrowed mutably, so we access the channel directly. + // We can't use self.fetch here because self can't be borrowed mutably, so we access the channel directly. if let Some(ref mut channel) = self.channel_tx { // ignore the error in case the channel has been closed already. let _ = channel.unbounded_send(StreamLoaderCommand::Fetch(range)); @@ -169,12 +224,6 @@ impl StreamLoaderController { self.send_stream_loader_command(StreamLoaderCommand::StreamMode()); } - pub fn set_stream_data_rate(&mut self, bytes_per_second: usize) { - // when optimising for streaming, assume a streaming rate of this many bytes per second. - self.bytes_per_second = bytes_per_second; - self.send_stream_loader_command(StreamLoaderCommand::StreamDataRate(bytes_per_second)); - } - pub fn close(&mut self) { // terminate stream loading and don't load any more data for this file. self.send_stream_loader_command(StreamLoaderCommand::Close()); @@ -200,11 +249,19 @@ struct AudioFileDownloadStatus { downloaded: RangeSet, } +#[derive(Copy, Clone)] +enum DownloadStrategy { + RandomAccess(), + Streaming(), +} + struct AudioFileShared { file_id: FileId, file_size: usize, + stream_data_rate: usize, cond: Condvar, download_status: Mutex, + download_strategy: Mutex, number_of_open_requests: AtomicUsize, ping_time_ms: AtomicUsize, read_position: AtomicUsize, @@ -216,8 +273,10 @@ impl AudioFileOpenStreaming { let shared = Arc::new(AudioFileShared { file_id: self.file_id, file_size: size, + stream_data_rate: self.streaming_data_rate, cond: Condvar::new(), download_status: Mutex::new(AudioFileDownloadStatus {requested: RangeSet::new(), downloaded: RangeSet::new()}), + download_strategy: Mutex::new(DownloadStrategy::RandomAccess()), // start with random access mode until someone tells us otherwise number_of_open_requests: AtomicUsize::new(0), ping_time_ms: AtomicUsize::new(0), read_position: AtomicUsize::new(0), @@ -296,7 +355,7 @@ impl Future for AudioFileOpenStreaming { } impl AudioFile { - pub fn open(session: &Session, file_id: FileId) -> AudioFileOpen { + pub fn open(session: &Session, file_id: FileId, bytes_per_second: usize, play_from_beginning: bool) -> AudioFileOpen { let cache = session.cache().cloned(); if let Some(file) = cache.as_ref().and_then(|cache| cache.file(file_id)) { @@ -307,7 +366,14 @@ impl AudioFile { debug!("Downloading file {}", file_id); let (complete_tx, complete_rx) = oneshot::channel(); - let initial_data_length = MINIMUM_CHUNK_SIZE; + let mut initial_data_length = if play_from_beginning { + INITIAL_DOWNLOAD_SIZE + max((READ_AHEAD_DURING_PLAYBACK_SECONDS * bytes_per_second as f64) as usize, (INITIAL_PING_TIME_ESTIMATE_SECONDS * READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS * bytes_per_second as f64) as usize) + } else { + INITIAL_DOWNLOAD_SIZE + }; + if initial_data_length % 4 != 0 { + initial_data_length += 4 - (initial_data_length % 4); + } let (headers, data) = request_range(session, file_id, 0, initial_data_length).split(); let open = AudioFileOpenStreaming { @@ -320,6 +386,8 @@ impl AudioFile { initial_request_sent_time: Instant::now(), complete_tx: Some(complete_tx), + streaming_data_rate: bytes_per_second, + }; let session_ = session.clone(); @@ -336,27 +404,23 @@ impl AudioFile { .or_else(|oneshot::Canceled| Ok(())) }); - AudioFileOpen::Streaming(open) + return AudioFileOpen::Streaming(open); } - pub fn get_stream_loader_controller(&self, bytes_per_second: usize) -> StreamLoaderController { + pub fn get_stream_loader_controller(&self) -> StreamLoaderController { match self { - AudioFile::Streaming(stream) => { - let mut result = StreamLoaderController { + AudioFile::Streaming(ref stream) => { + return StreamLoaderController { channel_tx: Some(stream.stream_loader_command_tx.clone()), stream_shared: Some(stream.shared.clone()), file_size: stream.shared.file_size, - bytes_per_second: bytes_per_second, }; - result.set_stream_data_rate(bytes_per_second); - return result; } AudioFile::Cached(ref file) => { return StreamLoaderController { channel_tx: None, stream_shared: None, file_size: file.metadata().unwrap().len() as usize, - bytes_per_second: bytes_per_second, } } } @@ -474,8 +538,8 @@ impl Future for AudioFileFetchDataReceiver { if let Some(request_sent_time) = self.request_sent_time { let duration = Instant::now() - request_sent_time; let duration_ms: u64; - if duration.as_secs() > MAXIMUM_ASSUMED_PING_TIME_SECONDS { - duration_ms = MAXIMUM_ASSUMED_PING_TIME_SECONDS * 1000; + if 0.001 * (duration.as_millis() as f64) > MAXIMUM_ASSUMED_PING_TIME_SECONDS { + duration_ms = (MAXIMUM_ASSUMED_PING_TIME_SECONDS * 1000.0) as u64; } else { duration_ms = duration.as_secs() * 1000 + duration.subsec_millis() as u64; } @@ -520,11 +584,6 @@ impl Future for AudioFileFetchDataReceiver { } -enum DownloadStrategy { - RandomAccess(), - Streaming(), -} - struct AudioFileFetch { session: Session, shared: Arc, @@ -533,11 +592,8 @@ struct AudioFileFetch { file_data_tx: mpsc::UnboundedSender, file_data_rx: mpsc::UnboundedReceiver, - //seek_rx: mpsc::UnboundedReceiver, stream_loader_command_rx: mpsc::UnboundedReceiver, complete_tx: Option>, - download_strategy: DownloadStrategy, - streaming_data_rate: usize, network_response_times_ms: Vec, } @@ -584,16 +640,18 @@ impl AudioFileFetch { stream_loader_command_rx: stream_loader_command_rx, complete_tx: Some(complete_tx), - download_strategy: DownloadStrategy::RandomAccess(), // start with random access mode until someone tells us otherwise - streaming_data_rate: 40, // assume 360 kbit per second unless someone tells us otherwise. network_response_times_ms: Vec::new(), } } + fn get_download_strategy(&mut self) -> DownloadStrategy { + *(self.shared.download_strategy.lock().unwrap()) + } + fn download_range(&mut self, mut offset: usize, mut length: usize) { - if length < MINIMUM_CHUNK_SIZE { - length = MINIMUM_CHUNK_SIZE; + if length < MINIMUM_DOWNLOAD_SIZE { + length = MINIMUM_DOWNLOAD_SIZE; } // ensure the values are within the bounds and align them by 4 for the spotify protocol. @@ -647,35 +705,43 @@ impl AudioFileFetch { } - fn pre_fetch_more_data(&mut self) { + fn pre_fetch_more_data(&mut self, bytes: usize) { - // determine what is still missing - let mut missing_data = RangeSet::new(); - missing_data.add_range(&Range::new(0,self.shared.file_size)); - { - let download_status = self.shared.download_status.lock().unwrap(); - missing_data.subtract_range_set(&download_status.downloaded); - missing_data.subtract_range_set(&download_status.requested); - } + let mut bytes_to_go = bytes; - // download data from after the current read position first - let mut tail_end = RangeSet::new(); - let read_position = self.shared.read_position.load(atomic::Ordering::Relaxed); - tail_end.add_range(&Range::new(read_position, self.shared.file_size - read_position)); - let tail_end = tail_end.intersection(&missing_data); + while bytes_to_go > 0 { - if ! tail_end.is_empty() { - let range = tail_end.get_range(0); - let offset = range.start; - let length = min(range.length, MAXIMUM_CHUNK_SIZE); - self.download_range(offset, length); + // determine what is still missing + let mut missing_data = RangeSet::new(); + missing_data.add_range(&Range::new(0, self.shared.file_size)); + { + let download_status = self.shared.download_status.lock().unwrap(); + missing_data.subtract_range_set(&download_status.downloaded); + missing_data.subtract_range_set(&download_status.requested); + } - } else if ! missing_data.is_empty() { - // ok, the tail is downloaded, download something fom the beginning. - let range = missing_data.get_range(0); - let offset = range.start; - let length = min(range.length, MAXIMUM_CHUNK_SIZE); - self.download_range(offset, length); + // download data from after the current read position first + let mut tail_end = RangeSet::new(); + let read_position = self.shared.read_position.load(atomic::Ordering::Relaxed); + tail_end.add_range(&Range::new(read_position, self.shared.file_size - read_position)); + let tail_end = tail_end.intersection(&missing_data); + + if !tail_end.is_empty() { + let range = tail_end.get_range(0); + let offset = range.start; + let length = min(range.length, bytes_to_go); + self.download_range(offset, length); + bytes_to_go -= length; + } else if !missing_data.is_empty() { + // ok, the tail is downloaded, download something fom the beginning. + let range = missing_data.get_range(0); + let offset = range.start; + let length = min(range.length, bytes_to_go); + self.download_range(offset, length); + bytes_to_go -= length; + } else { + return; + } } } @@ -774,13 +840,10 @@ impl AudioFileFetch { self.download_range(request.start, request.length); } Ok(Async::Ready(Some(StreamLoaderCommand::RandomAccessMode()))) => { - self.download_strategy = DownloadStrategy::RandomAccess(); + *(self.shared.download_strategy.lock().unwrap()) = DownloadStrategy::RandomAccess(); } Ok(Async::Ready(Some(StreamLoaderCommand::StreamMode()))) => { - self.download_strategy = DownloadStrategy::Streaming(); - } - Ok(Async::Ready(Some(StreamLoaderCommand::StreamDataRate(rate)))) => { - self.streaming_data_rate = rate; + *(self.shared.download_strategy.lock().unwrap()) = DownloadStrategy::Streaming(); } Ok(Async::Ready(Some(StreamLoaderCommand::Close()))) => { return Ok(Async::Ready(())); @@ -827,18 +890,22 @@ impl Future for AudioFileFetch { Err(()) => unreachable!(), } - - if let DownloadStrategy::Streaming() = self.download_strategy { + if let DownloadStrategy::Streaming() = self.get_download_strategy() { let bytes_pending: usize = { let download_status = self.shared.download_status.lock().unwrap(); download_status.requested.minus(&download_status.downloaded).len() }; - let ping_time = self.shared.ping_time_ms.load(atomic::Ordering::Relaxed); + let ping_time_seconds = 0.0001 * self.shared.ping_time_ms.load(atomic::Ordering::Relaxed) as f64; - if bytes_pending < 2 * ping_time * self.streaming_data_rate / 1000 { - trace!("Prefetching more data. pending bytes({}) < 2 * ping time ({}) * data rate({}) / 1000.",bytes_pending, ping_time, self.streaming_data_rate); - self.pre_fetch_more_data(); + let desired_pending_bytes = max( + (PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * self.shared.stream_data_rate as f64) as usize, + (FAST_PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * self.session.channel().get_download_rate_estimate() as f64) as usize + ); + + if bytes_pending < desired_pending_bytes { + trace!("Prefetching more data. pending bytes({}) < {}",bytes_pending, desired_pending_bytes); + self.pre_fetch_more_data(desired_pending_bytes - bytes_pending); } } @@ -857,14 +924,25 @@ impl Read for AudioFileStreaming { let length = min(output.len(), self.shared.file_size - offset); - if length == 0 { - return Ok(0); - } + + let length_to_request = match *(self.shared.download_strategy.lock().unwrap()) { + DownloadStrategy::RandomAccess() => { length } + DownloadStrategy::Streaming() => { + // Due to the read-ahead stuff, we potentially request more than the actual reqeust demanded. + let ping_time_seconds = 0.0001 * self.shared.ping_time_ms.load(atomic::Ordering::Relaxed) as f64; + + let length_to_request = length + max( + (READ_AHEAD_DURING_PLAYBACK_SECONDS * self.shared.stream_data_rate as f64) as usize, + (READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS * ping_time_seconds * self.shared.stream_data_rate as f64) as usize + ); + min(length_to_request, self.shared.file_size - offset) + } + }; let mut ranges_to_request = RangeSet::new(); - ranges_to_request.add_range(&Range::new(offset, length)); + ranges_to_request.add_range(&Range::new(offset, length_to_request)); trace!("reading at postion {} (length : {})", offset, length); @@ -878,6 +956,11 @@ impl Read for AudioFileStreaming { self.stream_loader_command_tx.unbounded_send(StreamLoaderCommand::Fetch(range.clone())).unwrap(); } + + if length == 0 { + return Ok(0); + } + while !download_status.downloaded.contains(offset) { trace!("waiting for download"); download_status = self.shared.cond.wait_timeout(download_status, Duration::from_millis(1000)).unwrap().0; diff --git a/audio/src/lib.rs b/audio/src/lib.rs index b178c395..845ba5f9 100644 --- a/audio/src/lib.rs +++ b/audio/src/lib.rs @@ -25,6 +25,7 @@ mod range_set; pub use decrypt::AudioDecrypt; pub use fetch::{AudioFile, AudioFileOpen, StreamLoaderController}; +pub use fetch::{READ_AHEAD_BEFORE_PLAYBACK_SECONDS, READ_AHEAD_BEFORE_PLAYBACK_ROUNDTRIPS, READ_AHEAD_DURING_PLAYBACK_SECONDS, READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS}; #[cfg(not(any(feature = "with-tremor", feature = "with-vorbis")))] pub use lewton_decoder::{VorbisDecoder, VorbisError, VorbisPacket}; diff --git a/core/src/channel.rs b/core/src/channel.rs index 3238a0a6..62620e36 100644 --- a/core/src/channel.rs +++ b/core/src/channel.rs @@ -3,6 +3,7 @@ use bytes::Bytes; use futures::sync::{mpsc, BiLock}; use futures::{Async, Poll, Stream}; use std::collections::HashMap; +use std::time::{Instant}; use util::SeqGenerator; @@ -10,6 +11,10 @@ component! { ChannelManager : ChannelManagerInner { sequence: SeqGenerator = SeqGenerator::new(0), channels: HashMap> = HashMap::new(), + download_rate_estimate: usize = 0, + download_measurement_start: Option = None, + download_measurement_bytes: usize = 0, + download_measurement_last_received: Option = None, } } @@ -59,14 +64,46 @@ impl ChannelManager { let id: u16 = BigEndian::read_u16(data.split_to(2).as_ref()); + + trace!("Received data for channel {}: {} bytes.", id, data.len()); self.lock(|inner| { + + let current_time = Instant::now(); + if let Some(download_measurement_start) = inner.download_measurement_start { + if let Some(download_measurement_last_received) = inner.download_measurement_last_received { + if (current_time - download_measurement_start).as_millis() > 1000 { + if (current_time - download_measurement_last_received).as_millis() <= 500 { + inner.download_rate_estimate = 1000 * inner.download_measurement_bytes / (current_time - download_measurement_start).as_millis() as usize; + } else { + inner.download_rate_estimate = 1000 * inner.download_measurement_bytes / (500+(download_measurement_last_received - download_measurement_start).as_millis() as usize); + } + + inner.download_measurement_start = Some(current_time); + inner.download_measurement_bytes = 0; + } + } + } else { + inner.download_measurement_start = Some(current_time); + } + + inner.download_measurement_last_received = Some(current_time); + inner.download_measurement_bytes += data.len(); + if let Entry::Occupied(entry) = inner.channels.entry(id) { let _ = entry.get().unbounded_send((cmd, data)); } }); } + + pub fn get_download_rate_estimate(&self) -> usize { + return self.lock(|inner| { + inner.download_rate_estimate + }); + + } + } impl Channel { diff --git a/playback/src/player.rs b/playback/src/player.rs index 32500e30..bdccea38 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -9,12 +9,14 @@ use std::mem; use std::sync::mpsc::{RecvError, RecvTimeoutError, TryRecvError}; use std::thread; use std::time::Duration; +use std::cmp::max; use config::{Bitrate, PlayerConfig}; use librespot_core::session::Session; use librespot_core::spotify_id::SpotifyId; use audio::{AudioDecrypt, AudioFile, StreamLoaderController}; +use audio::{READ_AHEAD_BEFORE_PLAYBACK_SECONDS, READ_AHEAD_BEFORE_PLAYBACK_ROUNDTRIPS, READ_AHEAD_DURING_PLAYBACK_SECONDS, READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS}; use audio::{VorbisDecoder, VorbisPacket}; use audio_backend::Sink; use metadata::{AudioItem, FileFormat}; @@ -203,6 +205,7 @@ enum PlayerState { end_of_track: oneshot::Sender<()>, normalisation_factor: f32, stream_loader_controller: StreamLoaderController, + bytes_per_second: usize, }, Playing { track_id: SpotifyId, @@ -210,6 +213,7 @@ enum PlayerState { end_of_track: oneshot::Sender<()>, normalisation_factor: f32, stream_loader_controller: StreamLoaderController, + bytes_per_second: usize, }, EndOfTrack { track_id: SpotifyId, @@ -269,6 +273,7 @@ impl PlayerState { end_of_track, normalisation_factor, stream_loader_controller, + bytes_per_second } => { *self = Playing { track_id: track_id, @@ -276,6 +281,7 @@ impl PlayerState { end_of_track: end_of_track, normalisation_factor: normalisation_factor, stream_loader_controller: stream_loader_controller, + bytes_per_second: bytes_per_second, }; } _ => panic!("invalid state"), @@ -291,6 +297,7 @@ impl PlayerState { end_of_track, normalisation_factor, stream_loader_controller, + bytes_per_second, } => { *self = Paused { track_id: track_id, @@ -298,6 +305,7 @@ impl PlayerState { end_of_track: end_of_track, normalisation_factor: normalisation_factor, stream_loader_controller: stream_loader_controller, + bytes_per_second: bytes_per_second, }; } _ => panic!("invalid state"), @@ -418,7 +426,7 @@ impl PlayerInternal { } match self.load_track(track_id, position as i64) { - Some((decoder, normalisation_factor, stream_loader_controller)) => { + Some((decoder, normalisation_factor, stream_loader_controller, bytes_per_second)) => { if play { match self.state { PlayerState::Playing { @@ -443,6 +451,7 @@ impl PlayerInternal { end_of_track: end_of_track, normalisation_factor: normalisation_factor, stream_loader_controller: stream_loader_controller, + bytes_per_second: bytes_per_second, }; } else { self.state = PlayerState::Paused { @@ -451,6 +460,7 @@ impl PlayerInternal { end_of_track: end_of_track, normalisation_factor: normalisation_factor, stream_loader_controller: stream_loader_controller, + bytes_per_second: bytes_per_second, }; match self.state { PlayerState::Playing { @@ -493,10 +503,21 @@ impl PlayerInternal { if let Some(stream_loader_controller) = self.state.stream_loader_controller() { stream_loader_controller.set_stream_mode(); } - if let PlayerState::Playing{..} = self.state { + if let PlayerState::Playing{bytes_per_second, ..} = self.state { if let Some(stream_loader_controller) = self.state.stream_loader_controller() { - let stream_data_rate = stream_loader_controller.data_rate(); - let wait_for_data_length = (2 * stream_loader_controller.ping_time_ms() * stream_data_rate) / 1000; + + // Request our read ahead range + let request_data_length = max( + (READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS * (0.001 * stream_loader_controller.ping_time_ms() as f64) * bytes_per_second as f64) as usize, + (READ_AHEAD_DURING_PLAYBACK_SECONDS * bytes_per_second as f64) as usize + ); + stream_loader_controller.fetch_next(request_data_length); + + // Request the part we want to wait for blocking. This effecively means we wait for the previous request to partially complete. + let wait_for_data_length = max( + (READ_AHEAD_BEFORE_PLAYBACK_ROUNDTRIPS * (0.001 * stream_loader_controller.ping_time_ms() as f64) * bytes_per_second as f64) as usize, + (READ_AHEAD_BEFORE_PLAYBACK_SECONDS * bytes_per_second as f64) as usize + ); stream_loader_controller.fetch_next_blocking(wait_for_data_length); } } @@ -580,7 +601,7 @@ impl PlayerInternal { } } - fn load_track(&self, spotify_id: SpotifyId, position: i64) -> Option<(Decoder, f32, StreamLoaderController)> { + fn load_track(&self, spotify_id: SpotifyId, position: i64) -> Option<(Decoder, f32, StreamLoaderController, usize)> { let audio = AudioItem::get_audio_item(&self.session, spotify_id) .wait() .unwrap(); @@ -624,14 +645,17 @@ impl PlayerInternal { } }; + let bytes_per_second = self.stream_data_rate(*format); + let play_from_beginning = position==0; + let key = self.session.audio_key().request(spotify_id, file_id); - let encrypted_file = AudioFile::open(&self.session, file_id); + let encrypted_file = AudioFile::open(&self.session, file_id, bytes_per_second, play_from_beginning); let encrypted_file = encrypted_file.wait().unwrap(); - let mut stream_loader_controller = encrypted_file.get_stream_loader_controller(self.stream_data_rate(*format)); + let mut stream_loader_controller = encrypted_file.get_stream_loader_controller(); - if position == 0 { + if play_from_beginning { // No need to seek -> we stream from the beginning stream_loader_controller.set_stream_mode(); } else { @@ -663,7 +687,7 @@ impl PlayerInternal { stream_loader_controller.set_stream_mode(); } info!("<{}> loaded", audio.name); - Some((decoder, normalisation_factor, stream_loader_controller)) + Some((decoder, normalisation_factor, stream_loader_controller, bytes_per_second)) } } From c4e0f15eb32af3284aa9e9bfc94c23bb12ad7802 Mon Sep 17 00:00:00 2001 From: Konstantin Seiler Date: Fri, 8 Nov 2019 08:58:17 +1100 Subject: [PATCH 35/43] Tune prefetch, squish bugs. --- audio/src/fetch.rs | 9 +++++---- audio/src/range_set.rs | 2 ++ core/src/channel.rs | 17 ++++------------- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index 46d8a88a..a791841c 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -541,7 +541,7 @@ impl Future for AudioFileFetchDataReceiver { if 0.001 * (duration.as_millis() as f64) > MAXIMUM_ASSUMED_PING_TIME_SECONDS { duration_ms = (MAXIMUM_ASSUMED_PING_TIME_SECONDS * 1000.0) as u64; } else { - duration_ms = duration.as_secs() * 1000 + duration.subsec_millis() as u64; + duration_ms = duration.as_millis() as u64; } let _ = self.file_data_tx.unbounded_send(ReceivedData::ResponseTimeMs(duration_ms as usize)); self.measure_ping_time = false; @@ -896,15 +896,16 @@ impl Future for AudioFileFetch { download_status.requested.minus(&download_status.downloaded).len() }; - let ping_time_seconds = 0.0001 * self.shared.ping_time_ms.load(atomic::Ordering::Relaxed) as f64; + let ping_time_seconds = 0.001 * self.shared.ping_time_ms.load(atomic::Ordering::Relaxed) as f64; + let download_rate = self.session.channel().get_download_rate_estimate(); let desired_pending_bytes = max( (PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * self.shared.stream_data_rate as f64) as usize, - (FAST_PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * self.session.channel().get_download_rate_estimate() as f64) as usize + (FAST_PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * download_rate as f64) as usize ); if bytes_pending < desired_pending_bytes { - trace!("Prefetching more data. pending bytes({}) < {}",bytes_pending, desired_pending_bytes); + trace!("Prefetching more data. pending: {}, desired: {}, ping: {}, rate: {}", bytes_pending, desired_pending_bytes, ping_time_seconds, download_rate); self.pre_fetch_more_data(desired_pending_bytes - bytes_pending); } } diff --git a/audio/src/range_set.rs b/audio/src/range_set.rs index 12b82997..835477be 100644 --- a/audio/src/range_set.rs +++ b/audio/src/range_set.rs @@ -186,6 +186,7 @@ impl RangeSet { } if index < self.ranges.len() && self.ranges[index].start < range.end() { + self.ranges[index].length -= range.end() - self.ranges[index].start; self.ranges[index].start = range.end(); } @@ -199,6 +200,7 @@ impl RangeSet { length: range.start - self.ranges[index].start, }; + self.ranges[index].length -= range.end() - self.ranges[index].start; self.ranges[index].start = range.end(); self.ranges.insert(index, first_range); diff --git a/core/src/channel.rs b/core/src/channel.rs index 62620e36..9471c07a 100644 --- a/core/src/channel.rs +++ b/core/src/channel.rs @@ -14,7 +14,6 @@ component! { download_rate_estimate: usize = 0, download_measurement_start: Option = None, download_measurement_bytes: usize = 0, - download_measurement_last_received: Option = None, } } @@ -72,23 +71,15 @@ impl ChannelManager { let current_time = Instant::now(); if let Some(download_measurement_start) = inner.download_measurement_start { - if let Some(download_measurement_last_received) = inner.download_measurement_last_received { - if (current_time - download_measurement_start).as_millis() > 1000 { - if (current_time - download_measurement_last_received).as_millis() <= 500 { - inner.download_rate_estimate = 1000 * inner.download_measurement_bytes / (current_time - download_measurement_start).as_millis() as usize; - } else { - inner.download_rate_estimate = 1000 * inner.download_measurement_bytes / (500+(download_measurement_last_received - download_measurement_start).as_millis() as usize); - } - - inner.download_measurement_start = Some(current_time); - inner.download_measurement_bytes = 0; - } + if (current_time - download_measurement_start).as_millis() > 1000 { + inner.download_rate_estimate = 1000 * inner.download_measurement_bytes / (current_time - download_measurement_start).as_millis() as usize; + inner.download_measurement_start = Some(current_time); + inner.download_measurement_bytes = 0; } } else { inner.download_measurement_start = Some(current_time); } - inner.download_measurement_last_received = Some(current_time); inner.download_measurement_bytes += data.len(); if let Entry::Occupied(entry) = inner.channels.entry(id) { From a2b2150dbec640d742d3cc72ece7680084fd8150 Mon Sep 17 00:00:00 2001 From: Konstantin Seiler Date: Fri, 8 Nov 2019 10:17:56 +1100 Subject: [PATCH 36/43] Update minimum Rust version to 1.33.0. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6a28f10a..4ba0b544 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: rust rust: - - 1.32.0 + - 1.33.0 - stable - beta - nightly From 1719ffc906cd15b21b4a37c821337b3ddf359cc2 Mon Sep 17 00:00:00 2001 From: ashthespy Date: Fri, 8 Nov 2019 09:58:43 +0100 Subject: [PATCH 37/43] [Travis] Build examples --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index fc3294af..0c150760 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,6 +35,7 @@ before_script: script: - cargo build --locked --no-default-features + - cargo build --locked --examples - cargo build --locked --no-default-features --features "with-tremor" - cargo build --locked --no-default-features --features "with-vorbis" - cargo build --locked --no-default-features --features "alsa-backend" From af715f9e8c23311e2dd340270a5dd40b5fbffbb3 Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Sat, 9 Nov 2019 15:19:30 +0100 Subject: [PATCH 38/43] Add publish.sh script for creating new version, update PUBLISHING.md --- PUBLISHING.md | 21 ++++++++++++- publish.sh | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) create mode 100755 publish.sh diff --git a/PUBLISHING.md b/PUBLISHING.md index 952a0b8c..ceab506c 100644 --- a/PUBLISHING.md +++ b/PUBLISHING.md @@ -1,9 +1,28 @@ # Publishing +## How To + +The bash script in the root of the project, named `publish.sh` can be used to publish a new version of librespot and it's corresponding crates. the command should be used as follows: `./publish 0.1.0` from the project root, substituting the new version number that you wish to publish. *Note the lack of a v prefix on the version number. This is important, do not add one.* The v prefix is added where appropriate by the script. + +## What the script does + +This is briefly how the script works: + + - Change to branch master, pull latest version, merge development branch. + - CD to working dir. + - Change version number in all files. + - Commit and tag changes. + - Publish crates in given order. + - Push version commit and tags to master. + +## Notes + Publishing librespot to crates.io is a slightly convoluted affair due to the various dependencies that each package has on other local packages. The order of publising that has been found to work is as follows: `protocol -> core -> audio -> metadata -> playback -> connect -> librespot` The `protocol` package needs to be published with `cargo publish --no-verify` due to the build script modifying the source during compile time. -Publishing can be done using the command `cargo publish` in each of the directories of the respecive crate. \ No newline at end of file +Publishing can be done using the command `cargo publish` in each of the directories of the respective crate. + +The script is meant to cover the standard publishing process. There are various improvements that could be made, such as adding options such as the user being able to add a change log, though this is not the main focus, as the script is intended to be run by a CI. Feel free to improve and extend functionality, keeping in mind that it should always be possible for the script to be run in a non-interactive fashion. diff --git a/publish.sh b/publish.sh new file mode 100755 index 00000000..6672dba0 --- /dev/null +++ b/publish.sh @@ -0,0 +1,82 @@ +#!/bin/bash + +WORKINGDIR="$( cd "$(dirname "$0")" ; pwd -P )" +cd $WORKINGDIR + +crates=( "protocol" "core" "audio" "metadata" "playback" "connect" "librespot" ) + +function switchBranch { + # You are expected to have committed/stashed your changes before running this. + echo "Switching to master branch and merging development." + git checkout master + git pull + git merge dev +} + +function updateVersion { + for CRATE in "${crates[@]}" + do + if [ "$CRATE" = "librespot" ] + then + CRATE='' + fi + crate_path="$WORKINGDIR/$CRATE/Cargo.toml" + crate_path=${crate_path//\/\///} + sed -i '' "s/^version.*/version = \"$1\"/g" "$crate_path" + echo "Path is $crate_path" + done +} + +function commitAndTag { + git commit -a -m "Update version numbers to $1" + git tag "v$1" -a -m "Update to version $1" +} + +function get_crate_name { + awk -v FS="name = " 'NF>1{print $2; exit}' Cargo.toml +} + +function publishCrates { + for CRATE in "${crates[@]}" + do + if [ "$CRATE" = "librespot" ] + then + CRATE='' + fi + + crate_path="$WORKINGDIR/$CRATE" + crate_path=${crate_path//\/\///} + cd $crate_path + + crate_name=`echo $( awk -v FS="name = " 'NF>1{print $2; exit}' Cargo.toml )` + echo "Publishing $crate_name to crates.io" + if [ "$CRATE" == "protocol" ] + then + # Protocol crate needs --no-verify option due to build.rs modification. + cargo publish --no-verify + else + cargo publish + fi + echo "Successfully published $crate_name to crates.io" + done +} + +function updateRepo { + cd $WORKINGDIR + echo "Pushing to master branch of repo." + git push origin master + echo "Pushing v$1 tag to master branch of repo." + git push origin v$1 +} + +function run { + # switchBranch + updateVersion $1 + commitAndTag $1 + publishCrates + updateRepo $1 + echo "Successfully published v$1 to crates.io and uploaded changes to repo." +} + +# First argument is new version number. +run $1 From 8eae57bad0043ba10d62c419bb74045ea9228161 Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Sat, 9 Nov 2019 15:21:12 +0100 Subject: [PATCH 39/43] Uncommented branch switch. --- publish.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/publish.sh b/publish.sh index 6672dba0..a7d1076a 100755 --- a/publish.sh +++ b/publish.sh @@ -70,7 +70,7 @@ function updateRepo { } function run { - # switchBranch + switchBranch updateVersion $1 commitAndTag $1 publishCrates From 3cefc57eb592f98940da05370ad148b5f557b7ae Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Sat, 9 Nov 2019 15:36:55 +0100 Subject: [PATCH 40/43] Correct bad bitrate flag in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 62dc52e8..204bcc94 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ _Note: librespot only works with Spotify Premium. This will remain the case for ## Quick start We're available on [crates.io](https://crates.io/crates/librespot) as the _librespot_ package. Simply run `cargo install librespot` to install librespot on your system. Check the wiki for more info and possible [usage options](https://github.com/librespot-org/librespot/wiki/Options). -After installation, you can run librespot form the CLI using a command such as `librespot -n "Librespot Speaker" -b 192` to create a speaker called _Librespot Speaker_ serving 192kbps audio. +After installation, you can run librespot form the CLI using a command such as `librespot -n "Librespot Speaker" -b 160` to create a speaker called _Librespot Speaker_ serving 160kbps audio. ## This fork As the origin by [plietar](https://github.com/plietar/) is no longer actively maintained, this organisation and repository have been set up so that the project may be maintained and upgraded in the future. From d2d6df0e2441e4d84de3037977d36ebea59f458a Mon Sep 17 00:00:00 2001 From: Konstantin Seiler Date: Mon, 11 Nov 2019 18:22:41 +1100 Subject: [PATCH 41/43] Run cargo fmt for my code. --- audio/src/fetch.rs | 278 ++++++++++++++++++++++++----------------- audio/src/lib.rs | 7 +- audio/src/range_set.rs | 45 ++----- core/src/channel.rs | 12 +- playback/src/player.rs | 64 +++++++--- 5 files changed, 228 insertions(+), 178 deletions(-) diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index a791841c..80df21a7 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -3,28 +3,27 @@ use bytes::Bytes; use futures::sync::{mpsc, oneshot}; use futures::Stream; use futures::{Async, Future, Poll}; -use std::cmp::{min, max}; +use range_set::{Range, RangeSet}; +use std::cmp::{max, min}; use std::fs; use std::io::{self, Read, Seek, SeekFrom, Write}; use std::sync::{Arc, Condvar, Mutex}; use std::time::{Duration, Instant}; use tempfile::NamedTempFile; -use range_set::{Range, RangeSet}; +use futures::sync::mpsc::unbounded; use librespot_core::channel::{Channel, ChannelData, ChannelError, ChannelHeaders}; use librespot_core::session::Session; use librespot_core::spotify_id::FileId; -use futures::sync::mpsc::unbounded; use std::sync::atomic; use std::sync::atomic::AtomicUsize; - const MINIMUM_DOWNLOAD_SIZE: usize = 1024 * 16; // The minimum size of a block that is requested from the Spotify servers in one request. // This is the block size that is typically requested while doing a seek() on a file. // Note: smaller requests can happen if part of the block is downloaded already. -const INITIAL_DOWNLOAD_SIZE: usize = 1024 * 16; // MUST be divisible by four!!! +const INITIAL_DOWNLOAD_SIZE: usize = 1024 * 16; // The amount of data that is requested when initially opening a file. // Note: if the file is opened to play from the beginning, the amount of data to // read ahead is requested in addition to this amount. If the file is opened to seek to @@ -78,8 +77,6 @@ const FAST_PREFETCH_THRESHOLD_FACTOR: f64 = 1.5; // performed while downloading. Values smaller than 1 cause the download rate to collapse and effectively // only PREFETCH_THRESHOLD_FACTOR is in effect. Thus, set to zero if bandwidth saturation is not wanted. - - pub enum AudioFile { Cached(fs::File), Streaming(AudioFileStreaming), @@ -101,15 +98,13 @@ pub struct AudioFileOpenStreaming { streaming_data_rate: usize, } - -enum StreamLoaderCommand{ - Fetch(Range), // signal the stream loader to fetch a range of the file +enum StreamLoaderCommand { + Fetch(Range), // signal the stream loader to fetch a range of the file RandomAccessMode(), // optimise download strategy for random access - StreamMode(), // optimise download strategy for streaming - Close(), // terminate and don't load any more data + StreamMode(), // optimise download strategy for streaming + Close(), // terminate and don't load any more data } - #[derive(Clone)] pub struct StreamLoaderController { channel_tx: Option>, @@ -117,7 +112,6 @@ pub struct StreamLoaderController { file_size: usize, } - impl StreamLoaderController { pub fn len(&self) -> usize { return self.file_size; @@ -126,7 +120,11 @@ impl StreamLoaderController { pub fn range_available(&self, range: Range) -> bool { if let Some(ref shared) = self.stream_shared { let download_status = shared.download_status.lock().unwrap(); - if range.length <= download_status.downloaded.contained_length_from_value(range.start) { + if range.length + <= download_status + .downloaded + .contained_length_from_value(range.start) + { return true; } else { return false; @@ -174,9 +172,22 @@ impl StreamLoaderController { if let Some(ref shared) = self.stream_shared { let mut download_status = shared.download_status.lock().unwrap(); - while range.length > download_status.downloaded.contained_length_from_value(range.start) { - download_status = shared.cond.wait_timeout(download_status, Duration::from_millis(1000)).unwrap().0; - if range.length > (download_status.downloaded.union(&download_status.requested).contained_length_from_value(range.start)) { + while range.length + > download_status + .downloaded + .contained_length_from_value(range.start) + { + download_status = shared + .cond + .wait_timeout(download_status, Duration::from_millis(1000)) + .unwrap() + .0; + if range.length + > (download_status + .downloaded + .union(&download_status.requested) + .contained_length_from_value(range.start)) + { // For some reason, the requested range is neither downloaded nor requested. // This could be due to a network error. Request it again. // We can't use self.fetch here because self can't be borrowed mutably, so we access the channel directly. @@ -187,11 +198,10 @@ impl StreamLoaderController { } } } - } pub fn fetch_next(&mut self, length: usize) { - let range:Range = if let Some(ref shared) = self.stream_shared { + let range: Range = if let Some(ref shared) = self.stream_shared { Range { start: shared.read_position.load(atomic::Ordering::Relaxed), length: length, @@ -203,7 +213,7 @@ impl StreamLoaderController { } pub fn fetch_next_blocking(&mut self, length: usize) { - let range:Range = if let Some(ref shared) = self.stream_shared { + let range: Range = if let Some(ref shared) = self.stream_shared { Range { start: shared.read_position.load(atomic::Ordering::Relaxed), length: length, @@ -228,11 +238,8 @@ impl StreamLoaderController { // terminate stream loading and don't load any more data for this file. self.send_stream_loader_command(StreamLoaderCommand::Close()); } - - } - pub struct AudioFileStreaming { read_file: fs::File, @@ -243,7 +250,6 @@ pub struct AudioFileStreaming { shared: Arc, } - struct AudioFileDownloadStatus { requested: RangeSet, downloaded: RangeSet, @@ -269,13 +275,15 @@ struct AudioFileShared { impl AudioFileOpenStreaming { fn finish(&mut self, size: usize) -> AudioFileStreaming { - let shared = Arc::new(AudioFileShared { file_id: self.file_id, file_size: size, stream_data_rate: self.streaming_data_rate, cond: Condvar::new(), - download_status: Mutex::new(AudioFileDownloadStatus {requested: RangeSet::new(), downloaded: RangeSet::new()}), + download_status: Mutex::new(AudioFileDownloadStatus { + requested: RangeSet::new(), + downloaded: RangeSet::new(), + }), download_strategy: Mutex::new(DownloadStrategy::RandomAccess()), // start with random access mode until someone tells us otherwise number_of_open_requests: AtomicUsize::new(0), ping_time_ms: AtomicUsize::new(0), @@ -292,7 +300,8 @@ impl AudioFileOpenStreaming { let initial_data_length = self.initial_data_length.take().unwrap(); let complete_tx = self.complete_tx.take().unwrap(); //let (seek_tx, seek_rx) = mpsc::unbounded(); - let (stream_loader_command_tx, stream_loader_command_rx) = mpsc::unbounded::(); + let (stream_loader_command_tx, stream_loader_command_rx) = + mpsc::unbounded::(); let fetcher = AudioFileFetch::new( self.session.clone(), @@ -355,7 +364,12 @@ impl Future for AudioFileOpenStreaming { } impl AudioFile { - pub fn open(session: &Session, file_id: FileId, bytes_per_second: usize, play_from_beginning: bool) -> AudioFileOpen { + pub fn open( + session: &Session, + file_id: FileId, + bytes_per_second: usize, + play_from_beginning: bool, + ) -> AudioFileOpen { let cache = session.cache().cloned(); if let Some(file) = cache.as_ref().and_then(|cache| cache.file(file_id)) { @@ -367,10 +381,16 @@ impl AudioFile { let (complete_tx, complete_rx) = oneshot::channel(); let mut initial_data_length = if play_from_beginning { - INITIAL_DOWNLOAD_SIZE + max((READ_AHEAD_DURING_PLAYBACK_SECONDS * bytes_per_second as f64) as usize, (INITIAL_PING_TIME_ESTIMATE_SECONDS * READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS * bytes_per_second as f64) as usize) - } else { - INITIAL_DOWNLOAD_SIZE - }; + INITIAL_DOWNLOAD_SIZE + + max( + (READ_AHEAD_DURING_PLAYBACK_SECONDS * bytes_per_second as f64) as usize, + (INITIAL_PING_TIME_ESTIMATE_SECONDS + * READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS + * bytes_per_second as f64) as usize, + ) + } else { + INITIAL_DOWNLOAD_SIZE + }; if initial_data_length % 4 != 0 { initial_data_length += 4 - (initial_data_length % 4); } @@ -387,7 +407,6 @@ impl AudioFile { complete_tx: Some(complete_tx), streaming_data_rate: bytes_per_second, - }; let session_ = session.clone(); @@ -427,17 +446,26 @@ impl AudioFile { } } - fn request_range(session: &Session, file: FileId, offset: usize, length: usize) -> Channel { - - assert!(offset % 4 == 0, "Range request start positions must be aligned by 4 bytes."); - assert!(length % 4 == 0, "Range request range lengths must be aligned by 4 bytes."); + assert!( + offset % 4 == 0, + "Range request start positions must be aligned by 4 bytes." + ); + assert!( + length % 4 == 0, + "Range request range lengths must be aligned by 4 bytes." + ); let start = offset / 4; - let end = (offset+length) / 4; + let end = (offset + length) / 4; let (id, channel) = session.channel().allocate(); - trace!("requesting range starting at {} of length {} on channel {}.", offset, length, id); + trace!( + "requesting range starting at {} of length {} on channel {}.", + offset, + length, + id + ); let mut data: Vec = Vec::new(); data.write_u16::(id).unwrap(); @@ -456,8 +484,6 @@ fn request_range(session: &Session, file: FileId, offset: usize, length: usize) channel } - - struct PartialFileData { offset: usize, data: Bytes, @@ -489,10 +515,11 @@ impl AudioFileFetchDataReceiver { request_length: usize, request_sent_time: Instant, ) -> AudioFileFetchDataReceiver { - let measure_ping_time = shared.number_of_open_requests.load(atomic::Ordering::SeqCst) == 0; - shared.number_of_open_requests.fetch_add(1, atomic::Ordering::SeqCst); + shared + .number_of_open_requests + .fetch_add(1, atomic::Ordering::SeqCst); AudioFileFetchDataReceiver { shared: shared, @@ -508,12 +535,9 @@ impl AudioFileFetchDataReceiver { } } - - impl AudioFileFetchDataReceiver { fn finish(&mut self) { if self.request_length > 0 { - let missing_range = Range::new(self.data_offset, self.request_length); let mut download_status = self.shared.download_status.lock().unwrap(); @@ -521,8 +545,9 @@ impl AudioFileFetchDataReceiver { self.shared.cond.notify_all(); } - self.shared.number_of_open_requests.fetch_sub(1, atomic::Ordering::SeqCst); - + self.shared + .number_of_open_requests + .fetch_sub(1, atomic::Ordering::SeqCst); } } @@ -538,18 +563,26 @@ impl Future for AudioFileFetchDataReceiver { if let Some(request_sent_time) = self.request_sent_time { let duration = Instant::now() - request_sent_time; let duration_ms: u64; - if 0.001 * (duration.as_millis() as f64) > MAXIMUM_ASSUMED_PING_TIME_SECONDS { + if 0.001 * (duration.as_millis() as f64) > MAXIMUM_ASSUMED_PING_TIME_SECONDS + { duration_ms = (MAXIMUM_ASSUMED_PING_TIME_SECONDS * 1000.0) as u64; } else { duration_ms = duration.as_millis() as u64; } - let _ = self.file_data_tx.unbounded_send(ReceivedData::ResponseTimeMs(duration_ms as usize)); + let _ = self + .file_data_tx + .unbounded_send(ReceivedData::ResponseTimeMs(duration_ms as usize)); self.measure_ping_time = false; } } let data_size = data.len(); trace!("data_receiver for range {} (+{}) got {} bytes of data starting at {}. ({} bytes pending).", self.initial_data_offset, self.initial_request_length, data_size, self.data_offset, self.request_length - data_size); - let _ = self.file_data_tx.unbounded_send(ReceivedData::Data(PartialFileData { offset: self.data_offset, data: data, })); + let _ = self + .file_data_tx + .unbounded_send(ReceivedData::Data(PartialFileData { + offset: self.data_offset, + data: data, + })); self.data_offset += data_size; if self.request_length < data_size { warn!("Data receiver for range {} (+{}) received more data from server than requested.", self.initial_data_offset, self.initial_request_length); @@ -558,7 +591,11 @@ impl Future for AudioFileFetchDataReceiver { self.request_length -= data_size; } if self.request_length == 0 { - trace!("Data receiver for range {} (+{}) completed.", self.initial_data_offset, self.initial_request_length); + trace!( + "Data receiver for range {} (+{}) completed.", + self.initial_data_offset, + self.initial_request_length + ); self.finish(); return Ok(Async::Ready(())); } @@ -574,7 +611,10 @@ impl Future for AudioFileFetchDataReceiver { return Ok(Async::NotReady); } Err(ChannelError) => { - warn!("Error from channel for data receiver for range {} (+{}).", self.initial_data_offset, self.initial_request_length); + warn!( + "Error from channel for data receiver for range {} (+{}).", + self.initial_data_offset, self.initial_request_length + ); self.finish(); return Ok(Async::Ready(())); } @@ -583,7 +623,6 @@ impl Future for AudioFileFetchDataReceiver { } } - struct AudioFileFetch { session: Session, shared: Arc, @@ -609,7 +648,6 @@ impl AudioFileFetch { stream_loader_command_rx: mpsc::UnboundedReceiver, complete_tx: oneshot::Sender, ) -> AudioFileFetch { - let (file_data_tx, file_data_rx) = unbounded::(); { @@ -618,7 +656,6 @@ impl AudioFileFetch { download_status.requested.add_range(&requested_range); } - let initial_data_receiver = AudioFileFetchDataReceiver::new( shared.clone(), file_data_tx.clone(), @@ -649,7 +686,6 @@ impl AudioFileFetch { } fn download_range(&mut self, mut offset: usize, mut length: usize) { - if length < MINIMUM_DOWNLOAD_SIZE { length = MINIMUM_DOWNLOAD_SIZE; } @@ -684,13 +720,12 @@ impl AudioFileFetch { ranges_to_request.subtract_range_set(&download_status.downloaded); ranges_to_request.subtract_range_set(&download_status.requested); - for range in ranges_to_request.iter() { - let (_headers, data) = request_range(&self.session, self.shared.file_id, range.start, range.length).split(); + let (_headers, data) = + request_range(&self.session, self.shared.file_id, range.start, range.length).split(); download_status.requested.add_range(range); - let receiver = AudioFileFetchDataReceiver::new( self.shared.clone(), self.file_data_tx.clone(), @@ -702,15 +737,12 @@ impl AudioFileFetch { self.session.spawn(move |_| receiver); } - } fn pre_fetch_more_data(&mut self, bytes: usize) { - let mut bytes_to_go = bytes; while bytes_to_go > 0 { - // determine what is still missing let mut missing_data = RangeSet::new(); missing_data.add_range(&Range::new(0, self.shared.file_size)); @@ -743,12 +775,9 @@ impl AudioFileFetch { return; } } - } - fn poll_file_data_rx(&mut self) -> Poll<(), ()> { - loop { match self.file_data_rx.poll() { Ok(Async::Ready(None)) => { @@ -768,7 +797,10 @@ impl AudioFileFetch { // stats::median is experimental. So we calculate the median of up to three ourselves. let ping_time_ms: usize = match self.network_response_times_ms.len() { 1 => self.network_response_times_ms[0] as usize, - 2 => ((self.network_response_times_ms[0] + self.network_response_times_ms[1]) / 2) as usize, + 2 => { + ((self.network_response_times_ms[0] + self.network_response_times_ms[1]) / 2) + as usize + } 3 => { let mut times = self.network_response_times_ms.clone(); times.sort(); @@ -778,20 +810,21 @@ impl AudioFileFetch { }; // store our new estimate for everyone to see - self.shared.ping_time_ms.store(ping_time_ms, atomic::Ordering::Relaxed); - - }, + self.shared + .ping_time_ms + .store(ping_time_ms, atomic::Ordering::Relaxed); + } Ok(Async::Ready(Some(ReceivedData::Data(data)))) => { - - self.output .as_mut() .unwrap() .seek(SeekFrom::Start(data.offset as u64)) .unwrap(); - self.output.as_mut().unwrap().write_all(data.data.as_ref()).unwrap(); - - + self.output + .as_mut() + .unwrap() + .write_all(data.data.as_ref()) + .unwrap(); let mut full = false; @@ -802,11 +835,17 @@ impl AudioFileFetch { download_status.downloaded.add_range(&received_range); self.shared.cond.notify_all(); - if download_status.downloaded.contained_length_from_value(0) >= self.shared.file_size { + if download_status.downloaded.contained_length_from_value(0) + >= self.shared.file_size + { full = true; } - trace!("Downloaded: {} Requested: {}", download_status.downloaded, download_status.requested.minus(&download_status.downloaded)); + trace!( + "Downloaded: {} Requested: {}", + download_status.downloaded, + download_status.requested.minus(&download_status.downloaded) + ); drop(download_status); } @@ -815,22 +854,16 @@ impl AudioFileFetch { self.finish(); return Ok(Async::Ready(())); } - - } Ok(Async::NotReady) => { return Ok(Async::NotReady); - }, + } Err(()) => unreachable!(), } - } - } - fn poll_stream_loader_command_rx(&mut self) -> Poll<(), ()> { - loop { match self.stream_loader_command_rx.poll() { Ok(Async::Ready(None)) => { @@ -848,13 +881,10 @@ impl AudioFileFetch { Ok(Async::Ready(Some(StreamLoaderCommand::Close()))) => { return Ok(Async::Ready(())); } - Ok(Async::NotReady) => { - return Ok(Async::NotReady) - }, + Ok(Async::NotReady) => return Ok(Async::NotReady), Err(()) => unreachable!(), } } - } fn finish(&mut self) { @@ -865,7 +895,6 @@ impl AudioFileFetch { output.seek(SeekFrom::Start(0)).unwrap(); let _ = complete_tx.send(output); } - } impl Future for AudioFileFetch { @@ -873,7 +902,6 @@ impl Future for AudioFileFetch { type Error = (); fn poll(&mut self) -> Poll<(), ()> { - match self.poll_stream_loader_command_rx() { Ok(Async::NotReady) => (), Ok(Async::Ready(_)) => { @@ -896,22 +924,29 @@ impl Future for AudioFileFetch { download_status.requested.minus(&download_status.downloaded).len() }; - let ping_time_seconds = 0.001 * self.shared.ping_time_ms.load(atomic::Ordering::Relaxed) as f64; + let ping_time_seconds = + 0.001 * self.shared.ping_time_ms.load(atomic::Ordering::Relaxed) as f64; let download_rate = self.session.channel().get_download_rate_estimate(); let desired_pending_bytes = max( - (PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * self.shared.stream_data_rate as f64) as usize, - (FAST_PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * download_rate as f64) as usize + (PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * self.shared.stream_data_rate as f64) + as usize, + (FAST_PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * download_rate as f64) as usize, ); if bytes_pending < desired_pending_bytes { - trace!("Prefetching more data. pending: {}, desired: {}, ping: {}, rate: {}", bytes_pending, desired_pending_bytes, ping_time_seconds, download_rate); + trace!( + "Prefetching more data. pending: {}, desired: {}, ping: {}, rate: {}", + bytes_pending, + desired_pending_bytes, + ping_time_seconds, + download_rate + ); self.pre_fetch_more_data(desired_pending_bytes - bytes_pending); } } - - return Ok(Async::NotReady) + return Ok(Async::NotReady); } } @@ -925,23 +960,25 @@ impl Read for AudioFileStreaming { let length = min(output.len(), self.shared.file_size - offset); - let length_to_request = match *(self.shared.download_strategy.lock().unwrap()) { - DownloadStrategy::RandomAccess() => { length } + DownloadStrategy::RandomAccess() => length, DownloadStrategy::Streaming() => { // Due to the read-ahead stuff, we potentially request more than the actual reqeust demanded. - let ping_time_seconds = 0.0001 * self.shared.ping_time_ms.load(atomic::Ordering::Relaxed) as f64; + let ping_time_seconds = + 0.0001 * self.shared.ping_time_ms.load(atomic::Ordering::Relaxed) as f64; - let length_to_request = length + max( - (READ_AHEAD_DURING_PLAYBACK_SECONDS * self.shared.stream_data_rate as f64) as usize, - (READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS * ping_time_seconds * self.shared.stream_data_rate as f64) as usize - ); + let length_to_request = length + + max( + (READ_AHEAD_DURING_PLAYBACK_SECONDS * self.shared.stream_data_rate as f64) + as usize, + (READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS + * ping_time_seconds + * self.shared.stream_data_rate as f64) as usize, + ); min(length_to_request, self.shared.file_size - offset) } }; - - let mut ranges_to_request = RangeSet::new(); ranges_to_request.add_range(&Range::new(offset, length_to_request)); @@ -951,27 +988,35 @@ impl Read for AudioFileStreaming { ranges_to_request.subtract_range_set(&download_status.downloaded); ranges_to_request.subtract_range_set(&download_status.requested); - for range in ranges_to_request.iter() { - trace!("requesting data at position {} (length : {})", range.start, range.length); - self.stream_loader_command_tx.unbounded_send(StreamLoaderCommand::Fetch(range.clone())).unwrap(); + trace!( + "requesting data at position {} (length : {})", + range.start, + range.length + ); + self.stream_loader_command_tx + .unbounded_send(StreamLoaderCommand::Fetch(range.clone())) + .unwrap(); } - if length == 0 { return Ok(0); } while !download_status.downloaded.contains(offset) { trace!("waiting for download"); - download_status = self.shared.cond.wait_timeout(download_status, Duration::from_millis(1000)).unwrap().0; + download_status = self + .shared + .cond + .wait_timeout(download_status, Duration::from_millis(1000)) + .unwrap() + .0; trace!("re-checking data availability at offset {}.", offset); } let available_length = download_status.downloaded.contained_length_from_value(offset); assert!(available_length > 0); drop(download_status); - self.position = self.read_file.seek(SeekFrom::Start(offset as u64)).unwrap(); let read_len = min(length, available_length); let read_len = try!(self.read_file.read(&mut output[..read_len])); @@ -979,8 +1024,9 @@ impl Read for AudioFileStreaming { trace!("read successfully at postion {} (length : {})", offset, read_len); self.position += read_len as u64; - self.shared.read_position.store(self.position as usize, atomic::Ordering::Relaxed); - + self.shared + .read_position + .store(self.position as usize, atomic::Ordering::Relaxed); return Ok(read_len); } @@ -990,7 +1036,9 @@ impl Seek for AudioFileStreaming { fn seek(&mut self, pos: SeekFrom) -> io::Result { self.position = try!(self.read_file.seek(pos)); // Do not seek past EOF - self.shared.read_position.store(self.position as usize, atomic::Ordering::Relaxed); + self.shared + .read_position + .store(self.position as usize, atomic::Ordering::Relaxed); Ok(self.position) } } diff --git a/audio/src/lib.rs b/audio/src/lib.rs index 845ba5f9..9a82f90e 100644 --- a/audio/src/lib.rs +++ b/audio/src/lib.rs @@ -3,13 +3,13 @@ extern crate futures; #[macro_use] extern crate log; +extern crate aes_ctr; extern crate bit_set; extern crate byteorder; extern crate bytes; extern crate num_bigint; extern crate num_traits; extern crate tempfile; -extern crate aes_ctr; extern crate librespot_core; @@ -25,7 +25,10 @@ mod range_set; pub use decrypt::AudioDecrypt; pub use fetch::{AudioFile, AudioFileOpen, StreamLoaderController}; -pub use fetch::{READ_AHEAD_BEFORE_PLAYBACK_SECONDS, READ_AHEAD_BEFORE_PLAYBACK_ROUNDTRIPS, READ_AHEAD_DURING_PLAYBACK_SECONDS, READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS}; +pub use fetch::{ + READ_AHEAD_BEFORE_PLAYBACK_ROUNDTRIPS, READ_AHEAD_BEFORE_PLAYBACK_SECONDS, + READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS, READ_AHEAD_DURING_PLAYBACK_SECONDS, +}; #[cfg(not(any(feature = "with-tremor", feature = "with-vorbis")))] pub use lewton_decoder::{VorbisDecoder, VorbisError, VorbisPacket}; diff --git a/audio/src/range_set.rs b/audio/src/range_set.rs index 835477be..448c0971 100644 --- a/audio/src/range_set.rs +++ b/audio/src/range_set.rs @@ -1,9 +1,6 @@ - -use std::cmp::{max,min}; -use std::slice::Iter; +use std::cmp::{max, min}; use std::fmt; - - +use std::slice::Iter; #[derive(Copy, Clone)] pub struct Range { @@ -13,27 +10,23 @@ pub struct Range { impl fmt::Display for Range { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - return write!(f, "[{}, {}]", self.start, self.start+self.length-1); + return write!(f, "[{}, {}]", self.start, self.start + self.length - 1); } } - impl Range { - pub fn new(start: usize, length: usize) -> Range { return Range { start: start, length: length, - } + }; } pub fn end(&self) -> usize { return self.start + self.length; } - } - #[derive(Clone)] pub struct RangeSet { ranges: Vec, @@ -49,11 +42,9 @@ impl fmt::Display for RangeSet { } } - - impl RangeSet { pub fn new() -> RangeSet { - RangeSet{ + RangeSet { ranges: Vec::::new(), } } @@ -98,7 +89,6 @@ impl RangeSet { } } return 0; - } #[allow(dead_code)] @@ -111,23 +101,20 @@ impl RangeSet { return true; } - - pub fn add_range(&mut self, range:&Range) { - + pub fn add_range(&mut self, range: &Range) { if range.length <= 0 { // the interval is empty or invalid -> nothing to do. return; } - for index in 0..self.ranges.len() { // the new range is clear of any ranges we already iterated over. - if range.end() < self.ranges[index].start{ + if range.end() < self.ranges[index].start { // the new range starts after anything we already passed and ends before the next range starts (they don't touch) -> insert it. self.ranges.insert(index, range.clone()); return; - - } else if range.start <= self.ranges[index].end() && self.ranges[index].start <= range.end() { + } else if range.start <= self.ranges[index].end() && self.ranges[index].start <= range.end() + { // the new range overlaps (or touches) the first range. They are to be merged. // In addition we might have to merge further ranges in as well. @@ -142,7 +129,6 @@ impl RangeSet { self.ranges.insert(index, new_range); return; - } } @@ -165,7 +151,6 @@ impl RangeSet { } pub fn subtract_range(&mut self, range: &Range) { - if range.length <= 0 { return; } @@ -175,8 +160,7 @@ impl RangeSet { if range.end() <= self.ranges[index].start { // the remaining ranges are past the one to subtract. -> we're done. - return - + return; } else if range.start <= self.ranges[index].start && self.ranges[index].start < range.end() { // the range to subtract started before the current range and reaches into the current range // -> we have to remove the beginning of the range or the entire range and do the same for following ranges. @@ -191,7 +175,6 @@ impl RangeSet { } return; - } else if range.end() < self.ranges[index].end() { // the range to subtract punches a hole into the current range -> we need to create two smaller ranges. @@ -206,11 +189,9 @@ impl RangeSet { self.ranges.insert(index, first_range); return; - } else if range.start < self.ranges[index].end() { // the range truncates the existing range -> truncate the range. Let the for loop take care of overlaps with other ranges. self.ranges[index].length = range.start - self.ranges[index].start; - } } } @@ -245,19 +226,15 @@ impl RangeSet { let new_start = max(self.ranges[self_index].start, other.ranges[other_index].start); let new_end = min(self.ranges[self_index].end(), other.ranges[other_index].end()); assert!(new_start <= new_end); - result.add_range(&Range::new(new_start, new_end-new_start)); + result.add_range(&Range::new(new_start, new_end - new_start)); if self.ranges[self_index].end() <= other.ranges[other_index].end() { self_index += 1; } else { other_index += 1; } - } - } return result; } - } - diff --git a/core/src/channel.rs b/core/src/channel.rs index 276f2bfc..a4785eb8 100644 --- a/core/src/channel.rs +++ b/core/src/channel.rs @@ -3,7 +3,7 @@ use bytes::Bytes; use futures::sync::{mpsc, BiLock}; use futures::{Async, Poll, Stream}; use std::collections::HashMap; -use std::time::{Instant}; +use std::time::Instant; use util::SeqGenerator; @@ -64,11 +64,11 @@ impl ChannelManager { let id: u16 = BigEndian::read_u16(data.split_to(2).as_ref()); self.lock(|inner| { - let current_time = Instant::now(); if let Some(download_measurement_start) = inner.download_measurement_start { if (current_time - download_measurement_start).as_millis() > 1000 { - inner.download_rate_estimate = 1000 * inner.download_measurement_bytes / (current_time - download_measurement_start).as_millis() as usize; + inner.download_rate_estimate = 1000 * inner.download_measurement_bytes + / (current_time - download_measurement_start).as_millis() as usize; inner.download_measurement_start = Some(current_time); inner.download_measurement_bytes = 0; } @@ -85,12 +85,8 @@ impl ChannelManager { } pub fn get_download_rate_estimate(&self) -> usize { - return self.lock(|inner| { - inner.download_rate_estimate - }); - + return self.lock(|inner| inner.download_rate_estimate); } - } impl Channel { diff --git a/playback/src/player.rs b/playback/src/player.rs index bdccea38..a54a577f 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -4,20 +4,23 @@ use futures::sync::oneshot; use futures::{future, Future}; use std; use std::borrow::Cow; +use std::cmp::max; use std::io::{Read, Result, Seek, SeekFrom}; use std::mem; use std::sync::mpsc::{RecvError, RecvTimeoutError, TryRecvError}; use std::thread; use std::time::Duration; -use std::cmp::max; use config::{Bitrate, PlayerConfig}; use librespot_core::session::Session; use librespot_core::spotify_id::SpotifyId; use audio::{AudioDecrypt, AudioFile, StreamLoaderController}; -use audio::{READ_AHEAD_BEFORE_PLAYBACK_SECONDS, READ_AHEAD_BEFORE_PLAYBACK_ROUNDTRIPS, READ_AHEAD_DURING_PLAYBACK_SECONDS, READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS}; use audio::{VorbisDecoder, VorbisPacket}; +use audio::{ + READ_AHEAD_BEFORE_PLAYBACK_ROUNDTRIPS, READ_AHEAD_BEFORE_PLAYBACK_SECONDS, + READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS, READ_AHEAD_DURING_PLAYBACK_SECONDS, +}; use audio_backend::Sink; use metadata::{AudioItem, FileFormat}; use mixer::AudioFilter; @@ -244,7 +247,14 @@ impl PlayerState { use self::PlayerState::*; match *self { Stopped | EndOfTrack { .. } => None, - Paused { ref mut stream_loader_controller, .. } | Playing { ref mut stream_loader_controller, .. } => Some(stream_loader_controller), + Paused { + ref mut stream_loader_controller, + .. + } + | Playing { + ref mut stream_loader_controller, + .. + } => Some(stream_loader_controller), Invalid => panic!("invalid state"), } } @@ -273,7 +283,7 @@ impl PlayerState { end_of_track, normalisation_factor, stream_loader_controller, - bytes_per_second + bytes_per_second, } => { *self = Playing { track_id: track_id, @@ -426,7 +436,12 @@ impl PlayerInternal { } match self.load_track(track_id, position as i64) { - Some((decoder, normalisation_factor, stream_loader_controller, bytes_per_second)) => { + Some(( + decoder, + normalisation_factor, + stream_loader_controller, + bytes_per_second, + )) => { if play { match self.state { PlayerState::Playing { @@ -503,25 +518,27 @@ impl PlayerInternal { if let Some(stream_loader_controller) = self.state.stream_loader_controller() { stream_loader_controller.set_stream_mode(); } - if let PlayerState::Playing{bytes_per_second, ..} = self.state { + if let PlayerState::Playing { bytes_per_second, .. } = self.state { if let Some(stream_loader_controller) = self.state.stream_loader_controller() { - // Request our read ahead range let request_data_length = max( - (READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS * (0.001 * stream_loader_controller.ping_time_ms() as f64) * bytes_per_second as f64) as usize, - (READ_AHEAD_DURING_PLAYBACK_SECONDS * bytes_per_second as f64) as usize + (READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS + * (0.001 * stream_loader_controller.ping_time_ms() as f64) + * bytes_per_second as f64) as usize, + (READ_AHEAD_DURING_PLAYBACK_SECONDS * bytes_per_second as f64) as usize, ); stream_loader_controller.fetch_next(request_data_length); // Request the part we want to wait for blocking. This effecively means we wait for the previous request to partially complete. let wait_for_data_length = max( - (READ_AHEAD_BEFORE_PLAYBACK_ROUNDTRIPS * (0.001 * stream_loader_controller.ping_time_ms() as f64) * bytes_per_second as f64) as usize, - (READ_AHEAD_BEFORE_PLAYBACK_SECONDS * bytes_per_second as f64) as usize + (READ_AHEAD_BEFORE_PLAYBACK_ROUNDTRIPS + * (0.001 * stream_loader_controller.ping_time_ms() as f64) + * bytes_per_second as f64) as usize, + (READ_AHEAD_BEFORE_PLAYBACK_SECONDS * bytes_per_second as f64) as usize, ); stream_loader_controller.fetch_next_blocking(wait_for_data_length); } } - } PlayerCommand::Play => { @@ -584,9 +601,9 @@ impl PlayerInternal { fn stream_data_rate(&self, format: FileFormat) -> usize { match format { - FileFormat::OGG_VORBIS_96 => 12 * 1024, + FileFormat::OGG_VORBIS_96 => 12 * 1024, FileFormat::OGG_VORBIS_160 => 20 * 1024, - FileFormat::OGG_VORBIS_320=> 40 * 1024, + FileFormat::OGG_VORBIS_320 => 40 * 1024, FileFormat::MP3_256 => 32 * 1024, FileFormat::MP3_320 => 40 * 1024, FileFormat::MP3_160 => 20 * 1024, @@ -601,7 +618,11 @@ impl PlayerInternal { } } - fn load_track(&self, spotify_id: SpotifyId, position: i64) -> Option<(Decoder, f32, StreamLoaderController, usize)> { + fn load_track( + &self, + spotify_id: SpotifyId, + position: i64, + ) -> Option<(Decoder, f32, StreamLoaderController, usize)> { let audio = AudioItem::get_audio_item(&self.session, spotify_id) .wait() .unwrap(); @@ -646,10 +667,11 @@ impl PlayerInternal { }; let bytes_per_second = self.stream_data_rate(*format); - let play_from_beginning = position==0; + let play_from_beginning = position == 0; let key = self.session.audio_key().request(spotify_id, file_id); - let encrypted_file = AudioFile::open(&self.session, file_id, bytes_per_second, play_from_beginning); + let encrypted_file = + AudioFile::open(&self.session, file_id, bytes_per_second, play_from_beginning); let encrypted_file = encrypted_file.wait().unwrap(); @@ -663,7 +685,6 @@ impl PlayerInternal { stream_loader_controller.set_random_access_mode(); } - let key = key.wait().unwrap(); let mut decrypted_file = AudioDecrypt::new(key, encrypted_file); @@ -687,7 +708,12 @@ impl PlayerInternal { stream_loader_controller.set_stream_mode(); } info!("<{}> loaded", audio.name); - Some((decoder, normalisation_factor, stream_loader_controller, bytes_per_second)) + Some(( + decoder, + normalisation_factor, + stream_loader_controller, + bytes_per_second, + )) } } From e4134806dfa4287608f6f674c6fc9ab4dc7f35d7 Mon Sep 17 00:00:00 2001 From: Konstantin Seiler Date: Mon, 11 Nov 2019 18:43:41 +1100 Subject: [PATCH 42/43] Remove debug messages. --- audio/src/fetch.rs | 47 +++++++++------------------------------------- 1 file changed, 9 insertions(+), 38 deletions(-) diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index 80df21a7..2331b5c6 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -460,13 +460,6 @@ fn request_range(session: &Session, file: FileId, offset: usize, length: usize) let (id, channel) = session.channel().allocate(); - trace!( - "requesting range starting at {} of length {} on channel {}.", - offset, - length, - id - ); - let mut data: Vec = Vec::new(); data.write_u16::(id).unwrap(); data.write_u8(0).unwrap(); @@ -576,7 +569,6 @@ impl Future for AudioFileFetchDataReceiver { } } let data_size = data.len(); - trace!("data_receiver for range {} (+{}) got {} bytes of data starting at {}. ({} bytes pending).", self.initial_data_offset, self.initial_request_length, data_size, self.data_offset, self.request_length - data_size); let _ = self .file_data_tx .unbounded_send(ReceivedData::Data(PartialFileData { @@ -591,11 +583,6 @@ impl Future for AudioFileFetchDataReceiver { self.request_length -= data_size; } if self.request_length == 0 { - trace!( - "Data receiver for range {} (+{}) completed.", - self.initial_data_offset, - self.initial_request_length - ); self.finish(); return Ok(Async::Ready(())); } @@ -784,7 +771,7 @@ impl AudioFileFetch { return Ok(Async::Ready(())); } Ok(Async::Ready(Some(ReceivedData::ResponseTimeMs(response_time_ms)))) => { - trace!("Received ping time estimate: {} ms.", response_time_ms); + trace!("Ping time estimated as: {} ms.", response_time_ms); // record the response time self.network_response_times_ms.push(response_time_ms); @@ -841,12 +828,6 @@ impl AudioFileFetch { full = true; } - trace!( - "Downloaded: {} Requested: {}", - download_status.downloaded, - download_status.requested.minus(&download_status.downloaded) - ); - drop(download_status); } @@ -888,7 +869,6 @@ impl AudioFileFetch { } fn finish(&mut self) { - trace!("====== FINISHED DOWNLOADING FILE! ======"); let mut output = self.output.take().unwrap(); let complete_tx = self.complete_tx.take().unwrap(); @@ -935,13 +915,6 @@ impl Future for AudioFileFetch { ); if bytes_pending < desired_pending_bytes { - trace!( - "Prefetching more data. pending: {}, desired: {}, ping: {}, rate: {}", - bytes_pending, - desired_pending_bytes, - ping_time_seconds, - download_rate - ); self.pre_fetch_more_data(desired_pending_bytes - bytes_pending); } } @@ -982,18 +955,11 @@ impl Read for AudioFileStreaming { let mut ranges_to_request = RangeSet::new(); ranges_to_request.add_range(&Range::new(offset, length_to_request)); - trace!("reading at postion {} (length : {})", offset, length); - let mut download_status = self.shared.download_status.lock().unwrap(); ranges_to_request.subtract_range_set(&download_status.downloaded); ranges_to_request.subtract_range_set(&download_status.requested); for range in ranges_to_request.iter() { - trace!( - "requesting data at position {} (length : {})", - range.start, - range.length - ); self.stream_loader_command_tx .unbounded_send(StreamLoaderCommand::Fetch(range.clone())) .unwrap(); @@ -1003,15 +969,18 @@ impl Read for AudioFileStreaming { return Ok(0); } + let mut download_message_printed = false; while !download_status.downloaded.contains(offset) { - trace!("waiting for download"); + if !download_message_printed { + debug!("Waiting for download of file position {}. Downloaded ranges: {}. Pending ranges: {}", offset, download_status.downloaded, download_status.requested.minus(&download_status.downloaded)); + download_message_printed = true; + } download_status = self .shared .cond .wait_timeout(download_status, Duration::from_millis(1000)) .unwrap() .0; - trace!("re-checking data availability at offset {}.", offset); } let available_length = download_status.downloaded.contained_length_from_value(offset); assert!(available_length > 0); @@ -1021,7 +990,9 @@ impl Read for AudioFileStreaming { let read_len = min(length, available_length); let read_len = try!(self.read_file.read(&mut output[..read_len])); - trace!("read successfully at postion {} (length : {})", offset, read_len); + if download_message_printed { + debug!("Read at postion {} completed. {} bytes returned, {} bytes were requested.", offset, read_len, output.len()); + } self.position += read_len as u64; self.shared From 5d8c9f8860e09ad98b23243659b592ee1be47e5c Mon Sep 17 00:00:00 2001 From: Konstantin Seiler Date: Mon, 11 Nov 2019 19:00:19 +1100 Subject: [PATCH 43/43] Hide waiting for download message during seek. --- audio/src/fetch.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index 2331b5c6..69e34d28 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -971,9 +971,11 @@ impl Read for AudioFileStreaming { let mut download_message_printed = false; while !download_status.downloaded.contains(offset) { - if !download_message_printed { - debug!("Waiting for download of file position {}. Downloaded ranges: {}. Pending ranges: {}", offset, download_status.downloaded, download_status.requested.minus(&download_status.downloaded)); - download_message_printed = true; + if let DownloadStrategy::Streaming() = *self.shared.download_strategy.lock().unwrap() { + if !download_message_printed { + debug!("Stream waiting for download of file position {}. Downloaded ranges: {}. Pending ranges: {}", offset, download_status.downloaded, download_status.requested.minus(&download_status.downloaded)); + download_message_printed = true; + } } download_status = self .shared