From 6cceb3cbfacb6f4416e49321a9b63b4ce7a9f036 Mon Sep 17 00:00:00 2001 From: salmonik Date: Mon, 18 May 2026 21:46:26 +0200 Subject: fix for new symphony API and less debug info in release --- Cargo.lock | 311 +++++++++++++++++++------------------------------------ Cargo.toml | 3 +- README.md | 66 ++++++------ src/audio.rs | 97 +++++++++-------- src/daemon.rs | 39 ++++--- src/lib.rs | 7 ++ src/main.rs | 1 + src/queue.rs | 64 ++++++------ src/scrobbler.rs | 72 ++++++++----- 9 files changed, 306 insertions(+), 354 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6d359ef..f2593f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,7 +9,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812947049edcd670a82cd5c73c3661d2e58468577ba8489de58e1a73c04cbd5d" dependencies = [ "alsa-sys", - "bitflags 2.11.1", + "bitflags", "cfg-if", "libc", ] @@ -89,12 +89,6 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - [[package]] name = "async-broadcast" version = "0.7.2" @@ -266,12 +260,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.11.1" @@ -502,7 +490,7 @@ version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d5d7dca3ebcf65a035582c9ad4385371a9d9ee6537474d2a278f4e1e475bb58" dependencies = [ - "bitflags 2.11.1", + "bitflags", "libc", "objc2-audio-toolbox", "objc2-core-audio", @@ -637,7 +625,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.11.1", + "bitflags", "block2", "libc", "objc2", @@ -1387,15 +1375,6 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - [[package]] name = "log" version = "0.4.29" @@ -1477,7 +1456,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.11.1", + "bitflags", "jni-sys 0.3.1", "log", "ndk-sys", @@ -1506,7 +1485,7 @@ version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3" dependencies = [ - "bitflags 2.11.1", + "bitflags", "cfg-if", "cfg_aliases", "libc", @@ -1526,6 +1505,15 @@ dependencies = [ "zbus", ] +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + [[package]] name = "num-conv" version = "0.2.1" @@ -1543,6 +1531,15 @@ 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-traits" version = "0.2.19" @@ -1589,7 +1586,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6948501a91121d6399b79abaa33a8aa4ea7857fe019f341b8c23ad6e81b79b08" dependencies = [ - "bitflags 2.11.1", + "bitflags", "libc", "objc2", "objc2-core-audio", @@ -1627,7 +1624,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a89f2ec274a0cf4a32642b2991e8b351a404d290da87bb6a9a9d8632490bd1c" dependencies = [ - "bitflags 2.11.1", + "bitflags", "objc2", ] @@ -1637,7 +1634,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.11.1", + "bitflags", "block2", "dispatch2", "libc", @@ -1656,7 +1653,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.11.1", + "bitflags", "block2", "libc", "objc2", @@ -1703,29 +1700,6 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link 0.2.1", -] - [[package]] name = "percent-encoding" version = "2.3.2" @@ -1803,6 +1777,15 @@ dependencies = [ "syn", ] +[[package]] +name = "primal-check" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc0d895b311e3af9902528fbb8f928688abbd95872819320517cc24ca6b2bd08" +dependencies = [ + "num-integer", +] + [[package]] name = "proc-macro-crate" version = "3.5.0" @@ -1953,15 +1936,6 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags 2.11.1", -] - [[package]] name = "redox_users" version = "0.5.2" @@ -1973,6 +1947,12 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "regex-lite" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973" + [[package]] name = "reqwest" version = "0.13.3" @@ -2053,7 +2033,6 @@ dependencies = [ "symphonia", "tempfile", "terminal_size", - "tokio", "toml", ] @@ -2073,7 +2052,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0d2b0146dd9661bf67bb107c0bb2a55064d556eeb3fc314151b957f313bcd4e" dependencies = [ - "bitflags 2.11.1", + "bitflags", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -2097,13 +2076,27 @@ dependencies = [ "semver", ] +[[package]] +name = "rustfft" +version = "6.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21db5f9893e91f41798c88680037dba611ca6674703c1a18601b01a72c8adb89" +dependencies = [ + "num-complex", + "num-integer", + "num-traits", + "primal-check", + "strength_reduce", + "transpose", +] + [[package]] name = "rustix" version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.11.1", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -2215,19 +2208,13 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "security-framework" version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.11.1", + "bitflags", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -2397,6 +2384,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "strength_reduce" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" + [[package]] name = "strsim" version = "0.11.1" @@ -2411,22 +2404,15 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "symphonia" -version = "0.5.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5773a4c030a19d9bfaa090f49746ff35c75dfddfa700df7a5939d5e076a57039" +checksum = "1758d6c853020a7244de03cc3e0185eaea3f58715122422dd3cc7452e6d4c16a" dependencies = [ "lazy_static", "symphonia-bundle-flac", "symphonia-bundle-mp3", - "symphonia-codec-aac", - "symphonia-codec-adpcm", - "symphonia-codec-alac", - "symphonia-codec-pcm", "symphonia-codec-vorbis", "symphonia-core", - "symphonia-format-caf", - "symphonia-format-isomp4", - "symphonia-format-mkv", "symphonia-format-ogg", "symphonia-format-riff", "symphonia-metadata", @@ -2434,147 +2420,81 @@ dependencies = [ [[package]] name = "symphonia-bundle-flac" -version = "0.5.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91565e180aea25d9b80a910c546802526ffd0072d0b8974e3ebe59b686c9976" +checksum = "ee69ad01236a67260b82fd1ff9790dd75ead29f2f46af145e63b7e72273e0e03" dependencies = [ "log", + "symphonia-common", "symphonia-core", "symphonia-metadata", - "symphonia-utils-xiph", ] [[package]] name = "symphonia-bundle-mp3" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4872dd6bb56bf5eac799e3e957aa1981086c3e613b27e0ac23b176054f7c57ed" -dependencies = [ - "lazy_static", - "log", - "symphonia-core", - "symphonia-metadata", -] - -[[package]] -name = "symphonia-codec-aac" -version = "0.5.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c263845aa86881416849c1729a54c7f55164f8b96111dba59de46849e73a790" +checksum = "350f1f2f2e19ad4dd315db94304d1eb361b29af070681f94e51b8fdaad769546" dependencies = [ "lazy_static", "log", "symphonia-core", ] -[[package]] -name = "symphonia-codec-adpcm" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dddc50e2bbea4cfe027441eece77c46b9f319748605ab8f3443350129ddd07f" -dependencies = [ - "log", - "symphonia-core", -] - -[[package]] -name = "symphonia-codec-alac" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8413fa754942ac16a73634c9dfd1500ed5c61430956b33728567f667fdd393ab" -dependencies = [ - "log", - "symphonia-core", -] - -[[package]] -name = "symphonia-codec-pcm" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e89d716c01541ad3ebe7c91ce4c8d38a7cf266a3f7b2f090b108fb0cb031d95" -dependencies = [ - "log", - "symphonia-core", -] - [[package]] name = "symphonia-codec-vorbis" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f025837c309cd69ffef572750b4a2257b59552c5399a5e49707cc5b1b85d1c73" -dependencies = [ - "log", - "symphonia-core", - "symphonia-utils-xiph", -] - -[[package]] -name = "symphonia-core" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea00cc4f79b7f6bb7ff87eddc065a1066f3a43fe1875979056672c9ef948c2af" -dependencies = [ - "arrayvec", - "bitflags 1.3.2", - "bytemuck", - "lazy_static", - "log", -] - -[[package]] -name = "symphonia-format-caf" -version = "0.5.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8faf379316b6b6e6bbc274d00e7a592e0d63ff1a7e182ce8ba25e24edd3d096" +checksum = "45b07b4423cd8e0fc472575909a5554b12c2f58e3c190b38c24f042e732fd8de" dependencies = [ "log", + "symphonia-common", "symphonia-core", - "symphonia-metadata", ] [[package]] -name = "symphonia-format-isomp4" -version = "0.5.5" +name = "symphonia-common" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243739585d11f81daf8dac8d9f3d18cc7898f6c09a259675fc364b382c30e0a5" +checksum = "8257891ffa7f05e02b58f4761e2abf7e5278c8744fd59e981559e050f86eef55" dependencies = [ - "encoding_rs", "log", "symphonia-core", "symphonia-metadata", - "symphonia-utils-xiph", ] [[package]] -name = "symphonia-format-mkv" -version = "0.5.5" +name = "symphonia-core" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "122d786d2c43a49beb6f397551b4a050d8229eaa54c7ddf9ee4b98899b8742d0" +checksum = "95ec293b5f288383b72a7bffcade6b2860b642cf66f28b3bd5967349a49938b1" dependencies = [ + "bitflags", + "bytemuck", "lazy_static", "log", - "symphonia-core", - "symphonia-metadata", - "symphonia-utils-xiph", + "num-complex", + "rustfft", + "smallvec", ] [[package]] name = "symphonia-format-ogg" -version = "0.5.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b4955c67c1ed3aa8ae8428d04ca8397fbef6a19b2b051e73b5da8b1435639cb" +checksum = "b05a67e02b1e4fca1a261ba4fe06910a9357489ad8c36aafdd2960e9c6559433" dependencies = [ "log", + "symphonia-common", "symphonia-core", "symphonia-metadata", - "symphonia-utils-xiph", ] [[package]] name = "symphonia-format-riff" -version = "0.5.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2d7c3df0e7d94efb68401d81906eae73c02b40d5ec1a141962c592d0f11a96f" +checksum = "17424452a777666d3eaf09a5c651029b15b6a333812fcc5b5474f2a3f0cff3f0" dependencies = [ "extended", "log", @@ -2584,26 +2504,17 @@ dependencies = [ [[package]] name = "symphonia-metadata" -version = "0.5.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36306ff42b9ffe6e5afc99d49e121e0bd62fe79b9db7b9681d48e29fa19e6b16" +checksum = "a31acf5cd623398a6208e2225d18f4b20f761c55098a796a5247ad516a4a8681" dependencies = [ - "encoding_rs", "lazy_static", "log", + "regex-lite", + "smallvec", "symphonia-core", ] -[[package]] -name = "symphonia-utils-xiph" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27c85ab799a338446b68eec77abf42e1a6f1bb490656e121c6e27bfbab9f16" -dependencies = [ - "symphonia-core", - "symphonia-metadata", -] - [[package]] name = "syn" version = "2.0.117" @@ -2641,7 +2552,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ - "bitflags 2.11.1", + "bitflags", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -2784,25 +2695,11 @@ dependencies = [ "bytes", "libc", "mio", - "parking_lot", "pin-project-lite", - "signal-hook-registry", "socket2", - "tokio-macros", "windows-sys 0.61.2", ] -[[package]] -name = "tokio-macros" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "tokio-rustls" version = "0.26.4" @@ -2898,7 +2795,7 @@ version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a28f0d049ccfaa566e14e9663d304d8577427b368cb4710a20528690287a738b" dependencies = [ - "bitflags 2.11.1", + "bitflags", "bytes", "futures-util", "http", @@ -2953,6 +2850,16 @@ dependencies = [ "once_cell", ] +[[package]] +name = "transpose" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad61aed86bc3faea4300c7aee358b4c6d0c8d6ccc36524c96e4c92ccf26e77e" +dependencies = [ + "num-integer", + "strength_reduce", +] + [[package]] name = "try-lock" version = "0.2.5" @@ -3161,7 +3068,7 @@ version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.11.1", + "bitflags", "hashbrown 0.15.5", "indexmap", "semver", @@ -3719,7 +3626,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.11.1", + "bitflags", "indexmap", "log", "serde", diff --git a/Cargo.toml b/Cargo.toml index 0393d3b..86a9b54 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,9 +22,8 @@ rusqlite = { version = "0.39", features = ["bundled"] } directories = "6.0" serde = { version = "1.0.228", features = ["derive"] } toml = "1.1.2" -tokio = { version = "1.52.2", features = ["full"] } reqwest = { version = "0.13.3", features = ["json", "form", "blocking"] } -symphonia = { version = "0.5.5", features = ["all"] } +symphonia = { version = "0.6", default-features = false, features = ["mp3", "flac", "vorbis", "wav", "ogg", "opt-simd"] } cpal = "0.17.3" chrono = "0.4.44" serde_json = "1.0.149" diff --git a/README.md b/README.md index 2092f2a..7826c41 100644 --- a/README.md +++ b/README.md @@ -7,47 +7,47 @@ cd RSPlayer ./install.sh ``` -install.sh will: -compile RSP (make sure you have rust properly installed!) -install shell autocompletions (zsh, bash and fish supported) -install user systemd service and activate it +install.sh will: +- compile RSP (make sure you have rust properly installed!) +- install shell autocompletions (zsh, bash and fish supported) +- install user systemd service and activate it ## Usage configuration is generated at startup in $XDG_CONFIG_HOME/rsplayer/config.toml -most important values there are: -listenbrainz_token (last.fm scrobbling not yet tested) -display_format (supports $ARTIST $ALBUM and $TRACK) -music_paths (for DB usage, still WIP) -scan_interval (same as above) +- most important values there are: +- listenbrainz_token (last.fm scrobbling not yet tested) +- display_format (supports $ARTIST $ALBUM and $TRACK) +- music_paths (for DB usage, still WIP) +- scan_interval (same as above) all other values can be changed in runtime using commands -as for commands: -RSP will be installed as rsp, in this fragment, rsp will be ommited - -these commands should only be used in testing or by systemd service: -`start-daemon` Start the daemon -`stop-daemon` Stop the daemon -`restart` Restart the daemon (kill existing and start new) - -these are normal commands: -`play` Play a track, album, or artist -`pause` Pause playback -`resume` Resume playback -`toggle` Toggle play/pause -`stop` Stop playback -`next` Skip to next track -`previous` Skip to previous track -`volume` Set volume (0-100) -`shuffle` Shuffle mode -`queue` Queue management -`status` Show player status -`scan` Scan music paths to populate database -`settings` Settings management -`help` Print this message or the help of the given subcommand(s) +as for commands: +RSP will be installed as rsp, in this fragment, rsp will be ommited + +these commands should only be used in testing or by systemd service: +- `start-daemon` Start the daemon +- `stop-daemon` Stop the daemon +- `restart` Restart the daemon (kill existing and start new) + +these are normal commands: +- `play` Play a track, album, or artist +- `pause` Pause playback +- `resume` Resume playback +- `toggle` Toggle play/pause +- `stop` Stop playback +- `next` Skip to next track +- `previous` Skip to previous track +- `volume` Set volume (0-100) +- `shuffle` Shuffle mode +- `queue` Queue management +- `status` Show player status +- `scan` Scan music paths to populate database +- `settings` Settings management +- `help` Print this message or the help of the given subcommand(s) ## Technical stuff -The main culprit of this player is lack of integration with programs such as playerctl +The main culprit of this player is lack of integration with programs such as playerctl this is due to the daemon not being asynchronous diff --git a/src/audio.rs b/src/audio.rs index 62afd93..62d13ff 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -101,7 +101,7 @@ impl AudioEngine { struct AudioData { format: Box, - decoder: Box, + decoder: Box, sample_rate: u32, channels: u16, sample_buffer: Vec, @@ -165,10 +165,10 @@ fn audio_thread( let device_sample_rate = config.sample_rate(); let channels = config.channels(); - eprintln!( + crate::debug_eprintln(format_args!( "Default output: {} Hz, {} channels", device_sample_rate, channels - ); + )); let mut current_stream: Option = None; let audio_data: Arc>> = Arc::new(Mutex::new(None)); @@ -186,13 +186,16 @@ fn audio_thread( match open_audio_file(&path) { Ok(mut data) => { - eprintln!("File: {} Hz, {} channels", data.sample_rate, data.channels); + crate::debug_eprintln(format_args!( + "File: {} Hz, {} channels", + data.sample_rate, data.channels + )); if data.sample_rate != device_sample_rate { - eprintln!( + crate::debug_eprintln(format_args!( "Resampling from {} Hz to {} Hz", data.sample_rate, device_sample_rate - ); + )); data.resample_ratio = Some(device_sample_rate as f64 / data.sample_rate as f64); } @@ -201,28 +204,23 @@ fn audio_thread( let channels = data.channels as usize; for _ in 0..100 { match data.format.next_packet() { - Ok(packet) => match data.decoder.decode(&packet) { + Ok(Some(packet)) => match data.decoder.decode(&packet) { Ok(decoded) => { - let spec = *decoded.spec(); - let mut sample_buf = symphonia::core::audio::SampleBuffer::< - f32, - >::new( - decoded.capacity() as u64, spec - ); - sample_buf.copy_interleaved_ref(decoded); - let samples = sample_buf.samples(); + let num_samples = decoded.samples_interleaved(); + let mut samples = vec![0.0f32; num_samples]; + decoded.copy_to_slice_interleaved(&mut samples); let resampled = if let Some(ratio) = data.resample_ratio { - resample_linear(samples, ratio, channels) + resample_linear(&samples, ratio, channels) } else { - samples.to_vec() + samples }; data.sample_buffer.extend(resampled); } Err(_) => break, }, - Err(_) => break, + _ => break, } } data.buffer_pos = 0; @@ -274,29 +272,26 @@ fn audio_thread( // Decode more data match state.format.next_packet() { - Ok(packet) => { + Ok(Some(packet)) => { match state.decoder.decode(&packet) { Ok(decoded) => { - let spec = *decoded.spec(); - let mut sample_buf = - symphonia::core::audio::SampleBuffer::< - f32, - >::new( - decoded.capacity() as u64, spec - ); - sample_buf - .copy_interleaved_ref(decoded); - let samples = sample_buf.samples(); + let num_samples = + decoded.samples_interleaved(); + let mut samples = + vec![0.0f32; num_samples]; + decoded.copy_to_slice_interleaved( + &mut samples, + ); // Resample if needed let resampled = if let Some(ratio) = state.resample_ratio { resample_linear( - samples, ratio, channels, + &samples, ratio, channels, ) } else { - samples.to_vec() + samples }; // Copy what we can to output @@ -323,7 +318,7 @@ fn audio_thread( Err(_) => break, } } - Err(_) => break, + _ => break, } } @@ -419,36 +414,50 @@ fn audio_thread( } fn open_audio_file(path: &PathBuf) -> Result> { - use symphonia::core::audio::Channels; + use symphonia::core::audio::layouts::CHANNEL_LAYOUT_STEREO; + use symphonia::core::codecs::audio::AudioDecoderOptions; + use symphonia::core::formats::probe::Hint; use symphonia::core::io::MediaSourceStream; let file = std::fs::File::open(path)?; let mss = MediaSourceStream::new(Box::new(file), Default::default()); - let hint = symphonia::core::probe::Hint::new(); - let probed = symphonia::default::get_probe().format( + let hint = Hint::new(); + let format = symphonia::default::get_probe().probe( &hint, mss, - &Default::default(), - &Default::default(), + Default::default(), + Default::default(), )?; - let format = probed.format; let track = format .tracks() .iter() - .find(|t| t.codec_params.sample_rate.is_some()) + .find(|t| { + t.codec_params + .as_ref() + .and_then(|p| p.audio()) + .and_then(|a| a.sample_rate) + .is_some() + }) .ok_or("No suitable track found")?; - let sample_rate = track.codec_params.sample_rate.unwrap_or(44100); - let channels = track + let codec_params = track .codec_params + .as_ref() + .ok_or("No codec parameters")? + .audio() + .ok_or("Not an audio track")?; + + let sample_rate = codec_params.sample_rate.unwrap_or(44100); + let channels = codec_params .channels - .unwrap_or(Channels::FRONT_LEFT | Channels::FRONT_RIGHT) + .clone() + .unwrap_or(CHANNEL_LAYOUT_STEREO) .count() as u16; - let decoder = - symphonia::default::get_codecs().make(&track.codec_params, &Default::default())?; + let decoder = symphonia::default::get_codecs() + .make_audio_decoder(codec_params, &AudioDecoderOptions::default())?; Ok(AudioData { format, diff --git a/src/daemon.rs b/src/daemon.rs index 59fc3d8..8b74357 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -33,10 +33,10 @@ impl ScrobbleState { .as_secs(); let title = track.title.clone().unwrap_or_default(); let artist = track.artist.clone().unwrap_or_default(); - eprintln!( + crate::debug_eprintln(format_args!( "scrobble: tracking start for '{} - {}' (ts={})", artist, title, ts - ); + )); self.track = Some(track); self.start_time = Some(Instant::now()); self.timestamp = Some(ts); @@ -44,7 +44,9 @@ impl ScrobbleState { fn should_scrobble(&self) -> bool { let (Some(track), Some(start)) = (&self.track, self.start_time) else { - eprintln!("scrobble: should_scrobble false — no track or start_time"); + crate::debug_eprintln(format_args!( + "scrobble: should_scrobble false — no track or start_time" + )); return false; }; let elapsed = start.elapsed().as_secs(); @@ -54,10 +56,10 @@ impl ScrobbleState { .map(|d| (d / 2.0) as u64) .unwrap_or(u64::MAX) .min(240); - eprintln!( + crate::debug_eprintln(format_args!( "scrobble: should_scrobble {} (elapsed={}s threshold={}s duration={:?})", result, elapsed, threshold, track.duration_secs - ); + )); result } @@ -158,10 +160,10 @@ fn try_scrobble_current(scrobbler: &RwLock, state: &mut ScrobbleState let artist = track.artist.as_deref().unwrap_or("(unknown artist)"); let title = track.title.as_deref().unwrap_or("(unknown title)"); let album = track.album.as_deref(); - eprintln!( + crate::debug_eprintln(format_args!( "scrobble: sending scrobble for '{} - {}' at ts={}", artist, title, ts - ); + )); if let Ok(s) = scrobbler.read() { s.scrobble(artist, title, album, ts); } @@ -171,10 +173,10 @@ fn try_scrobble_current(scrobbler: &RwLock, state: &mut ScrobbleState .as_ref() .and_then(|t| t.title.as_deref()) .unwrap_or("(no track)"); - eprintln!( + crate::debug_eprintln(format_args!( "scrobble: skipping scrobble for '{}' — not enough play time", title - ); + )); } state.clear(); } @@ -183,7 +185,10 @@ fn send_now_playing(scrobbler: &RwLock, track: &Track) { let artist = track.artist.as_deref().unwrap_or("(unknown artist)"); let title = track.title.as_deref().unwrap_or("(unknown title)"); let album = track.album.as_deref(); - eprintln!("scrobble: sending now_playing for '{} - {}'", artist, title); + crate::debug_eprintln(format_args!( + "scrobble: sending now_playing for '{} - {}'", + artist, title + )); if let Ok(s) = scrobbler.read() { s.now_playing(artist, title, album); } @@ -260,9 +265,17 @@ pub fn start_daemon() -> Result<(), Box> { && let Ok(s) = scrobbler.read() { match s.validate_listenbrainz_token() { - Ok(Some(user)) => eprintln!("scrobble: listenbrainz token valid (user: {})", user), - Ok(None) => eprintln!("scrobble: listenbrainz token invalid, scrobbling disabled"), - Err(e) => eprintln!("scrobble: listenbrainz validation error: {}", e), + Ok(Some(user)) => crate::debug_eprintln(format_args!( + "scrobble: listenbrainz token valid (user: {})", + user + )), + Ok(None) => crate::debug_eprintln(format_args!( + "scrobble: listenbrainz token invalid, scrobbling disabled" + )), + Err(e) => crate::debug_eprintln(format_args!( + "scrobble: listenbrainz validation error: {}", + e + )), } } let scrobble_state = Arc::new(Mutex::new(ScrobbleState::new())); diff --git a/src/lib.rs b/src/lib.rs index 825872f..4cdbb9b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,10 @@ +#[inline(always)] +pub fn debug_eprintln(args: core::fmt::Arguments<'_>) { + if cfg!(debug_assertions) { + eprintln!("{}", args); + } +} + pub mod audio; pub mod cli; pub mod config; diff --git a/src/main.rs b/src/main.rs index c1e42d0..fe450dd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,7 @@ mod scrobbler; use clap::Parser; use cli::Cli; +pub use rsp::debug_eprintln; fn main() { let cli = Cli::parse(); diff --git a/src/queue.rs b/src/queue.rs index 26aeb8b..b0acf5f 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -17,28 +17,27 @@ pub struct AudioMetadata { } pub fn extract_metadata(path: &Path) -> Option { + use symphonia::core::formats::probe::Hint; use symphonia::core::io::MediaSourceStream; - use symphonia::core::meta::StandardTagKey; - use symphonia::core::probe::Hint; + use symphonia::core::meta::StandardTag; let file = std::fs::File::open(path).ok()?; let mss = MediaSourceStream::new(Box::new(file), Default::default()); let hint = Hint::new(); let mut probed = symphonia::default::get_probe() - .format(&hint, mss, &Default::default(), &Default::default()) + .probe(&hint, mss, Default::default(), Default::default()) .ok()?; - // Extract duration from format track's codec parameters + // Extract duration from track's num_frames and time_base let duration_secs = probed - .format .tracks() .iter() - .find(|t| t.codec_params.n_frames.is_some() && t.codec_params.time_base.is_some()) + .find(|t| t.num_frames.is_some() && t.time_base.is_some()) .and_then(|t| { - let n_frames = t.codec_params.n_frames?; - let tb = t.codec_params.time_base?; - Some(n_frames as f64 * tb.numer as f64 / tb.denom as f64) + let n_frames = t.num_frames?; + let tb = t.time_base?; + Some(n_frames as f64 * tb.numer.get() as f64 / tb.denom.get() as f64) }); let mut metadata = AudioMetadata { @@ -46,38 +45,39 @@ pub fn extract_metadata(path: &Path) -> Option { ..Default::default() }; - if let Some(meta) = probed.metadata.get() - && let Some(rev) = meta.current() { - for tag in rev.tags() { - match tag.std_key { - Some(StandardTagKey::TrackTitle) => { - metadata.title = Some(tag.value.to_string()); - } - Some(StandardTagKey::Artist) => { - metadata.artist = Some(tag.value.to_string()); - } - Some(StandardTagKey::Album) => { - metadata.album = Some(tag.value.to_string()); + let meta = probed.metadata(); + if let Some(rev) = meta.current() { + for tag in &rev.media.tags { + match &tag.std { + Some(StandardTag::TrackTitle(value)) => { + metadata.title = Some(value.to_string()); + } + Some(StandardTag::Artist(value)) => { + metadata.artist = Some(value.to_string()); + } + Some(StandardTag::Album(value)) => { + metadata.album = Some(value.to_string()); + } + _ => {} } - _ => {} } } } if metadata.title.is_none() && metadata.artist.is_none() && metadata.album.is_none() { - let mut format = probed.format; - if let Some(rev) = format.metadata().current() { - for tag in rev.tags() { - match tag.std_key { - Some(StandardTagKey::TrackTitle) => { - metadata.title = Some(tag.value.to_string()); + let meta = probed.metadata(); + if let Some(rev) = meta.current() { + for tag in &rev.media.tags { + match &tag.std { + Some(StandardTag::TrackTitle(value)) => { + metadata.title = Some(value.to_string()); } - Some(StandardTagKey::Artist) => { - metadata.artist = Some(tag.value.to_string()); + Some(StandardTag::Artist(value)) => { + metadata.artist = Some(value.to_string()); } - Some(StandardTagKey::Album) => { - metadata.album = Some(tag.value.to_string()); + Some(StandardTag::Album(value)) => { + metadata.album = Some(value.to_string()); } _ => {} } diff --git a/src/scrobbler.rs b/src/scrobbler.rs index 2e79933..93cb3c2 100644 --- a/src/scrobbler.rs +++ b/src/scrobbler.rs @@ -47,10 +47,10 @@ impl Scrobbler { .send()?; if !resp.status().is_success() { - eprintln!( + crate::debug_eprintln(format_args!( "scrobble: listenbrainz token validation failed: {}", resp.status() - ); + )); return Ok(None); } @@ -62,13 +62,18 @@ impl Scrobbler { .and_then(|v| v.as_str()) .map(|s| s.to_string()); if let Some(ref u) = user { - eprintln!("scrobble: listenbrainz token valid (user: {})", u); + crate::debug_eprintln(format_args!( + "scrobble: listenbrainz token valid (user: {})", + u + )); } else { - eprintln!("scrobble: listenbrainz token valid"); + crate::debug_eprintln(format_args!("scrobble: listenbrainz token valid")); } Ok(user) } else { - eprintln!("scrobble: listenbrainz token invalid — scrobbling will fail"); + crate::debug_eprintln(format_args!( + "scrobble: listenbrainz token invalid — scrobbling will fail" + )); Ok(None) } } @@ -82,22 +87,29 @@ impl Scrobbler { && !secret.is_empty() && !session_key.is_empty() { - eprintln!("scrobble: now_playing -> lastfm '{} - {}'", artist, track); + crate::debug_eprintln(format_args!( + "scrobble: now_playing -> lastfm '{} - {}'", + artist, track + )); let _ = self.send_lastfm_now_playing(api_key, secret, session_key, artist, track, album); } else { - eprintln!("scrobble: now_playing -> lastfm skipped (no credentials)"); + crate::debug_eprintln(format_args!( + "scrobble: now_playing -> lastfm skipped (no credentials)" + )); } if let Some(token) = &self.listenbrainz_token && !token.is_empty() { - eprintln!( + crate::debug_eprintln(format_args!( "scrobble: now_playing -> listenbrainz '{} - {}'", artist, track - ); + )); let _ = self.send_listenbrainz_now_playing(token, artist, track, album); } else { - eprintln!("scrobble: now_playing -> listenbrainz skipped (no token)"); + crate::debug_eprintln(format_args!( + "scrobble: now_playing -> listenbrainz skipped (no token)" + )); } } @@ -110,10 +122,10 @@ impl Scrobbler { && !secret.is_empty() && !session_key.is_empty() { - eprintln!( + crate::debug_eprintln(format_args!( "scrobble: scrobble -> lastfm '{} - {}' (ts={})", artist, track, timestamp - ); + )); let _ = self.send_lastfm_scrobble( api_key, secret, @@ -124,18 +136,22 @@ impl Scrobbler { timestamp, ); } else { - eprintln!("scrobble: scrobble -> lastfm skipped (no credentials)"); + crate::debug_eprintln(format_args!( + "scrobble: scrobble -> lastfm skipped (no credentials)" + )); } if let Some(token) = &self.listenbrainz_token && !token.is_empty() { - eprintln!( + crate::debug_eprintln(format_args!( "scrobble: scrobble -> listenbrainz '{} - {}' (ts={})", artist, track, timestamp - ); + )); let _ = self.send_listenbrainz_scrobble(token, artist, track, album, timestamp); } else { - eprintln!("scrobble: scrobble -> listenbrainz skipped (no token)"); + crate::debug_eprintln(format_args!( + "scrobble: scrobble -> listenbrainz skipped (no token)" + )); } } @@ -177,13 +193,13 @@ impl Scrobbler { let resp = self.client.post(LASTFM_API_URL).form(¶ms).send()?; if resp.status().is_success() { - eprintln!("scrobble: lastfm now_playing ok"); + crate::debug_eprintln(format_args!("scrobble: lastfm now_playing ok")); } else { - eprintln!( + crate::debug_eprintln(format_args!( "scrobble: lastfm now_playing error: {} {}", resp.status(), resp.text().unwrap_or_default() - ); + )); } Ok(()) } @@ -217,13 +233,13 @@ impl Scrobbler { let resp = self.client.post(LASTFM_API_URL).form(¶ms).send()?; if resp.status().is_success() { - eprintln!("scrobble: lastfm scrobble ok"); + crate::debug_eprintln(format_args!("scrobble: lastfm scrobble ok")); } else { - eprintln!( + crate::debug_eprintln(format_args!( "scrobble: lastfm scrobble error: {} {}", resp.status(), resp.text().unwrap_or_default() - ); + )); } Ok(()) } @@ -257,13 +273,13 @@ impl Scrobbler { .json(&payload) .send()?; if resp.status().is_success() { - eprintln!("scrobble: listenbrainz now_playing ok"); + crate::debug_eprintln(format_args!("scrobble: listenbrainz now_playing ok")); } else { - eprintln!( + crate::debug_eprintln(format_args!( "scrobble: listenbrainz now_playing error: {} {}", resp.status(), resp.text().unwrap_or_default() - ); + )); } Ok(()) } @@ -299,13 +315,13 @@ impl Scrobbler { .json(&payload) .send()?; if resp.status().is_success() { - eprintln!("scrobble: listenbrainz scrobble ok"); + crate::debug_eprintln(format_args!("scrobble: listenbrainz scrobble ok")); } else { - eprintln!( + crate::debug_eprintln(format_args!( "scrobble: listenbrainz scrobble error: {} {}", resp.status(), resp.text().unwrap_or_default() - ); + )); } Ok(()) } -- cgit v1.2.3