mirror of
https://github.com/talwat/lowfi
synced 2025-09-27 10:50:02 +00:00
feat: the 1.7.0 release (#97)
* docs: update to be relevant to the current version * chore: bump version * fix: change default progress to 0 why it was ever -1.0 is a mystery to me, it doesn't make any logical sense... * fix: switch from rand to fastrand * feat: prepare for 1.7.0 release docs: explain music situation docs: more internal documentation feat: make timeout configurable chore: clean up some sections of code * fix: use boring fs functions for bookmark loading and writing * chore: remove useless internal doc * chore: bump version
This commit is contained in:
parent
4d4f5e0920
commit
0162421db4
@ -1,5 +1,10 @@
|
||||
# Using the chillhop list
|
||||
|
||||
> [!WARNING]
|
||||
> As of lowfi 1.7.0, the chillhop list is included by default. For a more
|
||||
> detailed explanation, see [MUSIC.md](MUSIC.md). This document is included
|
||||
> to preserve any old links or references. The instructions are still valid.
|
||||
|
||||
## Linux
|
||||
|
||||
```sh
|
||||
|
210
Cargo.lock
generated
210
Cargo.lock
generated
@ -46,7 +46,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43"
|
||||
dependencies = [
|
||||
"alsa-sys",
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.9.3",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
]
|
||||
@ -183,7 +183,7 @@ dependencies = [
|
||||
"futures-lite",
|
||||
"parking",
|
||||
"polling",
|
||||
"rustix",
|
||||
"rustix 0.38.42",
|
||||
"slab",
|
||||
"tracing",
|
||||
"windows-sys 0.59.0",
|
||||
@ -215,7 +215,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"event-listener",
|
||||
"futures-lite",
|
||||
"rustix",
|
||||
"rustix 0.38.42",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
@ -242,7 +242,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"rustix",
|
||||
"rustix 0.38.42",
|
||||
"signal-hook-registry",
|
||||
"slab",
|
||||
"windows-sys 0.59.0",
|
||||
@ -312,9 +312,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
version = "2.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
@ -480,6 +480,15 @@ dependencies = [
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.8.0"
|
||||
@ -562,16 +571,18 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.28.1"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
|
||||
checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.9.3",
|
||||
"crossterm_winapi",
|
||||
"derive_more 2.0.1",
|
||||
"document-features",
|
||||
"futures-core",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"rustix",
|
||||
"rustix 1.0.8",
|
||||
"signal-hook",
|
||||
"signal-hook-mio",
|
||||
"winapi",
|
||||
@ -636,6 +647,27 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"
|
||||
dependencies = [
|
||||
"derive_more-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more-impl"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
|
||||
dependencies = [
|
||||
"convert_case 0.7.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
@ -648,23 +680,23 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "5.0.1"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
||||
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
||||
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -673,7 +705,7 @@ version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.9.3",
|
||||
"objc2",
|
||||
]
|
||||
|
||||
@ -688,6 +720,15 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "document-features"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d"
|
||||
dependencies = [
|
||||
"litrs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "1.0.10"
|
||||
@ -1421,7 +1462,7 @@ version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.9.3",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@ -1431,12 +1472,24 @@ version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
|
||||
|
||||
[[package]]
|
||||
name = "litrs"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.12"
|
||||
@ -1455,24 +1508,24 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "lowfi"
|
||||
version = "1.7.0-dev"
|
||||
version = "1.7.0"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"atomic_float",
|
||||
"bytes",
|
||||
"clap",
|
||||
"color-eyre",
|
||||
"convert_case",
|
||||
"convert_case 0.8.0",
|
||||
"crossterm",
|
||||
"dirs",
|
||||
"eyre",
|
||||
"fastrand",
|
||||
"futures",
|
||||
"html-escape",
|
||||
"indicatif",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"mpris-server",
|
||||
"rand",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"rodio",
|
||||
@ -1603,7 +1656,7 @@ version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.9.3",
|
||||
"jni-sys",
|
||||
"log",
|
||||
"ndk-sys",
|
||||
@ -1638,7 +1691,7 @@ version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.9.3",
|
||||
"cfg-if",
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
@ -1732,7 +1785,7 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10cbe18d879e20a4aea544f8befe38bcf52255eb63d3f23eca2842f3319e4c07"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.9.3",
|
||||
"libc",
|
||||
"objc2",
|
||||
"objc2-core-audio",
|
||||
@ -1759,7 +1812,7 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0f1cc99bb07ad2ddb6527ddf83db6a15271bb036b3eb94b801cd44fdc666ee1"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.9.3",
|
||||
"objc2",
|
||||
]
|
||||
|
||||
@ -1769,7 +1822,7 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.9.3",
|
||||
"dispatch2",
|
||||
"objc2",
|
||||
]
|
||||
@ -1810,7 +1863,7 @@ version = "0.10.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.9.3",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
@ -1996,7 +2049,7 @@ dependencies = [
|
||||
"concurrent-queue",
|
||||
"hermit-abi",
|
||||
"pin-project-lite",
|
||||
"rustix",
|
||||
"rustix 0.38.42",
|
||||
"tracing",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
@ -2091,18 +2144,18 @@ version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.6"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
|
||||
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
|
||||
dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
"libredox",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2219,13 +2272,26 @@ version = "0.38.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.9.3",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"linux-raw-sys 0.4.14",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
|
||||
dependencies = [
|
||||
"bitflags 2.9.3",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.9.4",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.20"
|
||||
@ -2323,7 +2389,7 @@ version = "2.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.9.3",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
@ -2346,9 +2412,9 @@ version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd568a4c9bb598e291a08244a5c1f5a8a6650bee243b5b0f8dbb3d9cc1d87fe8"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.9.3",
|
||||
"cssparser",
|
||||
"derive_more",
|
||||
"derive_more 0.99.20",
|
||||
"fxhash",
|
||||
"log",
|
||||
"new_debug_unreachable",
|
||||
@ -2740,7 +2806,7 @@ version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.9.3",
|
||||
"core-foundation",
|
||||
"system-configuration-sys",
|
||||
]
|
||||
@ -2765,7 +2831,7 @@ dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.2.15",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"rustix 0.38.42",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
@ -3321,15 +3387,6 @@ dependencies = [
|
||||
"windows-targets 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
@ -3372,21 +3429,6 @@ dependencies = [
|
||||
"windows_x86_64_msvc 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.48.5",
|
||||
"windows_aarch64_msvc 0.48.5",
|
||||
"windows_i686_gnu 0.48.5",
|
||||
"windows_i686_msvc 0.48.5",
|
||||
"windows_x86_64_gnu 0.48.5",
|
||||
"windows_x86_64_gnullvm 0.48.5",
|
||||
"windows_x86_64_msvc 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
@ -3426,12 +3468,6 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
@ -3450,12 +3486,6 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
@ -3474,12 +3504,6 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
@ -3510,12 +3534,6 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
@ -3534,12 +3552,6 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
@ -3558,12 +3570,6 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
@ -3582,12 +3588,6 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
@ -3615,7 +3615,7 @@ version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "lowfi"
|
||||
version = "1.7.0-dev"
|
||||
version = "1.7.0"
|
||||
edition = "2021"
|
||||
description = "An extremely simple lofi player."
|
||||
license = "MIT"
|
||||
@ -25,7 +25,7 @@ scrape = ["dep:serde", "dep:serde_json", "dep:html-escape", "dep:scraper", "dep:
|
||||
# Basics
|
||||
clap = { version = "4.5.21", features = ["derive", "cargo"] }
|
||||
eyre = "0.6.12"
|
||||
rand = "0.8.5"
|
||||
fastrand = "2.3.0"
|
||||
thiserror = "2.0.12"
|
||||
color-eyre = { version = "0.6.5", default-features = false }
|
||||
|
||||
@ -39,10 +39,10 @@ reqwest = { version = "0.12.9", features = ["stream"] }
|
||||
bytes = "1.9.0"
|
||||
|
||||
# I/O
|
||||
crossterm = { version = "0.28.1", features = ["event-stream"] }
|
||||
crossterm = { version = "0.29.0", features = ["event-stream"] }
|
||||
rodio = { version = "0.21.1", features = ["symphonia-mp3", "playback"], default-features = false }
|
||||
mpris-server = { version = "0.8.1", optional = true }
|
||||
dirs = "5.0.1"
|
||||
dirs = "6.0.0"
|
||||
|
||||
# Misc
|
||||
convert_case = "0.8.0"
|
||||
|
75
MUSIC.md
Normal file
75
MUSIC.md
Normal file
@ -0,0 +1,75 @@
|
||||
# The State of Lowfi's Music
|
||||
|
||||
> [!WARNING]
|
||||
> This document will be a bit long and has almost nothing to do with the actual
|
||||
> usage of lowfi, just the music embedded by default.
|
||||
|
||||
Before that though, some context. lowfi includes an extensive track list
|
||||
embedded into the software, so you can download it and have it "just work"
|
||||
out of the box.
|
||||
|
||||
I always hated apps that required extensive configuration just to be usable.
|
||||
Sometimes it's justified, but often, it's just pointless when most will end up
|
||||
with the same set of "defaults" that aren't really defaults.
|
||||
|
||||
Lowfi is so nice and simple because of the "plug and play" aspect,
|
||||
but it's become a lot harder to continue it as of late.
|
||||
|
||||
## The Lofi Girl List
|
||||
|
||||
Originally, it was planned that lowfi would use music scraped from Lofi Girl's own
|
||||
website. The scraper actually came before the rest of the program, believe it or not.
|
||||
|
||||
However, after a long period of downtime, the Lofi Girl website was redone without the
|
||||
mp3 track files. Those are now pretty much inaccessible aside from paying for individual
|
||||
albums on bandcamp which gets very expensive very quickly.
|
||||
|
||||
Doing this was never actually disallowed, but it is now simply impossible. So, the question was,
|
||||
what to do next after losing lowfi's primary source of music?
|
||||
|
||||
## Tracklists
|
||||
|
||||
I was originally against the idea of custom tracklists, because of my almost purist
|
||||
ideals of a 100% no config at all vision for lowfi. But eventually, I gave in, which proved
|
||||
to be a very good decision in hindsight. Now, regardless of what choices I make on the music
|
||||
which is embedded, all may opt out of that and choose whatever they like.
|
||||
|
||||
This culminated in a few templates located in the `data` directory of this repository
|
||||
which included a handful of tracklists, and in particular, the chillhop list by user
|
||||
[danielwerg](https://github.com/danielwerg).
|
||||
|
||||
## The Switch
|
||||
|
||||
After `lofigirl.com` went down, I thought a bit and eventually decided
|
||||
to just bite the bullet and switch to the chillhop list. This was despite the fact
|
||||
that chillhop entirely bans third party players in their TOS. They also ban
|
||||
scrapers, which I only learned after writing one.
|
||||
|
||||
So, is lowfi really going to have to violate the TOS of it's own music provider?
|
||||
Well, yes. I thought about it, and came to the conclusion that lowfi is probably
|
||||
not much of a threat for a few reasons.
|
||||
|
||||
Firstly, it emulates exactly the behavior of chillhop's own radio player.
|
||||
The only difference is that one shoves you into a web browser, and the other,
|
||||
into a nice terminal window.
|
||||
|
||||
Then, I also realize that lowfi is just a small program used by few.
|
||||
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
|
||||
understand if it does.
|
||||
|
||||
## Well, *I* Hate the Chillhop Music
|
||||
|
||||
It's not as "lofi". It is almost certainly a compromise, that much I cannot even pretend to
|
||||
deny. I find myself hitting the skip button almost three times as often with chillhop.
|
||||
|
||||
If you are undeterred enough by TOS's to read this far, then you can use the `archive.txt`
|
||||
list in the `data` folder. The list is a product of me worrying that the tracks on `lofigirl.com`
|
||||
could've possibly been lost somehow, relating to the website going down.
|
||||
|
||||
It's hosted on `archive.org`, and could be taken down at any point for any reason.
|
||||
Being derived from my own local archive, it retains ~2700 out of the ~3700 tracks.
|
||||
That's not perfect, the organization is also *bad*, but it exists.
|
76
README.md
76
README.md
@ -7,18 +7,9 @@ It'll do this as simply as it can: no albums, no ads, just lofi.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> As of the 19th of July 2025, lofigirl.com is temporarily down. If your lowfi is up to date,
|
||||
> you can follow the [quick instructions](CHILLHOP.md) for using the [chillhop](https://chillhop.com/) alternative track list.
|
||||
>
|
||||
> Apologies for the inconvenience, it's out of lowfi's control.
|
||||
|
||||
**All** of the audio files embedded into in lowfi by default are from [Lofi Girl's](https://lofigirl.com/) website,
|
||||
under their [licensing guidelines](https://form.lofigirl.com/CommercialLicense).
|
||||
|
||||
If, god forbid, you're planning to use lowfi in a commercial setting, please
|
||||
follow their rules.
|
||||
As of the 1.7.0 version of lowfi, **all** of the audio files embedded
|
||||
by default are from [chillhop](https://chillhop.com/). Read
|
||||
[MUSIC.md] for more information.
|
||||
|
||||
## Why?
|
||||
|
||||
@ -135,6 +126,7 @@ Yeah, that's it.
|
||||
| `-`, `_`, `j`, `↓` | Volume Down 10% |
|
||||
| `←` | Volume Down 1% |
|
||||
| `q`, CTRL+C | Quit |
|
||||
| `b` | Bookmark |
|
||||
|
||||
> [!NOTE]
|
||||
> Besides its regular controls, lowfi offers compatibility with Media Keys
|
||||
@ -162,56 +154,54 @@ slightly tweak the UI or behaviour of the menu. The flags can be viewed with `lo
|
||||
|
||||
### Scraping
|
||||
|
||||
lowfi also has a `scrape` command which is usually not relevant, but
|
||||
if you're trying to download some files from Lofi Girls' website,
|
||||
it can be useful.
|
||||
lowfi also has an optional `scrape` command enabled by the `scrape` feature.
|
||||
It's usually not very useful, but is included for transparency's sake.
|
||||
|
||||
An example of scrape is as follows,
|
||||
|
||||
`lowfi scrape --extension zip --include-full`
|
||||
|
||||
where more information can be found by running `lowfi help scrape`.
|
||||
More information can be found by running `lowfi help scrape`.
|
||||
|
||||
### Custom Track Lists
|
||||
|
||||
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/)
|
||||
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.
|
||||
|
||||
> [!WARNING]
|
||||
> [!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/)
|
||||
> directory of this repo. You can use them with lowfi by using the `--track-list` flag.
|
||||
>
|
||||
> Custom track lists are going to be pretty particular.
|
||||
> This is because I still want to keep `lowfi` as simple as possible,
|
||||
> so custom lists will be very similar to how the built in list functions.
|
||||
>
|
||||
> This also means that there will be no added flexibility to these lists,
|
||||
> so you'll have to work that out on your own.
|
||||
> Feel free to contribute your own list with a PR.
|
||||
|
||||
lowfi also supports custom track lists, although the default one from Lofi Girl
|
||||
is embedded into the binary.
|
||||
|
||||
To use a custom list, use the `--track-list` flag. This can either be a path to some file,
|
||||
or it could also be the name of a file (without the `.txt` extension) in the data
|
||||
directory, so on Linux it's `~/.local/share/lowfi`.
|
||||
directory.
|
||||
|
||||
> [!NOTE]
|
||||
> Data directories:
|
||||
>
|
||||
> - Linux - `~/.local/share/lowfi`
|
||||
> - macOS - `~/Library/Application Support/lowfi`
|
||||
> - Windows - `%appdata%\Roaming\lowfi`
|
||||
|
||||
For example, `lowfi --track-list minipop` would load `~/.local/share/lowfi/minipop.txt`.
|
||||
Whereas if you did `lowfi --track-list ~/Music/minipop.txt` it would load from that
|
||||
specified directory.
|
||||
|
||||
All tracks must be in the MP3 format, unless lowfi has been compiled with the
|
||||
`extra-audio-formats` feature which includes support for some others.
|
||||
|
||||
#### The Format
|
||||
|
||||
In lists, the first line should be the base URL, followed by the rest of the tracks.
|
||||
This is also known as the "header", because it comes first.
|
||||
In lists, the first line is what's known as the header, followed by the rest of the tracks.
|
||||
Each track will be first appended to the header, and then use that to download
|
||||
the track.
|
||||
|
||||
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.
|
||||
> [!NOTE]
|
||||
> lowfi _will not_ put a `/` between the base & track for added flexibility,
|
||||
> so for most cases you should have a trailing `/` in your header.
|
||||
|
||||
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.
|
||||
The exception to this is if the track name begins with a protocol like `https://`,
|
||||
in which case the base will not be prepended to it. If all of your tracks are like this,
|
||||
then you can put `noheader` as the first line and not have a header at all.
|
||||
|
||||
For example, in this list:
|
||||
|
||||
@ -243,7 +233,7 @@ This is useful if you want to use a local file as the base URL, such as:
|
||||
```txt
|
||||
file:///home/user/Music/
|
||||
file.mp3
|
||||
file:///home/user/Music/second-file.mp3
|
||||
file:///home/user/Other Music/second-file.mp3
|
||||
```
|
||||
|
||||
Further examples can be found in the [data](https://github.com/talwat/lowfi/tree/main/data) folder.
|
||||
|
@ -1,2 +1,2 @@
|
||||
file:///home/user/Music/
|
||||
Anomaly.mp3
|
||||
Test.mp3
|
2
data/noheader.txt
Normal file
2
data/noheader.txt
Normal file
@ -0,0 +1,2 @@
|
||||
noheader
|
||||
https://stream.chillhop.com/mp3/9476
|
@ -1,4 +1,4 @@
|
||||
https://lofigirl.com/wp-content/uploads/
|
||||
2023/06/Foudroie-Finding-The-Edge-V2.mp3
|
||||
2023/04/2-In-Front-Of-Me.mp3
|
||||
https://file-examples.com/storage/fe85f7a43b689349d9c8f18/2017/11/file_example_MP3_1MG.mp3
|
||||
https://stream.chillhop.com/mp3/9476
|
@ -16,6 +16,7 @@ mod scrapers;
|
||||
|
||||
#[cfg(feature = "scrape")]
|
||||
use crate::scrapers::Source;
|
||||
|
||||
/// An extremely simple lofi player.
|
||||
#[derive(Parser, Clone)]
|
||||
#[command(about, version)]
|
||||
@ -41,6 +42,10 @@ struct Args {
|
||||
#[clap(long, short, default_value_t = 12)]
|
||||
fps: u8,
|
||||
|
||||
/// Timeout in seconds for music downloads.
|
||||
#[clap(long, default_value_t = 3)]
|
||||
timeout: u64,
|
||||
|
||||
/// Include ALSA & other logs.
|
||||
#[clap(long, short)]
|
||||
debug: bool,
|
||||
@ -50,7 +55,7 @@ struct Args {
|
||||
width: usize,
|
||||
|
||||
/// Use a custom track list
|
||||
#[clap(long, short, alias = "list", short_alias = 'l')]
|
||||
#[clap(long, short, alias = "list", alias = "tracks", short_alias = 'l')]
|
||||
track_list: Option<String>,
|
||||
|
||||
/// Internal song buffer size.
|
||||
@ -70,6 +75,7 @@ enum Commands {
|
||||
#[cfg(feature = "scrape")]
|
||||
Scrape {
|
||||
// The source to scrape from.
|
||||
#[clap(long, short)]
|
||||
source: scrapers::Source,
|
||||
},
|
||||
}
|
||||
@ -91,7 +97,6 @@ async fn main() -> eyre::Result<()> {
|
||||
|
||||
if let Some(command) = cli.command {
|
||||
match command {
|
||||
// TODO: Actually distinguish between sources.
|
||||
#[cfg(feature = "scrape")]
|
||||
Commands::Scrape { source } => match source {
|
||||
Source::Archive => scrapers::archive::scrape().await?,
|
||||
|
@ -70,7 +70,9 @@ pub async fn play(args: Args) -> eyre::Result<(), player::Error> {
|
||||
|
||||
drop(stream);
|
||||
player.sink.stop();
|
||||
ui.map(|x| x.abort());
|
||||
if let Some(x) = ui {
|
||||
x.abort();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -41,10 +41,6 @@ pub use error::Error;
|
||||
#[cfg(feature = "mpris")]
|
||||
pub mod mpris;
|
||||
|
||||
/// The time to wait in between errors.
|
||||
/// TODO: Make this configurable.
|
||||
const TIMEOUT: Duration = Duration::from_secs(3);
|
||||
|
||||
/// Main struct responsible for queuing up & playing tracks.
|
||||
// TODO: Consider refactoring [Player] from being stored in an [Arc], into containing many smaller [Arc]s.
|
||||
// TODO: In other words, this would change the type from `Arc<Player>` to just `Player`.
|
||||
@ -76,6 +72,9 @@ pub struct Player {
|
||||
/// The bookmarks, which are saved on quit.
|
||||
pub bookmarks: Bookmarks,
|
||||
|
||||
/// The timeout for track downloads, as a [Duration].
|
||||
timeout: Duration,
|
||||
|
||||
/// The actual list of tracks to be played.
|
||||
list: List,
|
||||
|
||||
@ -144,14 +143,15 @@ impl Player {
|
||||
"/",
|
||||
env!("CARGO_PKG_VERSION")
|
||||
))
|
||||
.timeout(TIMEOUT * 5)
|
||||
.timeout(Duration::from_secs(args.timeout * 5))
|
||||
.build()?;
|
||||
|
||||
let player = Self {
|
||||
tracks: RwLock::new(VecDeque::with_capacity(args.buffer_size)),
|
||||
buffer_size: args.buffer_size,
|
||||
current: ArcSwapOption::new(None),
|
||||
progress: AtomicF32::new(-1.0),
|
||||
progress: AtomicF32::new(0.0),
|
||||
timeout: Duration::from_secs(args.timeout),
|
||||
bookmarks,
|
||||
client,
|
||||
sink,
|
||||
@ -301,7 +301,7 @@ impl Player {
|
||||
let current = player.current.load();
|
||||
let current = current.as_ref().unwrap();
|
||||
|
||||
player.bookmarks.bookmark(&¤t).await?;
|
||||
player.bookmarks.bookmark(current).await?;
|
||||
}
|
||||
Message::Quit => break,
|
||||
}
|
||||
|
@ -1,12 +1,15 @@
|
||||
use std::io::SeekFrom;
|
||||
//! Module for handling saving, loading, and adding
|
||||
//! bookmarks.
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
use tokio::fs::{create_dir_all, File, OpenOptions};
|
||||
use tokio::io::{self, AsyncReadExt, AsyncSeekExt, AsyncWriteExt};
|
||||
use tokio::sync::RwLock;
|
||||
use tokio::{fs, io};
|
||||
|
||||
use crate::{data_dir, tracks};
|
||||
|
||||
/// Errors that might occur while managing bookmarks.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum BookmarkError {
|
||||
#[error("data directory not found")]
|
||||
@ -18,57 +21,51 @@ pub enum BookmarkError {
|
||||
|
||||
/// Manages the bookmarks in the current player.
|
||||
pub struct Bookmarks {
|
||||
/// The different entries in the bookmarks file.
|
||||
entries: RwLock<Vec<String>>,
|
||||
file: RwLock<File>,
|
||||
|
||||
/// The internal bookmarked register, which keeps track
|
||||
/// of whether a track is bookmarked or not.
|
||||
///
|
||||
/// This is much more efficient than checking every single frame.
|
||||
bookmarked: AtomicBool,
|
||||
}
|
||||
|
||||
impl Bookmarks {
|
||||
pub async fn load() -> eyre::Result<Self, BookmarkError> {
|
||||
/// Gets the path of the bookmarks file.
|
||||
pub async fn path() -> eyre::Result<PathBuf, BookmarkError> {
|
||||
let data_dir = data_dir().map_err(|_| BookmarkError::DataDir)?;
|
||||
create_dir_all(data_dir.clone()).await?;
|
||||
fs::create_dir_all(data_dir.clone()).await?;
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.read(true)
|
||||
.append(false)
|
||||
.truncate(false)
|
||||
.open(data_dir.join("bookmarks.txt"))
|
||||
.await?;
|
||||
|
||||
let mut text = String::new();
|
||||
file.read_to_string(&mut text).await?;
|
||||
Ok(data_dir.join("bookmarks.txt"))
|
||||
}
|
||||
/// Loads bookmarks from the `bookmarks.txt` file.
|
||||
pub async fn load() -> eyre::Result<Self, BookmarkError> {
|
||||
let text = fs::read_to_string(Self::path().await?).await?;
|
||||
|
||||
let lines: Vec<String> = text
|
||||
.trim_start_matches("noheader")
|
||||
.trim()
|
||||
.lines()
|
||||
.filter_map(|x| {
|
||||
if !x.is_empty() {
|
||||
Some(x.to_string())
|
||||
} else {
|
||||
if x.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(x.to_string())
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(Self {
|
||||
entries: RwLock::new(lines),
|
||||
file: RwLock::new(file),
|
||||
bookmarked: AtomicBool::new(false),
|
||||
})
|
||||
}
|
||||
|
||||
// Saves the bookmarks to the `bookmarks.txt` file.
|
||||
pub async fn save(&self) -> eyre::Result<(), BookmarkError> {
|
||||
let text = format!("noheader\n{}", self.entries.read().await.join("\n"));
|
||||
|
||||
let mut lock = self.file.write().await;
|
||||
lock.seek(SeekFrom::Start(0)).await?;
|
||||
lock.set_len(0).await?;
|
||||
lock.write_all(text.as_bytes()).await?;
|
||||
lock.flush().await?;
|
||||
|
||||
fs::write(Self::path().await?, text).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -91,10 +88,14 @@ impl Bookmarks {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns whether a track is bookmarked or not by using the internal
|
||||
/// bookmarked register.
|
||||
pub fn bookmarked(&self) -> bool {
|
||||
self.bookmarked.load(std::sync::atomic::Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// Sets the internal bookmarked register by checking against
|
||||
/// the current track's info.
|
||||
pub async fn set_bookmarked(&self, track: &tracks::Info) {
|
||||
let val = self.entries.read().await.contains(&track.to_entry());
|
||||
self.bookmarked
|
||||
|
@ -8,7 +8,7 @@ use tokio::{
|
||||
time::sleep,
|
||||
};
|
||||
|
||||
use super::{Player, TIMEOUT};
|
||||
use super::Player;
|
||||
|
||||
/// This struct is responsible for downloading tracks in the background.
|
||||
///
|
||||
@ -53,7 +53,7 @@ impl Downloader {
|
||||
}
|
||||
|
||||
if !error.is_timeout() {
|
||||
sleep(TIMEOUT).await;
|
||||
sleep(self.player.timeout).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use tokio::{sync::mpsc::Sender, time::sleep};
|
||||
|
||||
use crate::{
|
||||
messages::Message,
|
||||
player::{downloader::Downloader, Player, TIMEOUT},
|
||||
player::{downloader::Downloader, Player},
|
||||
tracks,
|
||||
};
|
||||
|
||||
@ -76,7 +76,7 @@ impl Player {
|
||||
}
|
||||
|
||||
if !error.is_timeout() {
|
||||
sleep(TIMEOUT).await;
|
||||
sleep(player.timeout).await;
|
||||
}
|
||||
|
||||
tx.send(Message::TryAgain).await?;
|
||||
|
@ -159,8 +159,6 @@ impl Window {
|
||||
/// The code for the terminal interface itself.
|
||||
///
|
||||
/// * `minimalist` - All this does is hide the bottom control bar.
|
||||
/// * `borderless` - Whether to include borders or not.
|
||||
/// * `width` - The width of player
|
||||
async fn interface(
|
||||
player: Arc<Player>,
|
||||
minimalist: bool,
|
||||
|
@ -87,7 +87,7 @@ impl ActionBar {
|
||||
Self::Muted => {
|
||||
let msg = "+ to increase volume";
|
||||
|
||||
("muted", Some((String::from(msg), msg.len())))
|
||||
("muted,", Some((String::from(msg), msg.len())))
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -12,6 +12,7 @@ pub mod archive;
|
||||
pub mod chillhop;
|
||||
pub mod lofigirl;
|
||||
|
||||
/// Represents the different sources which can be scraped.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, ValueEnum)]
|
||||
pub enum Source {
|
||||
Lofigirl,
|
||||
@ -20,6 +21,7 @@ pub enum Source {
|
||||
}
|
||||
|
||||
impl Source {
|
||||
/// Gets the cache directory name, for example, `chillhop`.
|
||||
pub fn cache_dir(&self) -> &'static str {
|
||||
match self {
|
||||
Source::Lofigirl => "lofigirl",
|
||||
@ -28,6 +30,7 @@ impl Source {
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the full root URL of the source.
|
||||
pub fn url(&self) -> &'static str {
|
||||
match self {
|
||||
Source::Chillhop => "https://chillhop.com",
|
||||
|
@ -135,7 +135,7 @@ impl Info {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Formats a name with [convert_case].
|
||||
/// Formats a name with [`convert_case`].
|
||||
///
|
||||
/// This will also strip the first few numbers that are
|
||||
/// usually present on most lofi tracks and do some other
|
||||
|
@ -44,7 +44,7 @@ where
|
||||
Kind: From<E>,
|
||||
{
|
||||
fn from((track, err): (T, E)) -> Self {
|
||||
Error {
|
||||
Self {
|
||||
track: track.into(),
|
||||
kind: Kind::from(err),
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ use atomic_float::AtomicF32;
|
||||
use bytes::{BufMut, Bytes, BytesMut};
|
||||
use eyre::OptionExt as _;
|
||||
use futures::StreamExt;
|
||||
use rand::Rng as _;
|
||||
use reqwest::Client;
|
||||
use tokio::fs;
|
||||
|
||||
@ -52,7 +51,7 @@ impl List {
|
||||
// We're also not pre-trimming `self.lines` into `base` & `tracks` due to
|
||||
// how rust vectors work, since it is slower to drain only a single element from
|
||||
// the start, so it's faster to just keep it in & work around it.
|
||||
let random = rand::thread_rng().gen_range(1..self.lines.len());
|
||||
let random = fastrand::usize(1..self.lines.len());
|
||||
let line = self.lines[random].clone();
|
||||
|
||||
if let Some((first, second)) = line.split_once('!') {
|
||||
@ -134,7 +133,7 @@ impl List {
|
||||
|
||||
let name = custom_name.map_or_else(
|
||||
|| super::TrackName::Raw(path.clone()),
|
||||
|formatted| super::TrackName::Formatted(formatted),
|
||||
super::TrackName::Formatted,
|
||||
);
|
||||
|
||||
Ok(QueuedTrack {
|
||||
@ -154,7 +153,7 @@ impl List {
|
||||
|
||||
Self {
|
||||
lines,
|
||||
path: path.map(|s| s.to_owned()),
|
||||
path: path.map(ToOwned::to_owned),
|
||||
name: name.to_owned(),
|
||||
}
|
||||
}
|
||||
@ -169,11 +168,9 @@ impl List {
|
||||
let raw = fs::read_to_string(path.clone()).await?;
|
||||
|
||||
// Get rid of special noheader case for tracklists without a header.
|
||||
let raw = if let Some(stripped) = raw.strip_prefix("noheader") {
|
||||
stripped
|
||||
} else {
|
||||
&raw
|
||||
};
|
||||
let raw = raw
|
||||
.strip_prefix("noheader")
|
||||
.map_or(raw.as_ref(), |stripped| stripped);
|
||||
|
||||
let name = path
|
||||
.file_stem()
|
||||
|
Loading…
x
Reference in New Issue
Block a user