mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
Merge pull request #652 from leshow/cleanup
clean up imports & clippy lints
This commit is contained in:
commit
38761395d3
27 changed files with 173 additions and 213 deletions
|
@ -138,19 +138,19 @@ impl StreamLoaderController {
|
|||
})
|
||||
}
|
||||
|
||||
fn send_stream_loader_command(&mut self, command: StreamLoaderCommand) {
|
||||
if let Some(ref mut channel) = self.channel_tx {
|
||||
fn send_stream_loader_command(&self, command: StreamLoaderCommand) {
|
||||
if let Some(ref channel) = self.channel_tx {
|
||||
// ignore the error in case the channel has been closed already.
|
||||
let _ = channel.send(command);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fetch(&mut self, range: Range) {
|
||||
pub fn fetch(&self, range: Range) {
|
||||
// signal the stream loader to fetch a range of the file
|
||||
self.send_stream_loader_command(StreamLoaderCommand::Fetch(range));
|
||||
}
|
||||
|
||||
pub fn fetch_blocking(&mut self, mut range: Range) {
|
||||
pub fn fetch_blocking(&self, mut range: Range) {
|
||||
// signal the stream loader to tech a range of the file and block until it is loaded.
|
||||
|
||||
// ensure the range is within the file's bounds.
|
||||
|
@ -182,47 +182,43 @@ impl StreamLoaderController {
|
|||
{
|
||||
// For some reason, the requested range is neither downloaded nor requested.
|
||||
// This could be due to a network error. Request it again.
|
||||
// We can't use self.fetch here because self can't be borrowed mutably, so we access the channel directly.
|
||||
if let Some(ref mut channel) = self.channel_tx {
|
||||
// ignore the error in case the channel has been closed already.
|
||||
let _ = channel.send(StreamLoaderCommand::Fetch(range));
|
||||
}
|
||||
self.fetch(range);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fetch_next(&mut self, length: usize) {
|
||||
pub fn fetch_next(&self, length: usize) {
|
||||
if let Some(ref shared) = self.stream_shared {
|
||||
let range = Range {
|
||||
start: shared.read_position.load(atomic::Ordering::Relaxed),
|
||||
length: length,
|
||||
length,
|
||||
};
|
||||
self.fetch(range)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fetch_next_blocking(&mut self, length: usize) {
|
||||
pub fn fetch_next_blocking(&self, length: usize) {
|
||||
if let Some(ref shared) = self.stream_shared {
|
||||
let range = Range {
|
||||
start: shared.read_position.load(atomic::Ordering::Relaxed),
|
||||
length: length,
|
||||
length,
|
||||
};
|
||||
self.fetch_blocking(range);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_random_access_mode(&mut self) {
|
||||
pub fn set_random_access_mode(&self) {
|
||||
// optimise download strategy for random access
|
||||
self.send_stream_loader_command(StreamLoaderCommand::RandomAccessMode());
|
||||
}
|
||||
|
||||
pub fn set_stream_mode(&mut self) {
|
||||
pub fn set_stream_mode(&self) {
|
||||
// optimise download strategy for streaming
|
||||
self.send_stream_loader_command(StreamLoaderCommand::StreamMode());
|
||||
}
|
||||
|
||||
pub fn close(&mut self) {
|
||||
pub fn close(&self) {
|
||||
// terminate stream loading and don't load any more data for this file.
|
||||
self.send_stream_loader_command(StreamLoaderCommand::Close());
|
||||
}
|
||||
|
@ -230,11 +226,8 @@ impl StreamLoaderController {
|
|||
|
||||
pub struct AudioFileStreaming {
|
||||
read_file: fs::File,
|
||||
|
||||
position: u64,
|
||||
|
||||
stream_loader_command_tx: mpsc::UnboundedSender<StreamLoaderCommand>,
|
||||
|
||||
shared: Arc<AudioFileShared>,
|
||||
}
|
||||
|
||||
|
@ -332,10 +325,7 @@ impl AudioFile {
|
|||
}
|
||||
|
||||
pub fn is_cached(&self) -> bool {
|
||||
match self {
|
||||
AudioFile::Cached { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(self, AudioFile::Cached { .. })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -359,7 +349,7 @@ impl AudioFileStreaming {
|
|||
let size = BigEndian::read_u32(&data) as usize * 4;
|
||||
|
||||
let shared = Arc::new(AudioFileShared {
|
||||
file_id: file_id,
|
||||
file_id,
|
||||
file_size: size,
|
||||
stream_data_rate: streaming_data_rate,
|
||||
cond: Condvar::new(),
|
||||
|
@ -396,11 +386,10 @@ impl AudioFileStreaming {
|
|||
|
||||
session.spawn(fetcher);
|
||||
Ok(AudioFileStreaming {
|
||||
read_file: read_file,
|
||||
read_file,
|
||||
position: 0,
|
||||
//seek: seek_tx,
|
||||
stream_loader_command_tx: stream_loader_command_tx,
|
||||
shared: shared,
|
||||
stream_loader_command_tx,
|
||||
shared,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -486,7 +475,7 @@ async fn audio_file_fetch_receive_data(
|
|||
let data_size = data.len();
|
||||
let _ = file_data_tx.send(ReceivedData::Data(PartialFileData {
|
||||
offset: data_offset,
|
||||
data: data,
|
||||
data,
|
||||
}));
|
||||
data_offset += data_size;
|
||||
if request_length < data_size {
|
||||
|
@ -728,14 +717,12 @@ impl AudioFileFetch {
|
|||
));
|
||||
|
||||
AudioFileFetch {
|
||||
session: session,
|
||||
shared: shared,
|
||||
session,
|
||||
shared,
|
||||
output: Some(output),
|
||||
|
||||
file_data_tx: file_data_tx,
|
||||
file_data_rx: file_data_rx,
|
||||
|
||||
stream_loader_command_rx: stream_loader_command_rx,
|
||||
file_data_tx,
|
||||
file_data_rx,
|
||||
stream_loader_command_rx,
|
||||
complete_tx: Some(complete_tx),
|
||||
network_response_times_ms: Vec::new(),
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use super::{AudioDecoder, AudioError, AudioPacket};
|
||||
|
||||
use lewton::inside_ogg::OggStreamReader;
|
||||
|
||||
use super::{AudioDecoder, AudioError, AudioPacket};
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
use std::io::{Read, Seek};
|
||||
|
@ -24,16 +25,15 @@ where
|
|||
fn seek(&mut self, ms: i64) -> Result<(), AudioError> {
|
||||
let absgp = ms * 44100 / 1000;
|
||||
match self.0.seek_absgp_pg(absgp as u64) {
|
||||
Ok(_) => return Ok(()),
|
||||
Err(err) => return Err(AudioError::VorbisError(err.into())),
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(AudioError::VorbisError(err.into())),
|
||||
}
|
||||
}
|
||||
|
||||
fn next_packet(&mut self) -> Result<Option<AudioPacket>, AudioError> {
|
||||
use lewton::audio::AudioReadError::AudioIsHeader;
|
||||
use lewton::OggReadError::NoCapturePatternFound;
|
||||
use lewton::VorbisError::BadAudio;
|
||||
use lewton::VorbisError::OggError;
|
||||
use lewton::VorbisError::{BadAudio, OggError};
|
||||
loop {
|
||||
match self.0.read_dec_packet_itl() {
|
||||
Ok(Some(packet)) => return Ok(Some(AudioPacket::Samples(packet))),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![allow(clippy::unused_io_amount)]
|
||||
#![allow(clippy::unused_io_amount, clippy::too_many_arguments)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
@ -85,13 +85,13 @@ impl fmt::Display for AudioError {
|
|||
|
||||
impl From<VorbisError> for AudioError {
|
||||
fn from(err: VorbisError) -> AudioError {
|
||||
AudioError::VorbisError(VorbisError::from(err))
|
||||
AudioError::VorbisError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PassthroughError> for AudioError {
|
||||
fn from(err: PassthroughError) -> AudioError {
|
||||
AudioError::PassthroughError(PassthroughError::from(err))
|
||||
AudioError::PassthroughError(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ fn write_headers<T: Read + Seek>(
|
|||
|
||||
// remove un-needed packets
|
||||
rdr.delete_unread_packets();
|
||||
return Ok(stream_serial);
|
||||
Ok(stream_serial)
|
||||
}
|
||||
|
||||
fn get_header<T>(
|
||||
|
@ -65,7 +65,7 @@ where
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
return Ok(*stream_serial);
|
||||
Ok(*stream_serial)
|
||||
}
|
||||
|
||||
pub struct PassthroughDecoder<R: Read + Seek> {
|
||||
|
@ -87,13 +87,13 @@ impl<R: Read + Seek> PassthroughDecoder<R> {
|
|||
let stream_serial = write_headers(&mut rdr, &mut wtr)?;
|
||||
info!("Starting passthrough track with serial {}", stream_serial);
|
||||
|
||||
return Ok(PassthroughDecoder {
|
||||
Ok(PassthroughDecoder {
|
||||
rdr,
|
||||
wtr,
|
||||
lastgp_page: Some(0),
|
||||
absgp_page: 0,
|
||||
stream_serial,
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,8 +107,8 @@ impl<R: Read + Seek> AudioDecoder for PassthroughDecoder<R> {
|
|||
|
||||
// hard-coded to 44.1 kHz
|
||||
match self.rdr.seek_absgp(None, (ms * 44100 / 1000) as u64) {
|
||||
Ok(_) => return Ok(()),
|
||||
Err(err) => return Err(AudioError::PassthroughError(err.into())),
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(AudioError::PassthroughError(err.into())),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,7 +164,7 @@ impl<R: Read + Seek> AudioDecoder for PassthroughDecoder<R> {
|
|||
|
||||
let data = self.wtr.inner_mut();
|
||||
|
||||
if data.len() > 0 {
|
||||
if !data.is_empty() {
|
||||
let result = AudioPacket::OggData(std::mem::take(data));
|
||||
return Ok(Some(result));
|
||||
}
|
||||
|
|
|
@ -16,14 +16,11 @@ impl fmt::Display for Range {
|
|||
|
||||
impl Range {
|
||||
pub fn new(start: usize, length: usize) -> Range {
|
||||
return Range {
|
||||
start: start,
|
||||
length: length,
|
||||
};
|
||||
Range { start, length }
|
||||
}
|
||||
|
||||
pub fn end(&self) -> usize {
|
||||
return self.start + self.length;
|
||||
self.start + self.length
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,7 +47,7 @@ impl RangeSet {
|
|||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
return self.ranges.is_empty();
|
||||
self.ranges.is_empty()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
|
@ -58,11 +55,11 @@ impl RangeSet {
|
|||
}
|
||||
|
||||
pub fn get_range(&self, index: usize) -> Range {
|
||||
return self.ranges[index].clone();
|
||||
self.ranges[index]
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> Iter<Range> {
|
||||
return self.ranges.iter();
|
||||
self.ranges.iter()
|
||||
}
|
||||
|
||||
pub fn contains(&self, value: usize) -> bool {
|
||||
|
@ -73,7 +70,7 @@ impl RangeSet {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
false
|
||||
}
|
||||
|
||||
pub fn contained_length_from_value(&self, value: usize) -> usize {
|
||||
|
@ -84,7 +81,7 @@ impl RangeSet {
|
|||
return range.end() - value;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
0
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
@ -144,7 +141,7 @@ impl RangeSet {
|
|||
pub fn union(&self, other: &RangeSet) -> RangeSet {
|
||||
let mut result = self.clone();
|
||||
result.add_range_set(other);
|
||||
return result;
|
||||
result
|
||||
}
|
||||
|
||||
pub fn subtract_range(&mut self, range: &Range) {
|
||||
|
@ -204,7 +201,7 @@ impl RangeSet {
|
|||
pub fn minus(&self, other: &RangeSet) -> RangeSet {
|
||||
let mut result = self.clone();
|
||||
result.subtract_range_set(other);
|
||||
return result;
|
||||
result
|
||||
}
|
||||
|
||||
pub fn intersection(&self, other: &RangeSet) -> RangeSet {
|
||||
|
@ -240,6 +237,6 @@ impl RangeSet {
|
|||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
result
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,34 +5,31 @@ use futures_core::Stream;
|
|||
use hmac::{Hmac, Mac, NewMac};
|
||||
use hyper::service::{make_service_fn, service_fn};
|
||||
use hyper::{Body, Method, Request, Response, StatusCode};
|
||||
use num_bigint::BigUint;
|
||||
use serde_json::json;
|
||||
use sha1::{Digest, Sha1};
|
||||
use tokio::sync::{mpsc, oneshot};
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::convert::Infallible;
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
#[cfg(feature = "with-dns-sd")]
|
||||
use dns_sd::DNSService;
|
||||
|
||||
#[cfg(not(feature = "with-dns-sd"))]
|
||||
use libmdns;
|
||||
|
||||
use num_bigint::BigUint;
|
||||
use rand;
|
||||
use std::collections::BTreeMap;
|
||||
use std::io;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use url;
|
||||
|
||||
use librespot_core::authentication::Credentials;
|
||||
use librespot_core::config::ConnectConfig;
|
||||
use librespot_core::diffie_hellman::{DH_GENERATOR, DH_PRIME};
|
||||
use librespot_core::util;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeMap;
|
||||
use std::convert::Infallible;
|
||||
use std::io;
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
type HmacSha1 = Hmac<Sha1>;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
const AP_FALLBACK: &'static str = "ap.spotify.com:443";
|
||||
const AP_FALLBACK: &str = "ap.spotify.com:443";
|
||||
|
||||
use url::Url;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "apresolve")] {
|
||||
const APRESOLVE_ENDPOINT: &'static str = "http://apresolve.spotify.com:80";
|
||||
const APRESOLVE_ENDPOINT: &str = "http://apresolve.spotify.com:80";
|
||||
|
||||
use std::error::Error;
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ pub struct Credentials {
|
|||
impl Credentials {
|
||||
pub fn with_password(username: String, password: String) -> Credentials {
|
||||
Credentials {
|
||||
username: username,
|
||||
username,
|
||||
auth_type: AuthenticationType::AUTHENTICATION_USER_PASS,
|
||||
auth_data: password.into_bytes(),
|
||||
}
|
||||
|
@ -103,9 +103,9 @@ impl Credentials {
|
|||
let auth_data = read_bytes(&mut cursor).unwrap();
|
||||
|
||||
Credentials {
|
||||
username: username,
|
||||
auth_type: auth_type,
|
||||
auth_data: auth_data,
|
||||
username,
|
||||
auth_type,
|
||||
auth_data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ impl ChannelManager {
|
|||
}
|
||||
|
||||
pub fn get_download_rate_estimate(&self) -> usize {
|
||||
return self.lock(|inner| inner.download_rate_estimate);
|
||||
self.lock(|inner| inner.download_rate_estimate)
|
||||
}
|
||||
|
||||
pub(crate) fn shutdown(&self) {
|
||||
|
@ -139,7 +139,7 @@ impl Stream for Channel {
|
|||
match self.state.clone() {
|
||||
ChannelState::Closed => panic!("Polling already terminated channel"),
|
||||
ChannelState::Header(mut data) => {
|
||||
if data.len() == 0 {
|
||||
if data.is_empty() {
|
||||
data = match self.recv_packet(cx) {
|
||||
Poll::Ready(Ok(x)) => x,
|
||||
Poll::Ready(Err(x)) => return Poll::Ready(Some(Err(x))),
|
||||
|
@ -168,7 +168,7 @@ impl Stream for Channel {
|
|||
Poll::Ready(Err(x)) => return Poll::Ready(Some(Err(x))),
|
||||
Poll::Pending => return Poll::Pending,
|
||||
};
|
||||
if data.len() == 0 {
|
||||
if data.is_empty() {
|
||||
self.receiver.close();
|
||||
self.state = ChannelState::Closed;
|
||||
return Poll::Ready(None);
|
||||
|
|
|
@ -30,8 +30,8 @@ impl DHLocalKeys {
|
|||
let public_key = util::powm(&DH_GENERATOR, &private_key, &DH_PRIME);
|
||||
|
||||
DHLocalKeys {
|
||||
private_key: private_key,
|
||||
public_key: public_key,
|
||||
private_key,
|
||||
public_key,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -211,30 +211,28 @@ impl MercuryManager {
|
|||
if let Some(cb) = pending.callback {
|
||||
let _ = cb.send(Err(MercuryError));
|
||||
}
|
||||
} else {
|
||||
if cmd == 0xb5 {
|
||||
self.lock(|inner| {
|
||||
let mut found = false;
|
||||
inner.subscriptions.retain(|&(ref prefix, ref sub)| {
|
||||
if response.uri.starts_with(prefix) {
|
||||
found = true;
|
||||
} else if cmd == 0xb5 {
|
||||
self.lock(|inner| {
|
||||
let mut found = false;
|
||||
inner.subscriptions.retain(|&(ref prefix, ref sub)| {
|
||||
if response.uri.starts_with(prefix) {
|
||||
found = true;
|
||||
|
||||
// if send fails, remove from list of subs
|
||||
// TODO: send unsub message
|
||||
sub.send(response.clone()).is_ok()
|
||||
} else {
|
||||
// URI doesn't match
|
||||
true
|
||||
}
|
||||
});
|
||||
|
||||
if !found {
|
||||
debug!("unknown subscription uri={}", response.uri);
|
||||
// if send fails, remove from list of subs
|
||||
// TODO: send unsub message
|
||||
sub.send(response.clone()).is_ok()
|
||||
} else {
|
||||
// URI doesn't match
|
||||
true
|
||||
}
|
||||
})
|
||||
} else if let Some(cb) = pending.callback {
|
||||
let _ = cb.send(Ok(response));
|
||||
}
|
||||
});
|
||||
|
||||
if !found {
|
||||
debug!("unknown subscription uri={}", response.uri);
|
||||
}
|
||||
})
|
||||
} else if let Some(cb) = pending.callback {
|
||||
let _ = cb.send(Ok(response));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,8 +12,8 @@ impl MercurySender {
|
|||
// TODO: pub(super) when stable
|
||||
pub(crate) fn new(mercury: MercuryManager, uri: String) -> MercurySender {
|
||||
MercurySender {
|
||||
mercury: mercury,
|
||||
uri: uri,
|
||||
mercury,
|
||||
uri,
|
||||
pending: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,25 +105,20 @@ impl Session {
|
|||
debug!("new Session[{}]", session_id);
|
||||
|
||||
let session = Session(Arc::new(SessionInternal {
|
||||
config: config,
|
||||
config,
|
||||
data: RwLock::new(SessionData {
|
||||
country: String::new(),
|
||||
canonical_username: username,
|
||||
invalid: false,
|
||||
time_delta: 0,
|
||||
}),
|
||||
|
||||
tx_connection: sender_tx,
|
||||
|
||||
cache: cache.map(Arc::new),
|
||||
|
||||
audio_key: OnceCell::new(),
|
||||
channel: OnceCell::new(),
|
||||
mercury: OnceCell::new(),
|
||||
|
||||
handle,
|
||||
|
||||
session_id: session_id,
|
||||
session_id,
|
||||
}));
|
||||
|
||||
let sender_task = UnboundedReceiverStream::new(sender_rx)
|
||||
|
|
|
@ -45,7 +45,7 @@ impl SpotifyId {
|
|||
const SIZE_BASE16: usize = 32;
|
||||
const SIZE_BASE62: usize = 22;
|
||||
|
||||
fn as_track(n: u128) -> SpotifyId {
|
||||
fn track(n: u128) -> SpotifyId {
|
||||
SpotifyId {
|
||||
id: n,
|
||||
audio_type: SpotifyAudioType::Track,
|
||||
|
@ -71,7 +71,7 @@ impl SpotifyId {
|
|||
dst += p;
|
||||
}
|
||||
|
||||
Ok(SpotifyId::as_track(dst))
|
||||
Ok(SpotifyId::track(dst))
|
||||
}
|
||||
|
||||
/// Parses a base62 encoded [Spotify ID] into a `SpotifyId`.
|
||||
|
@ -94,7 +94,7 @@ impl SpotifyId {
|
|||
dst += p;
|
||||
}
|
||||
|
||||
Ok(SpotifyId::as_track(dst))
|
||||
Ok(SpotifyId::track(dst))
|
||||
}
|
||||
|
||||
/// Creates a `SpotifyId` from a copy of `SpotifyId::SIZE` (16) bytes in big-endian order.
|
||||
|
@ -102,7 +102,7 @@ impl SpotifyId {
|
|||
/// The resulting `SpotifyId` will default to a `SpotifyAudioType::TRACK`.
|
||||
pub fn from_raw(src: &[u8]) -> Result<SpotifyId, SpotifyIdError> {
|
||||
match src.try_into() {
|
||||
Ok(dst) => Ok(SpotifyId::as_track(u128::from_be_bytes(dst))),
|
||||
Ok(dst) => Ok(SpotifyId::track(u128::from_be_bytes(dst))),
|
||||
Err(_) => Err(SpotifyIdError),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,33 +1,34 @@
|
|||
use librespot_core::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
// Test AP Resolve
|
||||
use apresolve::apresolve_or_fallback;
|
||||
#[tokio::test]
|
||||
async fn test_ap_resolve() {
|
||||
env_logger::init();
|
||||
let ap = apresolve_or_fallback(&None, &None).await;
|
||||
println!("AP: {:?}", ap);
|
||||
}
|
||||
// TODO: test is broken
|
||||
// #[cfg(test)]
|
||||
// mod tests {
|
||||
// use super::*;
|
||||
// // Test AP Resolve
|
||||
// use apresolve::apresolve_or_fallback;
|
||||
// #[tokio::test]
|
||||
// async fn test_ap_resolve() {
|
||||
// env_logger::init();
|
||||
// let ap = apresolve_or_fallback(&None, &None).await;
|
||||
// println!("AP: {:?}", ap);
|
||||
// }
|
||||
|
||||
// Test connect
|
||||
use authentication::Credentials;
|
||||
use config::SessionConfig;
|
||||
#[tokio::test]
|
||||
async fn test_connection() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("Running connection test");
|
||||
let ap = apresolve_or_fallback(&None, &None).await;
|
||||
let credentials = Credentials::with_password(String::from("test"), String::from("test"));
|
||||
let session_config = SessionConfig::default();
|
||||
let proxy = None;
|
||||
// // Test connect
|
||||
// use authentication::Credentials;
|
||||
// use config::SessionConfig;
|
||||
// #[tokio::test]
|
||||
// async fn test_connection() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// println!("Running connection test");
|
||||
// let ap = apresolve_or_fallback(&None, &None).await;
|
||||
// let credentials = Credentials::with_password(String::from("test"), String::from("test"));
|
||||
// let session_config = SessionConfig::default();
|
||||
// let proxy = None;
|
||||
|
||||
println!("Connecting to AP \"{}\"", ap);
|
||||
let mut connection = connection::connect(ap, &proxy).await?;
|
||||
let rc = connection::authenticate(&mut connection, credentials, &session_config.device_id)
|
||||
.await?;
|
||||
println!("Authenticated as \"{}\"", rc.username);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
// println!("Connecting to AP \"{}\"", ap);
|
||||
// let mut connection = connection::connect(ap, &proxy).await?;
|
||||
// let rc = connection::authenticate(&mut connection, credentials, &session_config.device_id)
|
||||
// .await?;
|
||||
// println!("Authenticated as \"{}\"", rc.username);
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -292,7 +292,7 @@ impl Metadata for Playlist {
|
|||
.get_items()
|
||||
.iter()
|
||||
.map(|item| {
|
||||
let uri_split = item.get_uri().split(":");
|
||||
let uri_split = item.get_uri().split(':');
|
||||
let uri_parts: Vec<&str> = uri_split.collect();
|
||||
SpotifyId::from_base62(uri_parts[2]).unwrap()
|
||||
})
|
||||
|
|
|
@ -2,9 +2,10 @@ use super::{Open, Sink};
|
|||
use crate::audio::AudioPacket;
|
||||
use gst::prelude::*;
|
||||
use gst::*;
|
||||
use zerocopy::*;
|
||||
|
||||
use std::sync::mpsc::{sync_channel, SyncSender};
|
||||
use std::{io, thread};
|
||||
use zerocopy::*;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct GstreamerSink {
|
||||
|
@ -91,10 +92,7 @@ impl Open for GstreamerSink {
|
|||
.set_state(gst::State::Playing)
|
||||
.expect("Unable to set the pipeline to the `Playing` state");
|
||||
|
||||
GstreamerSink {
|
||||
tx: tx,
|
||||
pipeline: pipeline,
|
||||
}
|
||||
GstreamerSink { tx, pipeline }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ impl Open for JackSink {
|
|||
|
||||
JackSink {
|
||||
send: tx,
|
||||
active_client: active_client,
|
||||
active_client,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ use self::pipe::StdoutSink;
|
|||
mod subprocess;
|
||||
use self::subprocess::SubprocessSink;
|
||||
|
||||
pub const BACKENDS: &'static [(&'static str, SinkBuilder)] = &[
|
||||
pub const BACKENDS: &[(&str, SinkBuilder)] = &[
|
||||
#[cfg(feature = "alsa-backend")]
|
||||
("alsa", mk_sink::<AlsaSink>),
|
||||
#[cfg(feature = "portaudio-backend")]
|
||||
|
|
|
@ -26,8 +26,8 @@ impl Open for PulseAudioSink {
|
|||
|
||||
PulseAudioSink {
|
||||
s: None,
|
||||
ss: ss,
|
||||
device: device,
|
||||
ss,
|
||||
device,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@ pub enum RodioError {
|
|||
|
||||
pub struct RodioSink {
|
||||
rodio_sink: rodio::Sink,
|
||||
|
||||
// will produce a TryRecvError on the receiver side when it is dropped.
|
||||
_close_tx: mpsc::SyncSender<Infallible>,
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ impl Open for SdlSink {
|
|||
.open_queue(None, &desired_spec)
|
||||
.expect("Could not open SDL audio device");
|
||||
|
||||
SdlSink { queue: queue }
|
||||
SdlSink { queue }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use super::{Open, Sink};
|
||||
use crate::audio::AudioPacket;
|
||||
|
||||
use shell_words::split;
|
||||
|
||||
use std::io::{self, Write};
|
||||
use std::mem;
|
||||
use std::process::{Child, Command, Stdio};
|
||||
|
@ -15,7 +17,7 @@ impl Open for SubprocessSink {
|
|||
fn open(shell_command: Option<String>) -> SubprocessSink {
|
||||
if let Some(shell_command) = shell_command {
|
||||
SubprocessSink {
|
||||
shell_command: shell_command,
|
||||
shell_command,
|
||||
child: None,
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
use super::AudioFilter;
|
||||
use super::{Mixer, MixerConfig};
|
||||
use std;
|
||||
use std::error::Error;
|
||||
|
||||
use alsa;
|
||||
|
||||
const SND_CTL_TLV_DB_GAIN_MUTE: i64 = -9999999;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -72,14 +69,14 @@ impl AlsaMixer {
|
|||
}
|
||||
|
||||
Ok(AlsaMixer {
|
||||
config: config,
|
||||
config,
|
||||
params: AlsaMixerVolumeParams {
|
||||
min: min,
|
||||
max: max,
|
||||
min,
|
||||
max,
|
||||
range: (max - min) as f64,
|
||||
min_db: min_db,
|
||||
max_db: max_db,
|
||||
has_switch: has_switch,
|
||||
min_db,
|
||||
max_db,
|
||||
has_switch,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
@ -252,8 +252,8 @@ impl Player {
|
|||
debug!("new Player[{}]", session.session_id());
|
||||
|
||||
let internal = PlayerInternal {
|
||||
session: session,
|
||||
config: config,
|
||||
session,
|
||||
config,
|
||||
commands: cmd_rx,
|
||||
|
||||
state: PlayerState::Stopped,
|
||||
|
@ -261,7 +261,7 @@ impl Player {
|
|||
sink: sink_builder(),
|
||||
sink_status: SinkStatus::Closed,
|
||||
sink_event_callback: None,
|
||||
audio_filter: audio_filter,
|
||||
audio_filter,
|
||||
event_senders: [event_sender].to_vec(),
|
||||
};
|
||||
|
||||
|
@ -432,18 +432,12 @@ impl PlayerState {
|
|||
#[allow(dead_code)]
|
||||
fn is_stopped(&self) -> bool {
|
||||
use self::PlayerState::*;
|
||||
match *self {
|
||||
Stopped => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(self, Stopped)
|
||||
}
|
||||
|
||||
fn is_loading(&self) -> bool {
|
||||
use self::PlayerState::*;
|
||||
match *self {
|
||||
Loading { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(self, Loading { .. })
|
||||
}
|
||||
|
||||
fn decoder(&mut self) -> Option<&mut Decoder> {
|
||||
|
@ -697,7 +691,7 @@ impl PlayerTrackLoader {
|
|||
};
|
||||
let is_cached = encrypted_file.is_cached();
|
||||
|
||||
let mut stream_loader_controller = encrypted_file.get_stream_loader_controller();
|
||||
let stream_loader_controller = encrypted_file.get_stream_loader_controller();
|
||||
|
||||
if play_from_beginning {
|
||||
// No need to seek -> we stream from the beginning
|
||||
|
@ -908,11 +902,7 @@ impl Future for PlayerInternal {
|
|||
.as_millis()
|
||||
as i64
|
||||
- stream_position_millis as i64;
|
||||
if lag > 1000 {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
lag > 1000
|
||||
}
|
||||
};
|
||||
if notify_about_position {
|
||||
|
|
37
src/main.rs
37
src/main.rs
|
@ -2,6 +2,23 @@ use futures_util::{future, FutureExt, StreamExt};
|
|||
use librespot_playback::player::PlayerEvent;
|
||||
use log::{error, info, warn};
|
||||
use sha1::{Digest, Sha1};
|
||||
use tokio::sync::mpsc::UnboundedReceiver;
|
||||
use url::Url;
|
||||
|
||||
use librespot::connect::spirc::Spirc;
|
||||
use librespot::core::authentication::Credentials;
|
||||
use librespot::core::cache::Cache;
|
||||
use librespot::core::config::{ConnectConfig, DeviceType, SessionConfig, VolumeCtrl};
|
||||
use librespot::core::session::Session;
|
||||
use librespot::core::version;
|
||||
use librespot::playback::audio_backend::{self, Sink, BACKENDS};
|
||||
use librespot::playback::config::{Bitrate, NormalisationType, PlayerConfig};
|
||||
use librespot::playback::mixer::{self, Mixer, MixerConfig};
|
||||
use librespot::playback::player::Player;
|
||||
|
||||
mod player_event_handler;
|
||||
use player_event_handler::{emit_sink_event, run_program_on_events};
|
||||
|
||||
use std::path::Path;
|
||||
use std::process::exit;
|
||||
use std::str::FromStr;
|
||||
|
@ -10,24 +27,6 @@ use std::{
|
|||
io::{stderr, Write},
|
||||
pin::Pin,
|
||||
};
|
||||
use tokio::sync::mpsc::UnboundedReceiver;
|
||||
use url::Url;
|
||||
|
||||
use librespot::core::authentication::Credentials;
|
||||
use librespot::core::cache::Cache;
|
||||
use librespot::core::config::{ConnectConfig, DeviceType, SessionConfig, VolumeCtrl};
|
||||
use librespot::core::session::Session;
|
||||
use librespot::core::version;
|
||||
|
||||
use librespot::connect::spirc::Spirc;
|
||||
use librespot::playback::audio_backend::{self, Sink, BACKENDS};
|
||||
use librespot::playback::config::{Bitrate, NormalisationType, PlayerConfig};
|
||||
use librespot::playback::mixer::{self, Mixer, MixerConfig};
|
||||
use librespot::playback::player::Player;
|
||||
|
||||
mod player_event_handler;
|
||||
|
||||
use player_event_handler::{emit_sink_event, run_program_on_events};
|
||||
|
||||
fn device_id(name: &str) -> String {
|
||||
hex::encode(Sha1::digest(name.as_bytes()))
|
||||
|
@ -453,7 +452,7 @@ fn setup(args: &[String]) -> Setup {
|
|||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() {
|
||||
if env::var("RUST_BACKTRACE").is_err() {
|
||||
env::set_var("RUST_BACKTRACE", "full")
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
use librespot::playback::player::PlayerEvent;
|
||||
use librespot::playback::player::SinkStatus;
|
||||
use log::info;
|
||||
use tokio::process::{Child as AsyncChild, Command as AsyncCommand};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::process::{Command, ExitStatus};
|
||||
|
||||
use librespot::playback::player::SinkStatus;
|
||||
use tokio::process::{Child as AsyncChild, Command as AsyncCommand};
|
||||
|
||||
pub fn run_program_on_events(event: PlayerEvent, onevent: &str) -> Option<io::Result<AsyncChild>> {
|
||||
let mut env_vars = HashMap::new();
|
||||
match event {
|
||||
|
|
Loading…
Reference in a new issue