mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
Remove the need for a application key.
This commit is contained in:
parent
e9aad29ae4
commit
4cca541339
5 changed files with 6 additions and 56 deletions
|
@ -70,5 +70,4 @@ with-tremor = ["tremor"]
|
||||||
facebook = ["hyper/ssl", "openssl"]
|
facebook = ["hyper/ssl", "openssl"]
|
||||||
portaudio-backend = ["portaudio"]
|
portaudio-backend = ["portaudio"]
|
||||||
pulseaudio-backend= ["libpulse-sys"]
|
pulseaudio-backend= ["libpulse-sys"]
|
||||||
static-appkey = []
|
|
||||||
default = ["with-syntex", "portaudio-backend"]
|
default = ["with-syntex", "portaudio-backend"]
|
||||||
|
|
|
@ -37,7 +37,7 @@ cargo build --release
|
||||||
A sample program implementing a headless Spotify Connect receiver is provided.
|
A sample program implementing a headless Spotify Connect receiver is provided.
|
||||||
Once you've built *librespot*, run it using :
|
Once you've built *librespot*, run it using :
|
||||||
```shell
|
```shell
|
||||||
target/release/librespot --appkey APPKEY --username USERNAME --cache CACHEDIR --name DEVICENAME
|
target/release/librespot --username USERNAME --cache CACHEDIR --name DEVICENAME
|
||||||
```
|
```
|
||||||
|
|
||||||
## Discovery mode
|
## Discovery mode
|
||||||
|
@ -49,7 +49,7 @@ For that, simply omit the `--username` argument.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
cargo build --release --features facebook
|
cargo build --release --features facebook
|
||||||
target/release/librespot --appkey APPKEY --cache CACHEDIR --name DEVICENAME --facebook
|
target/release/librespot --cache CACHEDIR --name DEVICENAME --facebook
|
||||||
```
|
```
|
||||||
|
|
||||||
This will print a link to the console, which must be visited on the same computer *librespot* is running on.
|
This will print a link to the console, which must be visited on the same computer *librespot* is running on.
|
||||||
|
@ -78,8 +78,8 @@ cargo build --no-default-features --features "nightly portaudio-backend"
|
||||||
This produces better compilation error messages than with the default configuration.
|
This produces better compilation error messages than with the default configuration.
|
||||||
|
|
||||||
## Disclaimer
|
## Disclaimer
|
||||||
Using this code to connect to Spotify's API is probably forbidden by them, and
|
Using this code to connect to Spotify's API is probably forbidden by them.
|
||||||
might result in your application key getting banned. Use at your own risk
|
Use at your own risk.
|
||||||
|
|
||||||
## Contact
|
## Contact
|
||||||
Come and hang out on gitter if you need help or want to offer some.
|
Come and hang out on gitter if you need help or want to offer some.
|
||||||
|
|
|
@ -60,11 +60,6 @@ pub mod version {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "static-appkey")]
|
|
||||||
static APPKEY: Option<&'static [u8]> = Some(include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/spotify_appkey.key")));
|
|
||||||
#[cfg(not(feature = "static-appkey"))]
|
|
||||||
static APPKEY: Option<&'static [u8]> = None;
|
|
||||||
|
|
||||||
#[cfg(feature = "with-syntex")]
|
#[cfg(feature = "with-syntex")]
|
||||||
include!(concat!(env!("OUT_DIR"), "/lib.rs"));
|
include!(concat!(env!("OUT_DIR"), "/lib.rs"));
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use getopts;
|
use getopts;
|
||||||
use rpassword;
|
use rpassword;
|
||||||
use std::fs::File;
|
use std::io::{stdout, Write};
|
||||||
use std::io::{stdout, Read, Write};
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::path::Path;
|
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
|
||||||
use audio_backend::{BACKENDS, Sink};
|
use audio_backend::{BACKENDS, Sink};
|
||||||
|
@ -12,7 +10,6 @@ use cache::{Cache, DefaultCache, NoCache};
|
||||||
use player::Player;
|
use player::Player;
|
||||||
use session::{Bitrate, Config, Session};
|
use session::{Bitrate, Config, Session};
|
||||||
use version;
|
use version;
|
||||||
use APPKEY;
|
|
||||||
|
|
||||||
pub fn find_backend(name: Option<&str>) -> &'static (Fn() -> Box<Sink> + Send + Sync) {
|
pub fn find_backend(name: Option<&str>) -> &'static (Fn() -> Box<Sink> + Send + Sync) {
|
||||||
match name {
|
match name {
|
||||||
|
@ -37,27 +34,10 @@ pub fn find_backend(name: Option<&str>) -> &'static (Fn() -> Box<Sink> + Send +
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_appkey<P: AsRef<Path>>(path: Option<P>) -> Vec<u8> {
|
|
||||||
path.map(|path| {
|
|
||||||
let mut file = File::open(path).expect("Could not open app key.");
|
|
||||||
|
|
||||||
let mut data = Vec::new();
|
|
||||||
file.read_to_end(&mut data).unwrap();
|
|
||||||
|
|
||||||
data
|
|
||||||
}).or_else(|| APPKEY.map(ToOwned::to_owned)).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_session_arguments(opts: &mut getopts::Options) {
|
pub fn add_session_arguments(opts: &mut getopts::Options) {
|
||||||
opts.optopt("c", "cache", "Path to a directory where files will be cached.", "CACHE")
|
opts.optopt("c", "cache", "Path to a directory where files will be cached.", "CACHE")
|
||||||
.reqopt("n", "name", "Device name", "NAME")
|
.reqopt("n", "name", "Device name", "NAME")
|
||||||
.optopt("b", "bitrate", "Bitrate (96, 160 or 320). Defaults to 160", "BITRATE");
|
.optopt("b", "bitrate", "Bitrate (96, 160 or 320). Defaults to 160", "BITRATE");
|
||||||
|
|
||||||
if APPKEY.is_none() {
|
|
||||||
opts.reqopt("a", "appkey", "Path to a spotify appkey", "APPKEY");
|
|
||||||
} else {
|
|
||||||
opts.optopt("a", "appkey", "Path to a spotify appkey", "APPKEY");
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_authentication_arguments(opts: &mut getopts::Options) {
|
pub fn add_authentication_arguments(opts: &mut getopts::Options) {
|
||||||
|
@ -79,7 +59,6 @@ pub fn create_session(matches: &getopts::Matches) -> Session {
|
||||||
version::commit_date(),
|
version::commit_date(),
|
||||||
version::short_now());
|
version::short_now());
|
||||||
|
|
||||||
let appkey = load_appkey(matches.opt_str("a"));
|
|
||||||
let name = matches.opt_str("n").unwrap();
|
let name = matches.opt_str("n").unwrap();
|
||||||
let bitrate = match matches.opt_str("b").as_ref().map(String::as_ref) {
|
let bitrate = match matches.opt_str("b").as_ref().map(String::as_ref) {
|
||||||
None => Bitrate::Bitrate160, // default value
|
None => Bitrate::Bitrate160, // default value
|
||||||
|
@ -98,7 +77,6 @@ pub fn create_session(matches: &getopts::Matches) -> Session {
|
||||||
}).unwrap_or_else(|| Box::new(NoCache) as Box<Cache + Send + Sync>);
|
}).unwrap_or_else(|| Box::new(NoCache) as Box<Cache + Send + Sync>);
|
||||||
|
|
||||||
let config = Config {
|
let config = Config {
|
||||||
application_key: appkey,
|
|
||||||
user_agent: version::version_string(),
|
user_agent: version::version_string(),
|
||||||
device_name: name,
|
device_name: name,
|
||||||
bitrate: bitrate,
|
bitrate: bitrate,
|
||||||
|
|
|
@ -36,7 +36,6 @@ pub enum Bitrate {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub application_key: Vec<u8>,
|
|
||||||
pub user_agent: String,
|
pub user_agent: String,
|
||||||
pub device_name: String,
|
pub device_name: String,
|
||||||
pub bitrate: Bitrate,
|
pub bitrate: Bitrate,
|
||||||
|
@ -102,33 +101,19 @@ impl Session {
|
||||||
|
|
||||||
let request = protobuf_init!(protocol::keyexchange::ClientHello::new(), {
|
let request = protobuf_init!(protocol::keyexchange::ClientHello::new(), {
|
||||||
build_info => {
|
build_info => {
|
||||||
product: protocol::keyexchange::Product::PRODUCT_LIBSPOTIFY_EMBEDDED,
|
product: protocol::keyexchange::Product::PRODUCT_PARTNER,
|
||||||
platform: protocol::keyexchange::Platform::PLATFORM_LINUX_X86,
|
platform: protocol::keyexchange::Platform::PLATFORM_LINUX_X86,
|
||||||
version: 0x10800000000,
|
version: 0x10800000000,
|
||||||
},
|
},
|
||||||
/*
|
|
||||||
fingerprints_supported => [
|
|
||||||
protocol::keyexchange::Fingerprint::FINGERPRINT_GRAIN
|
|
||||||
],
|
|
||||||
*/
|
|
||||||
cryptosuites_supported => [
|
cryptosuites_supported => [
|
||||||
protocol::keyexchange::Cryptosuite::CRYPTO_SUITE_SHANNON,
|
protocol::keyexchange::Cryptosuite::CRYPTO_SUITE_SHANNON,
|
||||||
//protocol::keyexchange::Cryptosuite::CRYPTO_SUITE_RC4_SHA1_HMAC
|
|
||||||
],
|
],
|
||||||
/*
|
|
||||||
powschemes_supported => [
|
|
||||||
protocol::keyexchange::Powscheme::POW_HASH_CASH
|
|
||||||
],
|
|
||||||
*/
|
|
||||||
login_crypto_hello.diffie_hellman => {
|
login_crypto_hello.diffie_hellman => {
|
||||||
gc: local_keys.public_key(),
|
gc: local_keys.public_key(),
|
||||||
server_keys_known: 1,
|
server_keys_known: 1,
|
||||||
},
|
},
|
||||||
client_nonce: util::rand_vec(&mut thread_rng(), 0x10),
|
client_nonce: util::rand_vec(&mut thread_rng(), 0x10),
|
||||||
padding: vec![0x1e],
|
padding: vec![0x1e],
|
||||||
feature_set => {
|
|
||||||
autoupdate2: true,
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let init_client_packet = connection.send_packet_prefix(&[0, 4],
|
let init_client_packet = connection.send_packet_prefix(&[0, 4],
|
||||||
|
@ -196,13 +181,6 @@ impl Session {
|
||||||
device_id: self.device_id().to_owned(),
|
device_id: self.device_id().to_owned(),
|
||||||
},
|
},
|
||||||
version_string: version::version_string(),
|
version_string: version::version_string(),
|
||||||
appkey => {
|
|
||||||
version: self.config().application_key[0] as u32,
|
|
||||||
devkey: self.config().application_key[0x1..0x81].to_vec(),
|
|
||||||
signature: self.config().application_key[0x81..0x141].to_vec(),
|
|
||||||
useragent: self.config().user_agent.clone(),
|
|
||||||
callback_hash: vec![0; 20],
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut connection = self.connect();
|
let mut connection = self.connect();
|
||||||
|
|
Loading…
Reference in a new issue