mirror of
https://github.com/talwat/lowfi
synced 2025-03-12 08:02:52 +00:00
feat: add experimental local file loading in track lists
This commit is contained in:
parent
b68ce27d19
commit
84f386e0eb
11
Cargo.lock
generated
11
Cargo.lock
generated
@ -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"
|
||||
|
@ -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"
|
||||
|
16
README.md
16
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>` | Width of the player, from 0 to 32 [default: 3] |
|
||||
| `-t`, `--tracklist <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.
|
||||
|
2
data/file.txt
Normal file
2
data/file.txt
Normal file
@ -0,0 +1,2 @@
|
||||
file:///home/user/Music/
|
||||
Anomaly.mp3
|
@ -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()?;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
@ -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<Bytes> {
|
||||
async fn download(&self, track: &str, client: &Client) -> (eyre::Result<Bytes>, 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<Track> {
|
||||
pub async fn random(&self, client: &Client) -> (eyre::Result<Track>, 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].
|
||||
|
Loading…
x
Reference in New Issue
Block a user