From 84f386e0eba64447920525ff38a453f47f5a0b9f Mon Sep 17 00:00:00 2001 From: talwat <83217276+talwat@users.noreply.github.com> Date: Fri, 28 Feb 2025 19:07:18 +0100 Subject: [PATCH] feat: add experimental local file loading in track lists --- Cargo.lock | 11 ++--------- Cargo.toml | 3 +-- README.md | 16 +++++++++++++--- data/file.txt | 2 ++ src/player.rs | 2 +- src/player/downloader.rs | 7 ++++--- src/tracks.rs | 4 ++-- src/tracks/list.rs | 28 +++++++++++++++++++++------- 8 files changed, 46 insertions(+), 27 deletions(-) create mode 100644 data/file.txt diff --git a/Cargo.lock b/Cargo.lock index 41a9df4..3ab9620 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -973,7 +973,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" dependencies = [ - "unicode-width 0.1.14", + "unicode-width", ] [[package]] @@ -1453,7 +1453,7 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lowfi" -version = "1.6.2-dev" +version = "1.6.3-dev" dependencies = [ "Inflector", "arc-swap", @@ -1472,7 +1472,6 @@ dependencies = [ "scraper", "tokio", "unicode-segmentation", - "unicode-width 0.2.0", "url", ] @@ -2819,12 +2818,6 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" -[[package]] -name = "unicode-width" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" - [[package]] name = "untrusted" version = "0.9.0" diff --git a/Cargo.toml b/Cargo.toml index 12218da..a734da8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lowfi" -version = "1.6.2-dev" +version = "1.6.3-dev" edition = "2021" description = "An extremely simple lofi player." license = "MIT" @@ -50,5 +50,4 @@ Inflector = "0.11.4" lazy_static = "1.5.0" libc = "0.2.167" url = "2.5.4" -unicode-width = "0.2.0" unicode-segmentation = "1.12.0" diff --git a/README.md b/README.md index 43a4bd2..6f88fa2 100644 --- a/README.md +++ b/README.md @@ -121,8 +121,18 @@ Yeah, that's it. ### Extra Flags -If you have something you'd like to tweak about lowfi, you can run `lowfi help` -to view the available options. +If you have something you'd like to tweak about lowfi, you use additional flags which +slightly tweak the UI or behaviour of the menu. The flags can be viewed with `lowfi help`. + +| Flag | Function | +| ------------------------------- | ---------------------------------------------- | +| `-a`, `--alternate` | Use an alternate terminal screen | +| `-m`, `--minimalist` | Hide the bottom control bar | +| `-b`, `--borderless` | Exclude borders in UI | +| `-p`, `--paused` | Start lowfi paused | +| `-d`, `--debug` | Include ALSA & other logs | +| `-w`, `--width ` | Width of the player, from 0 to 32 [default: 3] | +| `-t`, `--tracklist ` | Use a [custom track list](#custom-track-lists) | ### Scraping @@ -166,7 +176,7 @@ This is also known as the "header", because it comes first. Each track will be first appended to the base URL, and then the result use to download the track. All tracks must be in the MP3 format, as lowfi doesn't support any others currently. -Additionally, lowfi *won't* put a `/` between the base & track for added flexibility, +Additionally, lowfi _won't_ put a `/` between the base & track for added flexibility, so for most cases you should have a trailing `/` in your base url. The exception to this is if the track name begins with something like `https://`, where in that case the base will not be prepended to it. diff --git a/data/file.txt b/data/file.txt new file mode 100644 index 0000000..4042c0b --- /dev/null +++ b/data/file.txt @@ -0,0 +1,2 @@ +file:///home/user/Music/ +Anomaly.mp3 \ No newline at end of file diff --git a/src/player.rs b/src/player.rs index 408fc89..a6e583b 100644 --- a/src/player.rs +++ b/src/player.rs @@ -236,7 +236,7 @@ impl Player { // for only a frame in the other case that the buffer is not empty. self.current.store(None); - self.list.random(&self.client).await? + self.list.random(&self.client).await.0? }; let decoded = track.decode()?; diff --git a/src/player/downloader.rs b/src/player/downloader.rs index c74854a..07a0343 100644 --- a/src/player/downloader.rs +++ b/src/player/downloader.rs @@ -51,10 +51,11 @@ impl Downloader { while self.rx.recv().await == Some(()) { // For each update notification, we'll push tracks until the buffer is completely full. while self.player.tracks.read().await.len() < BUFFER_SIZE { - match self.player.list.random(&self.player.client).await { + let (data, timeout) = self.player.list.random(&self.player.client).await; + match data { Ok(track) => self.player.tracks.write().await.push_back(track), - Err(error) => { - if !error.is_timeout() { + Err(_) => { + if !timeout { sleep(TIMEOUT).await; } } diff --git a/src/tracks.rs b/src/tracks.rs index 2167b10..9bd3a4e 100644 --- a/src/tracks.rs +++ b/src/tracks.rs @@ -8,7 +8,7 @@ use bytes::Bytes; use eyre::OptionExt as _; use inflector::Inflector as _; use rodio::{Decoder, Source as _}; -use unicode_width::UnicodeWidthStr as _; +use unicode_segmentation::UnicodeSegmentation; use url::form_urlencoded; pub mod list; @@ -102,7 +102,7 @@ impl Info { Ok(Self { duration: decoded.total_duration(), - width: name.width(), + width: name.graphemes(true).count(), name, }) } diff --git a/src/tracks/list.rs b/src/tracks/list.rs index a3f845e..9a8f19f 100644 --- a/src/tracks/list.rs +++ b/src/tracks/list.rs @@ -50,7 +50,7 @@ impl List { } /// Downloads a raw track, but doesn't decode it. - async fn download(&self, track: &str, client: &Client) -> reqwest::Result { + async fn download(&self, track: &str, client: &Client) -> (eyre::Result, bool) { // If the track has a protocol, then we should ignore the base for it. let url = if track.contains("://") { track.to_owned() @@ -58,22 +58,36 @@ impl List { format!("{}{}", self.base(), track) }; - let response = client.get(url).send().await?; - let data = response.bytes().await?; + let (timeout, data) = if let Some(x) = url.strip_prefix("file://") { + let result = tokio::fs::read(x).await.unwrap(); + (false, Ok(result.into())) + } else { + let response = client.get(url).send().await; - Ok(data) + match response { + Ok(x) => (false, x.bytes().await), + Err(x) => (x.is_timeout(), Err(x)), + } + }; + + (data.map_err(|x| eyre::eyre!(x)), timeout) } /// Fetches and downloads a random track from the [List]. - pub async fn random(&self, client: &Client) -> reqwest::Result { + pub async fn random(&self, client: &Client) -> (eyre::Result, bool) { let (path, custom_name) = self.random_path(); - let data = self.download(&path, client).await?; + let (data, timeout) = self.download(&path, client).await; let name = custom_name.map_or(super::TrackName::Raw(path), |formatted| { super::TrackName::Formatted(formatted) }); - Ok(Track { name, data }) + let track = match data { + Ok(x) => Ok(Track { name, data: x }), + Err(x) => Err(x), + }; + + (track, timeout) } /// Parses text into a [List].