mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
commit
f3bb85c33a
7 changed files with 84 additions and 86 deletions
|
@ -1,8 +1,11 @@
|
||||||
use std::path::PathBuf;
|
use std::fs;
|
||||||
use std::io::Read;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
use std::io;
|
||||||
|
use std::io::Read;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use util::{FileId, mkdir_existing};
|
use util::FileId;
|
||||||
use authentication::Credentials;
|
use authentication::Credentials;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -11,6 +14,16 @@ pub struct Cache {
|
||||||
use_audio_cache: bool,
|
use_audio_cache: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mkdir_existing(path: &Path) -> io::Result<()> {
|
||||||
|
fs::create_dir(path).or_else(|err| {
|
||||||
|
if err.kind() == io::ErrorKind::AlreadyExists {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
impl Cache {
|
impl Cache {
|
||||||
pub fn new(location: PathBuf, use_audio_cache: bool) -> Cache {
|
pub fn new(location: PathBuf, use_audio_cache: bool) -> Cache {
|
||||||
mkdir_existing(&location).unwrap();
|
mkdir_existing(&location).unwrap();
|
||||||
|
|
|
@ -11,7 +11,7 @@ pub struct MercurySender {
|
||||||
|
|
||||||
impl MercurySender {
|
impl MercurySender {
|
||||||
// TODO: pub(super) when stable
|
// TODO: pub(super) when stable
|
||||||
pub fn new(mercury: MercuryManager, uri: String) -> MercurySender {
|
pub(crate) fn new(mercury: MercuryManager, uri: String) -> MercurySender {
|
||||||
MercurySender {
|
MercurySender {
|
||||||
mercury: mercury,
|
mercury: mercury,
|
||||||
uri: uri,
|
uri: uri,
|
||||||
|
|
|
@ -184,7 +184,7 @@ impl Session {
|
||||||
self.0.cache.as_ref()
|
self.0.cache.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn config(&self) -> &SessionConfig {
|
fn config(&self) -> &SessionConfig {
|
||||||
&self.0.config
|
&self.0.config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +200,7 @@ impl Session {
|
||||||
&self.config().device_id
|
&self.config().device_id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn weak(&self) -> SessionWeak {
|
fn weak(&self) -> SessionWeak {
|
||||||
SessionWeak(Arc::downgrade(&self.0))
|
SessionWeak(Arc::downgrade(&self.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,11 +213,11 @@ impl Session {
|
||||||
pub struct SessionWeak(pub Weak<SessionInternal>);
|
pub struct SessionWeak(pub Weak<SessionInternal>);
|
||||||
|
|
||||||
impl SessionWeak {
|
impl SessionWeak {
|
||||||
pub fn try_upgrade(&self) -> Option<Session> {
|
fn try_upgrade(&self) -> Option<Session> {
|
||||||
self.0.upgrade().map(Session)
|
self.0.upgrade().map(Session)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upgrade(&self) -> Session {
|
pub(crate) fn upgrade(&self) -> Session {
|
||||||
self.try_upgrade().expect("Session died")
|
self.try_upgrade().expect("Session died")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,54 +2,19 @@ use num_bigint::BigUint;
|
||||||
use num_traits::{Zero, One};
|
use num_traits::{Zero, One};
|
||||||
use num_integer::Integer;
|
use num_integer::Integer;
|
||||||
use rand::{Rng, Rand};
|
use rand::{Rng, Rand};
|
||||||
use std::io;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{Mul, Rem, Shr};
|
use std::ops::{Mul, Rem, Shr};
|
||||||
use std::fs;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::process::Command;
|
|
||||||
use std::time::{UNIX_EPOCH, SystemTime};
|
|
||||||
|
|
||||||
mod int128;
|
mod int128;
|
||||||
mod spotify_id;
|
mod spotify_id;
|
||||||
mod subfile;
|
|
||||||
|
|
||||||
pub use util::int128::u128;
|
pub use util::int128::u128;
|
||||||
pub use util::spotify_id::{SpotifyId, FileId};
|
pub use util::spotify_id::{SpotifyId, FileId};
|
||||||
pub use util::subfile::Subfile;
|
|
||||||
|
|
||||||
pub fn rand_vec<G: Rng, R: Rand>(rng: &mut G, size: usize) -> Vec<R> {
|
pub fn rand_vec<G: Rng, R: Rand>(rng: &mut G, size: usize) -> Vec<R> {
|
||||||
rng.gen_iter().take(size).collect()
|
rng.gen_iter().take(size).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn now_ms() -> i64 {
|
|
||||||
let dur = match SystemTime::now().duration_since(UNIX_EPOCH) {
|
|
||||||
Ok(dur) => dur,
|
|
||||||
Err(err) => err.duration(),
|
|
||||||
};
|
|
||||||
(dur.as_secs() * 1000 + (dur.subsec_nanos() / 1000_000) as u64) as i64
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mkdir_existing(path: &Path) -> io::Result<()> {
|
|
||||||
fs::create_dir(path).or_else(|err| {
|
|
||||||
if err.kind() == io::ErrorKind::AlreadyExists {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_program(program: &str) {
|
|
||||||
info!("Running {}", program);
|
|
||||||
let mut v: Vec<&str> = program.split_whitespace().collect();
|
|
||||||
let status = Command::new(&v.remove(0))
|
|
||||||
.args(&v)
|
|
||||||
.status()
|
|
||||||
.expect("program failed to start");
|
|
||||||
info!("Exit status: {}", status);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn powm(base: &BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint {
|
pub fn powm(base: &BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint {
|
||||||
let mut base = base.clone();
|
let mut base = base.clone();
|
||||||
let mut exp = exp.clone();
|
let mut exp = exp.clone();
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
use std::io::{Read, Seek, SeekFrom, Result};
|
|
||||||
|
|
||||||
pub struct Subfile<T: Read + Seek> {
|
|
||||||
stream: T,
|
|
||||||
offset: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Read + Seek> Subfile<T> {
|
|
||||||
pub fn new(mut stream: T, offset: u64) -> Subfile<T> {
|
|
||||||
stream.seek(SeekFrom::Start(offset)).unwrap();
|
|
||||||
Subfile {
|
|
||||||
stream: stream,
|
|
||||||
offset: offset,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Read + Seek> Read for Subfile<T> {
|
|
||||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
self.stream.read(buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Read + Seek> Seek for Subfile<T> {
|
|
||||||
fn seek(&mut self, mut pos: SeekFrom) -> Result<u64> {
|
|
||||||
pos = match pos {
|
|
||||||
SeekFrom::Start(offset) => SeekFrom::Start(offset + self.offset),
|
|
||||||
x => x,
|
|
||||||
};
|
|
||||||
|
|
||||||
let newpos = try!(self.stream.seek(pos));
|
|
||||||
if newpos > self.offset {
|
|
||||||
Ok(newpos - self.offset)
|
|
||||||
} else {
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +1,17 @@
|
||||||
use futures::sync::oneshot;
|
use futures::sync::oneshot;
|
||||||
use futures::{future, Future};
|
use futures::{future, Future};
|
||||||
|
use std;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::io::{Read, Seek, SeekFrom, Result};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::process::Command;
|
||||||
use std::sync::mpsc::{RecvError, TryRecvError, RecvTimeoutError};
|
use std::sync::mpsc::{RecvError, TryRecvError, RecvTimeoutError};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std;
|
|
||||||
|
|
||||||
use core::config::{Bitrate, PlayerConfig};
|
use core::config::{Bitrate, PlayerConfig};
|
||||||
use core::session::Session;
|
use core::session::Session;
|
||||||
use core::util::{self, SpotifyId, Subfile};
|
use core::util::SpotifyId;
|
||||||
|
|
||||||
use audio_backend::Sink;
|
use audio_backend::Sink;
|
||||||
use audio::{AudioFile, AudioDecrypt};
|
use audio::{AudioFile, AudioDecrypt};
|
||||||
|
@ -375,13 +377,13 @@ impl PlayerInternal {
|
||||||
|
|
||||||
fn run_onstart(&self) {
|
fn run_onstart(&self) {
|
||||||
if let Some(ref program) = self.config.onstart {
|
if let Some(ref program) = self.config.onstart {
|
||||||
util::run_program(program)
|
run_program(program)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_onstop(&self) {
|
fn run_onstop(&self) {
|
||||||
if let Some(ref program) = self.config.onstop {
|
if let Some(ref program) = self.config.onstop {
|
||||||
util::run_program(program)
|
run_program(program)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,3 +480,50 @@ impl ::std::fmt::Debug for PlayerCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Subfile<T: Read + Seek> {
|
||||||
|
stream: T,
|
||||||
|
offset: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Read + Seek> Subfile<T> {
|
||||||
|
pub fn new(mut stream: T, offset: u64) -> Subfile<T> {
|
||||||
|
stream.seek(SeekFrom::Start(offset)).unwrap();
|
||||||
|
Subfile {
|
||||||
|
stream: stream,
|
||||||
|
offset: offset,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Read + Seek> Read for Subfile<T> {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
self.stream.read(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Read + Seek> Seek for Subfile<T> {
|
||||||
|
fn seek(&mut self, mut pos: SeekFrom) -> Result<u64> {
|
||||||
|
pos = match pos {
|
||||||
|
SeekFrom::Start(offset) => SeekFrom::Start(offset + self.offset),
|
||||||
|
x => x,
|
||||||
|
};
|
||||||
|
|
||||||
|
let newpos = try!(self.stream.seek(pos));
|
||||||
|
if newpos > self.offset {
|
||||||
|
Ok(newpos - self.offset)
|
||||||
|
} else {
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_program(program: &str) {
|
||||||
|
info!("Running {}", program);
|
||||||
|
let mut v: Vec<&str> = program.split_whitespace().collect();
|
||||||
|
let status = Command::new(&v.remove(0))
|
||||||
|
.args(&v)
|
||||||
|
.status()
|
||||||
|
.expect("program failed to start");
|
||||||
|
info!("Exit status: {}", status);
|
||||||
|
}
|
||||||
|
|
11
src/spirc.rs
11
src/spirc.rs
|
@ -6,7 +6,7 @@ use protobuf::{self, Message};
|
||||||
use core::config::ConnectConfig;
|
use core::config::ConnectConfig;
|
||||||
use core::mercury::MercuryError;
|
use core::mercury::MercuryError;
|
||||||
use core::session::Session;
|
use core::session::Session;
|
||||||
use core::util::{now_ms, SpotifyId, SeqGenerator};
|
use core::util::{SpotifyId, SeqGenerator};
|
||||||
use core::version;
|
use core::version;
|
||||||
|
|
||||||
use protocol;
|
use protocol;
|
||||||
|
@ -18,6 +18,7 @@ use playback::player::Player;
|
||||||
use std;
|
use std;
|
||||||
use rand;
|
use rand;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
use std::time::{UNIX_EPOCH, SystemTime};
|
||||||
|
|
||||||
pub struct SpircTask {
|
pub struct SpircTask {
|
||||||
player: Player,
|
player: Player,
|
||||||
|
@ -53,6 +54,14 @@ pub struct Spirc {
|
||||||
commands: mpsc::UnboundedSender<SpircCommand>,
|
commands: mpsc::UnboundedSender<SpircCommand>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn now_ms() -> i64 {
|
||||||
|
let dur = match SystemTime::now().duration_since(UNIX_EPOCH) {
|
||||||
|
Ok(dur) => dur,
|
||||||
|
Err(err) => err.duration(),
|
||||||
|
};
|
||||||
|
(dur.as_secs() * 1000 + (dur.subsec_nanos() / 1000_000) as u64) as i64
|
||||||
|
}
|
||||||
|
|
||||||
fn initial_state() -> State {
|
fn initial_state() -> State {
|
||||||
protobuf_init!(protocol::spirc::State::new(), {
|
protobuf_init!(protocol::spirc::State::new(), {
|
||||||
repeat: false,
|
repeat: false,
|
||||||
|
|
Loading…
Reference in a new issue