mirror of
https://github.com/talwat/lowfi
synced 2025-09-30 04:10:13 +00:00
Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
e702c1de00 | ||
|
8f837302c3 | ||
|
226c674295 | ||
|
66f2243b2c | ||
|
05fe8069ea | ||
|
9b61dffb12 | ||
|
c2530453fb | ||
|
e4fd542edf | ||
|
632b298de2 | ||
|
41ba98b9cf | ||
|
0162421db4 | ||
|
4d4f5e0920 | ||
|
d41bd16069 | ||
|
d2c8bdb8aa |
@ -1,5 +1,10 @@
|
|||||||
# Using the chillhop list
|
# 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
|
## Linux
|
||||||
|
|
||||||
```sh
|
```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"
|
checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alsa-sys",
|
"alsa-sys",
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.9.3",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@ -183,7 +183,7 @@ dependencies = [
|
|||||||
"futures-lite",
|
"futures-lite",
|
||||||
"parking",
|
"parking",
|
||||||
"polling",
|
"polling",
|
||||||
"rustix",
|
"rustix 0.38.42",
|
||||||
"slab",
|
"slab",
|
||||||
"tracing",
|
"tracing",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
@ -215,7 +215,7 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"event-listener",
|
"event-listener",
|
||||||
"futures-lite",
|
"futures-lite",
|
||||||
"rustix",
|
"rustix 0.38.42",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -242,7 +242,7 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"rustix",
|
"rustix 0.38.42",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"slab",
|
"slab",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
@ -312,9 +312,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.6.0"
|
version = "2.9.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block-buffer"
|
name = "block-buffer"
|
||||||
@ -480,6 +480,15 @@ dependencies = [
|
|||||||
"windows-sys 0.60.2",
|
"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]]
|
[[package]]
|
||||||
name = "convert_case"
|
name = "convert_case"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
@ -562,16 +571,18 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossterm"
|
name = "crossterm"
|
||||||
version = "0.28.1"
|
version = "0.29.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
|
checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.9.3",
|
||||||
"crossterm_winapi",
|
"crossterm_winapi",
|
||||||
|
"derive_more 2.0.1",
|
||||||
|
"document-features",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"mio",
|
"mio",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"rustix",
|
"rustix 1.0.8",
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
"signal-hook-mio",
|
"signal-hook-mio",
|
||||||
"winapi",
|
"winapi",
|
||||||
@ -636,6 +647,27 @@ dependencies = [
|
|||||||
"syn",
|
"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]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.10.7"
|
version = "0.10.7"
|
||||||
@ -648,23 +680,23 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs"
|
name = "dirs"
|
||||||
version = "5.0.1"
|
version = "6.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dirs-sys",
|
"dirs-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs-sys"
|
name = "dirs-sys"
|
||||||
version = "0.4.1"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"option-ext",
|
"option-ext",
|
||||||
"redox_users",
|
"redox_users",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -673,7 +705,7 @@ version = "0.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
|
checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.9.3",
|
||||||
"objc2",
|
"objc2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -688,6 +720,15 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "document-features"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d"
|
||||||
|
dependencies = [
|
||||||
|
"litrs",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dtoa"
|
name = "dtoa"
|
||||||
version = "1.0.10"
|
version = "1.0.10"
|
||||||
@ -1421,7 +1462,7 @@ version = "0.1.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.9.3",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1431,12 +1472,24 @@ version = "0.4.14"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "litemap"
|
name = "litemap"
|
||||||
version = "0.7.4"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
|
checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "litrs"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.12"
|
version = "0.4.12"
|
||||||
@ -1455,24 +1508,24 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lowfi"
|
name = "lowfi"
|
||||||
version = "1.7.1-dev"
|
version = "1.7.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"atomic_float",
|
"atomic_float",
|
||||||
"bytes",
|
"bytes",
|
||||||
"clap",
|
"clap",
|
||||||
"color-eyre",
|
"color-eyre",
|
||||||
"convert_case",
|
"convert_case 0.8.0",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"dirs",
|
"dirs",
|
||||||
"eyre",
|
"eyre",
|
||||||
|
"fastrand",
|
||||||
"futures",
|
"futures",
|
||||||
"html-escape",
|
"html-escape",
|
||||||
"indicatif",
|
"indicatif",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"mpris-server",
|
"mpris-server",
|
||||||
"rand",
|
|
||||||
"regex",
|
"regex",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"rodio",
|
"rodio",
|
||||||
@ -1603,7 +1656,7 @@ version = "0.9.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4"
|
checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.9.3",
|
||||||
"jni-sys",
|
"jni-sys",
|
||||||
"log",
|
"log",
|
||||||
"ndk-sys",
|
"ndk-sys",
|
||||||
@ -1638,7 +1691,7 @@ version = "0.29.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
|
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.9.3",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"libc",
|
"libc",
|
||||||
@ -1732,7 +1785,7 @@ version = "0.3.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "10cbe18d879e20a4aea544f8befe38bcf52255eb63d3f23eca2842f3319e4c07"
|
checksum = "10cbe18d879e20a4aea544f8befe38bcf52255eb63d3f23eca2842f3319e4c07"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.9.3",
|
||||||
"libc",
|
"libc",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-core-audio",
|
"objc2-core-audio",
|
||||||
@ -1759,7 +1812,7 @@ version = "0.3.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c0f1cc99bb07ad2ddb6527ddf83db6a15271bb036b3eb94b801cd44fdc666ee1"
|
checksum = "c0f1cc99bb07ad2ddb6527ddf83db6a15271bb036b3eb94b801cd44fdc666ee1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.9.3",
|
||||||
"objc2",
|
"objc2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1769,7 +1822,7 @@ version = "0.3.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
|
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.9.3",
|
||||||
"dispatch2",
|
"dispatch2",
|
||||||
"objc2",
|
"objc2",
|
||||||
]
|
]
|
||||||
@ -1810,7 +1863,7 @@ version = "0.10.68"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
|
checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.9.3",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"foreign-types",
|
"foreign-types",
|
||||||
"libc",
|
"libc",
|
||||||
@ -1996,7 +2049,7 @@ dependencies = [
|
|||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"hermit-abi",
|
"hermit-abi",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"rustix",
|
"rustix 0.38.42",
|
||||||
"tracing",
|
"tracing",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
@ -2091,18 +2144,18 @@ version = "0.5.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
|
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.9.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_users"
|
name = "redox_users"
|
||||||
version = "0.4.6"
|
version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
|
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.2.15",
|
"getrandom 0.2.15",
|
||||||
"libredox",
|
"libredox",
|
||||||
"thiserror 1.0.69",
|
"thiserror 2.0.12",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2219,13 +2272,26 @@ version = "0.38.42"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
|
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.9.3",
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys 0.4.14",
|
||||||
"windows-sys 0.59.0",
|
"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]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.23.20"
|
version = "0.23.20"
|
||||||
@ -2323,7 +2389,7 @@ version = "2.11.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.9.3",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
"core-foundation-sys",
|
"core-foundation-sys",
|
||||||
"libc",
|
"libc",
|
||||||
@ -2346,9 +2412,9 @@ version = "0.26.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fd568a4c9bb598e291a08244a5c1f5a8a6650bee243b5b0f8dbb3d9cc1d87fe8"
|
checksum = "fd568a4c9bb598e291a08244a5c1f5a8a6650bee243b5b0f8dbb3d9cc1d87fe8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.9.3",
|
||||||
"cssparser",
|
"cssparser",
|
||||||
"derive_more",
|
"derive_more 0.99.20",
|
||||||
"fxhash",
|
"fxhash",
|
||||||
"log",
|
"log",
|
||||||
"new_debug_unreachable",
|
"new_debug_unreachable",
|
||||||
@ -2740,7 +2806,7 @@ version = "0.6.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
|
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.9.3",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
"system-configuration-sys",
|
"system-configuration-sys",
|
||||||
]
|
]
|
||||||
@ -2765,7 +2831,7 @@ dependencies = [
|
|||||||
"fastrand",
|
"fastrand",
|
||||||
"getrandom 0.2.15",
|
"getrandom 0.2.15",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix",
|
"rustix 0.38.42",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3321,15 +3387,6 @@ dependencies = [
|
|||||||
"windows-targets 0.42.2",
|
"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]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
@ -3372,21 +3429,6 @@ dependencies = [
|
|||||||
"windows_x86_64_msvc 0.42.2",
|
"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]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@ -3426,12 +3468,6 @@ version = "0.42.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_gnullvm"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@ -3450,12 +3486,6 @@ version = "0.42.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_msvc"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@ -3474,12 +3504,6 @@ version = "0.42.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnu"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@ -3510,12 +3534,6 @@ version = "0.42.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_msvc"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@ -3534,12 +3552,6 @@ version = "0.42.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
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]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@ -3558,12 +3570,6 @@ version = "0.42.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
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]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@ -3582,12 +3588,6 @@ version = "0.42.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
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]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@ -3615,7 +3615,7 @@ version = "0.39.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.9.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "lowfi"
|
name = "lowfi"
|
||||||
version = "1.7.1-dev"
|
version = "1.7.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "An extremely simple lofi player."
|
description = "An extremely simple lofi player."
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
@ -25,7 +25,7 @@ scrape = ["dep:serde", "dep:serde_json", "dep:html-escape", "dep:scraper", "dep:
|
|||||||
# Basics
|
# Basics
|
||||||
clap = { version = "4.5.21", features = ["derive", "cargo"] }
|
clap = { version = "4.5.21", features = ["derive", "cargo"] }
|
||||||
eyre = "0.6.12"
|
eyre = "0.6.12"
|
||||||
rand = "0.8.5"
|
fastrand = "2.3.0"
|
||||||
thiserror = "2.0.12"
|
thiserror = "2.0.12"
|
||||||
color-eyre = { version = "0.6.5", default-features = false }
|
color-eyre = { version = "0.6.5", default-features = false }
|
||||||
|
|
||||||
@ -39,10 +39,10 @@ reqwest = { version = "0.12.9", features = ["stream"] }
|
|||||||
bytes = "1.9.0"
|
bytes = "1.9.0"
|
||||||
|
|
||||||
# I/O
|
# 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 }
|
rodio = { version = "0.21.1", features = ["symphonia-mp3", "playback"], default-features = false }
|
||||||
mpris-server = { version = "0.8.1", optional = true }
|
mpris-server = { version = "0.8.1", optional = true }
|
||||||
dirs = "5.0.1"
|
dirs = "6.0.0"
|
||||||
|
|
||||||
# Misc
|
# Misc
|
||||||
convert_case = "0.8.0"
|
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.
|
88
README.md
88
README.md
@ -8,21 +8,17 @@ It'll do this as simply as it can: no albums, no ads, just lofi.
|
|||||||
## Disclaimer
|
## Disclaimer
|
||||||
|
|
||||||
As of the 1.7.0 version of lowfi, **all** of the audio files embedded
|
As of the 1.7.0 version of lowfi, **all** of the audio files embedded
|
||||||
by default are from [chillhop](https://chillhop.com/).
|
by default are from [chillhop](https://chillhop.com/). Read
|
||||||
|
[MUSIC.md](MUSIC.md) for more information.
|
||||||
<!-- TODO: Make seperate write-up about using chillhop. -->
|
|
||||||
|
|
||||||
## Why?
|
## Why?
|
||||||
|
|
||||||
I really hate modern music platforms, and I wanted a small, "suckless"
|
I really hate modern music platforms, and I wanted a small, simple
|
||||||
app that would just play random lofi without video.
|
app that would just play random ambient music without video and other fluff.
|
||||||
|
|
||||||
It was also designed to be fairly resilient to inconsistent networks,
|
Beyond that, it was also designed to be fairly resilient to inconsistent networks,
|
||||||
and as such it buffers 5 whole songs at a time instead of parts of the same song.
|
and as such it buffers 5 whole songs at a time instead of parts of the same song.
|
||||||
|
|
||||||
See [Scraping](#scraping) if you're interested in downloading the tracks.
|
|
||||||
Beware, there's a lot of them.
|
|
||||||
|
|
||||||
## Installing
|
## Installing
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
@ -38,8 +34,8 @@ On MacOS & Windows, no extra dependencies are needed.
|
|||||||
|
|
||||||
On Linux, you'll also need openssl & alsa, as well as their headers.
|
On Linux, you'll also need openssl & alsa, as well as their headers.
|
||||||
|
|
||||||
- `alsa-lib` on Arch, `libasound2-dev` on Ubuntu.
|
- `alsa-lib` on Arch, `libasound2-dev` on Ubuntu, `alsa-lib-devel` on Fedora.
|
||||||
- `openssl` on Arch, `libssl-dev` on Ubuntu.
|
- `openssl` on Arch, `libssl-dev` on Ubuntu, `openssl-devel` on Fedora.
|
||||||
|
|
||||||
Make sure to also install `pulseaudio-alsa` if you're using PulseAudio.
|
Make sure to also install `pulseaudio-alsa` if you're using PulseAudio.
|
||||||
|
|
||||||
@ -80,7 +76,7 @@ zypper install lowfi
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
curl -sS https://debian.griffo.io/3B9335DF576D3D58059C6AA50B56A1A69762E9FF.asc | gpg --dearmor --yes -o /etc/apt/trusted.gpg.d/debian.griffo.io.gpg
|
curl -sS https://debian.griffo.io/3B9335DF576D3D58059C6AA50B56A1A69762E9FF.asc | gpg --dearmor --yes -o /etc/apt/trusted.gpg.d/debian.griffo.io.gpg
|
||||||
echo "deb https://debian.griffo.io//apt $(lsb_release -sc 2>/dev/null) main" | sudo tee /etc/apt/sources.list.d/debian.griffo.io.list
|
echo "deb https://debian.griffo.io/apt $(lsb_release -sc 2>/dev/null) main" | sudo tee /etc/apt/sources.list.d/debian.griffo.io.list
|
||||||
sudo apt install -y lowfi
|
sudo apt install -y lowfi
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -127,12 +123,13 @@ Yeah, that's it.
|
|||||||
| `-`, `_`, `j`, `↓` | Volume Down 10% |
|
| `-`, `_`, `j`, `↓` | Volume Down 10% |
|
||||||
| `←` | Volume Down 1% |
|
| `←` | Volume Down 1% |
|
||||||
| `q`, CTRL+C | Quit |
|
| `q`, CTRL+C | Quit |
|
||||||
|
| `b` | Bookmark |
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> Besides its regular controls, lowfi offers compatibility with Media Keys
|
> Besides its regular controls, lowfi offers compatibility with Media Keys
|
||||||
> and [MPRIS](https://wiki.archlinux.org/title/MPRIS) (with tools like `playerctl`).
|
> and [MPRIS](https://wiki.archlinux.org/title/MPRIS) (with tools like `playerctl`).
|
||||||
>
|
>
|
||||||
> MPRIS is currently optional feature in cargo (enabled with `--features mpris`)
|
> MPRIS is currently an optional feature in cargo (enabled with `--features mpris`)
|
||||||
> due to it being only for Linux, as well as the fact that the main point of
|
> due to it being only for Linux, as well as the fact that the main point of
|
||||||
> lowfi is it's unique & minimal interface.
|
> lowfi is it's unique & minimal interface.
|
||||||
|
|
||||||
@ -141,42 +138,57 @@ Yeah, that's it.
|
|||||||
If you have something you'd like to tweak about lowfi, you use additional flags which
|
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`.
|
slightly tweak the UI or behaviour of the menu. The flags can be viewed with `lowfi help`.
|
||||||
|
|
||||||
| Flag | Function |
|
| Flag | Function |
|
||||||
| ----------------------------------- | ---------------------------------------------- |
|
| ----------------------------------- | --------------------------------------------------- |
|
||||||
| `-a`, `--alternate` | Use an alternate terminal screen |
|
| `-a`, `--alternate` | Use an alternate terminal screen |
|
||||||
| `-m`, `--minimalist` | Hide the bottom control bar |
|
| `-m`, `--minimalist` | Hide the bottom control bar |
|
||||||
| `-b`, `--borderless` | Exclude borders in UI |
|
| `-b`, `--borderless` | Exclude borders in UI |
|
||||||
| `-p`, `--paused` | Start lowfi paused |
|
| `-p`, `--paused` | Start lowfi paused |
|
||||||
| `-d`, `--debug` | Include ALSA & other logs |
|
| `-f`, `--fps` | FPS of the UI [default: 12] |
|
||||||
| `-w`, `--width <WIDTH>` | Width of the player, from 0 to 32 [default: 3] |
|
| `--timeout` | Timeout in seconds for music downloads [default: 3] |
|
||||||
| `-t`, `--track-list <TRACK_LIST>` | Use a [custom track list](#custom-track-lists) |
|
| `-d`, `--debug` | Include ALSA & other logs |
|
||||||
| `-s`, `--buffer-size <BUFFER_SIZE>` | Internal song buffer size [default: 5] |
|
| `-w`, `--width <WIDTH>` | Width of the player, from 0 to 32 [default: 3] |
|
||||||
|
| `-t`, `--track-list <TRACK_LIST>` | Use a [custom track list](#custom-track-lists) |
|
||||||
|
| `-s`, `--buffer-size <BUFFER_SIZE>` | Internal song buffer size [default: 5] |
|
||||||
|
|
||||||
### Scraping
|
### Extra Features
|
||||||
|
|
||||||
lowfi also has a `scrape` command which is usually not relevant, but
|
lowfi uses cargo/rust's "feature" system to make certain parts of the program optional,
|
||||||
if you're trying to download some files from Lofi Girls' website,
|
like those which are only expected to be used by a handful of users.
|
||||||
it can be useful.
|
|
||||||
|
|
||||||
An example of scrape is as follows,
|
#### `scrape` - Scraping
|
||||||
|
|
||||||
`lowfi scrape --extension zip --include-full`
|
This feature provides the `scrape` command.
|
||||||
|
It's usually not very useful, but is included for transparency's sake.
|
||||||
|
|
||||||
where more information can be found by running `lowfi help scrape`.
|
More information can be found by running `lowfi help scrape`.
|
||||||
|
|
||||||
|
#### `mpris` - MPRIS
|
||||||
|
|
||||||
|
Enables MPRIS. It's not rocket science.
|
||||||
|
|
||||||
|
#### `extra-audio-formats` - Extra Audio Formats
|
||||||
|
|
||||||
|
This is only relevant to those using a custom track list, in which case
|
||||||
|
it allows for more formats than just MP3. Those are FLAC, Vorbis, and WAV.
|
||||||
|
|
||||||
|
These should be sufficient for some 99% of music files people might want to play.
|
||||||
|
If you dealing with the 1% using another audio format which is in
|
||||||
|
[this list](https://github.com/pdeljanov/Symphonia?tab=readme-ov-file#codecs-decoders), open an issue.
|
||||||
|
|
||||||
### Custom Track Lists
|
### Custom Track Lists
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> Some nice users, especially [danielwerg](https://github.com/danielwerg),
|
> 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 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 `--tracks` flag.
|
> 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.
|
> Feel free to contribute your own list with a PR.
|
||||||
|
|
||||||
lowfi also supports custom track lists, although the default one from Lofi Girl
|
lowfi also supports custom track lists, although the default one from chillhop
|
||||||
is embedded into the binary.
|
is embedded into the binary.
|
||||||
|
|
||||||
To use a custom list, use the `--tracks` flag. This can either be a path to some file,
|
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
|
or it could also be the name of a file (without the `.txt` extension) in the data
|
||||||
directory.
|
directory.
|
||||||
|
|
||||||
@ -187,8 +199,8 @@ directory.
|
|||||||
> - macOS - `~/Library/Application Support/lowfi`
|
> - macOS - `~/Library/Application Support/lowfi`
|
||||||
> - Windows - `%appdata%\Roaming\lowfi`
|
> - Windows - `%appdata%\Roaming\lowfi`
|
||||||
|
|
||||||
For example, `lowfi --tracks minipop` would load `~/.local/share/lowfi/minipop.txt`.
|
For example, `lowfi --track-list minipop` would load `~/.local/share/lowfi/minipop.txt`.
|
||||||
Whereas if you did `lowfi --tracks ~/Music/minipop.txt` it would load from that
|
Whereas if you did `lowfi --track-list ~/Music/minipop.txt` it would load from that
|
||||||
specified directory.
|
specified directory.
|
||||||
|
|
||||||
All tracks must be in the MP3 format, unless lowfi has been compiled with the
|
All tracks must be in the MP3 format, unless lowfi has been compiled with the
|
||||||
@ -197,7 +209,7 @@ All tracks must be in the MP3 format, unless lowfi has been compiled with the
|
|||||||
#### The Format
|
#### The Format
|
||||||
|
|
||||||
In lists, the first line is what's known as the header, followed by the rest of the tracks.
|
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
|
Each track will be first appended to the header, and then use the combination to download
|
||||||
the track.
|
the track.
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
@ -232,8 +244,8 @@ For example, if you had an entry like this:
|
|||||||
|
|
||||||
Then lowfi would download from the first section, and display the second as the track name.
|
Then lowfi would download from the first section, and display the second as the track name.
|
||||||
|
|
||||||
You can also prepend `file://` to the header track name, which will make lowfi treat it as a local file.
|
`file://` can be used in front a track/header to make lowfi treat it as a local file.
|
||||||
This is useful if you want to use a local file as the base URL, such as:
|
This is useful if you want to use a local file as the base URL, for example:
|
||||||
|
|
||||||
```txt
|
```txt
|
||||||
file:///home/user/Music/
|
file:///home/user/Music/
|
||||||
|
@ -30,7 +30,6 @@ https://stream.chillhop.com/mp3/
|
|||||||
8943!Wondering
|
8943!Wondering
|
||||||
8906!Soundscapes
|
8906!Soundscapes
|
||||||
8421!Wine & Roses
|
8421!Wine & Roses
|
||||||
8469!Interlude
|
|
||||||
8464!Underwater
|
8464!Underwater
|
||||||
8221!The Creator
|
8221!The Creator
|
||||||
8467!Cloud Steps
|
8467!Cloud Steps
|
||||||
@ -151,7 +150,6 @@ https://stream.chillhop.com/mp3/
|
|||||||
8118!Too Young For Secrets
|
8118!Too Young For Secrets
|
||||||
8162!Noodlez
|
8162!Noodlez
|
||||||
9269!Le Voyage Du Coeur
|
9269!Le Voyage Du Coeur
|
||||||
8157!As Long As I Got You
|
|
||||||
8540!3UO
|
8540!3UO
|
||||||
8956!Tiger
|
8956!Tiger
|
||||||
9315!Sticks & Stones
|
9315!Sticks & Stones
|
||||||
@ -200,7 +198,6 @@ https://stream.chillhop.com/mp3/
|
|||||||
8274!Lazy Pacific
|
8274!Lazy Pacific
|
||||||
8144!Digital Sex
|
8144!Digital Sex
|
||||||
8768!White Cadillac
|
8768!White Cadillac
|
||||||
8141!All Your Love
|
|
||||||
8140!San Junipero
|
8140!San Junipero
|
||||||
8760!Body N Soul
|
8760!Body N Soul
|
||||||
8481!Hideout
|
8481!Hideout
|
||||||
@ -225,7 +222,6 @@ https://stream.chillhop.com/mp3/
|
|||||||
9372!Love from NGC 7318
|
9372!Love from NGC 7318
|
||||||
8554!Faces
|
8554!Faces
|
||||||
8005!Interstellar
|
8005!Interstellar
|
||||||
8001!The Dream
|
|
||||||
7998!Stay.
|
7998!Stay.
|
||||||
7994!Don't know why
|
7994!Don't know why
|
||||||
7991!Chinatown
|
7991!Chinatown
|
||||||
@ -313,7 +309,6 @@ https://stream.chillhop.com/mp3/
|
|||||||
7839!New Light
|
7839!New Light
|
||||||
7837!Lost Love
|
7837!Lost Love
|
||||||
7834!Foggy Road
|
7834!Foggy Road
|
||||||
7832!Isolated
|
|
||||||
7830!Wistful
|
7830!Wistful
|
||||||
7842!Nimbus
|
7842!Nimbus
|
||||||
7841!Chiaroscuro
|
7841!Chiaroscuro
|
||||||
@ -403,7 +398,6 @@ https://stream.chillhop.com/mp3/
|
|||||||
8604!Sleepwell
|
8604!Sleepwell
|
||||||
9485!Dusk
|
9485!Dusk
|
||||||
9484!Slowdrive
|
9484!Slowdrive
|
||||||
9446!Quietly, Now
|
|
||||||
8321!Loved
|
8321!Loved
|
||||||
7880!Get Up and Go
|
7880!Get Up and Go
|
||||||
9488!Goodmorning
|
9488!Goodmorning
|
||||||
@ -601,14 +595,12 @@ https://stream.chillhop.com/mp3/
|
|||||||
8536!Novel (Calm)
|
8536!Novel (Calm)
|
||||||
9255!Manner (Forms)
|
9255!Manner (Forms)
|
||||||
9447!Vinho Verde
|
9447!Vinho Verde
|
||||||
9396!Upstream Color
|
|
||||||
8083!You're Asleep So I Gotta Keep It Down Shh
|
8083!You're Asleep So I Gotta Keep It Down Shh
|
||||||
8688!Home Video
|
8688!Home Video
|
||||||
8514!Old Friends
|
8514!Old Friends
|
||||||
9219!Growing Apart
|
9219!Growing Apart
|
||||||
7925!Upset (hold it in)
|
7925!Upset (hold it in)
|
||||||
9222!Keep Going
|
9222!Keep Going
|
||||||
9217!Feeling Lost
|
|
||||||
9228!Reflection
|
9228!Reflection
|
||||||
9225!Tumbling
|
9225!Tumbling
|
||||||
9224!Fox
|
9224!Fox
|
||||||
@ -735,7 +727,6 @@ https://stream.chillhop.com/mp3/
|
|||||||
10450!Not A Cloud In Sight
|
10450!Not A Cloud In Sight
|
||||||
10460!Deeper
|
10460!Deeper
|
||||||
10454!Creswick
|
10454!Creswick
|
||||||
10448!Slim Bobby
|
|
||||||
9771!Her Eyes
|
9771!Her Eyes
|
||||||
9775!Perspectives
|
9775!Perspectives
|
||||||
8599!Otherside
|
8599!Otherside
|
||||||
@ -1003,7 +994,6 @@ https://stream.chillhop.com/mp3/
|
|||||||
24830!Learning How to Skateboard
|
24830!Learning How to Skateboard
|
||||||
24829!Fireworks Festival
|
24829!Fireworks Festival
|
||||||
24828!Man I Miss My Cats
|
24828!Man I Miss My Cats
|
||||||
24827!I Thought Graduating Would Feel Weirder
|
|
||||||
24826!Setting Up Our Beds in Minecraft
|
24826!Setting Up Our Beds in Minecraft
|
||||||
24825!Library Card
|
24825!Library Card
|
||||||
24824!Tournament Arc
|
24824!Tournament Arc
|
||||||
@ -1064,7 +1054,6 @@ https://stream.chillhop.com/mp3/
|
|||||||
31610!Chill'n
|
31610!Chill'n
|
||||||
31608!Vision Nocturne
|
31608!Vision Nocturne
|
||||||
31516!Tropical Midnight
|
31516!Tropical Midnight
|
||||||
31612!When I'm With U
|
|
||||||
31591!Night Fishing
|
31591!Night Fishing
|
||||||
31589!Lose Her Way
|
31589!Lose Her Way
|
||||||
32888!Glow
|
32888!Glow
|
||||||
@ -1120,7 +1109,6 @@ https://stream.chillhop.com/mp3/
|
|||||||
36922!Treecko is a Cool Starter
|
36922!Treecko is a Cool Starter
|
||||||
37133!Penpals Perhaps
|
37133!Penpals Perhaps
|
||||||
37127!Apple Turnover
|
37127!Apple Turnover
|
||||||
41956!Making a Way
|
|
||||||
43908!Memory
|
43908!Memory
|
||||||
43907!Soft Spot
|
43907!Soft Spot
|
||||||
43906!Envy You
|
43906!Envy You
|
||||||
@ -1177,7 +1165,6 @@ https://stream.chillhop.com/mp3/
|
|||||||
55317!Fly High Newborn
|
55317!Fly High Newborn
|
||||||
55313!Coffeebreak
|
55313!Coffeebreak
|
||||||
55310!Peaceful Dissociation
|
55310!Peaceful Dissociation
|
||||||
55372!Once
|
|
||||||
53592!Let Go
|
53592!Let Go
|
||||||
58841!Still Looking
|
58841!Still Looking
|
||||||
58840!Longest Wait
|
58840!Longest Wait
|
||||||
@ -1319,15 +1306,8 @@ https://stream.chillhop.com/mp3/
|
|||||||
64054!I Don't Want Love
|
64054!I Don't Want Love
|
||||||
64040!One for Florian
|
64040!One for Florian
|
||||||
75541!Seu Trio
|
75541!Seu Trio
|
||||||
64045!Cut Free
|
|
||||||
75544!You Bring Me Life
|
75544!You Bring Me Life
|
||||||
64036!Curtain Call
|
64045!Cut Free
|
||||||
64038!High Hope
|
|
||||||
64043!In the Sun
|
|
||||||
64047!Sleeping Norboo
|
|
||||||
64050!Autumn Turned Winter
|
|
||||||
64052!Light of World
|
|
||||||
64056!Harp Trees
|
|
||||||
75547!Last One
|
75547!Last One
|
||||||
75546!That Summer
|
75546!That Summer
|
||||||
75545!Hold it Down
|
75545!Hold it Down
|
||||||
@ -1335,6 +1315,12 @@ https://stream.chillhop.com/mp3/
|
|||||||
75542!Hope
|
75542!Hope
|
||||||
75540!When All I Heard Was Artifacts
|
75540!When All I Heard Was Artifacts
|
||||||
75539!Cantar
|
75539!Cantar
|
||||||
|
64036!Curtain Call
|
||||||
|
64038!High Hope
|
||||||
|
64043!In the Sun
|
||||||
|
64047!Sleeping Norboo
|
||||||
|
64050!Autumn Turned Winter
|
||||||
|
64056!Harp Trees
|
||||||
79272!Early June
|
79272!Early June
|
||||||
74856!Light of World
|
74856!Light of World
|
||||||
77527!Guitar Shop
|
77527!Guitar Shop
|
||||||
|
@ -16,6 +16,7 @@ mod scrapers;
|
|||||||
|
|
||||||
#[cfg(feature = "scrape")]
|
#[cfg(feature = "scrape")]
|
||||||
use crate::scrapers::Source;
|
use crate::scrapers::Source;
|
||||||
|
|
||||||
/// An extremely simple lofi player.
|
/// An extremely simple lofi player.
|
||||||
#[derive(Parser, Clone)]
|
#[derive(Parser, Clone)]
|
||||||
#[command(about, version)]
|
#[command(about, version)]
|
||||||
@ -41,6 +42,10 @@ struct Args {
|
|||||||
#[clap(long, short, default_value_t = 12)]
|
#[clap(long, short, default_value_t = 12)]
|
||||||
fps: u8,
|
fps: u8,
|
||||||
|
|
||||||
|
/// Timeout in seconds for music downloads.
|
||||||
|
#[clap(long, default_value_t = 3)]
|
||||||
|
timeout: u64,
|
||||||
|
|
||||||
/// Include ALSA & other logs.
|
/// Include ALSA & other logs.
|
||||||
#[clap(long, short)]
|
#[clap(long, short)]
|
||||||
debug: bool,
|
debug: bool,
|
||||||
@ -50,7 +55,7 @@ struct Args {
|
|||||||
width: usize,
|
width: usize,
|
||||||
|
|
||||||
/// Use a custom track list
|
/// 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>,
|
track_list: Option<String>,
|
||||||
|
|
||||||
/// Internal song buffer size.
|
/// Internal song buffer size.
|
||||||
@ -91,7 +96,6 @@ async fn main() -> eyre::Result<()> {
|
|||||||
|
|
||||||
if let Some(command) = cli.command {
|
if let Some(command) = cli.command {
|
||||||
match command {
|
match command {
|
||||||
// TODO: Actually distinguish between sources.
|
|
||||||
#[cfg(feature = "scrape")]
|
#[cfg(feature = "scrape")]
|
||||||
Commands::Scrape { source } => match source {
|
Commands::Scrape { source } => match source {
|
||||||
Source::Archive => scrapers::archive::scrape().await?,
|
Source::Archive => scrapers::archive::scrape().await?,
|
||||||
|
@ -70,7 +70,9 @@ pub async fn play(args: Args) -> eyre::Result<(), player::Error> {
|
|||||||
|
|
||||||
drop(stream);
|
drop(stream);
|
||||||
player.sink.stop();
|
player.sink.stop();
|
||||||
ui.map(|x| x.abort());
|
if let Some(x) = ui {
|
||||||
|
x.abort();
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -41,10 +41,6 @@ pub use error::Error;
|
|||||||
#[cfg(feature = "mpris")]
|
#[cfg(feature = "mpris")]
|
||||||
pub mod 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.
|
/// 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: 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`.
|
// 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.
|
/// The bookmarks, which are saved on quit.
|
||||||
pub bookmarks: Bookmarks,
|
pub bookmarks: Bookmarks,
|
||||||
|
|
||||||
|
/// The timeout for track downloads, as a [Duration].
|
||||||
|
timeout: Duration,
|
||||||
|
|
||||||
/// The actual list of tracks to be played.
|
/// The actual list of tracks to be played.
|
||||||
list: List,
|
list: List,
|
||||||
|
|
||||||
@ -144,14 +143,15 @@ impl Player {
|
|||||||
"/",
|
"/",
|
||||||
env!("CARGO_PKG_VERSION")
|
env!("CARGO_PKG_VERSION")
|
||||||
))
|
))
|
||||||
.timeout(TIMEOUT * 5)
|
.timeout(Duration::from_secs(args.timeout * 5))
|
||||||
.build()?;
|
.build()?;
|
||||||
|
|
||||||
let player = Self {
|
let player = Self {
|
||||||
tracks: RwLock::new(VecDeque::with_capacity(args.buffer_size)),
|
tracks: RwLock::new(VecDeque::with_capacity(args.buffer_size)),
|
||||||
buffer_size: args.buffer_size,
|
buffer_size: args.buffer_size,
|
||||||
current: ArcSwapOption::new(None),
|
current: ArcSwapOption::new(None),
|
||||||
progress: AtomicF32::new(-1.0),
|
progress: AtomicF32::new(0.0),
|
||||||
|
timeout: Duration::from_secs(args.timeout),
|
||||||
bookmarks,
|
bookmarks,
|
||||||
client,
|
client,
|
||||||
sink,
|
sink,
|
||||||
@ -301,7 +301,7 @@ impl Player {
|
|||||||
let current = player.current.load();
|
let current = player.current.load();
|
||||||
let current = current.as_ref().unwrap();
|
let current = current.as_ref().unwrap();
|
||||||
|
|
||||||
player.bookmarks.bookmark(&¤t).await?;
|
player.bookmarks.bookmark(current).await?;
|
||||||
}
|
}
|
||||||
Message::Quit => break,
|
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 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::sync::RwLock;
|
||||||
|
use tokio::{fs, io};
|
||||||
|
|
||||||
use crate::{data_dir, tracks};
|
use crate::{data_dir, tracks};
|
||||||
|
|
||||||
|
/// Errors that might occur while managing bookmarks.
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum BookmarkError {
|
pub enum BookmarkError {
|
||||||
#[error("data directory not found")]
|
#[error("data directory not found")]
|
||||||
@ -18,57 +21,54 @@ pub enum BookmarkError {
|
|||||||
|
|
||||||
/// Manages the bookmarks in the current player.
|
/// Manages the bookmarks in the current player.
|
||||||
pub struct Bookmarks {
|
pub struct Bookmarks {
|
||||||
|
/// The different entries in the bookmarks file.
|
||||||
entries: RwLock<Vec<String>>,
|
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,
|
bookmarked: AtomicBool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bookmarks {
|
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)?;
|
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()
|
Ok(data_dir.join("bookmarks.txt"))
|
||||||
.create(true)
|
}
|
||||||
.write(true)
|
|
||||||
.read(true)
|
|
||||||
.append(false)
|
|
||||||
.truncate(false)
|
|
||||||
.open(data_dir.join("bookmarks.txt"))
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let mut text = String::new();
|
/// Loads bookmarks from the `bookmarks.txt` file.
|
||||||
file.read_to_string(&mut text).await?;
|
pub async fn load() -> eyre::Result<Self, BookmarkError> {
|
||||||
|
let text = fs::read_to_string(Self::path().await?)
|
||||||
|
.await
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
let lines: Vec<String> = text
|
let lines: Vec<String> = text
|
||||||
.trim_start_matches("noheader")
|
.trim_start_matches("noheader")
|
||||||
.trim()
|
.trim()
|
||||||
.lines()
|
.lines()
|
||||||
.filter_map(|x| {
|
.filter_map(|x| {
|
||||||
if !x.is_empty() {
|
if x.is_empty() {
|
||||||
Some(x.to_string())
|
|
||||||
} else {
|
|
||||||
None
|
None
|
||||||
|
} else {
|
||||||
|
Some(x.to_string())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
entries: RwLock::new(lines),
|
entries: RwLock::new(lines),
|
||||||
file: RwLock::new(file),
|
|
||||||
bookmarked: AtomicBool::new(false),
|
bookmarked: AtomicBool::new(false),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Saves the bookmarks to the `bookmarks.txt` file.
|
||||||
pub async fn save(&self) -> eyre::Result<(), BookmarkError> {
|
pub async fn save(&self) -> eyre::Result<(), BookmarkError> {
|
||||||
let text = format!("noheader\n{}", self.entries.read().await.join("\n"));
|
let text = format!("noheader\n{}", self.entries.read().await.join("\n"));
|
||||||
|
fs::write(Self::path().await?, text).await?;
|
||||||
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?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,10 +91,14 @@ impl Bookmarks {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether a track is bookmarked or not by using the internal
|
||||||
|
/// bookmarked register.
|
||||||
pub fn bookmarked(&self) -> bool {
|
pub fn bookmarked(&self) -> bool {
|
||||||
self.bookmarked.load(std::sync::atomic::Ordering::Relaxed)
|
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) {
|
pub async fn set_bookmarked(&self, track: &tracks::Info) {
|
||||||
let val = self.entries.read().await.contains(&track.to_entry());
|
let val = self.entries.read().await.contains(&track.to_entry());
|
||||||
self.bookmarked
|
self.bookmarked
|
||||||
|
@ -8,7 +8,7 @@ use tokio::{
|
|||||||
time::sleep,
|
time::sleep,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Player, TIMEOUT};
|
use super::Player;
|
||||||
|
|
||||||
/// This struct is responsible for downloading tracks in the background.
|
/// This struct is responsible for downloading tracks in the background.
|
||||||
///
|
///
|
||||||
@ -53,7 +53,7 @@ impl Downloader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !error.is_timeout() {
|
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::{
|
use crate::{
|
||||||
messages::Message,
|
messages::Message,
|
||||||
player::{downloader::Downloader, Player, TIMEOUT},
|
player::{downloader::Downloader, Player},
|
||||||
tracks,
|
tracks,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ impl Player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !error.is_timeout() {
|
if !error.is_timeout() {
|
||||||
sleep(TIMEOUT).await;
|
sleep(player.timeout).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
tx.send(Message::TryAgain).await?;
|
tx.send(Message::TryAgain).await?;
|
||||||
|
@ -159,8 +159,6 @@ impl Window {
|
|||||||
/// The code for the terminal interface itself.
|
/// The code for the terminal interface itself.
|
||||||
///
|
///
|
||||||
/// * `minimalist` - All this does is hide the bottom control bar.
|
/// * `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(
|
async fn interface(
|
||||||
player: Arc<Player>,
|
player: Arc<Player>,
|
||||||
minimalist: bool,
|
minimalist: bool,
|
||||||
|
@ -87,7 +87,7 @@ impl ActionBar {
|
|||||||
Self::Muted => {
|
Self::Muted => {
|
||||||
let msg = "+ to increase volume";
|
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 chillhop;
|
||||||
pub mod lofigirl;
|
pub mod lofigirl;
|
||||||
|
|
||||||
|
/// Represents the different sources which can be scraped.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, ValueEnum)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, ValueEnum)]
|
||||||
pub enum Source {
|
pub enum Source {
|
||||||
Lofigirl,
|
Lofigirl,
|
||||||
@ -20,6 +21,7 @@ pub enum Source {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Source {
|
impl Source {
|
||||||
|
/// Gets the cache directory name, for example, `chillhop`.
|
||||||
pub fn cache_dir(&self) -> &'static str {
|
pub fn cache_dir(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Source::Lofigirl => "lofigirl",
|
Source::Lofigirl => "lofigirl",
|
||||||
@ -28,6 +30,7 @@ impl Source {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the full root URL of the source.
|
||||||
pub fn url(&self) -> &'static str {
|
pub fn url(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Source::Chillhop => "https://chillhop.com",
|
Source::Chillhop => "https://chillhop.com",
|
||||||
|
@ -118,13 +118,12 @@ pub async fn scrape() -> eyre::Result<()> {
|
|||||||
const USER_AGENT: &str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36";
|
const USER_AGENT: &str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36";
|
||||||
const TRACK_COUNT: u64 = 1625;
|
const TRACK_COUNT: u64 = 1625;
|
||||||
|
|
||||||
const IGNORED_TRACKS: [u32; 6] = [
|
const IGNORED_TRACKS: [u32; 20] = [
|
||||||
74707, // 404
|
// 404
|
||||||
21655, // Lyrics
|
74707, // Lyrics
|
||||||
21773, // Lyrics
|
21655, 21773, 8172, 55397, 75135, 24827, 8141, 8157, 64052, 31612, 41956, 8001, 9217,
|
||||||
8172, // Lyrics
|
55372, // Abnormal
|
||||||
55397, // Lyrics
|
8469, 7832, 10448, 9446, 9396,
|
||||||
75135, // Lyrics
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const IGNORED_ARTISTS: [&str; 1] = [
|
const IGNORED_ARTISTS: [&str; 1] = [
|
||||||
|
@ -135,7 +135,7 @@ impl Info {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Formats a name with [convert_case].
|
/// Formats a name with [`convert_case`].
|
||||||
///
|
///
|
||||||
/// This will also strip the first few numbers that are
|
/// This will also strip the first few numbers that are
|
||||||
/// usually present on most lofi tracks and do some other
|
/// usually present on most lofi tracks and do some other
|
||||||
|
@ -44,7 +44,7 @@ where
|
|||||||
Kind: From<E>,
|
Kind: From<E>,
|
||||||
{
|
{
|
||||||
fn from((track, err): (T, E)) -> Self {
|
fn from((track, err): (T, E)) -> Self {
|
||||||
Error {
|
Self {
|
||||||
track: track.into(),
|
track: track.into(),
|
||||||
kind: Kind::from(err),
|
kind: Kind::from(err),
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ use atomic_float::AtomicF32;
|
|||||||
use bytes::{BufMut, Bytes, BytesMut};
|
use bytes::{BufMut, Bytes, BytesMut};
|
||||||
use eyre::OptionExt as _;
|
use eyre::OptionExt as _;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use rand::Rng as _;
|
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
|
|
||||||
@ -52,7 +51,7 @@ impl List {
|
|||||||
// We're also not pre-trimming `self.lines` into `base` & `tracks` due to
|
// 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
|
// 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.
|
// 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();
|
let line = self.lines[random].clone();
|
||||||
|
|
||||||
if let Some((first, second)) = line.split_once('!') {
|
if let Some((first, second)) = line.split_once('!') {
|
||||||
@ -134,7 +133,7 @@ impl List {
|
|||||||
|
|
||||||
let name = custom_name.map_or_else(
|
let name = custom_name.map_or_else(
|
||||||
|| super::TrackName::Raw(path.clone()),
|
|| super::TrackName::Raw(path.clone()),
|
||||||
|formatted| super::TrackName::Formatted(formatted),
|
super::TrackName::Formatted,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(QueuedTrack {
|
Ok(QueuedTrack {
|
||||||
@ -154,7 +153,7 @@ impl List {
|
|||||||
|
|
||||||
Self {
|
Self {
|
||||||
lines,
|
lines,
|
||||||
path: path.map(|s| s.to_owned()),
|
path: path.map(ToOwned::to_owned),
|
||||||
name: name.to_owned(),
|
name: name.to_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,11 +168,9 @@ impl List {
|
|||||||
let raw = fs::read_to_string(path.clone()).await?;
|
let raw = fs::read_to_string(path.clone()).await?;
|
||||||
|
|
||||||
// Get rid of special noheader case for tracklists without a header.
|
// Get rid of special noheader case for tracklists without a header.
|
||||||
let raw = if let Some(stripped) = raw.strip_prefix("noheader") {
|
let raw = raw
|
||||||
stripped
|
.strip_prefix("noheader")
|
||||||
} else {
|
.map_or(raw.as_ref(), |stripped| stripped);
|
||||||
&raw
|
|
||||||
};
|
|
||||||
|
|
||||||
let name = path
|
let name = path
|
||||||
.file_stem()
|
.file_stem()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user