free-librespot/src/main_helper.rs
Jörg Krause 1d3c387fed Add --on{start,stop} command line option
The --onstart and --onstop command line options can be used to run a
program when the audio playback is about to begin or has ended.

Note, that librespot needs executions rights to run the program.
Furthermore, the full path needs to be specified, e.g.
`/usr/bin/logger`. Executable scripts must begin with a shebang, e.g.
`#!/bin/sh`.
2016-09-08 20:52:21 +02:00

141 lines
4.8 KiB
Rust

use getopts;
use rpassword;
use std::io::{stdout, Write};
use std::path::PathBuf;
use std::process::exit;
use audio_backend::{BACKENDS, Sink};
use authentication::{Credentials, facebook_login, discovery_login};
use cache::{Cache, DefaultCache, NoCache};
use player::Player;
use session::{Bitrate, Config, Session};
use version;
pub fn find_backend(name: Option<&str>) -> &'static (Fn(Option<&str>) -> Box<Sink> + Send + Sync) {
match name {
Some("?") => {
println!("Available Backends : ");
for (&(name, _), idx) in BACKENDS.iter().zip(0..) {
if idx == 0 {
println!("- {} (default)", name);
} else {
println!("- {}", name);
}
}
exit(0);
},
Some(name) => {
BACKENDS.iter().find(|backend| name == backend.0).expect("Unknown backend").1
},
None => {
BACKENDS.first().expect("No backends were enabled at build time").1
}
}
}
pub fn add_session_arguments(opts: &mut getopts::Options) {
opts.optopt("c", "cache", "Path to a directory where files will be cached.", "CACHE")
.reqopt("n", "name", "Device name", "NAME")
.optopt("b", "bitrate", "Bitrate (96, 160 or 320). Defaults to 160", "BITRATE");
}
pub fn add_authentication_arguments(opts: &mut getopts::Options) {
opts.optopt("u", "username", "Username to sign in with", "USERNAME")
.optopt("p", "password", "Password", "PASSWORD");
if cfg!(feature = "facebook") {
opts.optflag("", "facebook", "Login with a Facebook account");
}
}
pub fn add_player_arguments(opts: &mut getopts::Options) {
opts.optopt("", "backend", "Audio backend to use. Use '?' to list options", "BACKEND");
opts.optopt("", "device", "Audio device to use. Use '?' to list options", "DEVICE");
}
pub fn add_program_arguments(opts: &mut getopts::Options) {
opts.optopt("", "onstart", "Run PROGRAM when playback is about to begin.", "PROGRAM");
opts.optopt("", "onstop", "Run PROGRAM when playback has ended.", "PROGRAM");
}
pub fn create_session(matches: &getopts::Matches) -> Session {
info!("librespot {} ({}). Built on {}.",
version::short_sha(),
version::commit_date(),
version::short_now());
let name = matches.opt_str("n").unwrap();
let bitrate = match matches.opt_str("b").as_ref().map(String::as_ref) {
None => Bitrate::Bitrate160, // default value
Some("96") => Bitrate::Bitrate96,
Some("160") => Bitrate::Bitrate160,
Some("320") => Bitrate::Bitrate320,
Some(b) => {
error!("Invalid bitrate {}", b);
exit(1)
}
};
let cache = matches.opt_str("c").map(|cache_location| {
Box::new(DefaultCache::new(PathBuf::from(cache_location)).unwrap()) as Box<Cache + Send + Sync>
}).unwrap_or_else(|| Box::new(NoCache) as Box<Cache + Send + Sync>);
let onstart = matches.opt_str("onstart");
let onstop = matches.opt_str("onstop");
let config = Config {
user_agent: version::version_string(),
device_name: name,
bitrate: bitrate,
onstart: onstart,
onstop: onstop,
};
Session::new(config, cache)
}
pub fn get_credentials(session: &Session, matches: &getopts::Matches) -> Credentials {
let credentials = session.cache().get_credentials();
match (matches.opt_str("username"),
matches.opt_str("password"),
credentials) {
(Some(username), Some(password), _)
=> Credentials::with_password(username, password),
(Some(ref username), _, Some(ref credentials)) if *username == credentials.username
=> credentials.clone(),
(Some(username), None, _) => {
print!("Password for {}: ", username);
stdout().flush().unwrap();
let password = rpassword::read_password().unwrap();
Credentials::with_password(username.clone(), password)
}
(None, _, _) if cfg!(feature = "facebook") && matches.opt_present("facebook")
=> facebook_login().unwrap(),
(None, _, Some(credentials))
=> credentials,
(None, _, None) => {
info!("No username provided and no stored credentials, starting discovery ...");
discovery_login(&session.config().device_name, session.device_id()).unwrap()
}
}
}
pub fn create_player(session: &Session, matches: &getopts::Matches) -> Player {
let backend_name = matches.opt_str("backend");
let device_name = matches.opt_str("device");
let make_backend = find_backend(backend_name.as_ref().map(AsRef::as_ref));
Player::new(session.clone(), move || {
make_backend(device_name.as_ref().map(AsRef::as_ref))
})
}