fix: error reporting

docs: fix typos
This commit is contained in:
Tal 2025-12-06 17:28:11 +01:00
parent a26623f9c0
commit e44a8b85c4
9 changed files with 71 additions and 56 deletions

View File

@ -3,11 +3,13 @@
There are a few guidelines outlined here that will make it more likely for your PR to be accepted.
Only ones that are less obvious are going to be listed. If you need to ask, it's probably a no.
## 1. No AI
## 1. AI
You can use AI for searching and so on, and if there's something minor and tedious that you'd like
the AI to write then that's okay, but if it is noticable that you used AI then it is way too much.
If you used AI, you aren't helping any maintainer by submitting your slop, it's just a hassle for them.
You can use AI for searching or if there's something minor and tedious (eg. tests) that you'd like
to avoid having to do manually.
With that said, if it is noticeable that you used AI then it is way too much.
AI generated PR's do not help maintainers, it's just a hassle and frequently wastes their time.
## 2. Smaller is better

View File

@ -1,7 +1,7 @@
# Environment Variables
Lowfi has some more specific options, usually as a result of minor feature requests, which are only documented here.
If you have some behaviour you'd like to change, which is quite specific, then see if one of these options suits you.
If you have some behavior you'd like to change, which is quite specific, then see if one of these options suits you.
* `LOWFI_FIXED_MPRIS_NAME` - Limits the number of lowfi instances to one, but ensures the player name is always `lowfi`.
* `LOWFI_DISABLE_UI` - Disables the UI.

View File

@ -58,7 +58,7 @@ I'm not making money on any of this, and I think degrading the experience for my
fellow nerds who just want to listen to some lowfi without all the crap is not worth it.
At the end of the day, lowfi has a distinct UserAgent. Should chillhop ever take issue with
it's behaviour, banning it is extremely simple. I don't want that to happen, but I
it's behavior, banning it is extremely simple. I don't want that to happen, but I
understand if it does.
## Well, *I* Hate the Chillhop Music

View File

@ -5,24 +5,6 @@ It'll do this as simply as it can: no albums, no ads, just lofi.
![example image](media/example1.png)
## The Rewrite
This branch serves as a rewrite for lowfi. The main focus is to make the code more
maintainable. This includes such things as:
- Replacing `Mutex` & `Arc` with channels, massively improving readability and flow.
- More clearly handling tracks in different phases of loading, instead of having
a mess of different structs.
- Making the UI code cleaner and easier to follow.
- Rethinking input & control of the player, especially with MPRIS in mind.
- Making track loading simpler and more consistent.
This is an *internal rewrite*, and the goal is to retain every single feature.
If there is a feature present in the original version of lowfi that is not present
in the rewrite, then it is a bug and must be implemented.
Currently, it is in an extremely early and non-functional state.
## Disclaimer
As of the 1.7.0 version of lowfi, **all** of the audio files embedded
@ -207,7 +189,7 @@ If you are dealing with the 1% using another audio format which is in
> [!NOTE]
> Some nice users, especially [danielwerg](https://github.com/danielwerg),
> have aleady made alternative track lists located in the [data](https://github.com/talwat/lowfi/blob/main/data/)
> have already made alternative track lists located in the [data](https://github.com/talwat/lowfi/blob/main/data/)
> directory of this repo. You can use them with lowfi by using the `--track-list` flag.
>
> Feel free to contribute your own list with a PR.

View File

@ -15,39 +15,39 @@ pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// Errors while loading or saving the persistent volume settings.
#[error("unable to load/save the persistent volume: {0}")]
#[error("unable to load/save the persistent volume")]
PersistentVolume(#[from] volume::Error),
/// Errors while loading or saving bookmarks.
#[error("unable to load/save bookmarks: {0}")]
#[error("unable to load/save bookmarks")]
Bookmarks(#[from] bookmark::Error),
/// Network request failures from `reqwest`.
#[error("unable to fetch data: {0}")]
#[error("unable to fetch data")]
Request(#[from] reqwest::Error),
/// Failure converting to/from a C string (FFI helpers).
#[error("C string null error: {0}")]
#[error("C string null error")]
FfiNull(#[from] std::ffi::NulError),
/// Errors coming from the audio backend / stream handling.
#[error("audio playing error: {0}")]
#[error("audio playing error")]
Rodio(#[from] rodio::StreamError),
/// Failure to send an internal `Message` over the mpsc channel.
#[error("couldn't send internal message: {0}")]
#[error("couldn't send internal message")]
Send(#[from] mpsc::error::SendError<crate::Message>),
/// Failure to enqueue a track into the queue channel.
#[error("couldn't add track to the queue: {0}")]
#[error("couldn't add track to the queue")]
Queue(#[from] mpsc::error::SendError<tracks::Queued>),
/// Failure to broadcast UI updates.
#[error("couldn't update UI state: {0}")]
#[error("couldn't update UI state")]
Broadcast(#[from] broadcast::error::SendError<ui::Update>),
/// Generic IO error.
#[error("io error: {0}")]
#[error("io error")]
Io(#[from] std::io::Error),
/// Data directory was not found or could not be determined.
@ -59,7 +59,7 @@ pub enum Error {
Download,
/// Integer parsing errors.
#[error("couldn't parse integer: {0}")]
#[error("couldn't parse integer")]
Parse(#[from] std::num::ParseIntError),
/// Track subsystem error.

View File

@ -96,6 +96,14 @@ pub fn data_dir() -> crate::Result<PathBuf> {
Ok(dir)
}
async fn player(args: Args, environment: ui::Environment) -> crate::Result<()> {
let stream = audio::stream()?;
let mut player = Player::init(args, environment, stream.mixer()).await?;
player.run().await?;
Ok(())
}
/// Program entry point.
///
/// Parses CLI arguments, initializes the audio stream and player, then
@ -116,10 +124,9 @@ async fn main() -> eyre::Result<()> {
}
}
let stream = audio::stream()?;
let mut player = Player::init(args, stream.mixer()).await?;
let result = player.run().await;
let environment = ui::Environment::ready(args.alternate)?;
let result = player(args, environment).await;
environment.cleanup(result.is_ok())?;
player.environment().cleanup(result.is_ok())?;
Ok(result?)
}

View File

@ -115,7 +115,11 @@ impl Player {
/// This sets up the audio sink, UI, downloader, bookmarks and persistent
/// volume state. The function returns a fully constructed `Player` ready
/// to be driven via `run`.
pub async fn init(args: crate::Args, mixer: &rodio::mixer::Mixer) -> crate::Result<Self> {
pub async fn init(
args: crate::Args,
environment: ui::Environment,
mixer: &rodio::mixer::Mixer,
) -> crate::Result<Self> {
let (tx, rx) = mpsc::channel(8);
if args.paused {
tx.send(Message::Pause).await?;
@ -133,7 +137,7 @@ impl Player {
sink.set_volume(volume.float());
Ok(Self {
ui: ui::Handle::init(tx.clone(), urx, state, &args).await?,
ui: ui::Handle::init(tx.clone(), environment, urx, state, &args).await?,
downloader: Downloader::init(
args.buffer_size as usize,
args.timeout,

View File

@ -1,4 +1,4 @@
use std::sync::Arc;
use std::{env, sync::Arc};
use crate::{
player::Current,
@ -39,6 +39,9 @@ pub enum Error {
#[error("sharing state between backend and frontend failed: {0}")]
Send(#[from] tokio::sync::broadcast::error::SendError<Update>),
#[error("you can't disable the UI without MPRIS!")]
RejectedDisable,
#[cfg(feature = "mpris")]
#[error("mpris bus error: {0}")]
ZBus(#[from] mpris_server::zbus::Error),
@ -115,6 +118,27 @@ struct Tasks {
input: JoinHandle<Result<()>>,
}
impl Tasks {
pub fn spawn(
tx: Sender<crate::Message>,
updater: broadcast::Receiver<ui::Update>,
state: State,
params: interface::Params,
) -> Self {
Self {
render: tokio::spawn(Handle::ui(updater, state, params)),
input: tokio::spawn(input::listen(tx)),
}
}
}
impl Drop for Tasks {
fn drop(&mut self) {
self.input.abort();
self.render.abort();
}
}
/// The UI handle for controlling the state of the UI, as well as
/// updating MPRIS information and other small interfacing tasks.
pub struct Handle {
@ -126,14 +150,7 @@ pub struct Handle {
pub mpris: mpris::Server,
/// The UI's running tasks.
tasks: Tasks,
}
impl Drop for Handle {
fn drop(&mut self) {
self.tasks.input.abort();
self.tasks.render.abort();
}
_tasks: Option<Tasks>,
}
impl Handle {
@ -174,19 +191,22 @@ impl Handle {
#[allow(clippy::unused_async)]
pub async fn init(
tx: Sender<crate::Message>,
environment: Environment,
updater: broadcast::Receiver<ui::Update>,
state: State,
args: &Args,
) -> Result<Self> {
let environment = Environment::ready(args.alternate)?;
let disabled = env::var("LOWFI_DISABLE_UI").is_ok_and(|x| x == "1");
if disabled && !cfg!(feature = "mpris") {
return Err(Error::RejectedDisable);
}
Ok(Self {
#[cfg(feature = "mpris")]
mpris: mpris::Server::new(state.clone(), tx.clone(), updater.resubscribe()).await?,
environment,
tasks: Tasks {
render: tokio::spawn(Self::ui(updater, state, interface::Params::from(args))),
input: tokio::spawn(input::listen(tx)),
},
_tasks: (!disabled)
.then(|| Tasks::spawn(tx, updater, state, interface::Params::from(args))),
})
}
}

View File

@ -127,7 +127,7 @@ impl PlayerInterface for Player {
}
async fn stop(&self) -> fdo::Result<()> {
self.pause().await
self.sender.send(Message::Quit).await
}
async fn play(&self) -> fdo::Result<()> {