refactor: general small refactors to simplify code

- Remove `expect` in favor of `unwrap` when the `Result`'s error variant
  contains the info in the `expect` anyway (eg. when locking things).
  The line number/context are given by the backtrace.
- Remove over-specification of types (`&T` instead of
  `&RWReadLockGuard`)
- Put reused values into constants
- `FromStr` instead of manual function
- Change `if let Some(()) = ...` to `if T.is_some()`
This commit is contained in:
Thomas Frans
2024-02-01 22:05:43 +01:00
committed by Henrik Friedrichsen
parent c5d666f35c
commit 3c8e546445
12 changed files with 97 additions and 96 deletions

View File

@@ -1,7 +1,8 @@
use std::env;
use std::error::Error;
use std::str::FromStr;
use std::sync::{Arc, RwLock};
use std::time::{Duration, SystemTime};
use std::{env, fmt};
use futures::channel::oneshot;
use librespot_core::authentication::Credentials;
@@ -56,8 +57,6 @@ pub struct Spotify {
since: Arc<RwLock<Option<SystemTime>>>,
/// Channel to send commands to the worker thread.
channel: Arc<RwLock<Option<mpsc::UnboundedSender<WorkerCommand>>>>,
/// The username of the logged in user.
user: Option<String>,
}
impl Spotify {
@@ -71,19 +70,18 @@ impl Spotify {
elapsed: Arc::new(RwLock::new(None)),
since: Arc::new(RwLock::new(None)),
channel: Arc::new(RwLock::new(None)),
user: None,
};
let (user_tx, user_rx) = oneshot::channel();
spotify.start_worker(Some(user_tx));
spotify.user = ASYNC_RUNTIME.get().unwrap().block_on(user_rx).ok();
let user = ASYNC_RUNTIME.get().unwrap().block_on(user_rx).ok();
let volume = cfg.state().volume;
spotify.set_volume(volume);
spotify.api.set_worker_channel(spotify.channel.clone());
spotify.api.update_token();
spotify.api.set_user(spotify.user.clone());
spotify.api.set_user(user);
spotify
}
@@ -92,10 +90,7 @@ impl Spotify {
/// in user.
pub fn start_worker(&self, user_tx: Option<oneshot::Sender<String>>) {
let (tx, rx) = mpsc::unbounded_channel();
*self
.channel
.write()
.expect("can't writelock worker channel") = Some(tx);
*self.channel.write().unwrap() = Some(tx);
{
let worker_channel = self.channel.clone();
let cfg = self.cfg.clone();
@@ -144,9 +139,10 @@ impl Spotify {
credentials: Credentials,
) -> Result<Session, SessionError> {
let librespot_cache_path = config::cache_path("librespot");
let audio_cache_path = match cfg.values().audio_cache.unwrap_or(true) {
true => Some(librespot_cache_path.join("files")),
false => None,
let audio_cache_path = if let Some(false) = cfg.values().audio_cache {
None
} else {
Some(librespot_cache_path.join("files"))
};
let cache = Cache::new(
Some(librespot_cache_path.clone()),
@@ -243,18 +239,13 @@ impl Spotify {
worker.run_loop().await;
error!("worker thread died, requesting restart");
*worker_channel
.write()
.expect("can't writelock worker channel") = None;
*worker_channel.write().unwrap() = None;
events.send(Event::SessionDied)
}
/// Get the current playback status of the [Player].
pub fn get_current_status(&self) -> PlayerEvent {
let status = self
.status
.read()
.expect("could not acquire read lock on playback status");
let status = self.status.read().unwrap();
(*status).clone()
}
@@ -268,34 +259,22 @@ impl Spotify {
}
fn set_elapsed(&self, new_elapsed: Option<Duration>) {
let mut elapsed = self
.elapsed
.write()
.expect("could not acquire write lock on elapsed time");
let mut elapsed = self.elapsed.write().unwrap();
*elapsed = new_elapsed;
}
fn get_elapsed(&self) -> Option<Duration> {
let elapsed = self
.elapsed
.read()
.expect("could not acquire read lock on elapsed time");
let elapsed = self.elapsed.read().unwrap();
*elapsed
}
fn set_since(&self, new_since: Option<SystemTime>) {
let mut since = self
.since
.write()
.expect("could not acquire write lock on since time");
let mut since = self.since.write().unwrap();
*since = new_since;
}
fn get_since(&self) -> Option<SystemTime> {
let since = self
.since
.read()
.expect("could not acquire read lock on since time");
let since = self.since.read().unwrap();
*since
}
@@ -329,10 +308,7 @@ impl Spotify {
}
}
let mut status = self
.status
.write()
.expect("could not acquire write lock on player status");
let mut status = self.status.write().unwrap();
*status = new_status;
}
@@ -361,7 +337,7 @@ impl Spotify {
/// Send a [WorkerCommand] to the worker thread.
fn send_worker(&self, cmd: WorkerCommand) {
info!("sending command to worker: {:?}", cmd);
let channel = self.channel.read().expect("can't readlock worker channel");
let channel = self.channel.read().unwrap();
match channel.as_ref() {
Some(channel) => {
if let Err(e) = channel.send(cmd) {
@@ -407,7 +383,7 @@ impl Spotify {
/// Set the current volume of the [Player].
pub fn set_volume(&self, volume: u16) {
info!("setting volume to {}", volume);
self.cfg.with_state_mut(|mut s| s.volume = volume);
self.cfg.with_state_mut(|s| s.volume = volume);
self.send_worker(WorkerCommand::SetVolume(volume));
}
@@ -434,23 +410,59 @@ pub enum UriType {
Episode,
}
impl UriType {
/// Try to create a [UriType] from the given string.
pub fn from_uri(s: &str) -> Option<Self> {
#[derive(Debug)]
pub struct UriParseError;
impl fmt::Display for UriParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("invalid Spotify URI")
}
}
impl Error for UriParseError {}
impl FromStr for UriType {
type Err = UriParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.starts_with("spotify:album:") {
Some(Self::Album)
Ok(Self::Album)
} else if s.starts_with("spotify:artist:") {
Some(Self::Artist)
Ok(Self::Artist)
} else if s.starts_with("spotify:track:") {
Some(Self::Track)
Ok(Self::Track)
} else if s.starts_with("spotify:") && s.contains(":playlist:") {
Some(Self::Playlist)
Ok(Self::Playlist)
} else if s.starts_with("spotify:show:") {
Some(Self::Show)
Ok(Self::Show)
} else if s.starts_with("spotify:episode:") {
Some(Self::Episode)
Ok(Self::Episode)
} else {
None
Err(UriParseError)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_album_uri() {
let uri_type = "spotify:album:29F5MF6Q9VYlryDsYEQz6a".parse();
assert!(matches!(uri_type, Ok(UriType::Album)));
}
#[test]
fn parse_invalid_uri() {
let uri_type: Result<UriType, _> = "kayava".parse();
assert!(matches!(uri_type, Err(UriParseError)));
}
#[test]
fn parse_playlist_uri() {
let uri_type = "spotify:playlist:37i9dQZF1DX36Xw4IJIVKA".parse();
assert!(matches!(uri_type, Ok(UriType::Playlist)));
}
}