From f6bea9f048120c6dea6251612d10afa3897ca6dc Mon Sep 17 00:00:00 2001 From: Tal <83217276+talwat@users.noreply.github.com> Date: Tue, 5 Aug 2025 21:18:39 +0200 Subject: [PATCH] feat: experimental support for other file types chore: migrate to rodio v0.21.1 feat: add a currently nonfunctional source argument to the scrape command well, this is an important commit for anyone who has some interest in the workings of lowfi, so strap in. rodio finally updated cpal, so that ugly unsafe bit of code to implement send is no longer necessary since cpal did it themselves (a year ago) they also removed output stream handles and some other things which nobody really used anyway. next, the other file types is literally not even code, just adding a feature flag which enables the default rodio feature flags. i do feel a bit silly for thinking it'd be super difficult, so thanks rodio. lastly, the source flag is for a possible switch to the chillhop tracklist. anything embedded into lowfi should be generated with an open source script, hence if lowfi does switch to chillhop, it'll need to be selectable. --- Cargo.lock | 397 +++++++++++++++--------- Cargo.toml | 3 +- src/main.rs | 16 +- src/play.rs | 20 +- src/player.rs | 24 +- src/player/audio.rs | 9 +- src/scrapers.rs | 9 + src/{scrape.rs => scrapers/lofigirl.rs} | 0 src/tracks.rs | 11 +- src/tracks/list.rs | 2 +- 10 files changed, 291 insertions(+), 200 deletions(-) create mode 100644 src/scrapers.rs rename src/{scrape.rs => scrapers/lofigirl.rs} (100%) diff --git a/Cargo.lock b/Cargo.lock index 6cb6068..a51ea09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -308,24 +308,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "bindgen" -version = "0.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" -dependencies = [ - "bitflags 2.6.0", - "cexpr", - "clang-sys", - "itertools", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn", -] - [[package]] name = "bitflags" version = "1.3.2" @@ -390,8 +372,6 @@ version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7" dependencies = [ - "jobserver", - "libc", "shlex", ] @@ -401,15 +381,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - [[package]] name = "cfg-if" version = "1.0.0" @@ -422,17 +393,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - [[package]] name = "clap" version = "4.5.24" @@ -516,32 +476,25 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "coreaudio-rs" -version = "0.11.3" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace" +checksum = "1aae284fbaf7d27aa0e292f7677dfbe26503b0d555026f702940805a630eac17" dependencies = [ "bitflags 1.3.2", - "core-foundation-sys", - "coreaudio-sys", -] - -[[package]] -name = "coreaudio-sys" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ce857aa0b77d77287acc1ac3e37a05a8c95a2af3647d23b15f263bdaeb7562b" -dependencies = [ - "bindgen", + "libc", + "objc2-audio-toolbox", + "objc2-core-audio", + "objc2-core-audio-types", + "objc2-core-foundation", ] [[package]] name = "cpal" -version = "0.15.3" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779" +checksum = "cbd307f43cc2a697e2d1f8bc7a1d824b5269e052209e28883e5bc04d095aaa3f" dependencies = [ "alsa", - "core-foundation-sys", "coreaudio-rs", "dasp_sample", "jni", @@ -550,7 +503,11 @@ dependencies = [ "mach2", "ndk", "ndk-context", - "oboe", + "num-derive", + "num-traits", + "objc2-audio-toolbox", + "objc2-core-audio", + "objc2-core-audio-types", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -679,6 +636,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags 2.6.0", + "objc2", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -711,12 +678,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c6ba7d4eec39eaa9ab24d44a0e73a7949a1095a8b3f3abb11eddf27dbb56a53" -[[package]] -name = "either" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" - [[package]] name = "encoding_rs" version = "0.8.35" @@ -790,6 +751,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "extended" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af9673d8203fcb076b19dfd17e38b3d4ae9f44959416ea532ce72415a6020365" + [[package]] name = "eyre" version = "0.6.12" @@ -993,12 +960,6 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" -[[package]] -name = "glob" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" - [[package]] name = "h2" version = "0.4.7" @@ -1335,15 +1296,6 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.14" @@ -1372,15 +1324,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" -[[package]] -name = "jobserver" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" -dependencies = [ - "libc", -] - [[package]] name = "js-sys" version = "0.3.76" @@ -1403,16 +1346,6 @@ version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" -[[package]] -name = "libloading" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" -dependencies = [ - "cfg-if", - "windows-targets 0.52.6", -] - [[package]] name = "libredox" version = "0.1.3" @@ -1484,9 +1417,9 @@ checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" [[package]] name = "mach2" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" +checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" dependencies = [ "libc", ] @@ -1526,12 +1459,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "miniz_oxide" version = "0.8.2" @@ -1585,9 +1512,9 @@ dependencies = [ [[package]] name = "ndk" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ "bitflags 2.6.0", "jni-sys", @@ -1605,9 +1532,9 @@ checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" [[package]] name = "ndk-sys" -version = "0.5.0+25.2.9519653" +version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ "jni-sys", ] @@ -1632,13 +1559,13 @@ dependencies = [ ] [[package]] -name = "nom" -version = "7.1.3" +name = "num-bigint" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "memchr", - "minimal-lexical", + "num-integer", + "num-traits", ] [[package]] @@ -1652,6 +1579,26 @@ dependencies = [ "syn", ] +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -1663,18 +1610,19 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" dependencies = [ "num_enum_derive", + "rustversion", ] [[package]] name = "num_enum_derive" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1682,6 +1630,78 @@ dependencies = [ "syn", ] +[[package]] +name = "objc2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-audio-toolbox" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cbe18d879e20a4aea544f8befe38bcf52255eb63d3f23eca2842f3319e4c07" +dependencies = [ + "bitflags 2.6.0", + "libc", + "objc2", + "objc2-core-audio", + "objc2-core-audio-types", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-audio" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca44961e888e19313b808f23497073e3f6b3c22bb485056674c8b49f3b025c82" +dependencies = [ + "dispatch2", + "objc2", + "objc2-core-audio-types", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-core-audio-types" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f1cc99bb07ad2ddb6527ddf83db6a15271bb036b3eb94b801cd44fdc666ee1" +dependencies = [ + "bitflags 2.6.0", + "objc2", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +dependencies = [ + "bitflags 2.6.0", + "dispatch2", + "objc2", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" +dependencies = [ + "objc2", +] + [[package]] name = "object" version = "0.36.7" @@ -1691,29 +1711,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "oboe" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb" -dependencies = [ - "jni", - "ndk", - "ndk-context", - "num-derive", - "num-traits", - "oboe-sys", -] - -[[package]] -name = "oboe-sys" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bb09a4a2b1d668170cfe0a7d5bc103f8999fb316c98099b6a9939c9f2e79d" -dependencies = [ - "cc", -] - [[package]] name = "once_cell" version = "1.20.2" @@ -2112,11 +2109,13 @@ dependencies = [ [[package]] name = "rodio" -version = "0.20.1" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ceb6607dd738c99bc8cb28eff249b7cd5c8ec88b9db96c0608c1480d140fb1" +checksum = "e40ecf59e742e03336be6a3d53755e789fd05a059fa22dfa0ed624722319e183" dependencies = [ "cpal", + "dasp_sample", + "num-rational", "symphonia", ] @@ -2126,12 +2125,6 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustix" version = "0.38.42" @@ -2184,6 +2177,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustversion" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + [[package]] name = "ryu" version = "1.0.18" @@ -2483,9 +2482,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "815c942ae7ee74737bb00f965fa5b5a2ac2ce7b6c01c0cc169bbeaf7abd5f5a9" dependencies = [ "lazy_static", + "symphonia-bundle-flac", "symphonia-bundle-mp3", + "symphonia-codec-aac", + "symphonia-codec-pcm", + "symphonia-codec-vorbis", + "symphonia-core", + "symphonia-format-isomp4", + "symphonia-format-ogg", + "symphonia-format-riff", + "symphonia-metadata", +] + +[[package]] +name = "symphonia-bundle-flac" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72e34f34298a7308d4397a6c7fbf5b84c5d491231ce3dd379707ba673ab3bd97" +dependencies = [ + "log", "symphonia-core", "symphonia-metadata", + "symphonia-utils-xiph", ] [[package]] @@ -2500,6 +2518,38 @@ dependencies = [ "symphonia-metadata", ] +[[package]] +name = "symphonia-codec-aac" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdbf25b545ad0d3ee3e891ea643ad115aff4ca92f6aec472086b957a58522f70" +dependencies = [ + "lazy_static", + "log", + "symphonia-core", +] + +[[package]] +name = "symphonia-codec-pcm" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f395a67057c2ebc5e84d7bb1be71cce1a7ba99f64e0f0f0e303a03f79116f89b" +dependencies = [ + "log", + "symphonia-core", +] + +[[package]] +name = "symphonia-codec-vorbis" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a98765fb46a0a6732b007f7e2870c2129b6f78d87db7987e6533c8f164a9f30" +dependencies = [ + "log", + "symphonia-core", + "symphonia-utils-xiph", +] + [[package]] name = "symphonia-core" version = "0.5.4" @@ -2513,6 +2563,43 @@ dependencies = [ "log", ] +[[package]] +name = "symphonia-format-isomp4" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abfdf178d697e50ce1e5d9b982ba1b94c47218e03ec35022d9f0e071a16dc844" +dependencies = [ + "encoding_rs", + "log", + "symphonia-core", + "symphonia-metadata", + "symphonia-utils-xiph", +] + +[[package]] +name = "symphonia-format-ogg" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ada3505789516bcf00fc1157c67729eded428b455c27ca370e41f4d785bfa931" +dependencies = [ + "log", + "symphonia-core", + "symphonia-metadata", + "symphonia-utils-xiph", +] + +[[package]] +name = "symphonia-format-riff" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f7be232f962f937f4b7115cbe62c330929345434c834359425e043bfd15f50" +dependencies = [ + "extended", + "log", + "symphonia-core", + "symphonia-metadata", +] + [[package]] name = "symphonia-metadata" version = "0.5.4" @@ -2525,6 +2612,16 @@ dependencies = [ "symphonia-core", ] +[[package]] +name = "symphonia-utils-xiph" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "484472580fa49991afda5f6550ece662237b00c6f562c7d9638d1b086ed010fe" +dependencies = [ + "symphonia-core", + "symphonia-metadata", +] + [[package]] name = "syn" version = "2.0.95" @@ -3016,7 +3113,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index a474669..9a66386 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ repository = "https://github.com/talwat/lowfi" [features] mpris = ["dep:mpris-server"] +extra-audio-formats = ["rodio/default"] [dependencies] # Basics @@ -40,7 +41,7 @@ bytes = "1.9.0" # I/O crossterm = { version = "0.28.1", features = ["event-stream"] } -rodio = { version = "0.20.1", features = ["symphonia-mp3"], default-features = false } +rodio = { version = "0.21.1", features = ["symphonia-mp3", "playback"], default-features = false } mpris-server = { version = "0.8.1", optional = true } dirs = "5.0.1" diff --git a/src/main.rs b/src/main.rs index 1babc8a..e1fb2d4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,15 +13,12 @@ mod player; mod tracks; #[allow(clippy::all, clippy::pedantic, clippy::nursery, clippy::restriction)] -mod scrape; +mod scrapers; /// An extremely simple lofi player. #[derive(Parser, Clone)] #[command(about, version)] -#[allow( - clippy::struct_excessive_bools, - reason = "seƱor clippy, i assure you this is not a state machine" -)] +#[allow(clippy::struct_excessive_bools)] struct Args { /// Use an alternate terminal screen. #[clap(long, short)] @@ -68,8 +65,11 @@ struct Args { /// Defines all of the extra commands lowfi can run. #[derive(Subcommand, Clone)] enum Commands { - /// Scrapes the lofi girl website file server for files. + /// Scrapes a music source for files. Scrape { + // The source to scrape from. + source: scrapers::Sources, + /// The file extension to search for, defaults to mp3. #[clap(long, short, default_value = "mp3")] extension: String, @@ -98,10 +98,12 @@ async fn main() -> eyre::Result<()> { if let Some(command) = cli.command { match command { + // TODO: Actually distinguish between sources. Commands::Scrape { + source, extension, include_full, - } => scrape::scrape(extension, include_full).await, + } => scrapers::lofigirl::scrape(extension, include_full).await, } } else { play::play(cli).await diff --git a/src/play.rs b/src/play.rs index fc2c31e..98b4903 100644 --- a/src/play.rs +++ b/src/play.rs @@ -67,11 +67,11 @@ impl PersistentVolume { let config = Self::config().await?; let path = config.join(PathBuf::from("volume.txt")); + // Already rounded & absolute, therefore this should be safe. #[expect( clippy::as_conversions, clippy::cast_sign_loss, - clippy::cast_possible_truncation, - reason = "already rounded & absolute, therefore this should be safe" + clippy::cast_possible_truncation )] let percentage = (volume * 100.0).abs().round() as u16; @@ -81,20 +81,6 @@ impl PersistentVolume { } } -/// Wrapper around [`rodio::OutputStream`] to implement [Send], currently unsafely. -/// -/// This is more of a temporary solution until cpal implements [Send] on it's output stream. -pub struct SendableOutputStream(pub rodio::OutputStream); - -// SAFETY: This is necessary because [OutputStream] does not implement [Send], -// due to some limitation with Android's Audio API. -// I'm pretty sure nobody will use lowfi with android, so this is safe. -#[expect( - clippy::non_send_fields_in_send_ty, - reason = "this is expected because of the nature of the struct" -)] -unsafe impl Send for SendableOutputStream {} - /// Initializes the audio server, and then safely stops /// it when the frontend quits. pub async fn play(args: Args) -> eyre::Result<()> { @@ -123,7 +109,7 @@ pub async fn play(args: Args) -> eyre::Result<()> { // Save the volume.txt file for the next session. PersistentVolume::save(player.sink.volume()).await?; - drop(stream.0); + drop(stream); player.sink.stop(); ui.and_then(|x| Some(x.abort())); diff --git a/src/player.rs b/src/player.rs index eb6549d..1fabd1e 100644 --- a/src/player.rs +++ b/src/player.rs @@ -14,7 +14,7 @@ use std::{ use arc_swap::ArcSwapOption; use downloader::Downloader; use reqwest::Client; -use rodio::{OutputStream, OutputStreamHandle, Sink}; +use rodio::{OutputStream, OutputStreamBuilder, Sink}; use tokio::{ select, sync::{ @@ -29,7 +29,7 @@ use mpris_server::{PlaybackStatus, PlayerInterface, Property}; use crate::{ messages::Messages, - play::{PersistentVolume, SendableOutputStream}, + play::PersistentVolume, tracks::{self, list::List}, Args, }; @@ -82,11 +82,6 @@ pub struct Player { /// The web client, which can contain a `UserAgent` & some /// settings that help lowfi work more effectively. client: Client, - - /// The [`OutputStreamHandle`], which also can control some - /// playback, is for now unused and is here just to keep it - /// alive so the playback can function properly. - _handle: OutputStreamHandle, } impl Player { @@ -108,7 +103,7 @@ impl Player { /// Initializes the entire player, including audio devices & sink. /// /// This also will load the track list & persistent volume. - pub async fn new(args: &Args) -> eyre::Result<(Self, SendableOutputStream)> { + pub async fn new(args: &Args) -> eyre::Result<(Self, OutputStream)> { // Load the volume file. let volume = PersistentVolume::load().await?; @@ -117,17 +112,15 @@ impl Player { // We should only shut up alsa forcefully on Linux if we really have to. #[cfg(target_os = "linux")] - let (stream, handle) = if !args.alternate && !args.debug { + let mut stream = if !args.alternate && !args.debug { audio::silent_get_output_stream()? } else { - OutputStream::try_default()? + OutputStreamBuilder::open_default_stream()? }; - // If we're not on Linux, then there's no problem. - #[cfg(not(target_os = "linux"))] - let (stream, handle) = OutputStream::try_default()?; + stream.log_on_drop(false); // Frankly, this is a stupid feature. Stop shoving your crap into my beloved stderr!!! + let sink = Sink::connect_new(stream.mixer()); - let sink = Sink::try_new(&handle)?; if args.paused { sink.pause(); } @@ -149,11 +142,10 @@ impl Player { sink, volume, list, - _handle: handle, bookmarked: AtomicBool::new(false), }; - Ok((player, SendableOutputStream(stream))) + Ok((player, stream)) } /// This is the main "audio server". diff --git a/src/player/audio.rs b/src/player/audio.rs index 5942b6c..81d62a4 100644 --- a/src/player/audio.rs +++ b/src/player/audio.rs @@ -1,11 +1,12 @@ #[cfg(target_os = "linux")] -use rodio::{OutputStream, OutputStreamHandle}; +use rodio::OutputStream; /// This gets the output stream while also shutting up alsa with [libc]. /// Uses raw libc calls, and therefore is functional only on Linux. #[cfg(target_os = "linux")] -pub fn silent_get_output_stream() -> eyre::Result<(OutputStream, OutputStreamHandle)> { +pub fn silent_get_output_stream() -> eyre::Result { use libc::freopen; + use rodio::OutputStreamBuilder; use std::ffi::CString; // Get the file descriptor to stderr from libc. @@ -28,7 +29,7 @@ pub fn silent_get_output_stream() -> eyre::Result<(OutputStream, OutputStreamHan } // Make the OutputStream while stderr is still redirected to /dev/null. - let (stream, handle) = OutputStream::try_default()?; + let stream = OutputStreamBuilder::open_default_stream()?; // Redirect back to the current terminal, so that other output isn't silenced. let tty = CString::new("/dev/tty")?; @@ -38,5 +39,5 @@ pub fn silent_get_output_stream() -> eyre::Result<(OutputStream, OutputStreamHan freopen(tty.as_ptr(), mode.as_ptr(), stderr); } - Ok((stream, handle)) + Ok(stream) } diff --git a/src/scrapers.rs b/src/scrapers.rs new file mode 100644 index 0000000..1729657 --- /dev/null +++ b/src/scrapers.rs @@ -0,0 +1,9 @@ +use clap::ValueEnum; + +pub mod lofigirl; + +#[derive(Clone, Copy, PartialEq, Eq, Debug, ValueEnum)] +pub enum Sources { + Lofigirl, + Chillhop, +} diff --git a/src/scrape.rs b/src/scrapers/lofigirl.rs similarity index 100% rename from src/scrape.rs rename to src/scrapers/lofigirl.rs diff --git a/src/tracks.rs b/src/tracks.rs index e0ffb0c..cca38b1 100644 --- a/src/tracks.rs +++ b/src/tracks.rs @@ -15,7 +15,7 @@ //! 2. [`Info`] created from decoded data. //! 3. [`Decoded`] made from [`Info`] and the original decoded data. -use std::{io::Cursor, time::Duration}; +use std::{io::Cursor, path::Path, time::Duration}; use bytes::Bytes; use inflector::Inflector as _; @@ -137,10 +137,13 @@ impl Info { /// This will also strip the first few numbers that are /// usually present on most lofi tracks. fn format_name(name: &str) -> eyre::Result { - let split = name.split('/').last().ok_or(TrackError::InvalidName)?; + let path = Path::new(name); - let stripped = split.strip_suffix(".mp3").unwrap_or(split); - let formatted = Self::decode_url(stripped) + let stem = path + .file_stem() + .and_then(|x| x.to_str()) + .ok_or(TrackError::InvalidName)?; + let formatted = Self::decode_url(stem) .to_lowercase() .to_title_case() // Inflector doesn't like contractions... diff --git a/src/tracks/list.rs b/src/tracks/list.rs index b41af93..8de291f 100644 --- a/src/tracks/list.rs +++ b/src/tracks/list.rs @@ -1,5 +1,5 @@ //! The module containing all of the logic behind track lists, -//! as well as obtaining track names & downloading the raw mp3 data. +//! as well as obtaining track names & downloading the raw audio data use bytes::Bytes; use eyre::OptionExt as _;