fix: reform errors for track fetching

This commit is contained in:
talwat 2025-03-12 14:21:32 +01:00
parent 27fc505830
commit adcb20f2d0
3 changed files with 32 additions and 28 deletions

View File

@ -69,7 +69,7 @@ pub enum Messages {
} }
/// The time to wait in between errors. /// The time to wait in between errors.
const TIMEOUT: Duration = Duration::from_secs(5); const TIMEOUT: Duration = Duration::from_secs(1);
/// The amount of songs to buffer up. /// The amount of songs to buffer up.
const BUFFER_SIZE: usize = 5; const BUFFER_SIZE: usize = 5;
@ -222,7 +222,7 @@ impl Player {
/// This will play the next track, as well as refilling the buffer in the background. /// This will play the next track, as well as refilling the buffer in the background.
/// ///
/// This will also set `current` to the newly loaded song. /// This will also set `current` to the newly loaded song.
pub async fn next(&self) -> eyre::Result<tracks::Decoded> { pub async fn next(&self) -> Result<tracks::Decoded, bool> {
// TODO: Consider replacing this with `unwrap_or_else` when async closures are stablized. // TODO: Consider replacing this with `unwrap_or_else` when async closures are stablized.
let track = self.tracks.write().await.pop_front(); let track = self.tracks.write().await.pop_front();
let track = if let Some(track) = track { let track = if let Some(track) = track {
@ -235,11 +235,12 @@ impl Player {
// We're doing it here so that we don't get the "loading" display // We're doing it here so that we don't get the "loading" display
// for only a frame in the other case that the buffer is not empty. // for only a frame in the other case that the buffer is not empty.
self.current.store(None); self.current.store(None);
self.list
self.list.random(&self.client).await.0? .random(&self.client)
.await?
}; };
let decoded = track.decode()?; let decoded = track.decode().map_err(|_| false)?;
// Set the current track. // Set the current track.
self.set_current(decoded.info.clone()); self.set_current(decoded.info.clone());
@ -277,8 +278,8 @@ impl Player {
// Notify the audio server that the next song has actually been downloaded. // Notify the audio server that the next song has actually been downloaded.
tx.send(Messages::NewSong).await?; tx.send(Messages::NewSong).await?;
} }
Err(error) => { Err(timeout) => {
if !error.downcast::<reqwest::Error>()?.is_timeout() { if !timeout {
sleep(TIMEOUT).await; sleep(TIMEOUT).await;
} }

View File

@ -51,10 +51,10 @@ impl Downloader {
while self.rx.recv().await == Some(()) { while self.rx.recv().await == Some(()) {
// For each update notification, we'll push tracks until the buffer is completely full. // For each update notification, we'll push tracks until the buffer is completely full.
while self.player.tracks.read().await.len() < BUFFER_SIZE { while self.player.tracks.read().await.len() < BUFFER_SIZE {
let (data, timeout) = 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(_) => { Err(timeout) => {
if !timeout { if !timeout {
sleep(TIMEOUT).await; sleep(TIMEOUT).await;
} }

View File

@ -50,7 +50,7 @@ impl List {
} }
/// Downloads a raw track, but doesn't decode it. /// Downloads a raw track, but doesn't decode it.
async fn download(&self, track: &str, client: &Client) -> (eyre::Result<Bytes>, bool) { async fn download(&self, track: &str, client: &Client) -> Result<Bytes, bool> {
// If the track has a protocol, then we should ignore the base for it. // If the track has a protocol, then we should ignore the base for it.
let url = if track.contains("://") { let url = if track.contains("://") {
track.to_owned() track.to_owned()
@ -58,36 +58,39 @@ impl List {
format!("{}{}", self.base(), track) format!("{}{}", self.base(), track)
}; };
let (timeout, data) = if let Some(x) = url.strip_prefix("file://") { let data: Bytes = if let Some(x) = url.strip_prefix("file://") {
let result = tokio::fs::read(x).await.unwrap(); let path = if x.starts_with("~") {
(false, Ok(result.into())) let home_path = dirs::home_dir().ok_or(false)?;
} else { let home = home_path.to_str().ok_or(false)?;
let response = client.get(url).send().await;
match response { x.replace("~", home)
Ok(x) => (false, x.bytes().await), } else {
Err(x) => (x.is_timeout(), Err(x)), x.to_owned()
} };
let result = tokio::fs::read(path).await.map_err(|_| false)?;
result.into()
} else {
let response = client.get(url).send().await.map_err(|x| x.is_timeout())?;
response.bytes().await.map_err(|_| false)?
}; };
(data.map_err(|x| eyre::eyre!(x)), timeout) Ok(data)
} }
/// Fetches and downloads a random track from the [List]. /// Fetches and downloads a random track from the [List].
pub async fn random(&self, client: &Client) -> (eyre::Result<Track>, bool) { ///
/// The Result's error is a bool, which is true if a timeout error occured,
/// and false otherwise. This tells lowfi if it shouldn't wait to try again.
pub async fn random(&self, client: &Client) -> Result<Track, bool> {
let (path, custom_name) = self.random_path(); let (path, custom_name) = self.random_path();
let (data, timeout) = self.download(&path, client).await; let data = self.download(&path, client).await?;
let name = custom_name.map_or(super::TrackName::Raw(path), |formatted| { let name = custom_name.map_or(super::TrackName::Raw(path), |formatted| {
super::TrackName::Formatted(formatted) super::TrackName::Formatted(formatted)
}); });
let track = match data { Ok(Track { name, data: data })
Ok(x) => Ok(Track { name, data: x }),
Err(x) => Err(x),
};
(track, timeout)
} }
/// Parses text into a [List]. /// Parses text into a [List].