mirror of
https://github.com/talwat/lowfi
synced 2025-07-18 08:02:44 +00:00
chore: refactor track error to use thiserror
This commit is contained in:
parent
1af976ad77
commit
b6a81c9634
29
Cargo.lock
generated
29
Cargo.lock
generated
@ -1361,7 +1361,7 @@ dependencies = [
|
|||||||
"combine",
|
"combine",
|
||||||
"jni-sys",
|
"jni-sys",
|
||||||
"log",
|
"log",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
"windows-sys 0.45.0",
|
"windows-sys 0.45.0",
|
||||||
]
|
]
|
||||||
@ -1470,6 +1470,7 @@ dependencies = [
|
|||||||
"reqwest",
|
"reqwest",
|
||||||
"rodio",
|
"rodio",
|
||||||
"scraper",
|
"scraper",
|
||||||
|
"thiserror 2.0.12",
|
||||||
"tokio",
|
"tokio",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
"url",
|
"url",
|
||||||
@ -1593,7 +1594,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"ndk-sys",
|
"ndk-sys",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2018,7 +2019,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
"libredox",
|
"libredox",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2607,7 +2608,16 @@ version = "1.0.69"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl 1.0.69",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "2.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl 2.0.12",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2621,6 +2631,17 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "2.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinystr"
|
name = "tinystr"
|
||||||
version = "0.7.6"
|
version = "0.7.6"
|
||||||
|
@ -51,3 +51,4 @@ lazy_static = "1.5.0"
|
|||||||
libc = "0.2.167"
|
libc = "0.2.167"
|
||||||
url = "2.5.4"
|
url = "2.5.4"
|
||||||
unicode-segmentation = "1.12.0"
|
unicode-segmentation = "1.12.0"
|
||||||
|
thiserror = "2.0.12"
|
||||||
|
@ -31,7 +31,7 @@ use mpris_server::{PlaybackStatus, PlayerInterface, Property};
|
|||||||
use crate::{
|
use crate::{
|
||||||
messages::Messages,
|
messages::Messages,
|
||||||
play::{PersistentVolume, SendableOutputStream},
|
play::{PersistentVolume, SendableOutputStream},
|
||||||
tracks::{self, bookmark, list::List, TrackError},
|
tracks::{self, bookmark, list::List},
|
||||||
Args,
|
Args,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -209,7 +209,7 @@ impl Player {
|
|||||||
self.list.random(&self.client).await?
|
self.list.random(&self.client).await?
|
||||||
};
|
};
|
||||||
|
|
||||||
let decoded = track.decode().map_err(|x| TrackError::new_eyre(false, x))?;
|
let decoded = track.decode()?;
|
||||||
|
|
||||||
// Set the current track.
|
// Set the current track.
|
||||||
self.set_current(decoded.info.clone());
|
self.set_current(decoded.info.clone());
|
||||||
@ -249,7 +249,7 @@ impl Player {
|
|||||||
tx.send(Messages::NewSong).await?;
|
tx.send(Messages::NewSong).await?;
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
if !error.timeout {
|
if !error.is_timeout() {
|
||||||
if debug {
|
if debug {
|
||||||
panic!("{:?}", error)
|
panic!("{:?}", error)
|
||||||
}
|
}
|
||||||
|
@ -62,15 +62,14 @@ impl Downloader {
|
|||||||
let data = self.player.list.random(&self.player.client).await;
|
let data = self.player.list.random(&self.player.client).await;
|
||||||
match data {
|
match data {
|
||||||
Ok(track) => self.player.tracks.write().await.push_back(track),
|
Ok(track) => self.player.tracks.write().await.push_back(track),
|
||||||
Err(error) => {
|
Err(error) if !error.is_timeout() => {
|
||||||
if !error.timeout {
|
|
||||||
if debug {
|
if debug {
|
||||||
panic!("{}", error)
|
panic!("{}", error)
|
||||||
}
|
}
|
||||||
|
|
||||||
sleep(TIMEOUT).await;
|
sleep(TIMEOUT).await;
|
||||||
}
|
}
|
||||||
}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,18 +15,46 @@
|
|||||||
//! 2. [`Info`] created from decoded data.
|
//! 2. [`Info`] created from decoded data.
|
||||||
//! 3. [`Decoded`] made from [`Info`] and the original decoded data.
|
//! 3. [`Decoded`] made from [`Info`] and the original decoded data.
|
||||||
|
|
||||||
use std::{error::Error, io::Cursor, time::Duration};
|
use std::{io::Cursor, time::Duration};
|
||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use eyre::OptionExt as _;
|
|
||||||
use inflector::Inflector as _;
|
use inflector::Inflector as _;
|
||||||
use rodio::{Decoder, Source as _};
|
use rodio::{Decoder, Source as _};
|
||||||
|
use thiserror::Error;
|
||||||
|
use tokio::io;
|
||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
use url::form_urlencoded;
|
use url::form_urlencoded;
|
||||||
|
|
||||||
pub mod bookmark;
|
pub mod bookmark;
|
||||||
pub mod list;
|
pub mod list;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum TrackError {
|
||||||
|
#[error("timeout")]
|
||||||
|
Timeout,
|
||||||
|
|
||||||
|
#[error("unable to decode")]
|
||||||
|
Decode(#[from] rodio::decoder::DecoderError),
|
||||||
|
|
||||||
|
#[error("invalid name")]
|
||||||
|
InvalidName,
|
||||||
|
|
||||||
|
#[error("invalid file path")]
|
||||||
|
InvalidPath,
|
||||||
|
|
||||||
|
#[error("unable to read file")]
|
||||||
|
File(#[from] io::Error),
|
||||||
|
|
||||||
|
#[error("unable to fetch data")]
|
||||||
|
Request(#[from] reqwest::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TrackError {
|
||||||
|
pub fn is_timeout(&self) -> bool {
|
||||||
|
return matches!(self, TrackError::Timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Just a shorthand for a decoded [Bytes].
|
/// Just a shorthand for a decoded [Bytes].
|
||||||
pub type DecodedData = Decoder<Cursor<Bytes>>;
|
pub type DecodedData = Decoder<Cursor<Bytes>>;
|
||||||
|
|
||||||
@ -61,7 +89,7 @@ impl Track {
|
|||||||
/// This will actually decode and format the track,
|
/// This will actually decode and format the track,
|
||||||
/// returning a [`DecodedTrack`] which can be played
|
/// returning a [`DecodedTrack`] which can be played
|
||||||
/// and also has a duration & formatted name.
|
/// and also has a duration & formatted name.
|
||||||
pub fn decode(self) -> eyre::Result<Decoded> {
|
pub fn decode(self) -> eyre::Result<Decoded, TrackError> {
|
||||||
Decoded::new(self)
|
Decoded::new(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,11 +133,8 @@ impl Info {
|
|||||||
/// Formats a name with [Inflector].
|
/// Formats a name with [Inflector].
|
||||||
/// This will also strip the first few numbers that are
|
/// This will also strip the first few numbers that are
|
||||||
/// usually present on most lofi tracks.
|
/// usually present on most lofi tracks.
|
||||||
fn format_name(name: &str) -> eyre::Result<String> {
|
fn format_name(name: &str) -> eyre::Result<String, TrackError> {
|
||||||
let split = name
|
let split = name.split('/').last().ok_or(TrackError::InvalidName)?;
|
||||||
.split('/')
|
|
||||||
.last()
|
|
||||||
.ok_or_eyre("split is never supposed to return nothing")?;
|
|
||||||
|
|
||||||
let stripped = split.strip_suffix(".mp3").unwrap_or(split);
|
let stripped = split.strip_suffix(".mp3").unwrap_or(split);
|
||||||
let formatted = Self::decode_url(stripped)
|
let formatted = Self::decode_url(stripped)
|
||||||
@ -150,7 +175,11 @@ impl Info {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new [`TrackInfo`] from a possibly raw name & decoded data.
|
/// Creates a new [`TrackInfo`] from a possibly raw name & decoded data.
|
||||||
pub fn new(name: TrackName, full_path: String, decoded: &DecodedData) -> eyre::Result<Self> {
|
pub fn new(
|
||||||
|
name: TrackName,
|
||||||
|
full_path: String,
|
||||||
|
decoded: &DecodedData,
|
||||||
|
) -> eyre::Result<Self, TrackError> {
|
||||||
let (display_name, custom_name) = match name {
|
let (display_name, custom_name) = match name {
|
||||||
TrackName::Raw(raw) => (Self::format_name(&raw)?, false),
|
TrackName::Raw(raw) => (Self::format_name(&raw)?, false),
|
||||||
TrackName::Formatted(custom) => (custom, true),
|
TrackName::Formatted(custom) => (custom, true),
|
||||||
@ -179,55 +208,10 @@ pub struct Decoded {
|
|||||||
impl Decoded {
|
impl Decoded {
|
||||||
/// Creates a new track.
|
/// Creates a new track.
|
||||||
/// This is equivalent to [`Track::decode`].
|
/// This is equivalent to [`Track::decode`].
|
||||||
pub fn new(track: Track) -> eyre::Result<Self> {
|
pub fn new(track: Track) -> eyre::Result<Self, TrackError> {
|
||||||
let data = Decoder::new(Cursor::new(track.data))?;
|
let data = Decoder::new(Cursor::new(track.data))?;
|
||||||
let info = Info::new(track.name, track.full_path, &data)?;
|
let info = Info::new(track.name, track.full_path, &data)?;
|
||||||
|
|
||||||
Ok(Self { info, data })
|
Ok(Self { info, data })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct TrackError {
|
|
||||||
pub timeout: bool,
|
|
||||||
inner: Option<eyre::Error>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> std::fmt::Display for TrackError {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"TrackError (timeout: {}): {:?}",
|
|
||||||
self.timeout, self.inner
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> std::error::Error for TrackError {
|
|
||||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
|
||||||
self.inner.as_ref().map(|e| e.as_ref())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TrackError {
|
|
||||||
pub fn new<T: Error + 'static + Send + Sync>(timeout: bool, inner: T) -> Self {
|
|
||||||
Self {
|
|
||||||
inner: Some(eyre::eyre!(inner)),
|
|
||||||
timeout,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_eyre(timeout: bool, inner: eyre::Error) -> Self {
|
|
||||||
Self {
|
|
||||||
inner: Some(inner),
|
|
||||||
timeout,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn empty(timeout: bool) -> Self {
|
|
||||||
Self {
|
|
||||||
inner: None,
|
|
||||||
timeout,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -62,28 +62,28 @@ impl List {
|
|||||||
|
|
||||||
let data: Bytes = if let Some(x) = full_path.strip_prefix("file://") {
|
let data: Bytes = if let Some(x) = full_path.strip_prefix("file://") {
|
||||||
let path = if x.starts_with("~") {
|
let path = if x.starts_with("~") {
|
||||||
let home_path = dirs::home_dir().ok_or(TrackError::empty(false))?;
|
let home_path = dirs::home_dir().ok_or(TrackError::InvalidPath)?;
|
||||||
let home = home_path.to_str().ok_or(TrackError::empty(false))?;
|
let home = home_path.to_str().ok_or(TrackError::InvalidPath)?;
|
||||||
|
|
||||||
x.replace("~", home)
|
x.replace("~", home)
|
||||||
} else {
|
} else {
|
||||||
x.to_owned()
|
x.to_owned()
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = tokio::fs::read(path)
|
let result = tokio::fs::read(path).await?;
|
||||||
.await
|
|
||||||
.map_err(|x| TrackError::new(false, x))?;
|
|
||||||
result.into()
|
result.into()
|
||||||
} else {
|
} else {
|
||||||
let response = client
|
let response = match client.get(full_path.clone()).send().await {
|
||||||
.get(full_path.clone())
|
Ok(x) => Ok(x),
|
||||||
.send()
|
Err(x) => {
|
||||||
.await
|
if x.is_timeout() {
|
||||||
.map_err(|x| TrackError::new(x.is_timeout(), x))?;
|
Err(TrackError::Timeout)
|
||||||
response
|
} else {
|
||||||
.bytes()
|
Err(TrackError::Request(x))
|
||||||
.await
|
}
|
||||||
.map_err(|x| TrackError::new(false, x))?
|
}
|
||||||
|
}?;
|
||||||
|
response.bytes().await?
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((data, full_path))
|
Ok((data, full_path))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user