mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
Merge branch 'master' into error-source-fix
This commit is contained in:
commit
1ccf00cfbb
29 changed files with 1549 additions and 875 deletions
1046
Cargo.lock
generated
1046
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
12
Cargo.toml
12
Cargo.toml
|
@ -43,35 +43,31 @@ num-bigint = "0.1.35"
|
|||
protobuf = "1.1"
|
||||
rand = "0.6"
|
||||
rpassword = "0.3.0"
|
||||
rust-crypto = "0.2.36"
|
||||
serde = "0.9.6"
|
||||
serde_derive = "0.9.6"
|
||||
serde_json = "0.9.5"
|
||||
tokio-core = "0.1.2"
|
||||
tokio-io = "0.1"
|
||||
tokio-process = "0.2.2"
|
||||
tokio-signal = "0.1.2"
|
||||
url = "1.7.0"
|
||||
sha-1 = "0.8.0"
|
||||
hex = "0.3.2"
|
||||
|
||||
[build-dependencies]
|
||||
rand = "0.6"
|
||||
vergen = "0.1.0"
|
||||
|
||||
[replace]
|
||||
"rust-crypto:0.2.36" = { git = "https://github.com/awmath/rust-crypto.git", branch = "avx2" }
|
||||
|
||||
[features]
|
||||
alsa-backend = ["librespot-playback/alsa-backend"]
|
||||
portaudio-backend = ["librespot-playback/portaudio-backend"]
|
||||
pulseaudio-backend = ["librespot-playback/pulseaudio-backend"]
|
||||
jackaudio-backend = ["librespot-playback/jackaudio-backend"]
|
||||
rodio-backend = ["librespot-playback/rodio-backend"]
|
||||
|
||||
with-tremor = ["librespot-audio/with-tremor"]
|
||||
with-vorbis = ["librespot-audio/with-vorbis"]
|
||||
|
||||
with-dns-sd = ["librespot-connect/with-dns-sd"]
|
||||
|
||||
default = ["librespot-playback/portaudio-backend"]
|
||||
default = ["librespot-playback/rodio-backend"]
|
||||
|
||||
[package.metadata.deb]
|
||||
maintainer = "librespot-org"
|
||||
|
|
|
@ -14,8 +14,8 @@ lewton = "0.9.3"
|
|||
log = "0.3.5"
|
||||
num-bigint = "0.1.35"
|
||||
num-traits = "0.1.36"
|
||||
rust-crypto = "0.2.36"
|
||||
tempfile = "2.1"
|
||||
aes-ctr = "0.3.0"
|
||||
|
||||
tremor = { git = "https://github.com/plietar/rust-tremor", optional = true }
|
||||
vorbis = { version ="0.1.0", optional = true }
|
||||
|
|
|
@ -1,39 +1,38 @@
|
|||
use crypto::aes;
|
||||
use crypto::symmetriccipher::SynchronousStreamCipher;
|
||||
use num_bigint::BigUint;
|
||||
use num_traits::FromPrimitive;
|
||||
use std::io;
|
||||
use std::ops::Add;
|
||||
|
||||
use aes_ctr::Aes128Ctr;
|
||||
use aes_ctr::stream_cipher::{
|
||||
NewStreamCipher, SyncStreamCipher, SyncStreamCipherSeek
|
||||
};
|
||||
use aes_ctr::stream_cipher::generic_array::GenericArray;
|
||||
|
||||
use core::audio_key::AudioKey;
|
||||
|
||||
const AUDIO_AESIV: &'static [u8] = &[
|
||||
0x72, 0xe0, 0x67, 0xfb, 0xdd, 0xcb, 0xcf, 0x77, 0xeb, 0xe8, 0xbc, 0x64, 0x3f, 0x63, 0x0d, 0x93,
|
||||
const AUDIO_AESIV: [u8; 16] = [
|
||||
0x72, 0xe0, 0x67, 0xfb, 0xdd, 0xcb, 0xcf, 0x77,
|
||||
0xeb, 0xe8, 0xbc, 0x64, 0x3f, 0x63, 0x0d, 0x93,
|
||||
];
|
||||
|
||||
pub struct AudioDecrypt<T: io::Read> {
|
||||
cipher: Box<SynchronousStreamCipher + 'static>,
|
||||
key: AudioKey,
|
||||
cipher: Aes128Ctr,
|
||||
reader: T,
|
||||
}
|
||||
|
||||
impl<T: io::Read> AudioDecrypt<T> {
|
||||
pub fn new(key: AudioKey, reader: T) -> AudioDecrypt<T> {
|
||||
let cipher = aes::ctr(aes::KeySize::KeySize128, &key.0, AUDIO_AESIV);
|
||||
AudioDecrypt {
|
||||
cipher: cipher,
|
||||
key: key,
|
||||
reader: reader,
|
||||
}
|
||||
let cipher = Aes128Ctr::new(
|
||||
&GenericArray::from_slice(&key.0),
|
||||
&GenericArray::from_slice(&AUDIO_AESIV),
|
||||
);
|
||||
AudioDecrypt { cipher, reader }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: io::Read> io::Read for AudioDecrypt<T> {
|
||||
fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
|
||||
let mut buffer = vec![0u8; output.len()];
|
||||
let len = try!(self.reader.read(&mut buffer));
|
||||
let len = try!(self.reader.read(output));
|
||||
|
||||
self.cipher.process(&buffer[..len], &mut output[..len]);
|
||||
self.cipher.apply_keystream(&mut output[..len]);
|
||||
|
||||
Ok(len)
|
||||
}
|
||||
|
@ -42,17 +41,9 @@ impl<T: io::Read> io::Read for AudioDecrypt<T> {
|
|||
impl<T: io::Read + io::Seek> io::Seek for AudioDecrypt<T> {
|
||||
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
|
||||
let newpos = try!(self.reader.seek(pos));
|
||||
let skip = newpos % 16;
|
||||
|
||||
let iv = BigUint::from_bytes_be(AUDIO_AESIV)
|
||||
.add(BigUint::from_u64(newpos / 16).unwrap())
|
||||
.to_bytes_be();
|
||||
self.cipher = aes::ctr(aes::KeySize::KeySize128, &self.key.0, &iv);
|
||||
self.cipher.seek(newpos);
|
||||
|
||||
let buf = vec![0u8; skip as usize];
|
||||
let mut buf2 = vec![0u8; skip as usize];
|
||||
self.cipher.process(&buf, &mut buf2);
|
||||
|
||||
Ok(newpos as u64)
|
||||
Ok(newpos)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,10 +5,10 @@ extern crate log;
|
|||
|
||||
extern crate bit_set;
|
||||
extern crate byteorder;
|
||||
extern crate crypto;
|
||||
extern crate num_bigint;
|
||||
extern crate num_traits;
|
||||
extern crate tempfile;
|
||||
extern crate aes_ctr;
|
||||
|
||||
extern crate librespot_core as core;
|
||||
|
||||
|
|
|
@ -18,12 +18,15 @@ log = "0.3.5"
|
|||
num-bigint = "0.1.35"
|
||||
protobuf = "2.0.5"
|
||||
rand = "0.6"
|
||||
rust-crypto = "0.2.36"
|
||||
serde = "0.9.6"
|
||||
serde_derive = "0.9.6"
|
||||
serde_json = "0.9.5"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
tokio-core = "0.1.2"
|
||||
url = "1.3"
|
||||
sha-1 = "0.8.0"
|
||||
hmac = "0.7.0"
|
||||
aes-ctr = "0.3.0"
|
||||
block-modes = "0.2.0"
|
||||
|
||||
dns-sd = { version = "0.1.3", optional = true }
|
||||
mdns = { git = "https://github.com/plietar/rust-mdns", optional = true }
|
||||
|
|
86
connect/src/context.rs
Normal file
86
connect/src/context.rs
Normal file
|
@ -0,0 +1,86 @@
|
|||
use core::spotify_id::SpotifyId;
|
||||
use protocol::spirc::TrackRef;
|
||||
|
||||
use serde;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct StationContext {
|
||||
pub uri: Option<String>,
|
||||
pub next_page_url: String,
|
||||
#[serde(deserialize_with = "deserialize_protobuf_TrackRef")]
|
||||
pub tracks: Vec<TrackRef>,
|
||||
// Not required for core functionality
|
||||
// pub seeds: Vec<String>,
|
||||
// #[serde(rename = "imageUri")]
|
||||
// pub image_uri: String,
|
||||
// pub subtitle: Option<String>,
|
||||
// pub subtitles: Vec<String>,
|
||||
// #[serde(rename = "subtitleUri")]
|
||||
// pub subtitle_uri: Option<String>,
|
||||
// pub title: String,
|
||||
// #[serde(rename = "titleUri")]
|
||||
// pub title_uri: String,
|
||||
// pub related_artists: Vec<ArtistContext>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct PageContext {
|
||||
pub uri: String,
|
||||
pub next_page_url: String,
|
||||
#[serde(deserialize_with = "deserialize_protobuf_TrackRef")]
|
||||
pub tracks: Vec<TrackRef>,
|
||||
// Not required for core functionality
|
||||
// pub url: String,
|
||||
// // pub restrictions:
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct TrackContext {
|
||||
#[serde(rename = "original_gid")]
|
||||
pub gid: String,
|
||||
pub uri: String,
|
||||
pub uid: String,
|
||||
// Not required for core functionality
|
||||
// pub album_uri: String,
|
||||
// pub artist_uri: String,
|
||||
// pub metadata: MetadataContext,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ArtistContext {
|
||||
artist_name: String,
|
||||
artist_uri: String,
|
||||
image_uri: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct MetadataContext {
|
||||
album_title: String,
|
||||
artist_name: String,
|
||||
artist_uri: String,
|
||||
image_url: String,
|
||||
title: String,
|
||||
uid: String,
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn deserialize_protobuf_TrackRef<'d, D>(de: D) -> Result<Vec<TrackRef>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'d>,
|
||||
{
|
||||
let v: Vec<TrackContext> = try!(serde::Deserialize::deserialize(de));
|
||||
let track_vec = v
|
||||
.iter()
|
||||
.map(|v| {
|
||||
let mut t = TrackRef::new();
|
||||
// This has got to be the most round about way of doing this.
|
||||
t.set_gid(SpotifyId::from_base62(&v.gid).unwrap().to_raw().to_vec());
|
||||
t.set_uri(v.uri.to_owned());
|
||||
|
||||
t
|
||||
})
|
||||
.collect::<Vec<TrackRef>>();
|
||||
|
||||
Ok(track_vec)
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
use base64;
|
||||
use crypto;
|
||||
use crypto::digest::Digest;
|
||||
use crypto::mac::Mac;
|
||||
use sha1::{Sha1, Digest};
|
||||
use hmac::{Hmac, Mac};
|
||||
use aes_ctr::Aes128Ctr;
|
||||
use aes_ctr::stream_cipher::{NewStreamCipher, SyncStreamCipher};
|
||||
use aes_ctr::stream_cipher::generic_array::GenericArray;
|
||||
use futures::sync::mpsc;
|
||||
use futures::{Future, Poll, Stream};
|
||||
use hyper::server::{Http, Request, Response, Service};
|
||||
|
@ -26,6 +28,8 @@ use core::config::ConnectConfig;
|
|||
use core::diffie_hellman::{DH_GENERATOR, DH_PRIME};
|
||||
use core::util;
|
||||
|
||||
type HmacSha1 = Hmac<Sha1>;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Discovery(Arc<DiscoveryInner>);
|
||||
struct DiscoveryInner {
|
||||
|
@ -106,39 +110,45 @@ impl Discovery {
|
|||
let encrypted = &encrypted_blob[16..encrypted_blob.len() - 20];
|
||||
let cksum = &encrypted_blob[encrypted_blob.len() - 20..encrypted_blob.len()];
|
||||
|
||||
let base_key = {
|
||||
let mut data = [0u8; 20];
|
||||
let mut h = crypto::sha1::Sha1::new();
|
||||
h.input(&shared_key.to_bytes_be());
|
||||
h.result(&mut data);
|
||||
data[..16].to_owned()
|
||||
};
|
||||
let base_key = Sha1::digest(&shared_key.to_bytes_be());
|
||||
let base_key = &base_key[..16];
|
||||
|
||||
let checksum_key = {
|
||||
let mut h = crypto::hmac::Hmac::new(crypto::sha1::Sha1::new(), &base_key);
|
||||
let mut h = HmacSha1::new_varkey(base_key)
|
||||
.expect("HMAC can take key of any size");
|
||||
h.input(b"checksum");
|
||||
h.result().code().to_owned()
|
||||
h.result().code()
|
||||
};
|
||||
|
||||
let encryption_key = {
|
||||
let mut h = crypto::hmac::Hmac::new(crypto::sha1::Sha1::new(), &base_key);
|
||||
let mut h = HmacSha1::new_varkey(&base_key)
|
||||
.expect("HMAC can take key of any size");
|
||||
h.input(b"encryption");
|
||||
h.result().code().to_owned()
|
||||
h.result().code()
|
||||
};
|
||||
|
||||
let mac = {
|
||||
let mut h = crypto::hmac::Hmac::new(crypto::sha1::Sha1::new(), &checksum_key);
|
||||
let mut h = HmacSha1::new_varkey(&checksum_key)
|
||||
.expect("HMAC can take key of any size");
|
||||
h.input(encrypted);
|
||||
h.result().code().to_owned()
|
||||
};
|
||||
if let Err(_) = h.verify(cksum) {
|
||||
warn!("Login error for user {:?}: MAC mismatch", username);
|
||||
let result = json!({
|
||||
"status": 102,
|
||||
"spotifyError": 1,
|
||||
"statusString": "ERROR-MAC"
|
||||
});
|
||||
|
||||
assert_eq!(&mac[..], cksum);
|
||||
let body = result.to_string();
|
||||
return ::futures::finished(Response::new().with_body(body))
|
||||
}
|
||||
|
||||
let decrypted = {
|
||||
let mut data = vec![0u8; encrypted.len()];
|
||||
let mut cipher =
|
||||
crypto::aes::ctr(crypto::aes::KeySize::KeySize128, &encryption_key[0..16], iv);
|
||||
cipher.process(encrypted, &mut data);
|
||||
let mut data = encrypted.to_vec();
|
||||
let mut cipher = Aes128Ctr::new(
|
||||
&GenericArray::from_slice(&encryption_key[0..16]),
|
||||
&GenericArray::from_slice(iv),
|
||||
);
|
||||
cipher.apply_keystream(&mut data);
|
||||
String::from_utf8(data).unwrap()
|
||||
};
|
||||
|
||||
|
@ -221,7 +231,6 @@ pub fn discovery(
|
|||
|
||||
let serve = {
|
||||
let http = Http::new();
|
||||
debug!("Zeroconf server listening on 0.0.0.0:{}", port);
|
||||
http.serve_addr_handle(
|
||||
&format!("0.0.0.0:{}", port).parse().unwrap(),
|
||||
&handle,
|
||||
|
@ -230,6 +239,7 @@ pub fn discovery(
|
|||
};
|
||||
|
||||
let s_port = serve.incoming_ref().local_addr().port();
|
||||
debug!("Zeroconf server listening on 0.0.0.0:{}", s_port);
|
||||
|
||||
let server_future = {
|
||||
let handle = handle.clone();
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
extern crate log;
|
||||
#[macro_use]
|
||||
extern crate serde_json;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate serde;
|
||||
|
||||
extern crate base64;
|
||||
extern crate crypto;
|
||||
extern crate futures;
|
||||
extern crate hyper;
|
||||
extern crate num_bigint;
|
||||
|
@ -13,6 +15,11 @@ extern crate rand;
|
|||
extern crate tokio_core;
|
||||
extern crate url;
|
||||
|
||||
extern crate sha1;
|
||||
extern crate hmac;
|
||||
extern crate aes_ctr;
|
||||
extern crate block_modes;
|
||||
|
||||
#[cfg(feature = "with-dns-sd")]
|
||||
extern crate dns_sd;
|
||||
|
||||
|
@ -23,5 +30,6 @@ extern crate librespot_core as core;
|
|||
extern crate librespot_playback as playback;
|
||||
extern crate librespot_protocol as protocol;
|
||||
|
||||
pub mod context;
|
||||
pub mod discovery;
|
||||
pub mod spirc;
|
||||
|
|
|
@ -16,7 +16,9 @@ use protocol::spirc::{DeviceState, Frame, MessageType, PlayStatus, State};
|
|||
|
||||
use playback::mixer::Mixer;
|
||||
use playback::player::Player;
|
||||
use serde_json;
|
||||
|
||||
use context::StationContext;
|
||||
use rand;
|
||||
use rand::seq::SliceRandom;
|
||||
use std;
|
||||
|
@ -40,6 +42,8 @@ pub struct SpircTask {
|
|||
|
||||
shutdown: bool,
|
||||
session: Session,
|
||||
context_fut: Box<Future<Item = serde_json::Value, Error = MercuryError>>,
|
||||
context: Option<StationContext>,
|
||||
}
|
||||
|
||||
pub enum SpircCommand {
|
||||
|
@ -53,6 +57,9 @@ pub enum SpircCommand {
|
|||
Shutdown,
|
||||
}
|
||||
|
||||
const CONTEXT_TRACKS_HISTORY: usize = 10;
|
||||
const CONTEXT_FETCH_THRESHOLD: u32 = 5;
|
||||
|
||||
pub struct Spirc {
|
||||
commands: mpsc::UnboundedSender<SpircCommand>,
|
||||
}
|
||||
|
@ -139,6 +146,15 @@ fn initial_device_state(config: ConnectConfig) -> DeviceState {
|
|||
};
|
||||
msg
|
||||
};
|
||||
{
|
||||
let msg = repeated.push_default();
|
||||
msg.set_typ(protocol::spirc::CapabilityType::kSupportsPlaylistV2);
|
||||
{
|
||||
let repeated = msg.mut_intValue();
|
||||
repeated.push(64)
|
||||
};
|
||||
msg
|
||||
};
|
||||
{
|
||||
let msg = repeated.push_default();
|
||||
msg.set_typ(protocol::spirc::CapabilityType::kSupportedContexts);
|
||||
|
@ -176,7 +192,7 @@ fn calc_logarithmic_volume(volume: u16) -> u16 {
|
|||
// Volume conversion taken from https://www.dr-lex.be/info-stuff/volumecontrols.html#ideal2
|
||||
// Convert the given volume [0..0xffff] to a dB gain
|
||||
// We assume a dB range of 60dB.
|
||||
// Use the equatation: a * exp(b * x)
|
||||
// Use the equation: a * exp(b * x)
|
||||
// in which a = IDEAL_FACTOR, b = 1/1000
|
||||
const IDEAL_FACTOR: f64 = 6.908;
|
||||
let normalized_volume = volume as f64 / std::u16::MAX as f64; // To get a value between 0 and 1
|
||||
|
@ -259,6 +275,9 @@ impl Spirc {
|
|||
|
||||
shutdown: false,
|
||||
session: session.clone(),
|
||||
|
||||
context_fut: Box::new(future::empty()),
|
||||
context: None,
|
||||
};
|
||||
|
||||
task.set_volume(volume);
|
||||
|
@ -335,6 +354,39 @@ impl Future for SpircTask {
|
|||
Ok(Async::NotReady) => (),
|
||||
Err(oneshot::Canceled) => self.end_of_track = Box::new(future::empty()),
|
||||
}
|
||||
|
||||
match self.context_fut.poll() {
|
||||
Ok(Async::Ready(value)) => {
|
||||
let r_context = serde_json::from_value::<StationContext>(value.clone());
|
||||
self.context = match r_context {
|
||||
Ok(context) => {
|
||||
info!(
|
||||
"Resolved {:?} tracks from <{:?}>",
|
||||
context.tracks.len(),
|
||||
self.state.get_context_uri(),
|
||||
);
|
||||
Some(context)
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Unable to parse JSONContext {:?}\n{:?}", e, value);
|
||||
None
|
||||
}
|
||||
};
|
||||
// It needn't be so verbose - can be as simple as
|
||||
// if let Some(ref context) = r_context {
|
||||
// info!("Got {:?} tracks from <{}>", context.tracks.len(), context.uri);
|
||||
// }
|
||||
// self.context = r_context;
|
||||
|
||||
progress = true;
|
||||
self.context_fut = Box::new(future::empty());
|
||||
}
|
||||
Ok(Async::NotReady) => (),
|
||||
Err(err) => {
|
||||
self.context_fut = Box::new(future::empty());
|
||||
error!("ContextError: {:?}", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let poll_sender = self.sender.poll_complete().unwrap();
|
||||
|
@ -455,6 +507,7 @@ impl SpircTask {
|
|||
let play = frame.get_state().get_status() == PlayStatus::kPlayStatusPlay;
|
||||
self.load_track(play);
|
||||
} else {
|
||||
info!("No more tracks left in queue");
|
||||
self.state.set_status(PlayStatus::kPlayStatusStop);
|
||||
}
|
||||
|
||||
|
@ -600,6 +653,21 @@ impl SpircTask {
|
|||
fn handle_next(&mut self) {
|
||||
let mut new_index = self.consume_queued_track() as u32;
|
||||
let mut continue_playing = true;
|
||||
debug!(
|
||||
"At track {:?} of {:?} <{:?}> update [{}]",
|
||||
new_index,
|
||||
self.state.get_track().len(),
|
||||
self.state.get_context_uri(),
|
||||
self.state.get_track().len() as u32 - new_index < CONTEXT_FETCH_THRESHOLD
|
||||
);
|
||||
let context_uri = self.state.get_context_uri().to_owned();
|
||||
if (context_uri.starts_with("spotify:station:") || context_uri.starts_with("spotify:dailymix:"))
|
||||
&& ((self.state.get_track().len() as u32) - new_index) < CONTEXT_FETCH_THRESHOLD
|
||||
{
|
||||
self.context_fut = self.resolve_station(&context_uri);
|
||||
self.update_tracks_from_context();
|
||||
}
|
||||
|
||||
if new_index >= self.state.get_track().len() as u32 {
|
||||
new_index = 0; // Loop around back to start
|
||||
continue_playing = self.state.get_repeat();
|
||||
|
@ -680,10 +748,59 @@ impl SpircTask {
|
|||
self.state.get_position_ms() + diff as u32
|
||||
}
|
||||
|
||||
fn resolve_station(&self, uri: &str) -> Box<Future<Item = serde_json::Value, Error = MercuryError>> {
|
||||
let radio_uri = format!("hm://radio-apollo/v3/stations/{}", uri);
|
||||
|
||||
self.resolve_uri(&radio_uri)
|
||||
}
|
||||
|
||||
fn resolve_uri(&self, uri: &str) -> Box<Future<Item = serde_json::Value, Error = MercuryError>> {
|
||||
let request = self.session.mercury().get(uri);
|
||||
|
||||
Box::new(request.and_then(move |response| {
|
||||
let data = response.payload.first().expect("Empty payload on context uri");
|
||||
let response: serde_json::Value = serde_json::from_slice(&data).unwrap();
|
||||
|
||||
Ok(response)
|
||||
}))
|
||||
}
|
||||
|
||||
fn update_tracks_from_context(&mut self) {
|
||||
if let Some(ref context) = self.context {
|
||||
self.context_fut = self.resolve_uri(&context.next_page_url);
|
||||
|
||||
let new_tracks = &context.tracks;
|
||||
debug!("Adding {:?} tracks from context to playlist", new_tracks.len());
|
||||
let current_index = self.state.get_playing_track_index();
|
||||
let mut new_index = 0;
|
||||
{
|
||||
let mut tracks = self.state.mut_track();
|
||||
// Does this need to be optimised - we don't need to actually traverse the len of tracks
|
||||
let tracks_len = tracks.len();
|
||||
if tracks_len > CONTEXT_TRACKS_HISTORY {
|
||||
tracks.rotate_right(tracks_len - CONTEXT_TRACKS_HISTORY);
|
||||
tracks.truncate(CONTEXT_TRACKS_HISTORY);
|
||||
}
|
||||
// tracks.extend_from_slice(&mut new_tracks); // method doesn't exist for protobuf::RepeatedField
|
||||
for t in new_tracks {
|
||||
tracks.push(t.to_owned());
|
||||
}
|
||||
if current_index > CONTEXT_TRACKS_HISTORY as u32 {
|
||||
new_index = current_index - CONTEXT_TRACKS_HISTORY as u32;
|
||||
}
|
||||
}
|
||||
self.state.set_playing_track_index(new_index);
|
||||
}
|
||||
}
|
||||
|
||||
fn update_tracks(&mut self, frame: &protocol::spirc::Frame) {
|
||||
let index = frame.get_state().get_playing_track_index();
|
||||
let tracks = frame.get_state().get_track();
|
||||
let context_uri = frame.get_state().get_context_uri().to_owned();
|
||||
let tracks = frame.get_state().get_track();
|
||||
debug!("Frame has {:?} tracks", tracks.len());
|
||||
if context_uri.starts_with("spotify:station:") || context_uri.starts_with("spotify:dailymix:") {
|
||||
self.context_fut = self.resolve_station(&context_uri);
|
||||
}
|
||||
|
||||
self.state.set_playing_track_index(index);
|
||||
self.state.set_track(tracks.into_iter().cloned().collect());
|
||||
|
@ -693,13 +810,25 @@ impl SpircTask {
|
|||
}
|
||||
|
||||
fn load_track(&mut self, play: bool) {
|
||||
let index = self.state.get_playing_track_index();
|
||||
let track = {
|
||||
let gid = self.state.get_track()[index as usize].get_gid();
|
||||
SpotifyId::from_raw(gid).unwrap()
|
||||
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 track_ref = &self.state.get_track()[index as usize];
|
||||
while track_ref.get_gid().len() != 16 {
|
||||
warn!(
|
||||
"Skipping track {:?} at position [{}] of {}",
|
||||
track_ref.get_uri(),
|
||||
index,
|
||||
tracks_len
|
||||
);
|
||||
index = if index + 1 < tracks_len { index + 1 } else { 0 };
|
||||
track_ref = &self.state.get_track()[index as usize];
|
||||
}
|
||||
SpotifyId::from_raw(track_ref.get_gid()).unwrap()
|
||||
};
|
||||
let position = self.state.get_position_ms();
|
||||
|
||||
let position = self.state.get_position_ms();
|
||||
let end_of_track = self.player.load(track, play, position);
|
||||
|
||||
if play {
|
||||
|
|
|
@ -25,16 +25,19 @@ num-traits = "0.1.36"
|
|||
protobuf = "2.0.5"
|
||||
rand = "0.6"
|
||||
rpassword = "0.3.0"
|
||||
rust-crypto = "0.2.36"
|
||||
serde = "0.9.6"
|
||||
serde_derive = "0.9.6"
|
||||
serde_json = "0.9.5"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
shannon = "0.2.0"
|
||||
tokio-codec = "0.1.1"
|
||||
tokio-core = "0.1.2"
|
||||
tokio-io = "0.1"
|
||||
url = "1.7.0"
|
||||
uuid = { version = "0.4", features = ["v4"] }
|
||||
sha-1 = "0.8.0"
|
||||
hmac = "0.7.0"
|
||||
pbkdf2 = "0.3.0"
|
||||
aes = "0.3.0"
|
||||
|
||||
[build-dependencies]
|
||||
rand = "0.6"
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
use base64;
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
use crypto;
|
||||
use crypto::aes;
|
||||
use crypto::digest::Digest;
|
||||
use crypto::hmac::Hmac;
|
||||
use crypto::pbkdf2::pbkdf2;
|
||||
use crypto::sha1::Sha1;
|
||||
use aes::Aes192;
|
||||
use hmac::Hmac;
|
||||
use sha1::{Sha1, Digest};
|
||||
use pbkdf2::pbkdf2;
|
||||
use protobuf::ProtobufEnum;
|
||||
use serde;
|
||||
use serde_json;
|
||||
|
@ -63,42 +61,34 @@ impl Credentials {
|
|||
Ok(data)
|
||||
}
|
||||
|
||||
let encrypted_blob = base64::decode(encrypted_blob).unwrap();
|
||||
|
||||
let secret = {
|
||||
let mut data = [0u8; 20];
|
||||
let mut h = crypto::sha1::Sha1::new();
|
||||
h.input(device_id.as_bytes());
|
||||
h.result(&mut data);
|
||||
data
|
||||
};
|
||||
let secret = Sha1::digest(device_id.as_bytes());
|
||||
|
||||
let key = {
|
||||
let mut data = [0u8; 24];
|
||||
let mut mac = Hmac::new(Sha1::new(), &secret);
|
||||
pbkdf2(&mut mac, username.as_bytes(), 0x100, &mut data[0..20]);
|
||||
let mut key = [0u8; 24];
|
||||
pbkdf2::<Hmac<Sha1>>(&secret, username.as_bytes(), 0x100, &mut key[0..20]);
|
||||
|
||||
let mut hash = Sha1::new();
|
||||
hash.input(&data[0..20]);
|
||||
hash.result(&mut data[0..20]);
|
||||
BigEndian::write_u32(&mut data[20..], 20);
|
||||
data
|
||||
let hash = &Sha1::digest(&key[..20]);
|
||||
key[..20].copy_from_slice(hash);
|
||||
BigEndian::write_u32(&mut key[20..], 20);
|
||||
key
|
||||
};
|
||||
|
||||
// decrypt data using ECB mode without padding
|
||||
let blob = {
|
||||
// Anyone know what this block mode is ?
|
||||
let mut data = vec![0u8; encrypted_blob.len()];
|
||||
let mut cipher =
|
||||
aes::ecb_decryptor(aes::KeySize::KeySize192, &key, crypto::blockmodes::NoPadding);
|
||||
cipher
|
||||
.decrypt(
|
||||
&mut crypto::buffer::RefReadBuffer::new(&encrypted_blob),
|
||||
&mut crypto::buffer::RefWriteBuffer::new(&mut data),
|
||||
true,
|
||||
)
|
||||
.unwrap();
|
||||
use aes::block_cipher_trait::BlockCipher;
|
||||
use aes::block_cipher_trait::generic_array::GenericArray;
|
||||
use aes::block_cipher_trait::generic_array::typenum::Unsigned;
|
||||
|
||||
let l = encrypted_blob.len();
|
||||
let mut data = base64::decode(encrypted_blob).unwrap();
|
||||
let cipher = Aes192::new(GenericArray::from_slice(&key));
|
||||
let block_size = <Aes192 as BlockCipher>::BlockSize::to_usize();
|
||||
assert_eq!(data.len() % block_size, 0);
|
||||
// replace to chunks_exact_mut with MSRV bump to 1.31
|
||||
for chunk in data.chunks_mut(block_size) {
|
||||
cipher.decrypt_block(GenericArray::from_mut_slice(chunk));
|
||||
}
|
||||
|
||||
let l = data.len();
|
||||
for i in 0..l - 0x10 {
|
||||
data[l - i - 1] ^= data[l - i - 0x11];
|
||||
}
|
||||
|
@ -152,10 +142,10 @@ where
|
|||
serde::Serialize::serialize(&v.value(), ser)
|
||||
}
|
||||
|
||||
fn deserialize_protobuf_enum<T, D>(de: D) -> Result<T, D::Error>
|
||||
fn deserialize_protobuf_enum<'de, T, D>(de: D) -> Result<T, D::Error>
|
||||
where
|
||||
T: ProtobufEnum,
|
||||
D: serde::Deserializer,
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let v: i32 = try!(serde::Deserialize::deserialize(de));
|
||||
T::from_i32(v).ok_or_else(|| serde::de::Error::custom("Invalid enum value"))
|
||||
|
@ -169,9 +159,9 @@ where
|
|||
serde::Serialize::serialize(&base64::encode(v.as_ref()), ser)
|
||||
}
|
||||
|
||||
fn deserialize_base64<D>(de: D) -> Result<Vec<u8>, D::Error>
|
||||
fn deserialize_base64<'de, D>(de: D) -> Result<Vec<u8>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer,
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let v: String = try!(serde::Deserialize::deserialize(de));
|
||||
base64::decode(&v).map_err(|e| serde::de::Error::custom(e.to_string()))
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
|
||||
use crypto::hmac::Hmac;
|
||||
use crypto::mac::Mac;
|
||||
use crypto::sha1::Sha1;
|
||||
use hmac::{Hmac, Mac};
|
||||
use sha1::Sha1;
|
||||
use futures::{Async, Future, Poll};
|
||||
use protobuf::{self, Message};
|
||||
use rand::thread_rng;
|
||||
|
@ -89,7 +88,7 @@ fn client_hello<T: AsyncWrite>(connection: T, gc: Vec<u8>) -> WriteAll<T, Vec<u8
|
|||
packet
|
||||
.mut_build_info()
|
||||
.set_platform(protocol::keyexchange::Platform::PLATFORM_LINUX_X86);
|
||||
packet.mut_build_info().set_version(0x10800000000);
|
||||
packet.mut_build_info().set_version(109800078);
|
||||
packet
|
||||
.mut_cryptosuites_supported()
|
||||
.push(protocol::keyexchange::Cryptosuite::CRYPTO_SUITE_SHANNON);
|
||||
|
@ -187,17 +186,19 @@ fn read_into_accumulator<T: AsyncRead>(
|
|||
}
|
||||
|
||||
fn compute_keys(shared_secret: &[u8], packets: &[u8]) -> (Vec<u8>, Vec<u8>, Vec<u8>) {
|
||||
let mut data = Vec::with_capacity(0x64);
|
||||
let mut mac = Hmac::new(Sha1::new(), &shared_secret);
|
||||
type HmacSha1 = Hmac<Sha1>;
|
||||
|
||||
let mut data = Vec::with_capacity(0x64);
|
||||
for i in 1..6 {
|
||||
let mut mac = HmacSha1::new_varkey(&shared_secret)
|
||||
.expect("HMAC can take key of any size");
|
||||
mac.input(packets);
|
||||
mac.input(&[i]);
|
||||
data.extend_from_slice(&mac.result().code());
|
||||
mac.reset();
|
||||
}
|
||||
|
||||
mac = Hmac::new(Sha1::new(), &data[..0x14]);
|
||||
let mut mac = HmacSha1::new_varkey(&data[..0x14])
|
||||
.expect("HMAC can take key of any size");;
|
||||
mac.input(packets);
|
||||
|
||||
(
|
||||
|
|
|
@ -14,7 +14,6 @@ extern crate serde_derive;
|
|||
extern crate base64;
|
||||
extern crate byteorder;
|
||||
extern crate bytes;
|
||||
extern crate crypto;
|
||||
extern crate extprim;
|
||||
extern crate httparse;
|
||||
extern crate hyper;
|
||||
|
@ -33,6 +32,10 @@ extern crate tokio_core;
|
|||
extern crate tokio_io;
|
||||
extern crate url;
|
||||
extern crate uuid;
|
||||
extern crate sha1;
|
||||
extern crate hmac;
|
||||
extern crate pbkdf2;
|
||||
extern crate aes;
|
||||
|
||||
extern crate librespot_protocol as protocol;
|
||||
|
||||
|
|
|
@ -20,9 +20,12 @@ portaudio-rs = { version = "0.3.0", optional = true }
|
|||
libpulse-sys = { version = "0.0.0", optional = true }
|
||||
jack = { version = "0.5.3", optional = true }
|
||||
libc = { version = "0.2", optional = true }
|
||||
rodio = { git = "https://github.com/tomaka/rodio", optional = true, default-features = false }
|
||||
cpal = { version = "*", optional = true }
|
||||
|
||||
[features]
|
||||
alsa-backend = ["alsa"]
|
||||
portaudio-backend = ["portaudio-rs"]
|
||||
pulseaudio-backend = ["libpulse-sys", "libc"]
|
||||
jackaudio-backend = ["jack"]
|
||||
rodio-backend = ["rodio", "cpal"]
|
||||
|
|
|
@ -34,6 +34,11 @@ mod jackaudio;
|
|||
#[cfg(feature = "jackaudio-backend")]
|
||||
use self::jackaudio::JackSink;
|
||||
|
||||
#[cfg(feature = "rodio-backend")]
|
||||
mod rodio;
|
||||
#[cfg(feature = "rodio-backend")]
|
||||
use self::rodio::RodioSink;
|
||||
|
||||
mod pipe;
|
||||
use self::pipe::StdoutSink;
|
||||
|
||||
|
@ -46,6 +51,8 @@ pub const BACKENDS: &'static [(&'static str, fn(Option<String>) -> Box<Sink>)] =
|
|||
("pulseaudio", mk_sink::<PulseAudioSink>),
|
||||
#[cfg(feature = "jackaudio-backend")]
|
||||
("jackaudio", mk_sink::<JackSink>),
|
||||
#[cfg(feature = "rodio-backend")]
|
||||
("rodio", mk_sink::<RodioSink>),
|
||||
("pipe", mk_sink::<StdoutSink>),
|
||||
];
|
||||
|
||||
|
|
115
playback/src/audio_backend/rodio.rs
Normal file
115
playback/src/audio_backend/rodio.rs
Normal file
|
@ -0,0 +1,115 @@
|
|||
use super::{Open, Sink};
|
||||
extern crate rodio;
|
||||
extern crate cpal;
|
||||
use std::{io, thread, time};
|
||||
use std::process::exit;
|
||||
|
||||
pub struct RodioSink {
|
||||
rodio_sink: rodio::Sink,
|
||||
}
|
||||
|
||||
fn list_formats(ref device: &rodio::Device) {
|
||||
let default_fmt = match device.default_output_format() {
|
||||
Ok(fmt) => cpal::SupportedFormat::from(fmt),
|
||||
Err(e) => {
|
||||
warn!("Error getting default rodio::Sink format: {:?}", e);
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
let mut output_formats = match device.supported_output_formats() {
|
||||
Ok(f) => f.peekable(),
|
||||
Err(e) => {
|
||||
warn!("Error getting supported rodio::Sink formats: {:?}", e);
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
if output_formats.peek().is_some() {
|
||||
debug!(" Available formats:");
|
||||
for format in output_formats {
|
||||
let s = format!("{}ch, {:?}, min {:?}, max {:?}", format.channels, format.data_type, format.min_sample_rate, format.max_sample_rate);
|
||||
if format == default_fmt {
|
||||
debug!(" (default) {}", s);
|
||||
} else {
|
||||
debug!(" {:?}", format);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn list_outputs() {
|
||||
let default_device = rodio::default_output_device().unwrap();
|
||||
println!("Default Audio Device:\n {}", default_device.name());
|
||||
list_formats(&default_device);
|
||||
|
||||
println!("Other Available Audio Devices:");
|
||||
for device in rodio::output_devices() {
|
||||
if device.name() != default_device.name() {
|
||||
println!(" {}", device.name());
|
||||
list_formats(&device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Open for RodioSink {
|
||||
fn open(device: Option<String>) -> RodioSink {
|
||||
debug!("Using rodio sink");
|
||||
|
||||
let mut rodio_device = rodio::default_output_device().expect("no output device available");
|
||||
if device.is_some() {
|
||||
let device_name = device.unwrap();
|
||||
|
||||
if device_name == "?".to_string() {
|
||||
list_outputs();
|
||||
exit(0)
|
||||
}
|
||||
let mut found = false;
|
||||
for d in rodio::output_devices() {
|
||||
if d.name() == device_name {
|
||||
rodio_device = d;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
println!("No output sink matching '{}' found.", device_name);
|
||||
exit(0)
|
||||
}
|
||||
}
|
||||
let sink = rodio::Sink::new(&rodio_device);
|
||||
|
||||
RodioSink {
|
||||
rodio_sink: sink,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sink for RodioSink {
|
||||
fn start(&mut self) -> io::Result<()> {
|
||||
// More similar to an "unpause" than "play". Doesn't undo "stop".
|
||||
// self.rodio_sink.play();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn stop(&mut self) -> io::Result<()> {
|
||||
// This will immediately stop playback, but the sink is then unusable.
|
||||
// We just have to let the current buffer play till the end.
|
||||
// self.rodio_sink.stop();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write(&mut self, data: &[i16]) -> io::Result<()> {
|
||||
let source = rodio::buffer::SamplesBuffer::new(2, 44100, data);
|
||||
self.rodio_sink.append(source);
|
||||
|
||||
// Chunk sizes seem to be about 256 to 3000 ish items long.
|
||||
// Assuming they're on average 1628 then a half second buffer is:
|
||||
// 44100 elements --> about 27 chunks
|
||||
while self.rodio_sink.len() > 26 {
|
||||
// sleep and wait for rodio to drain a bit
|
||||
thread::sleep(time::Duration::from_millis(10));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -560,12 +560,12 @@ impl PlayerInternal {
|
|||
let key = self
|
||||
.session
|
||||
.audio_key()
|
||||
.request(track.id, file_id)
|
||||
.wait()
|
||||
.unwrap();
|
||||
.request(track.id, file_id);
|
||||
let encrypted_file = AudioFile::open(&self.session, file_id);
|
||||
|
||||
let encrypted_file = AudioFile::open(&self.session, file_id).wait().unwrap();
|
||||
|
||||
let encrypted_file = encrypted_file.wait().unwrap();
|
||||
let key = key.wait().unwrap();
|
||||
let mut decrypted_file = AudioDecrypt::new(key, encrypted_file);
|
||||
|
||||
let normalisation_factor = match NormalisationData::parse_from_file(&mut decrypted_file) {
|
||||
|
@ -580,10 +580,12 @@ impl PlayerInternal {
|
|||
|
||||
let mut decoder = VorbisDecoder::new(audio_file).unwrap();
|
||||
|
||||
if position != 0 {
|
||||
match decoder.seek(position) {
|
||||
Ok(_) => (),
|
||||
Err(err) => error!("Vorbis error: {:?}", err),
|
||||
}
|
||||
}
|
||||
|
||||
info!("Track \"{}\" loaded", track.name);
|
||||
|
||||
|
|
|
@ -8,4 +8,4 @@ build = "build.rs"
|
|||
protobuf = "2.0.5"
|
||||
|
||||
[build-dependencies]
|
||||
protoc-rust = "2.0.5"
|
||||
protobuf-codegen-pure = "2.0.5"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
extern crate protoc_rust;
|
||||
use protoc_rust::Customize;
|
||||
extern crate protobuf_codegen_pure;
|
||||
use protobuf_codegen_pure::Customize;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
|
||||
|
@ -14,7 +14,7 @@ fn main() {
|
|||
for &(path, expected_checksum) in files::FILES {
|
||||
let actual = cksum_file(path).unwrap();
|
||||
if expected_checksum != actual {
|
||||
protoc_rust::run(protoc_rust::Args {
|
||||
protobuf_codegen_pure::run(protobuf_codegen_pure::Args {
|
||||
out_dir: "src",
|
||||
input: &[path],
|
||||
includes: &["proto"],
|
||||
|
@ -28,7 +28,6 @@ fn main() {
|
|||
if changed {
|
||||
// Write new checksums to file
|
||||
let mut file = File::create("files.rs").unwrap();
|
||||
println!("f_str: {:?}",f_str);
|
||||
file.write_all(f_str.as_bytes()).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
set -eu
|
||||
|
||||
SRC="authentication keyexchange mercury
|
||||
metadata pubsub spirc"
|
||||
|
||||
cat > src/lib.rs <<EOF
|
||||
// Autogenerated by build.sh
|
||||
|
||||
extern crate protobuf;
|
||||
EOF
|
||||
|
||||
cat > files.rs <<EOF
|
||||
// Autogenerated by build.sh
|
||||
|
||||
pub const FILES : &'static [(&'static str, u32)] = &[
|
||||
EOF
|
||||
|
||||
for name in $SRC; do
|
||||
src=proto/$name.proto
|
||||
out=src/$name.rs
|
||||
checksum=$(cksum $src | cut -f 1 -d' ')
|
||||
|
||||
protoc --rust_out src/ -I proto/ proto/$name.proto
|
||||
|
||||
echo "pub mod $name;" >> src/lib.rs
|
||||
echo " (\"$src\", $checksum)," >> files.rs
|
||||
done
|
||||
|
||||
echo "];" >> files.rs
|
|
@ -4965,84 +4965,83 @@ impl ::protobuf::reflect::ProtobufValue for AccountType {
|
|||
}
|
||||
|
||||
static file_descriptor_proto_data: &'static [u8] = b"\
|
||||
\n\x14authentication.proto\"\xec\x03\n\x17ClientResponseEncrypted\x12>\n\
|
||||
\x11login_credentials\x18\n\x20\x02(\x0b2\x11.LoginCredentialsR\x10login\
|
||||
Credentials\x12;\n\x10account_creation\x18\x14\x20\x01(\x0e2\x10.Account\
|
||||
CreationR\x0faccountCreation\x12L\n\x14fingerprint_response\x18\x1e\x20\
|
||||
\x01(\x0b2\x19.FingerprintResponseUnionR\x13fingerprintResponse\x121\n\
|
||||
\x0bpeer_ticket\x18(\x20\x01(\x0b2\x10.PeerTicketUnionR\npeerTicket\x12,\
|
||||
\n\x0bsystem_info\x182\x20\x02(\x0b2\x0b.SystemInfoR\nsystemInfo\x12%\n\
|
||||
\x0eplatform_model\x18<\x20\x01(\tR\rplatformModel\x12%\n\x0eversion_str\
|
||||
ing\x18F\x20\x01(\tR\rversionString\x12)\n\x06appkey\x18P\x20\x01(\x0b2\
|
||||
\x11.LibspotifyAppKeyR\x06appkey\x12,\n\x0bclient_info\x18Z\x20\x01(\x0b\
|
||||
2\x0b.ClientInfoR\nclientInfo\"r\n\x10LoginCredentials\x12\x1a\n\x08user\
|
||||
name\x18\n\x20\x01(\tR\x08username\x12%\n\x03typ\x18\x14\x20\x02(\x0e2\
|
||||
\x13.AuthenticationTypeR\x03typ\x12\x1b\n\tauth_data\x18\x1e\x20\x01(\
|
||||
\x0cR\x08authData\"\x8c\x01\n\x18FingerprintResponseUnion\x12/\n\x05grai\
|
||||
n\x18\n\x20\x01(\x0b2\x19.FingerprintGrainResponseR\x05grain\x12?\n\x0bh\
|
||||
mac_ripemd\x18\x14\x20\x01(\x0b2\x1e.FingerprintHmacRipemdResponseR\nhma\
|
||||
cRipemd\"?\n\x18FingerprintGrainResponse\x12#\n\rencrypted_key\x18\n\x20\
|
||||
\x02(\x0cR\x0cencryptedKey\"3\n\x1dFingerprintHmacRipemdResponse\x12\x12\
|
||||
\n\x04hmac\x18\n\x20\x02(\x0cR\x04hmac\"u\n\x0fPeerTicketUnion\x123\n\np\
|
||||
ublic_key\x18\n\x20\x01(\x0b2\x14.PeerTicketPublicKeyR\tpublicKey\x12-\n\
|
||||
\nold_ticket\x18\x14\x20\x01(\x0b2\x0e.PeerTicketOldR\toldTicket\"4\n\
|
||||
\x13PeerTicketPublicKey\x12\x1d\n\npublic_key\x18\n\x20\x02(\x0cR\tpubli\
|
||||
cKey\"d\n\rPeerTicketOld\x12\x1f\n\x0bpeer_ticket\x18\n\x20\x02(\x0cR\np\
|
||||
eerTicket\x122\n\x15peer_ticket_signature\x18\x14\x20\x02(\x0cR\x13peerT\
|
||||
icketSignature\"\xd4\x02\n\nSystemInfo\x12)\n\ncpu_family\x18\n\x20\x02(\
|
||||
\x0e2\n.CpuFamilyR\tcpuFamily\x12\x1f\n\x0bcpu_subtype\x18\x14\x20\x01(\
|
||||
\rR\ncpuSubtype\x12\x17\n\x07cpu_ext\x18\x1e\x20\x01(\rR\x06cpuExt\x12\
|
||||
\x1c\n\x05brand\x18(\x20\x01(\x0e2\x06.BrandR\x05brand\x12\x1f\n\x0bbran\
|
||||
d_flags\x182\x20\x01(\rR\nbrandFlags\x12\x13\n\x02os\x18<\x20\x02(\x0e2\
|
||||
\x03.OsR\x02os\x12\x1d\n\nos_version\x18F\x20\x01(\rR\tosVersion\x12\x15\
|
||||
\n\x06os_ext\x18P\x20\x01(\rR\x05osExt\x12:\n\x19system_information_stri\
|
||||
ng\x18Z\x20\x01(\tR\x17systemInformationString\x12\x1b\n\tdevice_id\x18d\
|
||||
\x20\x01(\tR\x08deviceId\"\xa5\x01\n\x10LibspotifyAppKey\x12\x18\n\x07ve\
|
||||
rsion\x18\x01\x20\x02(\rR\x07version\x12\x16\n\x06devkey\x18\x02\x20\x02\
|
||||
(\x0cR\x06devkey\x12\x1c\n\tsignature\x18\x03\x20\x02(\x0cR\tsignature\
|
||||
\x12\x1c\n\tuseragent\x18\x04\x20\x02(\tR\tuseragent\x12#\n\rcallback_ha\
|
||||
sh\x18\x05\x20\x02(\x0cR\x0ccallbackHash\"g\n\nClientInfo\x12\x18\n\x07l\
|
||||
imited\x18\x01\x20\x01(\x08R\x07limited\x12#\n\x02fb\x18\x02\x20\x01(\
|
||||
\x0b2\x13.ClientInfoFacebookR\x02fb\x12\x1a\n\x08language\x18\x03\x20\
|
||||
\x01(\tR\x08language\"3\n\x12ClientInfoFacebook\x12\x1d\n\nmachine_id\
|
||||
\x18\x01\x20\x01(\tR\tmachineId\"\xd4\x03\n\tAPWelcome\x12-\n\x12canonic\
|
||||
al_username\x18\n\x20\x02(\tR\x11canonicalUsername\x12A\n\x16account_typ\
|
||||
e_logged_in\x18\x14\x20\x02(\x0e2\x0c.AccountTypeR\x13accountTypeLoggedI\
|
||||
n\x12I\n\x1acredentials_type_logged_in\x18\x19\x20\x02(\x0e2\x0c.Account\
|
||||
TypeR\x17credentialsTypeLoggedIn\x12X\n\x1ereusable_auth_credentials_typ\
|
||||
e\x18\x1e\x20\x02(\x0e2\x13.AuthenticationTypeR\x1breusableAuthCredentia\
|
||||
lsType\x12:\n\x19reusable_auth_credentials\x18(\x20\x02(\x0cR\x17reusabl\
|
||||
eAuthCredentials\x12\x1d\n\nlfs_secret\x182\x20\x01(\x0cR\tlfsSecret\x12\
|
||||
/\n\x0caccount_info\x18<\x20\x01(\x0b2\x0c.AccountInfoR\x0baccountInfo\
|
||||
\x12$\n\x02fb\x18F\x20\x01(\x0b2\x14.AccountInfoFacebookR\x02fb\"n\n\x0b\
|
||||
AccountInfo\x12-\n\x07spotify\x18\x01\x20\x01(\x0b2\x13.AccountInfoSpoti\
|
||||
fyR\x07spotify\x120\n\x08facebook\x18\x02\x20\x01(\x0b2\x14.AccountInfoF\
|
||||
acebookR\x08facebook\"\x14\n\x12AccountInfoSpotify\"W\n\x13AccountInfoFa\
|
||||
cebook\x12!\n\x0caccess_token\x18\x01\x20\x01(\tR\x0baccessToken\x12\x1d\
|
||||
\n\nmachine_id\x18\x02\x20\x01(\tR\tmachineId*\xd6\x01\n\x12Authenticati\
|
||||
onType\x12\x1c\n\x18AUTHENTICATION_USER_PASS\x10\0\x12-\n)AUTHENTICATION\
|
||||
_STORED_SPOTIFY_CREDENTIALS\x10\x01\x12.\n*AUTHENTICATION_STORED_FACEBOO\
|
||||
K_CREDENTIALS\x10\x02\x12\x20\n\x1cAUTHENTICATION_SPOTIFY_TOKEN\x10\x03\
|
||||
\x12!\n\x1dAUTHENTICATION_FACEBOOK_TOKEN\x10\x04*Y\n\x0fAccountCreation\
|
||||
\x12\"\n\x1eACCOUNT_CREATION_ALWAYS_PROMPT\x10\x01\x12\"\n\x1eACCOUNT_CR\
|
||||
EATION_ALWAYS_CREATE\x10\x03*\x9d\x01\n\tCpuFamily\x12\x0f\n\x0bCPU_UNKN\
|
||||
OWN\x10\0\x12\x0b\n\x07CPU_X86\x10\x01\x12\x0e\n\nCPU_X86_64\x10\x02\x12\
|
||||
\x0b\n\x07CPU_PPC\x10\x03\x12\x0e\n\nCPU_PPC_64\x10\x04\x12\x0b\n\x07CPU\
|
||||
_ARM\x10\x05\x12\x0c\n\x08CPU_IA64\x10\x06\x12\n\n\x06CPU_SH\x10\x07\x12\
|
||||
\x0c\n\x08CPU_MIPS\x10\x08\x12\x10\n\x0cCPU_BLACKFIN\x10\t*K\n\x05Brand\
|
||||
\x12\x13\n\x0fBRAND_UNBRANDED\x10\0\x12\r\n\tBRAND_INQ\x10\x01\x12\r\n\t\
|
||||
BRAND_HTC\x10\x02\x12\x0f\n\x0bBRAND_NOKIA\x10\x03*\xd1\x02\n\x02Os\x12\
|
||||
\x0e\n\nOS_UNKNOWN\x10\0\x12\x0e\n\nOS_WINDOWS\x10\x01\x12\n\n\x06OS_OSX\
|
||||
\x10\x02\x12\r\n\tOS_IPHONE\x10\x03\x12\n\n\x06OS_S60\x10\x04\x12\x0c\n\
|
||||
\x08OS_LINUX\x10\x05\x12\x11\n\rOS_WINDOWS_CE\x10\x06\x12\x0e\n\nOS_ANDR\
|
||||
OID\x10\x07\x12\x0b\n\x07OS_PALM\x10\x08\x12\x0e\n\nOS_FREEBSD\x10\t\x12\
|
||||
\x11\n\rOS_BLACKBERRY\x10\n\x12\x0c\n\x08OS_SONOS\x10\x0b\x12\x0f\n\x0bO\
|
||||
S_LOGITECH\x10\x0c\x12\n\n\x06OS_WP7\x10\r\x12\x0c\n\x08OS_ONKYO\x10\x0e\
|
||||
\x12\x0e\n\nOS_PHILIPS\x10\x0f\x12\t\n\x05OS_WD\x10\x10\x12\x0c\n\x08OS_\
|
||||
VOLVO\x10\x11\x12\x0b\n\x07OS_TIVO\x10\x12\x12\x0b\n\x07OS_AWOX\x10\x13\
|
||||
\x12\x0c\n\x08OS_MEEGO\x10\x14\x12\r\n\tOS_QNXNTO\x10\x15\x12\n\n\x06OS_\
|
||||
BCO\x10\x16*(\n\x0bAccountType\x12\x0b\n\x07Spotify\x10\0\x12\x0c\n\x08F\
|
||||
acebook\x10\x01\
|
||||
\n\x14authentication.proto\x12\0\"\x8e\x03\n\x17ClientResponseEncrypted\
|
||||
\x120\n\x11login_credentials\x18\n\x20\x02(\x0b2\x11.LoginCredentialsB\
|
||||
\x02\x18\0\x12.\n\x10account_creation\x18\x14\x20\x01(\x0e2\x10.AccountC\
|
||||
reationB\x02\x18\0\x12;\n\x14fingerprint_response\x18\x1e\x20\x01(\x0b2\
|
||||
\x19.FingerprintResponseUnionB\x02\x18\0\x12)\n\x0bpeer_ticket\x18(\x20\
|
||||
\x01(\x0b2\x10.PeerTicketUnionB\x02\x18\0\x12$\n\x0bsystem_info\x182\x20\
|
||||
\x02(\x0b2\x0b.SystemInfoB\x02\x18\0\x12\x1a\n\x0eplatform_model\x18<\
|
||||
\x20\x01(\tB\x02\x18\0\x12\x1a\n\x0eversion_string\x18F\x20\x01(\tB\x02\
|
||||
\x18\0\x12%\n\x06appkey\x18P\x20\x01(\x0b2\x11.LibspotifyAppKeyB\x02\x18\
|
||||
\0\x12$\n\x0bclient_info\x18Z\x20\x01(\x0b2\x0b.ClientInfoB\x02\x18\0\"e\
|
||||
\n\x10LoginCredentials\x12\x14\n\x08username\x18\n\x20\x01(\tB\x02\x18\0\
|
||||
\x12$\n\x03typ\x18\x14\x20\x02(\x0e2\x13.AuthenticationTypeB\x02\x18\0\
|
||||
\x12\x15\n\tauth_data\x18\x1e\x20\x01(\x0cB\x02\x18\0\"\x81\x01\n\x18Fin\
|
||||
gerprintResponseUnion\x12,\n\x05grain\x18\n\x20\x01(\x0b2\x19.Fingerprin\
|
||||
tGrainResponseB\x02\x18\0\x127\n\x0bhmac_ripemd\x18\x14\x20\x01(\x0b2\
|
||||
\x1e.FingerprintHmacRipemdResponseB\x02\x18\0\"5\n\x18FingerprintGrainRe\
|
||||
sponse\x12\x19\n\rencrypted_key\x18\n\x20\x02(\x0cB\x02\x18\0\"1\n\x1dFi\
|
||||
ngerprintHmacRipemdResponse\x12\x10\n\x04hmac\x18\n\x20\x02(\x0cB\x02\
|
||||
\x18\0\"g\n\x0fPeerTicketUnion\x12,\n\npublic_key\x18\n\x20\x01(\x0b2\
|
||||
\x14.PeerTicketPublicKeyB\x02\x18\0\x12&\n\nold_ticket\x18\x14\x20\x01(\
|
||||
\x0b2\x0e.PeerTicketOldB\x02\x18\0\"-\n\x13PeerTicketPublicKey\x12\x16\n\
|
||||
\npublic_key\x18\n\x20\x02(\x0cB\x02\x18\0\"K\n\rPeerTicketOld\x12\x17\n\
|
||||
\x0bpeer_ticket\x18\n\x20\x02(\x0cB\x02\x18\0\x12!\n\x15peer_ticket_sign\
|
||||
ature\x18\x14\x20\x02(\x0cB\x02\x18\0\"\x91\x02\n\nSystemInfo\x12\"\n\nc\
|
||||
pu_family\x18\n\x20\x02(\x0e2\n.CpuFamilyB\x02\x18\0\x12\x17\n\x0bcpu_su\
|
||||
btype\x18\x14\x20\x01(\rB\x02\x18\0\x12\x13\n\x07cpu_ext\x18\x1e\x20\x01\
|
||||
(\rB\x02\x18\0\x12\x19\n\x05brand\x18(\x20\x01(\x0e2\x06.BrandB\x02\x18\
|
||||
\0\x12\x17\n\x0bbrand_flags\x182\x20\x01(\rB\x02\x18\0\x12\x13\n\x02os\
|
||||
\x18<\x20\x02(\x0e2\x03.OsB\x02\x18\0\x12\x16\n\nos_version\x18F\x20\x01\
|
||||
(\rB\x02\x18\0\x12\x12\n\x06os_ext\x18P\x20\x01(\rB\x02\x18\0\x12%\n\x19\
|
||||
system_information_string\x18Z\x20\x01(\tB\x02\x18\0\x12\x15\n\tdevice_i\
|
||||
d\x18d\x20\x01(\tB\x02\x18\0\"\x84\x01\n\x10LibspotifyAppKey\x12\x13\n\
|
||||
\x07version\x18\x01\x20\x02(\rB\x02\x18\0\x12\x12\n\x06devkey\x18\x02\
|
||||
\x20\x02(\x0cB\x02\x18\0\x12\x15\n\tsignature\x18\x03\x20\x02(\x0cB\x02\
|
||||
\x18\0\x12\x15\n\tuseragent\x18\x04\x20\x02(\tB\x02\x18\0\x12\x19\n\rcal\
|
||||
lback_hash\x18\x05\x20\x02(\x0cB\x02\x18\0\"\\\n\nClientInfo\x12\x13\n\
|
||||
\x07limited\x18\x01\x20\x01(\x08B\x02\x18\0\x12#\n\x02fb\x18\x02\x20\x01\
|
||||
(\x0b2\x13.ClientInfoFacebookB\x02\x18\0\x12\x14\n\x08language\x18\x03\
|
||||
\x20\x01(\tB\x02\x18\0\",\n\x12ClientInfoFacebook\x12\x16\n\nmachine_id\
|
||||
\x18\x01\x20\x01(\tB\x02\x18\0\"\xe1\x02\n\tAPWelcome\x12\x1e\n\x12canon\
|
||||
ical_username\x18\n\x20\x02(\tB\x02\x18\0\x120\n\x16account_type_logged_\
|
||||
in\x18\x14\x20\x02(\x0e2\x0c.AccountTypeB\x02\x18\0\x124\n\x1acredential\
|
||||
s_type_logged_in\x18\x19\x20\x02(\x0e2\x0c.AccountTypeB\x02\x18\0\x12?\n\
|
||||
\x1ereusable_auth_credentials_type\x18\x1e\x20\x02(\x0e2\x13.Authenticat\
|
||||
ionTypeB\x02\x18\0\x12%\n\x19reusable_auth_credentials\x18(\x20\x02(\x0c\
|
||||
B\x02\x18\0\x12\x16\n\nlfs_secret\x182\x20\x01(\x0cB\x02\x18\0\x12&\n\
|
||||
\x0caccount_info\x18<\x20\x01(\x0b2\x0c.AccountInfoB\x02\x18\0\x12$\n\
|
||||
\x02fb\x18F\x20\x01(\x0b2\x14.AccountInfoFacebookB\x02\x18\0\"c\n\x0bAcc\
|
||||
ountInfo\x12(\n\x07spotify\x18\x01\x20\x01(\x0b2\x13.AccountInfoSpotifyB\
|
||||
\x02\x18\0\x12*\n\x08facebook\x18\x02\x20\x01(\x0b2\x14.AccountInfoFaceb\
|
||||
ookB\x02\x18\0\"\x14\n\x12AccountInfoSpotify\"G\n\x13AccountInfoFacebook\
|
||||
\x12\x18\n\x0caccess_token\x18\x01\x20\x01(\tB\x02\x18\0\x12\x16\n\nmach\
|
||||
ine_id\x18\x02\x20\x01(\tB\x02\x18\0*\xda\x01\n\x12AuthenticationType\
|
||||
\x12\x1c\n\x18AUTHENTICATION_USER_PASS\x10\0\x12-\n)AUTHENTICATION_STORE\
|
||||
D_SPOTIFY_CREDENTIALS\x10\x01\x12.\n*AUTHENTICATION_STORED_FACEBOOK_CRED\
|
||||
ENTIALS\x10\x02\x12\x20\n\x1cAUTHENTICATION_SPOTIFY_TOKEN\x10\x03\x12!\n\
|
||||
\x1dAUTHENTICATION_FACEBOOK_TOKEN\x10\x04\x1a\x02\x10\0*]\n\x0fAccountCr\
|
||||
eation\x12\"\n\x1eACCOUNT_CREATION_ALWAYS_PROMPT\x10\x01\x12\"\n\x1eACCO\
|
||||
UNT_CREATION_ALWAYS_CREATE\x10\x03\x1a\x02\x10\0*\xa1\x01\n\tCpuFamily\
|
||||
\x12\x0f\n\x0bCPU_UNKNOWN\x10\0\x12\x0b\n\x07CPU_X86\x10\x01\x12\x0e\n\n\
|
||||
CPU_X86_64\x10\x02\x12\x0b\n\x07CPU_PPC\x10\x03\x12\x0e\n\nCPU_PPC_64\
|
||||
\x10\x04\x12\x0b\n\x07CPU_ARM\x10\x05\x12\x0c\n\x08CPU_IA64\x10\x06\x12\
|
||||
\n\n\x06CPU_SH\x10\x07\x12\x0c\n\x08CPU_MIPS\x10\x08\x12\x10\n\x0cCPU_BL\
|
||||
ACKFIN\x10\t\x1a\x02\x10\0*O\n\x05Brand\x12\x13\n\x0fBRAND_UNBRANDED\x10\
|
||||
\0\x12\r\n\tBRAND_INQ\x10\x01\x12\r\n\tBRAND_HTC\x10\x02\x12\x0f\n\x0bBR\
|
||||
AND_NOKIA\x10\x03\x1a\x02\x10\0*\xd5\x02\n\x02Os\x12\x0e\n\nOS_UNKNOWN\
|
||||
\x10\0\x12\x0e\n\nOS_WINDOWS\x10\x01\x12\n\n\x06OS_OSX\x10\x02\x12\r\n\t\
|
||||
OS_IPHONE\x10\x03\x12\n\n\x06OS_S60\x10\x04\x12\x0c\n\x08OS_LINUX\x10\
|
||||
\x05\x12\x11\n\rOS_WINDOWS_CE\x10\x06\x12\x0e\n\nOS_ANDROID\x10\x07\x12\
|
||||
\x0b\n\x07OS_PALM\x10\x08\x12\x0e\n\nOS_FREEBSD\x10\t\x12\x11\n\rOS_BLAC\
|
||||
KBERRY\x10\n\x12\x0c\n\x08OS_SONOS\x10\x0b\x12\x0f\n\x0bOS_LOGITECH\x10\
|
||||
\x0c\x12\n\n\x06OS_WP7\x10\r\x12\x0c\n\x08OS_ONKYO\x10\x0e\x12\x0e\n\nOS\
|
||||
_PHILIPS\x10\x0f\x12\t\n\x05OS_WD\x10\x10\x12\x0c\n\x08OS_VOLVO\x10\x11\
|
||||
\x12\x0b\n\x07OS_TIVO\x10\x12\x12\x0b\n\x07OS_AWOX\x10\x13\x12\x0c\n\x08\
|
||||
OS_MEEGO\x10\x14\x12\r\n\tOS_QNXNTO\x10\x15\x12\n\n\x06OS_BCO\x10\x16\
|
||||
\x1a\x02\x10\0*,\n\x0bAccountType\x12\x0b\n\x07Spotify\x10\0\x12\x0c\n\
|
||||
\x08Facebook\x10\x01\x1a\x02\x10\0B\0b\x06proto2\
|
||||
";
|
||||
|
||||
static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy {
|
||||
|
|
|
@ -6705,105 +6705,103 @@ impl ::protobuf::reflect::ProtobufValue for ErrorCode {
|
|||
}
|
||||
|
||||
static file_descriptor_proto_data: &'static [u8] = b"\
|
||||
\n\x11keyexchange.proto\"\xb2\x03\n\x0bClientHello\x12)\n\nbuild_info\
|
||||
\x18\n\x20\x02(\x0b2\n.BuildInfoR\tbuildInfo\x12C\n\x16fingerprints_supp\
|
||||
orted\x18\x14\x20\x03(\x0e2\x0c.FingerprintR\x15fingerprintsSupported\
|
||||
\x12C\n\x16cryptosuites_supported\x18\x1e\x20\x03(\x0e2\x0c.CryptosuiteR\
|
||||
\x15cryptosuitesSupported\x12=\n\x14powschemes_supported\x18(\x20\x03(\
|
||||
\x0e2\n.PowschemeR\x13powschemesSupported\x12D\n\x12login_crypto_hello\
|
||||
\x182\x20\x02(\x0b2\x16.LoginCryptoHelloUnionR\x10loginCryptoHello\x12!\
|
||||
\n\x0cclient_nonce\x18<\x20\x02(\x0cR\x0bclientNonce\x12\x18\n\x07paddin\
|
||||
g\x18F\x20\x01(\x0cR\x07padding\x12,\n\x0bfeature_set\x18P\x20\x01(\x0b2\
|
||||
\x0b.FeatureSetR\nfeatureSet\"\xa4\x01\n\tBuildInfo\x12\"\n\x07product\
|
||||
\x18\n\x20\x02(\x0e2\x08.ProductR\x07product\x122\n\rproduct_flags\x18\
|
||||
\x14\x20\x03(\x0e2\r.ProductFlagsR\x0cproductFlags\x12%\n\x08platform\
|
||||
\x18\x1e\x20\x02(\x0e2\t.PlatformR\x08platform\x12\x18\n\x07version\x18(\
|
||||
\x20\x02(\x04R\x07version\"^\n\x15LoginCryptoHelloUnion\x12E\n\x0ediffie\
|
||||
_hellman\x18\n\x20\x01(\x0b2\x1e.LoginCryptoDiffieHellmanHelloR\rdiffieH\
|
||||
ellman\"[\n\x1dLoginCryptoDiffieHellmanHello\x12\x0e\n\x02gc\x18\n\x20\
|
||||
\x02(\x0cR\x02gc\x12*\n\x11server_keys_known\x18\x14\x20\x02(\rR\x0fserv\
|
||||
erKeysKnown\"Y\n\nFeatureSet\x12\x20\n\x0bautoupdate2\x18\x01\x20\x01(\
|
||||
\x08R\x0bautoupdate2\x12)\n\x10current_location\x18\x02\x20\x01(\x08R\
|
||||
\x0fcurrentLocation\"\xa5\x01\n\x11APResponseMessage\x12*\n\tchallenge\
|
||||
\x18\n\x20\x01(\x0b2\x0c.APChallengeR\tchallenge\x121\n\x07upgrade\x18\
|
||||
\x14\x20\x01(\x0b2\x17.UpgradeRequiredMessageR\x07upgrade\x121\n\x0clogi\
|
||||
n_failed\x18\x1e\x20\x01(\x0b2\x0e.APLoginFailedR\x0bloginFailed\"\xe8\
|
||||
\x02\n\x0bAPChallenge\x12P\n\x16login_crypto_challenge\x18\n\x20\x02(\
|
||||
\x0b2\x1a.LoginCryptoChallengeUnionR\x14loginCryptoChallenge\x12O\n\x15f\
|
||||
ingerprint_challenge\x18\x14\x20\x02(\x0b2\x1a.FingerprintChallengeUnion\
|
||||
R\x14fingerprintChallenge\x127\n\rpow_challenge\x18\x1e\x20\x02(\x0b2\
|
||||
\x12.PoWChallengeUnionR\x0cpowChallenge\x12@\n\x10crypto_challenge\x18(\
|
||||
\x20\x02(\x0b2\x15.CryptoChallengeUnionR\x0fcryptoChallenge\x12!\n\x0cse\
|
||||
rver_nonce\x182\x20\x02(\x0cR\x0bserverNonce\x12\x18\n\x07padding\x18<\
|
||||
\x20\x01(\x0cR\x07padding\"f\n\x19LoginCryptoChallengeUnion\x12I\n\x0edi\
|
||||
ffie_hellman\x18\n\x20\x01(\x0b2\".LoginCryptoDiffieHellmanChallengeR\rd\
|
||||
iffieHellman\"\x88\x01\n!LoginCryptoDiffieHellmanChallenge\x12\x0e\n\x02\
|
||||
gs\x18\n\x20\x02(\x0cR\x02gs\x120\n\x14server_signature_key\x18\x14\x20\
|
||||
\x02(\x05R\x12serverSignatureKey\x12!\n\x0cgs_signature\x18\x1e\x20\x02(\
|
||||
\x0cR\x0bgsSignature\"\x8f\x01\n\x19FingerprintChallengeUnion\x120\n\x05\
|
||||
grain\x18\n\x20\x01(\x0b2\x1a.FingerprintGrainChallengeR\x05grain\x12@\n\
|
||||
\x0bhmac_ripemd\x18\x14\x20\x01(\x0b2\x1f.FingerprintHmacRipemdChallenge\
|
||||
R\nhmacRipemd\"-\n\x19FingerprintGrainChallenge\x12\x10\n\x03kek\x18\n\
|
||||
\x20\x02(\x0cR\x03kek\">\n\x1eFingerprintHmacRipemdChallenge\x12\x1c\n\t\
|
||||
challenge\x18\n\x20\x02(\x0cR\tchallenge\"G\n\x11PoWChallengeUnion\x122\
|
||||
\n\thash_cash\x18\n\x20\x01(\x0b2\x15.PoWHashCashChallengeR\x08hashCash\
|
||||
\"^\n\x14PoWHashCashChallenge\x12\x16\n\x06prefix\x18\n\x20\x01(\x0cR\
|
||||
\x06prefix\x12\x16\n\x06length\x18\x14\x20\x01(\x05R\x06length\x12\x16\n\
|
||||
\x06target\x18\x1e\x20\x01(\x05R\x06target\"\x8a\x01\n\x14CryptoChalleng\
|
||||
eUnion\x121\n\x07shannon\x18\n\x20\x01(\x0b2\x17.CryptoShannonChallengeR\
|
||||
\x07shannon\x12?\n\rrc4_sha1_hmac\x18\x14\x20\x01(\x0b2\x1b.CryptoRc4Sha\
|
||||
1HmacChallengeR\x0brc4Sha1Hmac\"\x18\n\x16CryptoShannonChallenge\"\x1c\n\
|
||||
\x1aCryptoRc4Sha1HmacChallenge\"\x87\x01\n\x16UpgradeRequiredMessage\x12\
|
||||
.\n\x13upgrade_signed_part\x18\n\x20\x02(\x0cR\x11upgradeSignedPart\x12\
|
||||
\x1c\n\tsignature\x18\x14\x20\x02(\x0cR\tsignature\x12\x1f\n\x0bhttp_suf\
|
||||
fix\x18\x1e\x20\x01(\tR\nhttpSuffix\"\xa0\x01\n\rAPLoginFailed\x12)\n\ne\
|
||||
rror_code\x18\n\x20\x02(\x0e2\n.ErrorCodeR\terrorCode\x12\x1f\n\x0bretry\
|
||||
_delay\x18\x14\x20\x01(\x05R\nretryDelay\x12\x16\n\x06expiry\x18\x1e\x20\
|
||||
\x01(\x05R\x06expiry\x12+\n\x11error_description\x18(\x20\x01(\tR\x10err\
|
||||
orDescription\"\xdd\x01\n\x17ClientResponsePlaintext\x12M\n\x15login_cry\
|
||||
pto_response\x18\n\x20\x02(\x0b2\x19.LoginCryptoResponseUnionR\x13loginC\
|
||||
ryptoResponse\x124\n\x0cpow_response\x18\x14\x20\x02(\x0b2\x11.PoWRespon\
|
||||
seUnionR\x0bpowResponse\x12=\n\x0fcrypto_response\x18\x1e\x20\x02(\x0b2\
|
||||
\x14.CryptoResponseUnionR\x0ecryptoResponse\"d\n\x18LoginCryptoResponseU\
|
||||
nion\x12H\n\x0ediffie_hellman\x18\n\x20\x01(\x0b2!.LoginCryptoDiffieHell\
|
||||
manResponseR\rdiffieHellman\"6\n\x20LoginCryptoDiffieHellmanResponse\x12\
|
||||
\x12\n\x04hmac\x18\n\x20\x02(\x0cR\x04hmac\"E\n\x10PoWResponseUnion\x121\
|
||||
\n\thash_cash\x18\n\x20\x01(\x0b2\x14.PoWHashCashResponseR\x08hashCash\"\
|
||||
6\n\x13PoWHashCashResponse\x12\x1f\n\x0bhash_suffix\x18\n\x20\x02(\x0cR\
|
||||
\nhashSuffix\"\x87\x01\n\x13CryptoResponseUnion\x120\n\x07shannon\x18\n\
|
||||
\x20\x01(\x0b2\x16.CryptoShannonResponseR\x07shannon\x12>\n\rrc4_sha1_hm\
|
||||
ac\x18\x14\x20\x01(\x0b2\x1a.CryptoRc4Sha1HmacResponseR\x0brc4Sha1Hmac\"\
|
||||
-\n\x15CryptoShannonResponse\x12\x14\n\x05dummy\x18\x01\x20\x01(\x05R\
|
||||
\x05dummy\"1\n\x19CryptoRc4Sha1HmacResponse\x12\x14\n\x05dummy\x18\x01\
|
||||
\x20\x01(\x05R\x05dummy*\x7f\n\x07Product\x12\x12\n\x0ePRODUCT_CLIENT\
|
||||
\x10\0\x12\x16\n\x12PRODUCT_LIBSPOTIFY\x10\x01\x12\x12\n\x0ePRODUCT_MOBI\
|
||||
LE\x10\x02\x12\x13\n\x0fPRODUCT_PARTNER\x10\x03\x12\x1f\n\x1bPRODUCT_LIB\
|
||||
SPOTIFY_EMBEDDED\x10\x05*A\n\x0cProductFlags\x12\x15\n\x11PRODUCT_FLAG_N\
|
||||
ONE\x10\0\x12\x1a\n\x16PRODUCT_FLAG_DEV_BUILD\x10\x01*\xdc\x04\n\x08Plat\
|
||||
form\x12\x16\n\x12PLATFORM_WIN32_X86\x10\0\x12\x14\n\x10PLATFORM_OSX_X86\
|
||||
\x10\x01\x12\x16\n\x12PLATFORM_LINUX_X86\x10\x02\x12\x17\n\x13PLATFORM_I\
|
||||
PHONE_ARM\x10\x03\x12\x14\n\x10PLATFORM_S60_ARM\x10\x04\x12\x14\n\x10PLA\
|
||||
TFORM_OSX_PPC\x10\x05\x12\x18\n\x14PLATFORM_ANDROID_ARM\x10\x06\x12\x1b\
|
||||
\n\x17PLATFORM_WINDOWS_CE_ARM\x10\x07\x12\x19\n\x15PLATFORM_LINUX_X86_64\
|
||||
\x10\x08\x12\x17\n\x13PLATFORM_OSX_X86_64\x10\t\x12\x15\n\x11PLATFORM_PA\
|
||||
LM_ARM\x10\n\x12\x15\n\x11PLATFORM_LINUX_SH\x10\x0b\x12\x18\n\x14PLATFOR\
|
||||
M_FREEBSD_X86\x10\x0c\x12\x1b\n\x17PLATFORM_FREEBSD_X86_64\x10\r\x12\x1b\
|
||||
\n\x17PLATFORM_BLACKBERRY_ARM\x10\x0e\x12\x12\n\x0ePLATFORM_SONOS\x10\
|
||||
\x0f\x12\x17\n\x13PLATFORM_LINUX_MIPS\x10\x10\x12\x16\n\x12PLATFORM_LINU\
|
||||
X_ARM\x10\x11\x12\x19\n\x15PLATFORM_LOGITECH_ARM\x10\x12\x12\x1b\n\x17PL\
|
||||
ATFORM_LINUX_BLACKFIN\x10\x13\x12\x14\n\x10PLATFORM_WP7_ARM\x10\x14\x12\
|
||||
\x16\n\x12PLATFORM_ONKYO_ARM\x10\x15\x12\x17\n\x13PLATFORM_QNXNTO_ARM\
|
||||
\x10\x16\x12\x14\n\x10PLATFORM_BCO_ARM\x10\x17*A\n\x0bFingerprint\x12\
|
||||
\x15\n\x11FINGERPRINT_GRAIN\x10\0\x12\x1b\n\x17FINGERPRINT_HMAC_RIPEMD\
|
||||
\x10\x01*G\n\x0bCryptosuite\x12\x18\n\x14CRYPTO_SUITE_SHANNON\x10\0\x12\
|
||||
\x1e\n\x1aCRYPTO_SUITE_RC4_SHA1_HMAC\x10\x01*\x1e\n\tPowscheme\x12\x11\n\
|
||||
\rPOW_HASH_CASH\x10\0*\x89\x02\n\tErrorCode\x12\x11\n\rProtocolError\x10\
|
||||
\0\x12\x10\n\x0cTryAnotherAP\x10\x02\x12\x13\n\x0fBadConnectionId\x10\
|
||||
\x05\x12\x15\n\x11TravelRestriction\x10\t\x12\x1a\n\x16PremiumAccountReq\
|
||||
uired\x10\x0b\x12\x12\n\x0eBadCredentials\x10\x0c\x12\x1f\n\x1bCouldNotV\
|
||||
alidateCredentials\x10\r\x12\x11\n\rAccountExists\x10\x0e\x12\x1d\n\x19E\
|
||||
xtraVerificationRequired\x10\x0f\x12\x11\n\rInvalidAppKey\x10\x10\x12\
|
||||
\x15\n\x11ApplicationBanned\x10\x11\
|
||||
\n\x11keyexchange.proto\x12\0\"\xd0\x02\n\x0bClientHello\x12\"\n\nbuild_\
|
||||
info\x18\n\x20\x02(\x0b2\n.BuildInfoB\x02\x18\0\x120\n\x16fingerprints_s\
|
||||
upported\x18\x14\x20\x03(\x0e2\x0c.FingerprintB\x02\x18\0\x120\n\x16cryp\
|
||||
tosuites_supported\x18\x1e\x20\x03(\x0e2\x0c.CryptosuiteB\x02\x18\0\x12,\
|
||||
\n\x14powschemes_supported\x18(\x20\x03(\x0e2\n.PowschemeB\x02\x18\0\x12\
|
||||
6\n\x12login_crypto_hello\x182\x20\x02(\x0b2\x16.LoginCryptoHelloUnionB\
|
||||
\x02\x18\0\x12\x18\n\x0cclient_nonce\x18<\x20\x02(\x0cB\x02\x18\0\x12\
|
||||
\x13\n\x07padding\x18F\x20\x01(\x0cB\x02\x18\0\x12$\n\x0bfeature_set\x18\
|
||||
P\x20\x01(\x0b2\x0b.FeatureSetB\x02\x18\0\"\x8a\x01\n\tBuildInfo\x12\x1d\
|
||||
\n\x07product\x18\n\x20\x02(\x0e2\x08.ProductB\x02\x18\0\x12(\n\rproduct\
|
||||
_flags\x18\x14\x20\x03(\x0e2\r.ProductFlagsB\x02\x18\0\x12\x1f\n\x08plat\
|
||||
form\x18\x1e\x20\x02(\x0e2\t.PlatformB\x02\x18\0\x12\x13\n\x07version\
|
||||
\x18(\x20\x02(\x04B\x02\x18\0\"S\n\x15LoginCryptoHelloUnion\x12:\n\x0edi\
|
||||
ffie_hellman\x18\n\x20\x01(\x0b2\x1e.LoginCryptoDiffieHellmanHelloB\x02\
|
||||
\x18\0\"N\n\x1dLoginCryptoDiffieHellmanHello\x12\x0e\n\x02gc\x18\n\x20\
|
||||
\x02(\x0cB\x02\x18\0\x12\x1d\n\x11server_keys_known\x18\x14\x20\x02(\rB\
|
||||
\x02\x18\0\"C\n\nFeatureSet\x12\x17\n\x0bautoupdate2\x18\x01\x20\x01(\
|
||||
\x08B\x02\x18\0\x12\x1c\n\x10current_location\x18\x02\x20\x01(\x08B\x02\
|
||||
\x18\0\"\x90\x01\n\x11APResponseMessage\x12#\n\tchallenge\x18\n\x20\x01(\
|
||||
\x0b2\x0c.APChallengeB\x02\x18\0\x12,\n\x07upgrade\x18\x14\x20\x01(\x0b2\
|
||||
\x17.UpgradeRequiredMessageB\x02\x18\0\x12(\n\x0clogin_failed\x18\x1e\
|
||||
\x20\x01(\x0b2\x0e.APLoginFailedB\x02\x18\0\"\x9f\x02\n\x0bAPChallenge\
|
||||
\x12>\n\x16login_crypto_challenge\x18\n\x20\x02(\x0b2\x1a.LoginCryptoCha\
|
||||
llengeUnionB\x02\x18\0\x12=\n\x15fingerprint_challenge\x18\x14\x20\x02(\
|
||||
\x0b2\x1a.FingerprintChallengeUnionB\x02\x18\0\x12-\n\rpow_challenge\x18\
|
||||
\x1e\x20\x02(\x0b2\x12.PoWChallengeUnionB\x02\x18\0\x123\n\x10crypto_cha\
|
||||
llenge\x18(\x20\x02(\x0b2\x15.CryptoChallengeUnionB\x02\x18\0\x12\x18\n\
|
||||
\x0cserver_nonce\x182\x20\x02(\x0cB\x02\x18\0\x12\x13\n\x07padding\x18<\
|
||||
\x20\x01(\x0cB\x02\x18\0\"[\n\x19LoginCryptoChallengeUnion\x12>\n\x0edif\
|
||||
fie_hellman\x18\n\x20\x01(\x0b2\".LoginCryptoDiffieHellmanChallengeB\x02\
|
||||
\x18\0\"o\n!LoginCryptoDiffieHellmanChallenge\x12\x0e\n\x02gs\x18\n\x20\
|
||||
\x02(\x0cB\x02\x18\0\x12\x20\n\x14server_signature_key\x18\x14\x20\x02(\
|
||||
\x05B\x02\x18\0\x12\x18\n\x0cgs_signature\x18\x1e\x20\x02(\x0cB\x02\x18\
|
||||
\0\"\x84\x01\n\x19FingerprintChallengeUnion\x12-\n\x05grain\x18\n\x20\
|
||||
\x01(\x0b2\x1a.FingerprintGrainChallengeB\x02\x18\0\x128\n\x0bhmac_ripem\
|
||||
d\x18\x14\x20\x01(\x0b2\x1f.FingerprintHmacRipemdChallengeB\x02\x18\0\",\
|
||||
\n\x19FingerprintGrainChallenge\x12\x0f\n\x03kek\x18\n\x20\x02(\x0cB\x02\
|
||||
\x18\0\"7\n\x1eFingerprintHmacRipemdChallenge\x12\x15\n\tchallenge\x18\n\
|
||||
\x20\x02(\x0cB\x02\x18\0\"A\n\x11PoWChallengeUnion\x12,\n\thash_cash\x18\
|
||||
\n\x20\x01(\x0b2\x15.PoWHashCashChallengeB\x02\x18\0\"R\n\x14PoWHashCash\
|
||||
Challenge\x12\x12\n\x06prefix\x18\n\x20\x01(\x0cB\x02\x18\0\x12\x12\n\
|
||||
\x06length\x18\x14\x20\x01(\x05B\x02\x18\0\x12\x12\n\x06target\x18\x1e\
|
||||
\x20\x01(\x05B\x02\x18\0\"|\n\x14CryptoChallengeUnion\x12,\n\x07shannon\
|
||||
\x18\n\x20\x01(\x0b2\x17.CryptoShannonChallengeB\x02\x18\0\x126\n\rrc4_s\
|
||||
ha1_hmac\x18\x14\x20\x01(\x0b2\x1b.CryptoRc4Sha1HmacChallengeB\x02\x18\0\
|
||||
\"\x18\n\x16CryptoShannonChallenge\"\x1c\n\x1aCryptoRc4Sha1HmacChallenge\
|
||||
\"i\n\x16UpgradeRequiredMessage\x12\x1f\n\x13upgrade_signed_part\x18\n\
|
||||
\x20\x02(\x0cB\x02\x18\0\x12\x15\n\tsignature\x18\x14\x20\x02(\x0cB\x02\
|
||||
\x18\0\x12\x17\n\x0bhttp_suffix\x18\x1e\x20\x01(\tB\x02\x18\0\"\x7f\n\rA\
|
||||
PLoginFailed\x12\"\n\nerror_code\x18\n\x20\x02(\x0e2\n.ErrorCodeB\x02\
|
||||
\x18\0\x12\x17\n\x0bretry_delay\x18\x14\x20\x01(\x05B\x02\x18\0\x12\x12\
|
||||
\n\x06expiry\x18\x1e\x20\x01(\x05B\x02\x18\0\x12\x1d\n\x11error_descript\
|
||||
ion\x18(\x20\x01(\tB\x02\x18\0\"\xb7\x01\n\x17ClientResponsePlaintext\
|
||||
\x12<\n\x15login_crypto_response\x18\n\x20\x02(\x0b2\x19.LoginCryptoResp\
|
||||
onseUnionB\x02\x18\0\x12+\n\x0cpow_response\x18\x14\x20\x02(\x0b2\x11.Po\
|
||||
WResponseUnionB\x02\x18\0\x121\n\x0fcrypto_response\x18\x1e\x20\x02(\x0b\
|
||||
2\x14.CryptoResponseUnionB\x02\x18\0\"Y\n\x18LoginCryptoResponseUnion\
|
||||
\x12=\n\x0ediffie_hellman\x18\n\x20\x01(\x0b2!.LoginCryptoDiffieHellmanR\
|
||||
esponseB\x02\x18\0\"4\n\x20LoginCryptoDiffieHellmanResponse\x12\x10\n\
|
||||
\x04hmac\x18\n\x20\x02(\x0cB\x02\x18\0\"?\n\x10PoWResponseUnion\x12+\n\t\
|
||||
hash_cash\x18\n\x20\x01(\x0b2\x14.PoWHashCashResponseB\x02\x18\0\".\n\
|
||||
\x13PoWHashCashResponse\x12\x17\n\x0bhash_suffix\x18\n\x20\x02(\x0cB\x02\
|
||||
\x18\0\"y\n\x13CryptoResponseUnion\x12+\n\x07shannon\x18\n\x20\x01(\x0b2\
|
||||
\x16.CryptoShannonResponseB\x02\x18\0\x125\n\rrc4_sha1_hmac\x18\x14\x20\
|
||||
\x01(\x0b2\x1a.CryptoRc4Sha1HmacResponseB\x02\x18\0\"*\n\x15CryptoShanno\
|
||||
nResponse\x12\x11\n\x05dummy\x18\x01\x20\x01(\x05B\x02\x18\0\".\n\x19Cry\
|
||||
ptoRc4Sha1HmacResponse\x12\x11\n\x05dummy\x18\x01\x20\x01(\x05B\x02\x18\
|
||||
\0*\x83\x01\n\x07Product\x12\x12\n\x0ePRODUCT_CLIENT\x10\0\x12\x16\n\x12\
|
||||
PRODUCT_LIBSPOTIFY\x10\x01\x12\x12\n\x0ePRODUCT_MOBILE\x10\x02\x12\x13\n\
|
||||
\x0fPRODUCT_PARTNER\x10\x03\x12\x1f\n\x1bPRODUCT_LIBSPOTIFY_EMBEDDED\x10\
|
||||
\x05\x1a\x02\x10\0*E\n\x0cProductFlags\x12\x15\n\x11PRODUCT_FLAG_NONE\
|
||||
\x10\0\x12\x1a\n\x16PRODUCT_FLAG_DEV_BUILD\x10\x01\x1a\x02\x10\0*\xe0\
|
||||
\x04\n\x08Platform\x12\x16\n\x12PLATFORM_WIN32_X86\x10\0\x12\x14\n\x10PL\
|
||||
ATFORM_OSX_X86\x10\x01\x12\x16\n\x12PLATFORM_LINUX_X86\x10\x02\x12\x17\n\
|
||||
\x13PLATFORM_IPHONE_ARM\x10\x03\x12\x14\n\x10PLATFORM_S60_ARM\x10\x04\
|
||||
\x12\x14\n\x10PLATFORM_OSX_PPC\x10\x05\x12\x18\n\x14PLATFORM_ANDROID_ARM\
|
||||
\x10\x06\x12\x1b\n\x17PLATFORM_WINDOWS_CE_ARM\x10\x07\x12\x19\n\x15PLATF\
|
||||
ORM_LINUX_X86_64\x10\x08\x12\x17\n\x13PLATFORM_OSX_X86_64\x10\t\x12\x15\
|
||||
\n\x11PLATFORM_PALM_ARM\x10\n\x12\x15\n\x11PLATFORM_LINUX_SH\x10\x0b\x12\
|
||||
\x18\n\x14PLATFORM_FREEBSD_X86\x10\x0c\x12\x1b\n\x17PLATFORM_FREEBSD_X86\
|
||||
_64\x10\r\x12\x1b\n\x17PLATFORM_BLACKBERRY_ARM\x10\x0e\x12\x12\n\x0ePLAT\
|
||||
FORM_SONOS\x10\x0f\x12\x17\n\x13PLATFORM_LINUX_MIPS\x10\x10\x12\x16\n\
|
||||
\x12PLATFORM_LINUX_ARM\x10\x11\x12\x19\n\x15PLATFORM_LOGITECH_ARM\x10\
|
||||
\x12\x12\x1b\n\x17PLATFORM_LINUX_BLACKFIN\x10\x13\x12\x14\n\x10PLATFORM_\
|
||||
WP7_ARM\x10\x14\x12\x16\n\x12PLATFORM_ONKYO_ARM\x10\x15\x12\x17\n\x13PLA\
|
||||
TFORM_QNXNTO_ARM\x10\x16\x12\x14\n\x10PLATFORM_BCO_ARM\x10\x17\x1a\x02\
|
||||
\x10\0*E\n\x0bFingerprint\x12\x15\n\x11FINGERPRINT_GRAIN\x10\0\x12\x1b\n\
|
||||
\x17FINGERPRINT_HMAC_RIPEMD\x10\x01\x1a\x02\x10\0*K\n\x0bCryptosuite\x12\
|
||||
\x18\n\x14CRYPTO_SUITE_SHANNON\x10\0\x12\x1e\n\x1aCRYPTO_SUITE_RC4_SHA1_\
|
||||
HMAC\x10\x01\x1a\x02\x10\0*\"\n\tPowscheme\x12\x11\n\rPOW_HASH_CASH\x10\
|
||||
\0\x1a\x02\x10\0*\x8d\x02\n\tErrorCode\x12\x11\n\rProtocolError\x10\0\
|
||||
\x12\x10\n\x0cTryAnotherAP\x10\x02\x12\x13\n\x0fBadConnectionId\x10\x05\
|
||||
\x12\x15\n\x11TravelRestriction\x10\t\x12\x1a\n\x16PremiumAccountRequire\
|
||||
d\x10\x0b\x12\x12\n\x0eBadCredentials\x10\x0c\x12\x1f\n\x1bCouldNotValid\
|
||||
ateCredentials\x10\r\x12\x11\n\rAccountExists\x10\x0e\x12\x1d\n\x19Extra\
|
||||
VerificationRequired\x10\x0f\x12\x11\n\rInvalidAppKey\x10\x10\x12\x15\n\
|
||||
\x11ApplicationBanned\x10\x11\x1a\x02\x10\0B\0b\x06proto2\
|
||||
";
|
||||
|
||||
static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy {
|
||||
|
|
|
@ -1775,26 +1775,27 @@ impl ::protobuf::reflect::ProtobufValue for UserField {
|
|||
}
|
||||
|
||||
static file_descriptor_proto_data: &'static [u8] = b"\
|
||||
\n\rmercury.proto\"C\n\x16MercuryMultiGetRequest\x12)\n\x07request\x18\
|
||||
\x01\x20\x03(\x0b2\x0f.MercuryRequestR\x07request\";\n\x14MercuryMultiGe\
|
||||
tReply\x12#\n\x05reply\x18\x01\x20\x03(\x0b2\r.MercuryReplyR\x05reply\"m\
|
||||
\n\x0eMercuryRequest\x12\x10\n\x03uri\x18\x01\x20\x01(\tR\x03uri\x12!\n\
|
||||
\x0ccontent_type\x18\x02\x20\x01(\tR\x0bcontentType\x12\x12\n\x04body\
|
||||
\x18\x03\x20\x01(\x0cR\x04body\x12\x12\n\x04etag\x18\x04\x20\x01(\x0cR\
|
||||
\x04etag\"\xb3\x02\n\x0cMercuryReply\x12\x1f\n\x0bstatus_code\x18\x01\
|
||||
\x20\x01(\x11R\nstatusCode\x12%\n\x0estatus_message\x18\x02\x20\x01(\tR\
|
||||
\rstatusMessage\x12<\n\x0ccache_policy\x18\x03\x20\x01(\x0e2\x19.Mercury\
|
||||
Reply.CachePolicyR\x0bcachePolicy\x12\x10\n\x03ttl\x18\x04\x20\x01(\x11R\
|
||||
\x03ttl\x12\x12\n\x04etag\x18\x05\x20\x01(\x0cR\x04etag\x12!\n\x0cconten\
|
||||
t_type\x18\x06\x20\x01(\tR\x0bcontentType\x12\x12\n\x04body\x18\x07\x20\
|
||||
\x01(\x0cR\x04body\"@\n\x0bCachePolicy\x12\x0c\n\x08CACHE_NO\x10\x01\x12\
|
||||
\x11\n\rCACHE_PRIVATE\x10\x02\x12\x10\n\x0cCACHE_PUBLIC\x10\x03\"\xa3\
|
||||
\x01\n\x06Header\x12\x10\n\x03uri\x18\x01\x20\x01(\tR\x03uri\x12!\n\x0cc\
|
||||
ontent_type\x18\x02\x20\x01(\tR\x0bcontentType\x12\x16\n\x06method\x18\
|
||||
\x03\x20\x01(\tR\x06method\x12\x1f\n\x0bstatus_code\x18\x04\x20\x01(\x11\
|
||||
R\nstatusCode\x12+\n\x0buser_fields\x18\x06\x20\x03(\x0b2\n.UserFieldR\n\
|
||||
userFields\"3\n\tUserField\x12\x10\n\x03key\x18\x01\x20\x01(\tR\x03key\
|
||||
\x12\x14\n\x05value\x18\x02\x20\x01(\x0cR\x05value\
|
||||
\n\rmercury.proto\x12\0\">\n\x16MercuryMultiGetRequest\x12$\n\x07request\
|
||||
\x18\x01\x20\x03(\x0b2\x0f.MercuryRequestB\x02\x18\0\"8\n\x14MercuryMult\
|
||||
iGetReply\x12\x20\n\x05reply\x18\x01\x20\x03(\x0b2\r.MercuryReplyB\x02\
|
||||
\x18\0\"_\n\x0eMercuryRequest\x12\x0f\n\x03uri\x18\x01\x20\x01(\tB\x02\
|
||||
\x18\0\x12\x18\n\x0ccontent_type\x18\x02\x20\x01(\tB\x02\x18\0\x12\x10\n\
|
||||
\x04body\x18\x03\x20\x01(\x0cB\x02\x18\0\x12\x10\n\x04etag\x18\x04\x20\
|
||||
\x01(\x0cB\x02\x18\0\"\x8d\x02\n\x0cMercuryReply\x12\x17\n\x0bstatus_cod\
|
||||
e\x18\x01\x20\x01(\x11B\x02\x18\0\x12\x1a\n\x0estatus_message\x18\x02\
|
||||
\x20\x01(\tB\x02\x18\0\x123\n\x0ccache_policy\x18\x03\x20\x01(\x0e2\x19.\
|
||||
MercuryReply.CachePolicyB\x02\x18\0\x12\x0f\n\x03ttl\x18\x04\x20\x01(\
|
||||
\x11B\x02\x18\0\x12\x10\n\x04etag\x18\x05\x20\x01(\x0cB\x02\x18\0\x12\
|
||||
\x18\n\x0ccontent_type\x18\x06\x20\x01(\tB\x02\x18\0\x12\x10\n\x04body\
|
||||
\x18\x07\x20\x01(\x0cB\x02\x18\0\"D\n\x0bCachePolicy\x12\x0c\n\x08CACHE_\
|
||||
NO\x10\x01\x12\x11\n\rCACHE_PRIVATE\x10\x02\x12\x10\n\x0cCACHE_PUBLIC\
|
||||
\x10\x03\x1a\x02\x10\0\"\x85\x01\n\x06Header\x12\x0f\n\x03uri\x18\x01\
|
||||
\x20\x01(\tB\x02\x18\0\x12\x18\n\x0ccontent_type\x18\x02\x20\x01(\tB\x02\
|
||||
\x18\0\x12\x12\n\x06method\x18\x03\x20\x01(\tB\x02\x18\0\x12\x17\n\x0bst\
|
||||
atus_code\x18\x04\x20\x01(\x11B\x02\x18\0\x12#\n\x0buser_fields\x18\x06\
|
||||
\x20\x03(\x0b2\n.UserFieldB\x02\x18\0\"/\n\tUserField\x12\x0f\n\x03key\
|
||||
\x18\x01\x20\x01(\tB\x02\x18\0\x12\x11\n\x05value\x18\x02\x20\x01(\x0cB\
|
||||
\x02\x18\0B\0b\x06proto2\
|
||||
";
|
||||
|
||||
static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy {
|
||||
|
|
|
@ -6093,91 +6093,92 @@ impl ::protobuf::reflect::ProtobufValue for AudioFile_Format {
|
|||
}
|
||||
|
||||
static file_descriptor_proto_data: &'static [u8] = b"\
|
||||
\n\x0emetadata.proto\"C\n\tTopTracks\x12\x18\n\x07country\x18\x01\x20\
|
||||
\x01(\tR\x07country\x12\x1c\n\x05track\x18\x02\x20\x03(\x0b2\x06.TrackR\
|
||||
\x05track\"b\n\x0eActivityPeriod\x12\x1d\n\nstart_year\x18\x01\x20\x01(\
|
||||
\x11R\tstartYear\x12\x19\n\x08end_year\x18\x02\x20\x01(\x11R\x07endYear\
|
||||
\x12\x16\n\x06decade\x18\x03\x20\x01(\x11R\x06decade\"\xd0\x05\n\x06Arti\
|
||||
st\x12\x10\n\x03gid\x18\x01\x20\x01(\x0cR\x03gid\x12\x12\n\x04name\x18\
|
||||
\x02\x20\x01(\tR\x04name\x12\x1e\n\npopularity\x18\x03\x20\x01(\x11R\npo\
|
||||
pularity\x12'\n\ttop_track\x18\x04\x20\x03(\x0b2\n.TopTracksR\x08topTrac\
|
||||
k\x12,\n\x0balbum_group\x18\x05\x20\x03(\x0b2\x0b.AlbumGroupR\nalbumGrou\
|
||||
p\x12.\n\x0csingle_group\x18\x06\x20\x03(\x0b2\x0b.AlbumGroupR\x0bsingle\
|
||||
Group\x128\n\x11compilation_group\x18\x07\x20\x03(\x0b2\x0b.AlbumGroupR\
|
||||
\x10compilationGroup\x125\n\x10appears_on_group\x18\x08\x20\x03(\x0b2\
|
||||
\x0b.AlbumGroupR\x0eappearsOnGroup\x12\x14\n\x05genre\x18\t\x20\x03(\tR\
|
||||
\x05genre\x12,\n\x0bexternal_id\x18\n\x20\x03(\x0b2\x0b.ExternalIdR\next\
|
||||
ernalId\x12\"\n\x08portrait\x18\x0b\x20\x03(\x0b2\x06.ImageR\x08portrait\
|
||||
\x12(\n\tbiography\x18\x0c\x20\x03(\x0b2\n.BiographyR\tbiography\x128\n\
|
||||
\x0factivity_period\x18\r\x20\x03(\x0b2\x0f.ActivityPeriodR\x0eactivityP\
|
||||
eriod\x12.\n\x0brestriction\x18\x0e\x20\x03(\x0b2\x0c.RestrictionR\x0bre\
|
||||
striction\x12!\n\x07related\x18\x0f\x20\x03(\x0b2\x07.ArtistR\x07related\
|
||||
\x125\n\x17is_portrait_album_cover\x18\x10\x20\x01(\x08R\x14isPortraitAl\
|
||||
bumCover\x122\n\x0eportrait_group\x18\x11\x20\x01(\x0b2\x0b.ImageGroupR\
|
||||
\rportraitGroup\"*\n\nAlbumGroup\x12\x1c\n\x05album\x18\x01\x20\x03(\x0b\
|
||||
2\x06.AlbumR\x05album\"B\n\x04Date\x12\x12\n\x04year\x18\x01\x20\x01(\
|
||||
\x11R\x04year\x12\x14\n\x05month\x18\x02\x20\x01(\x11R\x05month\x12\x10\
|
||||
\n\x03day\x18\x03\x20\x01(\x11R\x03day\"\xe3\x04\n\x05Album\x12\x10\n\
|
||||
\x03gid\x18\x01\x20\x01(\x0cR\x03gid\x12\x12\n\x04name\x18\x02\x20\x01(\
|
||||
\tR\x04name\x12\x1f\n\x06artist\x18\x03\x20\x03(\x0b2\x07.ArtistR\x06art\
|
||||
ist\x12\x1d\n\x03typ\x18\x04\x20\x01(\x0e2\x0b.Album.TypeR\x03typ\x12\
|
||||
\x14\n\x05label\x18\x05\x20\x01(\tR\x05label\x12\x19\n\x04date\x18\x06\
|
||||
\x20\x01(\x0b2\x05.DateR\x04date\x12\x1e\n\npopularity\x18\x07\x20\x01(\
|
||||
\x11R\npopularity\x12\x14\n\x05genre\x18\x08\x20\x03(\tR\x05genre\x12\
|
||||
\x1c\n\x05cover\x18\t\x20\x03(\x0b2\x06.ImageR\x05cover\x12,\n\x0bextern\
|
||||
al_id\x18\n\x20\x03(\x0b2\x0b.ExternalIdR\nexternalId\x12\x19\n\x04disc\
|
||||
\x18\x0b\x20\x03(\x0b2\x05.DiscR\x04disc\x12\x16\n\x06review\x18\x0c\x20\
|
||||
\x03(\tR\x06review\x12(\n\tcopyright\x18\r\x20\x03(\x0b2\n.CopyrightR\tc\
|
||||
opyright\x12.\n\x0brestriction\x18\x0e\x20\x03(\x0b2\x0c.RestrictionR\
|
||||
\x0brestriction\x12\x20\n\x07related\x18\x0f\x20\x03(\x0b2\x06.AlbumR\
|
||||
\x07related\x12,\n\x0bsale_period\x18\x10\x20\x03(\x0b2\x0b.SalePeriodR\
|
||||
\nsalePeriod\x12,\n\x0bcover_group\x18\x11\x20\x01(\x0b2\x0b.ImageGroupR\
|
||||
\ncoverGroup\"6\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\"\xf9\x03\
|
||||
\n\x05Track\x12\x10\n\x03gid\x18\x01\x20\x01(\x0cR\x03gid\x12\x12\n\x04n\
|
||||
ame\x18\x02\x20\x01(\tR\x04name\x12\x1c\n\x05album\x18\x03\x20\x01(\x0b2\
|
||||
\x06.AlbumR\x05album\x12\x1f\n\x06artist\x18\x04\x20\x03(\x0b2\x07.Artis\
|
||||
tR\x06artist\x12\x16\n\x06number\x18\x05\x20\x01(\x11R\x06number\x12\x1f\
|
||||
\n\x0bdisc_number\x18\x06\x20\x01(\x11R\ndiscNumber\x12\x1a\n\x08duratio\
|
||||
n\x18\x07\x20\x01(\x11R\x08duration\x12\x1e\n\npopularity\x18\x08\x20\
|
||||
\x01(\x11R\npopularity\x12\x1a\n\x08explicit\x18\t\x20\x01(\x08R\x08expl\
|
||||
icit\x12,\n\x0bexternal_id\x18\n\x20\x03(\x0b2\x0b.ExternalIdR\nexternal\
|
||||
Id\x12.\n\x0brestriction\x18\x0b\x20\x03(\x0b2\x0c.RestrictionR\x0brestr\
|
||||
iction\x12\x1e\n\x04file\x18\x0c\x20\x03(\x0b2\n.AudioFileR\x04file\x12(\
|
||||
\n\x0balternative\x18\r\x20\x03(\x0b2\x06.TrackR\x0balternative\x12,\n\
|
||||
\x0bsale_period\x18\x0e\x20\x03(\x0b2\x0b.SalePeriodR\nsalePeriod\x12$\n\
|
||||
\x07preview\x18\x0f\x20\x03(\x0b2\n.AudioFileR\x07preview\"\xa6\x01\n\
|
||||
\x05Image\x12\x17\n\x07file_id\x18\x01\x20\x01(\x0cR\x06fileId\x12\x1f\n\
|
||||
\x04size\x18\x02\x20\x01(\x0e2\x0b.Image.SizeR\x04size\x12\x14\n\x05widt\
|
||||
h\x18\x03\x20\x01(\x11R\x05width\x12\x16\n\x06height\x18\x04\x20\x01(\
|
||||
\x11R\x06height\"5\n\x04Size\x12\x0b\n\x07DEFAULT\x10\0\x12\t\n\x05SMALL\
|
||||
\x10\x01\x12\t\n\x05LARGE\x10\x02\x12\n\n\x06XLARGE\x10\x03\"*\n\nImageG\
|
||||
roup\x12\x1c\n\x05image\x18\x01\x20\x03(\x0b2\x06.ImageR\x05image\"w\n\t\
|
||||
Biography\x12\x12\n\x04text\x18\x01\x20\x01(\tR\x04text\x12\"\n\x08portr\
|
||||
ait\x18\x02\x20\x03(\x0b2\x06.ImageR\x08portrait\x122\n\x0eportrait_grou\
|
||||
p\x18\x03\x20\x03(\x0b2\x0b.ImageGroupR\rportraitGroup\"P\n\x04Disc\x12\
|
||||
\x16\n\x06number\x18\x01\x20\x01(\x11R\x06number\x12\x12\n\x04name\x18\
|
||||
\x02\x20\x01(\tR\x04name\x12\x1c\n\x05track\x18\x03\x20\x03(\x0b2\x06.Tr\
|
||||
ackR\x05track\"X\n\tCopyright\x12!\n\x03typ\x18\x01\x20\x01(\x0e2\x0f.Co\
|
||||
pyright.TypeR\x03typ\x12\x12\n\x04text\x18\x02\x20\x01(\tR\x04text\"\x14\
|
||||
\n\x04Type\x12\x05\n\x01P\x10\0\x12\x05\n\x01C\x10\x01\"\xcc\x01\n\x0bRe\
|
||||
striction\x12+\n\x11countries_allowed\x18\x02\x20\x01(\tR\x10countriesAl\
|
||||
lowed\x12/\n\x13countries_forbidden\x18\x03\x20\x01(\tR\x12countriesForb\
|
||||
idden\x12#\n\x03typ\x18\x04\x20\x01(\x0e2\x11.Restriction.TypeR\x03typ\
|
||||
\x12#\n\rcatalogue_str\x18\x05\x20\x03(\tR\x0ccatalogueStr\"\x15\n\x04Ty\
|
||||
pe\x12\r\n\tSTREAMING\x10\0\"r\n\nSalePeriod\x12.\n\x0brestriction\x18\
|
||||
\x01\x20\x03(\x0b2\x0c.RestrictionR\x0brestriction\x12\x1b\n\x05start\
|
||||
\x18\x02\x20\x01(\x0b2\x05.DateR\x05start\x12\x17\n\x03end\x18\x03\x20\
|
||||
\x01(\x0b2\x05.DateR\x03end\".\n\nExternalId\x12\x10\n\x03typ\x18\x01\
|
||||
\x20\x01(\tR\x03typ\x12\x0e\n\x02id\x18\x02\x20\x01(\tR\x02id\"\xa3\x02\
|
||||
\n\tAudioFile\x12\x17\n\x07file_id\x18\x01\x20\x01(\x0cR\x06fileId\x12)\
|
||||
\n\x06format\x18\x02\x20\x01(\x0e2\x11.AudioFile.FormatR\x06format\"\xd1\
|
||||
\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\x07MP3_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\
|
||||
\n\x0emetadata.proto\x12\0\";\n\tTopTracks\x12\x13\n\x07country\x18\x01\
|
||||
\x20\x01(\tB\x02\x18\0\x12\x19\n\x05track\x18\x02\x20\x03(\x0b2\x06.Trac\
|
||||
kB\x02\x18\0\"R\n\x0eActivityPeriod\x12\x16\n\nstart_year\x18\x01\x20\
|
||||
\x01(\x11B\x02\x18\0\x12\x14\n\x08end_year\x18\x02\x20\x01(\x11B\x02\x18\
|
||||
\0\x12\x12\n\x06decade\x18\x03\x20\x01(\x11B\x02\x18\0\"\xc5\x04\n\x06Ar\
|
||||
tist\x12\x0f\n\x03gid\x18\x01\x20\x01(\x0cB\x02\x18\0\x12\x10\n\x04name\
|
||||
\x18\x02\x20\x01(\tB\x02\x18\0\x12\x16\n\npopularity\x18\x03\x20\x01(\
|
||||
\x11B\x02\x18\0\x12!\n\ttop_track\x18\x04\x20\x03(\x0b2\n.TopTracksB\x02\
|
||||
\x18\0\x12$\n\x0balbum_group\x18\x05\x20\x03(\x0b2\x0b.AlbumGroupB\x02\
|
||||
\x18\0\x12%\n\x0csingle_group\x18\x06\x20\x03(\x0b2\x0b.AlbumGroupB\x02\
|
||||
\x18\0\x12*\n\x11compilation_group\x18\x07\x20\x03(\x0b2\x0b.AlbumGroupB\
|
||||
\x02\x18\0\x12)\n\x10appears_on_group\x18\x08\x20\x03(\x0b2\x0b.AlbumGro\
|
||||
upB\x02\x18\0\x12\x11\n\x05genre\x18\t\x20\x03(\tB\x02\x18\0\x12$\n\x0be\
|
||||
xternal_id\x18\n\x20\x03(\x0b2\x0b.ExternalIdB\x02\x18\0\x12\x1c\n\x08po\
|
||||
rtrait\x18\x0b\x20\x03(\x0b2\x06.ImageB\x02\x18\0\x12!\n\tbiography\x18\
|
||||
\x0c\x20\x03(\x0b2\n.BiographyB\x02\x18\0\x12,\n\x0factivity_period\x18\
|
||||
\r\x20\x03(\x0b2\x0f.ActivityPeriodB\x02\x18\0\x12%\n\x0brestriction\x18\
|
||||
\x0e\x20\x03(\x0b2\x0c.RestrictionB\x02\x18\0\x12\x1c\n\x07related\x18\
|
||||
\x0f\x20\x03(\x0b2\x07.ArtistB\x02\x18\0\x12#\n\x17is_portrait_album_cov\
|
||||
er\x18\x10\x20\x01(\x08B\x02\x18\0\x12'\n\x0eportrait_group\x18\x11\x20\
|
||||
\x01(\x0b2\x0b.ImageGroupB\x02\x18\0\"'\n\nAlbumGroup\x12\x19\n\x05album\
|
||||
\x18\x01\x20\x03(\x0b2\x06.AlbumB\x02\x18\0\"<\n\x04Date\x12\x10\n\x04ye\
|
||||
ar\x18\x01\x20\x01(\x11B\x02\x18\0\x12\x11\n\x05month\x18\x02\x20\x01(\
|
||||
\x11B\x02\x18\0\x12\x0f\n\x03day\x18\x03\x20\x01(\x11B\x02\x18\0\"\x99\
|
||||
\x04\n\x05Album\x12\x0f\n\x03gid\x18\x01\x20\x01(\x0cB\x02\x18\0\x12\x10\
|
||||
\n\x04name\x18\x02\x20\x01(\tB\x02\x18\0\x12\x1b\n\x06artist\x18\x03\x20\
|
||||
\x03(\x0b2\x07.ArtistB\x02\x18\0\x12\x1c\n\x03typ\x18\x04\x20\x01(\x0e2\
|
||||
\x0b.Album.TypeB\x02\x18\0\x12\x11\n\x05label\x18\x05\x20\x01(\tB\x02\
|
||||
\x18\0\x12\x17\n\x04date\x18\x06\x20\x01(\x0b2\x05.DateB\x02\x18\0\x12\
|
||||
\x16\n\npopularity\x18\x07\x20\x01(\x11B\x02\x18\0\x12\x11\n\x05genre\
|
||||
\x18\x08\x20\x03(\tB\x02\x18\0\x12\x19\n\x05cover\x18\t\x20\x03(\x0b2\
|
||||
\x06.ImageB\x02\x18\0\x12$\n\x0bexternal_id\x18\n\x20\x03(\x0b2\x0b.Exte\
|
||||
rnalIdB\x02\x18\0\x12\x17\n\x04disc\x18\x0b\x20\x03(\x0b2\x05.DiscB\x02\
|
||||
\x18\0\x12\x12\n\x06review\x18\x0c\x20\x03(\tB\x02\x18\0\x12!\n\tcopyrig\
|
||||
ht\x18\r\x20\x03(\x0b2\n.CopyrightB\x02\x18\0\x12%\n\x0brestriction\x18\
|
||||
\x0e\x20\x03(\x0b2\x0c.RestrictionB\x02\x18\0\x12\x1b\n\x07related\x18\
|
||||
\x0f\x20\x03(\x0b2\x06.AlbumB\x02\x18\0\x12$\n\x0bsale_period\x18\x10\
|
||||
\x20\x03(\x0b2\x0b.SalePeriodB\x02\x18\0\x12$\n\x0bcover_group\x18\x11\
|
||||
\x20\x01(\x0b2\x0b.ImageGroupB\x02\x18\0\":\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\x02\x10\0\"\xa6\x03\n\x05Track\x12\x0f\n\x03gid\
|
||||
\x18\x01\x20\x01(\x0cB\x02\x18\0\x12\x10\n\x04name\x18\x02\x20\x01(\tB\
|
||||
\x02\x18\0\x12\x19\n\x05album\x18\x03\x20\x01(\x0b2\x06.AlbumB\x02\x18\0\
|
||||
\x12\x1b\n\x06artist\x18\x04\x20\x03(\x0b2\x07.ArtistB\x02\x18\0\x12\x12\
|
||||
\n\x06number\x18\x05\x20\x01(\x11B\x02\x18\0\x12\x17\n\x0bdisc_number\
|
||||
\x18\x06\x20\x01(\x11B\x02\x18\0\x12\x14\n\x08duration\x18\x07\x20\x01(\
|
||||
\x11B\x02\x18\0\x12\x16\n\npopularity\x18\x08\x20\x01(\x11B\x02\x18\0\
|
||||
\x12\x14\n\x08explicit\x18\t\x20\x01(\x08B\x02\x18\0\x12$\n\x0bexternal_\
|
||||
id\x18\n\x20\x03(\x0b2\x0b.ExternalIdB\x02\x18\0\x12%\n\x0brestriction\
|
||||
\x18\x0b\x20\x03(\x0b2\x0c.RestrictionB\x02\x18\0\x12\x1c\n\x04file\x18\
|
||||
\x0c\x20\x03(\x0b2\n.AudioFileB\x02\x18\0\x12\x1f\n\x0balternative\x18\r\
|
||||
\x20\x03(\x0b2\x06.TrackB\x02\x18\0\x12$\n\x0bsale_period\x18\x0e\x20\
|
||||
\x03(\x0b2\x0b.SalePeriodB\x02\x18\0\x12\x1f\n\x07preview\x18\x0f\x20\
|
||||
\x03(\x0b2\n.AudioFileB\x02\x18\0\"\x9d\x01\n\x05Image\x12\x13\n\x07file\
|
||||
_id\x18\x01\x20\x01(\x0cB\x02\x18\0\x12\x1d\n\x04size\x18\x02\x20\x01(\
|
||||
\x0e2\x0b.Image.SizeB\x02\x18\0\x12\x11\n\x05width\x18\x03\x20\x01(\x11B\
|
||||
\x02\x18\0\x12\x12\n\x06height\x18\x04\x20\x01(\x11B\x02\x18\0\"9\n\x04S\
|
||||
ize\x12\x0b\n\x07DEFAULT\x10\0\x12\t\n\x05SMALL\x10\x01\x12\t\n\x05LARGE\
|
||||
\x10\x02\x12\n\n\x06XLARGE\x10\x03\x1a\x02\x10\0\"'\n\nImageGroup\x12\
|
||||
\x19\n\x05image\x18\x01\x20\x03(\x0b2\x06.ImageB\x02\x18\0\"d\n\tBiograp\
|
||||
hy\x12\x10\n\x04text\x18\x01\x20\x01(\tB\x02\x18\0\x12\x1c\n\x08portrait\
|
||||
\x18\x02\x20\x03(\x0b2\x06.ImageB\x02\x18\0\x12'\n\x0eportrait_group\x18\
|
||||
\x03\x20\x03(\x0b2\x0b.ImageGroupB\x02\x18\0\"G\n\x04Disc\x12\x12\n\x06n\
|
||||
umber\x18\x01\x20\x01(\x11B\x02\x18\0\x12\x10\n\x04name\x18\x02\x20\x01(\
|
||||
\tB\x02\x18\0\x12\x19\n\x05track\x18\x03\x20\x03(\x0b2\x06.TrackB\x02\
|
||||
\x18\0\"Y\n\tCopyright\x12\x20\n\x03typ\x18\x01\x20\x01(\x0e2\x0f.Copyri\
|
||||
ght.TypeB\x02\x18\0\x12\x10\n\x04text\x18\x02\x20\x01(\tB\x02\x18\0\"\
|
||||
\x18\n\x04Type\x12\x05\n\x01P\x10\0\x12\x05\n\x01C\x10\x01\x1a\x02\x10\0\
|
||||
\"\xa7\x01\n\x0bRestriction\x12\x1d\n\x11countries_allowed\x18\x02\x20\
|
||||
\x01(\tB\x02\x18\0\x12\x1f\n\x13countries_forbidden\x18\x03\x20\x01(\tB\
|
||||
\x02\x18\0\x12\"\n\x03typ\x18\x04\x20\x01(\x0e2\x11.Restriction.TypeB\
|
||||
\x02\x18\0\x12\x19\n\rcatalogue_str\x18\x05\x20\x03(\tB\x02\x18\0\"\x19\
|
||||
\n\x04Type\x12\r\n\tSTREAMING\x10\0\x1a\x02\x10\0\"e\n\nSalePeriod\x12%\
|
||||
\n\x0brestriction\x18\x01\x20\x03(\x0b2\x0c.RestrictionB\x02\x18\0\x12\
|
||||
\x18\n\x05start\x18\x02\x20\x01(\x0b2\x05.DateB\x02\x18\0\x12\x16\n\x03e\
|
||||
nd\x18\x03\x20\x01(\x0b2\x05.DateB\x02\x18\0\"-\n\nExternalId\x12\x0f\n\
|
||||
\x03typ\x18\x01\x20\x01(\tB\x02\x18\0\x12\x0e\n\x02id\x18\x02\x20\x01(\t\
|
||||
B\x02\x18\0\"\x9f\x02\n\tAudioFile\x12\x13\n\x07file_id\x18\x01\x20\x01(\
|
||||
\x0cB\x02\x18\0\x12%\n\x06format\x18\x02\x20\x01(\x0e2\x11.AudioFile.For\
|
||||
matB\x02\x18\0\"\xd5\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\x07MP3_\
|
||||
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\x02\x10\0B\0b\x06proto2\
|
||||
";
|
||||
|
||||
static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy {
|
||||
|
|
|
@ -273,9 +273,10 @@ impl ::protobuf::reflect::ProtobufValue for Subscription {
|
|||
}
|
||||
|
||||
static file_descriptor_proto_data: &'static [u8] = b"\
|
||||
\n\x0cpubsub.proto\"Y\n\x0cSubscription\x12\x10\n\x03uri\x18\x01\x20\x01\
|
||||
(\tR\x03uri\x12\x16\n\x06expiry\x18\x02\x20\x01(\x05R\x06expiry\x12\x1f\
|
||||
\n\x0bstatus_code\x18\x03\x20\x01(\x05R\nstatusCode\
|
||||
\n\x0cpubsub.proto\x12\0\"L\n\x0cSubscription\x12\x0f\n\x03uri\x18\x01\
|
||||
\x20\x01(\tB\x02\x18\0\x12\x12\n\x06expiry\x18\x02\x20\x01(\x05B\x02\x18\
|
||||
\0\x12\x17\n\x0bstatus_code\x18\x03\x20\x01(\x05B\x02\x18\0B\0b\x06proto\
|
||||
2\
|
||||
";
|
||||
|
||||
static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy {
|
||||
|
|
|
@ -4002,79 +4002,79 @@ impl ::protobuf::reflect::ProtobufValue for PlayStatus {
|
|||
}
|
||||
|
||||
static file_descriptor_proto_data: &'static [u8] = b"\
|
||||
\n\x0bspirc.proto\"\xfa\x03\n\x05Frame\x12\x18\n\x07version\x18\x01\x20\
|
||||
\x01(\rR\x07version\x12\x14\n\x05ident\x18\x02\x20\x01(\tR\x05ident\x12)\
|
||||
\n\x10protocol_version\x18\x03\x20\x01(\tR\x0fprotocolVersion\x12\x15\n\
|
||||
\x06seq_nr\x18\x04\x20\x01(\rR\x05seqNr\x12\x1e\n\x03typ\x18\x05\x20\x01\
|
||||
(\x0e2\x0c.MessageTypeR\x03typ\x12/\n\x0cdevice_state\x18\x07\x20\x01(\
|
||||
\x0b2\x0c.DeviceStateR\x0bdeviceState\x12\"\n\x07goodbye\x18\x0b\x20\x01\
|
||||
(\x0b2\x08.GoodbyeR\x07goodbye\x12\x1c\n\x05state\x18\x0c\x20\x01(\x0b2\
|
||||
\x06.StateR\x05state\x12\x1a\n\x08position\x18\r\x20\x01(\rR\x08position\
|
||||
\x12\x16\n\x06volume\x18\x0e\x20\x01(\rR\x06volume\x12&\n\x0fstate_updat\
|
||||
e_id\x18\x11\x20\x01(\x03R\rstateUpdateId\x12\x1c\n\trecipient\x18\x12\
|
||||
\x20\x03(\tR\trecipient\x120\n\x14context_player_state\x18\x13\x20\x01(\
|
||||
\x0cR\x12contextPlayerState\x12\x19\n\x08new_name\x18\x14\x20\x01(\tR\
|
||||
\x07newName\x12%\n\x08metadata\x18\x19\x20\x01(\x0b2\t.MetadataR\x08meta\
|
||||
data\"\x88\x03\n\x0bDeviceState\x12\x1d\n\nsw_version\x18\x01\x20\x01(\t\
|
||||
R\tswVersion\x12\x1b\n\tis_active\x18\n\x20\x01(\x08R\x08isActive\x12\
|
||||
\x19\n\x08can_play\x18\x0b\x20\x01(\x08R\x07canPlay\x12\x16\n\x06volume\
|
||||
\x18\x0c\x20\x01(\rR\x06volume\x12\x12\n\x04name\x18\r\x20\x01(\tR\x04na\
|
||||
me\x12\x1d\n\nerror_code\x18\x0e\x20\x01(\rR\terrorCode\x12(\n\x10became\
|
||||
_active_at\x18\x0f\x20\x01(\x03R\x0ebecameActiveAt\x12#\n\rerror_message\
|
||||
\x18\x10\x20\x01(\tR\x0cerrorMessage\x12/\n\x0ccapabilities\x18\x11\x20\
|
||||
\x03(\x0b2\x0b.CapabilityR\x0ccapabilities\x120\n\x14context_player_erro\
|
||||
r\x18\x14\x20\x01(\tR\x12contextPlayerError\x12%\n\x08metadata\x18\x19\
|
||||
\x20\x03(\x0b2\t.MetadataR\x08metadata\"m\n\nCapability\x12!\n\x03typ\
|
||||
\x18\x01\x20\x01(\x0e2\x0f.CapabilityTypeR\x03typ\x12\x1a\n\x08intValue\
|
||||
\x18\x02\x20\x03(\x03R\x08intValue\x12\x20\n\x0bstringValue\x18\x03\x20\
|
||||
\x03(\tR\x0bstringValue\"!\n\x07Goodbye\x12\x16\n\x06reason\x18\x01\x20\
|
||||
\x01(\tR\x06reason\"\xa1\x04\n\x05State\x12\x1f\n\x0bcontext_uri\x18\x02\
|
||||
\x20\x01(\tR\ncontextUri\x12\x14\n\x05index\x18\x03\x20\x01(\rR\x05index\
|
||||
\x12\x1f\n\x0bposition_ms\x18\x04\x20\x01(\rR\npositionMs\x12#\n\x06stat\
|
||||
us\x18\x05\x20\x01(\x0e2\x0b.PlayStatusR\x06status\x120\n\x14position_me\
|
||||
asured_at\x18\x07\x20\x01(\x04R\x12positionMeasuredAt\x12/\n\x13context_\
|
||||
description\x18\x08\x20\x01(\tR\x12contextDescription\x12\x18\n\x07shuff\
|
||||
le\x18\r\x20\x01(\x08R\x07shuffle\x12\x16\n\x06repeat\x18\x0e\x20\x01(\
|
||||
\x08R\x06repeat\x12,\n\x12last_command_ident\x18\x14\x20\x01(\tR\x10last\
|
||||
CommandIdent\x12,\n\x12last_command_msgid\x18\x15\x20\x01(\rR\x10lastCom\
|
||||
mandMsgid\x122\n\x15playing_from_fallback\x18\x18\x20\x01(\x08R\x13playi\
|
||||
ngFromFallback\x12\x10\n\x03row\x18\x19\x20\x01(\rR\x03row\x12.\n\x13pla\
|
||||
ying_track_index\x18\x1a\x20\x01(\rR\x11playingTrackIndex\x12\x1f\n\x05t\
|
||||
rack\x18\x1b\x20\x03(\x0b2\t.TrackRefR\x05track\x12\x13\n\x02ad\x18\x1c\
|
||||
\x20\x01(\x0b2\x03.AdR\x02ad\"`\n\x08TrackRef\x12\x10\n\x03gid\x18\x01\
|
||||
\x20\x01(\x0cR\x03gid\x12\x10\n\x03uri\x18\x02\x20\x01(\tR\x03uri\x12\
|
||||
\x16\n\x06queued\x18\x03\x20\x01(\x08R\x06queued\x12\x18\n\x07context\
|
||||
\x18\x04\x20\x01(\tR\x07context\"\xfa\x01\n\x02Ad\x12\x12\n\x04next\x18\
|
||||
\x01\x20\x01(\x05R\x04next\x12\x17\n\x07ogg_fid\x18\x02\x20\x01(\x0cR\
|
||||
\x06oggFid\x12\x1b\n\timage_fid\x18\x03\x20\x01(\x0cR\x08imageFid\x12\
|
||||
\x1a\n\x08duration\x18\x04\x20\x01(\x05R\x08duration\x12\x1b\n\tclick_ur\
|
||||
l\x18\x05\x20\x01(\tR\x08clickUrl\x12%\n\x0eimpression_url\x18\x06\x20\
|
||||
\x01(\tR\rimpressionUrl\x12\x18\n\x07product\x18\x07\x20\x01(\tR\x07prod\
|
||||
uct\x12\x1e\n\nadvertiser\x18\x08\x20\x01(\tR\nadvertiser\x12\x10\n\x03g\
|
||||
id\x18\t\x20\x01(\x0cR\x03gid\":\n\x08Metadata\x12\x12\n\x04type\x18\x01\
|
||||
\x20\x01(\tR\x04type\x12\x1a\n\x08metadata\x18\x02\x20\x01(\tR\x08metada\
|
||||
ta*\x8d\x04\n\x0bMessageType\x12\x15\n\x11kMessageTypeHello\x10\x01\x12\
|
||||
\x17\n\x13kMessageTypeGoodbye\x10\x02\x12\x15\n\x11kMessageTypeProbe\x10\
|
||||
\x03\x12\x16\n\x12kMessageTypeNotify\x10\n\x12\x14\n\x10kMessageTypeLoad\
|
||||
\x10\x14\x12\x14\n\x10kMessageTypePlay\x10\x15\x12\x15\n\x11kMessageType\
|
||||
Pause\x10\x16\x12\x19\n\x15kMessageTypePlayPause\x10\x17\x12\x14\n\x10kM\
|
||||
essageTypeSeek\x10\x18\x12\x14\n\x10kMessageTypePrev\x10\x19\x12\x14\n\
|
||||
\x10kMessageTypeNext\x10\x1a\x12\x16\n\x12kMessageTypeVolume\x10\x1b\x12\
|
||||
\x17\n\x13kMessageTypeShuffle\x10\x1c\x12\x16\n\x12kMessageTypeRepeat\
|
||||
\x10\x1d\x12\x1a\n\x16kMessageTypeVolumeDown\x10\x1f\x12\x18\n\x14kMessa\
|
||||
geTypeVolumeUp\x10\x20\x12\x17\n\x13kMessageTypeReplace\x10!\x12\x16\n\
|
||||
\x12kMessageTypeLogout\x10\"\x12\x16\n\x12kMessageTypeAction\x10#\x12\
|
||||
\x16\n\x12kMessageTypeRename\x10$\x12\x1f\n\x1akMessageTypeUpdateMetadat\
|
||||
a\x10\x80\x01*\xb2\x02\n\x0eCapabilityType\x12\x16\n\x12kSupportedContex\
|
||||
ts\x10\x01\x12\x10\n\x0ckCanBePlayer\x10\x02\x12\x14\n\x10kRestrictToLoc\
|
||||
al\x10\x03\x12\x0f\n\x0bkDeviceType\x10\x04\x12\x14\n\x10kGaiaEqConnectI\
|
||||
d\x10\x05\x12\x13\n\x0fkSupportsLogout\x10\x06\x12\x11\n\rkIsObservable\
|
||||
\n\x0bspirc.proto\x12\0\"\x99\x03\n\x05Frame\x12\x13\n\x07version\x18\
|
||||
\x01\x20\x01(\rB\x02\x18\0\x12\x11\n\x05ident\x18\x02\x20\x01(\tB\x02\
|
||||
\x18\0\x12\x1c\n\x10protocol_version\x18\x03\x20\x01(\tB\x02\x18\0\x12\
|
||||
\x12\n\x06seq_nr\x18\x04\x20\x01(\rB\x02\x18\0\x12\x1d\n\x03typ\x18\x05\
|
||||
\x20\x01(\x0e2\x0c.MessageTypeB\x02\x18\0\x12&\n\x0cdevice_state\x18\x07\
|
||||
\x20\x01(\x0b2\x0c.DeviceStateB\x02\x18\0\x12\x1d\n\x07goodbye\x18\x0b\
|
||||
\x20\x01(\x0b2\x08.GoodbyeB\x02\x18\0\x12\x19\n\x05state\x18\x0c\x20\x01\
|
||||
(\x0b2\x06.StateB\x02\x18\0\x12\x14\n\x08position\x18\r\x20\x01(\rB\x02\
|
||||
\x18\0\x12\x12\n\x06volume\x18\x0e\x20\x01(\rB\x02\x18\0\x12\x1b\n\x0fst\
|
||||
ate_update_id\x18\x11\x20\x01(\x03B\x02\x18\0\x12\x15\n\trecipient\x18\
|
||||
\x12\x20\x03(\tB\x02\x18\0\x12\x20\n\x14context_player_state\x18\x13\x20\
|
||||
\x01(\x0cB\x02\x18\0\x12\x14\n\x08new_name\x18\x14\x20\x01(\tB\x02\x18\0\
|
||||
\x12\x1f\n\x08metadata\x18\x19\x20\x01(\x0b2\t.MetadataB\x02\x18\0\"\xb3\
|
||||
\x02\n\x0bDeviceState\x12\x16\n\nsw_version\x18\x01\x20\x01(\tB\x02\x18\
|
||||
\0\x12\x15\n\tis_active\x18\n\x20\x01(\x08B\x02\x18\0\x12\x14\n\x08can_p\
|
||||
lay\x18\x0b\x20\x01(\x08B\x02\x18\0\x12\x12\n\x06volume\x18\x0c\x20\x01(\
|
||||
\rB\x02\x18\0\x12\x10\n\x04name\x18\r\x20\x01(\tB\x02\x18\0\x12\x16\n\ne\
|
||||
rror_code\x18\x0e\x20\x01(\rB\x02\x18\0\x12\x1c\n\x10became_active_at\
|
||||
\x18\x0f\x20\x01(\x03B\x02\x18\0\x12\x19\n\rerror_message\x18\x10\x20\
|
||||
\x01(\tB\x02\x18\0\x12%\n\x0ccapabilities\x18\x11\x20\x03(\x0b2\x0b.Capa\
|
||||
bilityB\x02\x18\0\x12\x20\n\x14context_player_error\x18\x14\x20\x01(\tB\
|
||||
\x02\x18\0\x12\x1f\n\x08metadata\x18\x19\x20\x03(\x0b2\t.MetadataB\x02\
|
||||
\x18\0\"]\n\nCapability\x12\x20\n\x03typ\x18\x01\x20\x01(\x0e2\x0f.Capab\
|
||||
ilityTypeB\x02\x18\0\x12\x14\n\x08intValue\x18\x02\x20\x03(\x03B\x02\x18\
|
||||
\0\x12\x17\n\x0bstringValue\x18\x03\x20\x03(\tB\x02\x18\0\"\x1d\n\x07Goo\
|
||||
dbye\x12\x12\n\x06reason\x18\x01\x20\x01(\tB\x02\x18\0\"\xa1\x03\n\x05St\
|
||||
ate\x12\x17\n\x0bcontext_uri\x18\x02\x20\x01(\tB\x02\x18\0\x12\x11\n\x05\
|
||||
index\x18\x03\x20\x01(\rB\x02\x18\0\x12\x17\n\x0bposition_ms\x18\x04\x20\
|
||||
\x01(\rB\x02\x18\0\x12\x1f\n\x06status\x18\x05\x20\x01(\x0e2\x0b.PlaySta\
|
||||
tusB\x02\x18\0\x12\x20\n\x14position_measured_at\x18\x07\x20\x01(\x04B\
|
||||
\x02\x18\0\x12\x1f\n\x13context_description\x18\x08\x20\x01(\tB\x02\x18\
|
||||
\0\x12\x13\n\x07shuffle\x18\r\x20\x01(\x08B\x02\x18\0\x12\x12\n\x06repea\
|
||||
t\x18\x0e\x20\x01(\x08B\x02\x18\0\x12\x1e\n\x12last_command_ident\x18\
|
||||
\x14\x20\x01(\tB\x02\x18\0\x12\x1e\n\x12last_command_msgid\x18\x15\x20\
|
||||
\x01(\rB\x02\x18\0\x12!\n\x15playing_from_fallback\x18\x18\x20\x01(\x08B\
|
||||
\x02\x18\0\x12\x0f\n\x03row\x18\x19\x20\x01(\rB\x02\x18\0\x12\x1f\n\x13p\
|
||||
laying_track_index\x18\x1a\x20\x01(\rB\x02\x18\0\x12\x1c\n\x05track\x18\
|
||||
\x1b\x20\x03(\x0b2\t.TrackRefB\x02\x18\0\x12\x13\n\x02ad\x18\x1c\x20\x01\
|
||||
(\x0b2\x03.AdB\x02\x18\0\"U\n\x08TrackRef\x12\x0f\n\x03gid\x18\x01\x20\
|
||||
\x01(\x0cB\x02\x18\0\x12\x0f\n\x03uri\x18\x02\x20\x01(\tB\x02\x18\0\x12\
|
||||
\x12\n\x06queued\x18\x03\x20\x01(\x08B\x02\x18\0\x12\x13\n\x07context\
|
||||
\x18\x04\x20\x01(\tB\x02\x18\0\"\xc9\x01\n\x02Ad\x12\x10\n\x04next\x18\
|
||||
\x01\x20\x01(\x05B\x02\x18\0\x12\x13\n\x07ogg_fid\x18\x02\x20\x01(\x0cB\
|
||||
\x02\x18\0\x12\x15\n\timage_fid\x18\x03\x20\x01(\x0cB\x02\x18\0\x12\x14\
|
||||
\n\x08duration\x18\x04\x20\x01(\x05B\x02\x18\0\x12\x15\n\tclick_url\x18\
|
||||
\x05\x20\x01(\tB\x02\x18\0\x12\x1a\n\x0eimpression_url\x18\x06\x20\x01(\
|
||||
\tB\x02\x18\0\x12\x13\n\x07product\x18\x07\x20\x01(\tB\x02\x18\0\x12\x16\
|
||||
\n\nadvertiser\x18\x08\x20\x01(\tB\x02\x18\0\x12\x0f\n\x03gid\x18\t\x20\
|
||||
\x01(\x0cB\x02\x18\0\"2\n\x08Metadata\x12\x10\n\x04type\x18\x01\x20\x01(\
|
||||
\tB\x02\x18\0\x12\x14\n\x08metadata\x18\x02\x20\x01(\tB\x02\x18\0*\x91\
|
||||
\x04\n\x0bMessageType\x12\x15\n\x11kMessageTypeHello\x10\x01\x12\x17\n\
|
||||
\x13kMessageTypeGoodbye\x10\x02\x12\x15\n\x11kMessageTypeProbe\x10\x03\
|
||||
\x12\x16\n\x12kMessageTypeNotify\x10\n\x12\x14\n\x10kMessageTypeLoad\x10\
|
||||
\x14\x12\x14\n\x10kMessageTypePlay\x10\x15\x12\x15\n\x11kMessageTypePaus\
|
||||
e\x10\x16\x12\x19\n\x15kMessageTypePlayPause\x10\x17\x12\x14\n\x10kMessa\
|
||||
geTypeSeek\x10\x18\x12\x14\n\x10kMessageTypePrev\x10\x19\x12\x14\n\x10kM\
|
||||
essageTypeNext\x10\x1a\x12\x16\n\x12kMessageTypeVolume\x10\x1b\x12\x17\n\
|
||||
\x13kMessageTypeShuffle\x10\x1c\x12\x16\n\x12kMessageTypeRepeat\x10\x1d\
|
||||
\x12\x1a\n\x16kMessageTypeVolumeDown\x10\x1f\x12\x18\n\x14kMessageTypeVo\
|
||||
lumeUp\x10\x20\x12\x17\n\x13kMessageTypeReplace\x10!\x12\x16\n\x12kMessa\
|
||||
geTypeLogout\x10\"\x12\x16\n\x12kMessageTypeAction\x10#\x12\x16\n\x12kMe\
|
||||
ssageTypeRename\x10$\x12\x1f\n\x1akMessageTypeUpdateMetadata\x10\x80\x01\
|
||||
\x1a\x02\x10\0*\xb6\x02\n\x0eCapabilityType\x12\x16\n\x12kSupportedConte\
|
||||
xts\x10\x01\x12\x10\n\x0ckCanBePlayer\x10\x02\x12\x14\n\x10kRestrictToLo\
|
||||
cal\x10\x03\x12\x0f\n\x0bkDeviceType\x10\x04\x12\x14\n\x10kGaiaEqConnect\
|
||||
Id\x10\x05\x12\x13\n\x0fkSupportsLogout\x10\x06\x12\x11\n\rkIsObservable\
|
||||
\x10\x07\x12\x10\n\x0ckVolumeSteps\x10\x08\x12\x13\n\x0fkSupportedTypes\
|
||||
\x10\t\x12\x10\n\x0ckCommandAcks\x10\n\x12\x13\n\x0fkSupportsRename\x10\
|
||||
\x0b\x12\x0b\n\x07kHidden\x10\x0c\x12\x17\n\x13kSupportsPlaylistV2\x10\r\
|
||||
\x12\x1d\n\x19kSupportsExternalEpisodes\x10\x0e*d\n\nPlayStatus\x12\x13\
|
||||
\n\x0fkPlayStatusStop\x10\0\x12\x13\n\x0fkPlayStatusPlay\x10\x01\x12\x14\
|
||||
\n\x10kPlayStatusPause\x10\x02\x12\x16\n\x12kPlayStatusLoading\x10\x03\
|
||||
\x12\x1d\n\x19kSupportsExternalEpisodes\x10\x0e\x1a\x02\x10\0*h\n\nPlayS\
|
||||
tatus\x12\x13\n\x0fkPlayStatusStop\x10\0\x12\x13\n\x0fkPlayStatusPlay\
|
||||
\x10\x01\x12\x14\n\x10kPlayStatusPause\x10\x02\x12\x16\n\x12kPlayStatusL\
|
||||
oading\x10\x03\x1a\x02\x10\0B\0b\x06proto2\
|
||||
";
|
||||
|
||||
static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy {
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#![cfg_attr(feature = "cargo-clippy", allow(unused_io_amount))]
|
||||
|
||||
extern crate base64;
|
||||
extern crate crypto;
|
||||
extern crate futures;
|
||||
extern crate hyper;
|
||||
extern crate num_bigint;
|
||||
|
|
16
src/main.rs
16
src/main.rs
|
@ -1,4 +1,3 @@
|
|||
extern crate crypto;
|
||||
extern crate env_logger;
|
||||
extern crate futures;
|
||||
extern crate getopts;
|
||||
|
@ -11,9 +10,10 @@ extern crate tokio_io;
|
|||
extern crate tokio_process;
|
||||
extern crate tokio_signal;
|
||||
extern crate url;
|
||||
extern crate sha1;
|
||||
extern crate hex;
|
||||
|
||||
use crypto::digest::Digest;
|
||||
use crypto::sha1::Sha1;
|
||||
use sha1::{Sha1, Digest};
|
||||
use env_logger::LogBuilder;
|
||||
use futures::sync::mpsc::UnboundedReceiver;
|
||||
use futures::{Async, Future, Poll, Stream};
|
||||
|
@ -44,9 +44,7 @@ mod player_event_handler;
|
|||
use player_event_handler::run_program_on_events;
|
||||
|
||||
fn device_id(name: &str) -> String {
|
||||
let mut h = Sha1::new();
|
||||
h.input_str(name);
|
||||
h.result_str()
|
||||
hex::encode(Sha1::digest(name.as_bytes()))
|
||||
}
|
||||
|
||||
fn usage(program: &str, opts: &getopts::Options) -> String {
|
||||
|
@ -202,6 +200,10 @@ fn setup(args: &[String]) -> Setup {
|
|||
let backend = audio_backend::find(backend_name).expect("Invalid backend");
|
||||
|
||||
let device = matches.opt_str("device");
|
||||
if device == Some("?".into()) {
|
||||
backend(device);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
let mixer_name = matches.opt_str("mixer");
|
||||
let mixer = mixer::find(mixer_name.as_ref()).expect("Invalid mixer");
|
||||
|
@ -445,6 +447,8 @@ impl Future for Main {
|
|||
if !self.shutdown {
|
||||
if let Some(ref spirc) = self.spirc {
|
||||
spirc.shutdown();
|
||||
} else {
|
||||
return Ok(Async::Ready(()));
|
||||
}
|
||||
self.shutdown = true;
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue