2015-07-09 19:08:56 +00:00
|
|
|
#![feature(scoped)]
|
2015-07-19 20:36:14 +00:00
|
|
|
#![feature(result_expect)]
|
2015-07-02 17:24:25 +00:00
|
|
|
#![allow(deprecated)]
|
2015-04-25 20:32:07 +00:00
|
|
|
|
2015-07-19 20:36:14 +00:00
|
|
|
extern crate getopts;
|
2015-07-09 19:08:56 +00:00
|
|
|
extern crate librespot;
|
2015-07-19 20:36:14 +00:00
|
|
|
extern crate rpassword;
|
2015-04-25 20:32:07 +00:00
|
|
|
|
2015-06-23 14:38:29 +00:00
|
|
|
use std::clone::Clone;
|
2015-05-09 10:07:24 +00:00
|
|
|
use std::fs::File;
|
2015-07-19 20:36:14 +00:00
|
|
|
use std::io::{stdout, Read, Write};
|
2015-05-09 10:07:24 +00:00
|
|
|
use std::path::Path;
|
2015-07-02 17:24:25 +00:00
|
|
|
use std::thread;
|
2015-07-07 21:40:31 +00:00
|
|
|
use std::path::PathBuf;
|
2015-05-09 10:07:24 +00:00
|
|
|
|
2015-07-19 20:36:14 +00:00
|
|
|
use getopts::Options;
|
|
|
|
use rpassword::read_password;
|
|
|
|
|
2015-07-08 18:28:17 +00:00
|
|
|
use librespot::session::{Config, Session};
|
|
|
|
use librespot::util::version::version_string;
|
2015-07-08 19:50:44 +00:00
|
|
|
use librespot::player::Player;
|
|
|
|
use librespot::spirc::SpircManager;
|
2015-04-25 20:32:07 +00:00
|
|
|
|
2015-07-19 20:36:14 +00:00
|
|
|
fn usage(program: &str, opts: &Options) -> String {
|
|
|
|
let brief = format!("Usage: {} [options]", program);
|
|
|
|
format!("{}", opts.usage(&brief))
|
|
|
|
}
|
|
|
|
|
2015-04-25 20:32:07 +00:00
|
|
|
fn main() {
|
2015-07-19 20:36:14 +00:00
|
|
|
let args: Vec<String> = std::env::args().collect();
|
|
|
|
let program = args[0].clone();
|
|
|
|
|
|
|
|
let mut opts = Options::new();
|
|
|
|
opts.reqopt("a", "appkey", "Path to a spotify appkey", "APPKEY");
|
|
|
|
opts.reqopt("u", "username", "Username to sign in with", "USERNAME");
|
|
|
|
opts.optopt("p", "password", "Password (optional)", "PASSWORD");
|
|
|
|
opts.reqopt("c", "cache", "Path to a directory where files will be cached.", "CACHE");
|
|
|
|
opts.reqopt("n", "name", "Device name", "NAME");
|
|
|
|
let matches = match opts.parse(&args[1..]) {
|
|
|
|
Ok(m) => { m },
|
|
|
|
Err(f) => {
|
|
|
|
print!("Error: {}\n{}", f.to_string(), usage(&*program, &opts));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut appkey_file = File::open(
|
|
|
|
Path::new(&*matches.opt_str("a").unwrap())
|
|
|
|
).expect("Could not open app key.");
|
|
|
|
|
|
|
|
let username = matches.opt_str("u").unwrap();
|
|
|
|
let cache_location = matches.opt_str("c").unwrap();
|
|
|
|
let name = matches.opt_str("n").unwrap();
|
|
|
|
|
|
|
|
let password = matches.opt_str("p").unwrap_or_else(|| {
|
|
|
|
print!("Password: ");
|
|
|
|
stdout().flush().unwrap();
|
|
|
|
read_password().unwrap()
|
|
|
|
});
|
2015-05-09 10:07:24 +00:00
|
|
|
|
|
|
|
let mut appkey = Vec::new();
|
|
|
|
appkey_file.read_to_end(&mut appkey).unwrap();
|
|
|
|
|
|
|
|
let config = Config {
|
|
|
|
application_key: appkey,
|
2015-07-01 23:27:19 +00:00
|
|
|
user_agent: version_string(),
|
2015-07-07 21:40:31 +00:00
|
|
|
device_id: name.clone(),
|
|
|
|
cache_location: PathBuf::from(cache_location)
|
2015-05-09 10:07:24 +00:00
|
|
|
};
|
2015-06-23 14:38:29 +00:00
|
|
|
let session = Session::new(config);
|
2015-07-01 23:27:19 +00:00
|
|
|
session.login(username.clone(), password);
|
2015-06-23 14:38:29 +00:00
|
|
|
session.poll();
|
2015-05-09 10:07:24 +00:00
|
|
|
|
2015-07-02 17:24:25 +00:00
|
|
|
let poll_thread = thread::scoped(|| {
|
|
|
|
loop {
|
|
|
|
session.poll();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2015-07-02 19:42:49 +00:00
|
|
|
let player = Player::new(&session);
|
|
|
|
|
2015-07-09 20:08:14 +00:00
|
|
|
let mut spirc_manager = SpircManager::new(&session, player, username, name);
|
2015-07-08 19:50:44 +00:00
|
|
|
spirc_manager.run();
|
2015-07-01 17:49:03 +00:00
|
|
|
|
2015-07-02 17:24:25 +00:00
|
|
|
poll_thread.join();
|
2015-07-01 17:49:03 +00:00
|
|
|
}
|
|
|
|
|