From b42292f0f8be93aef914de3ae241f70fd2b7bf9f Mon Sep 17 00:00:00 2001 From: DaXcess Date: Fri, 17 Nov 2023 15:31:48 +0100 Subject: [PATCH] Goodbye boilerplate, hello poise --- Cargo.lock | 654 +++- Cargo.toml | 15 +- Dockerfile | 2 +- spoticord_audio/.gitignore | 1 + spoticord_audio/Cargo.lock | 3483 +++++++++++++++++ spoticord_audio/Cargo.toml | 13 + .../mod.rs => spoticord_audio/src/lib.rs | 3 - {src/audio => spoticord_audio/src}/stream.rs | 6 +- src/bot/commands/core/help.rs | 59 +- src/bot/commands/core/link.rs | 230 +- src/bot/commands/core/mod.rs | 6 + src/bot/commands/core/rename.rs | 220 +- src/bot/commands/core/unlink.rs | 130 +- src/bot/commands/core/version.rs | 60 +- src/bot/commands/mod.rs | 306 +- src/bot/commands/music/join.rs | 582 ++- src/bot/commands/music/leave.rs | 123 +- src/bot/commands/music/mod.rs | 4 + src/bot/commands/music/playing.rs | 423 +- src/bot/commands/ping.rs | 37 +- src/bot/commands/token.rs | 61 +- src/bot/events.rs | 136 - src/bot/mod.rs | 132 +- src/database.rs | 64 +- src/main.rs | 114 +- src/player/mod.rs | 2 +- src/session/manager.rs | 13 +- src/session/mod.rs | 51 +- src/utils/discord.rs | 20 +- src/utils/embed.rs | 97 +- 30 files changed, 4987 insertions(+), 2060 deletions(-) create mode 100644 spoticord_audio/.gitignore create mode 100644 spoticord_audio/Cargo.lock create mode 100644 spoticord_audio/Cargo.toml rename src/audio/mod.rs => spoticord_audio/src/lib.rs (93%) rename {src/audio => spoticord_audio/src}/stream.rs (95%) delete mode 100644 src/bot/events.rs diff --git a/Cargo.lock b/Cargo.lock index bed4138..df76936 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,6 +79,28 @@ dependencies = [ "memchr", ] +[[package]] +name = "alsa" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5915f52fe2cf65e83924d037b6c5290b7cee097c6b5c8700746e6168a343fd6b" +dependencies = [ + "alsa-sys", + "bitflags 1.3.2", + "libc", + "nix", +] + +[[package]] +name = "alsa-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" +dependencies = [ + "libc", + "pkg-config", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -197,6 +219,26 @@ version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +[[package]] +name = "bindgen" +version = "0.69.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ffcebc3849946a7170a05992aac39da343a90676ab392c51a4280981d6379c2" +dependencies = [ + "bitflags 2.4.1", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.39", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -257,9 +299,25 @@ version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ + "jobserver", "libc", ] +[[package]] +name = "cesu8" +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" @@ -276,6 +334,7 @@ dependencies = [ "iana-time-zone", "js-sys", "num-traits 0.2.17", + "serde", "wasm-bindgen", "windows-targets", ] @@ -298,6 +357,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "clang-sys" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "cmake" version = "0.1.50" @@ -317,17 +387,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "command_attr" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07b787d19b9806dd4c9c34b2b4147d1a61d6120d93ee289521ab9b0294d198e4" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "core-foundation" version = "0.9.3" @@ -344,6 +403,50 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +[[package]] +name = "coreaudio-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11894b20ebfe1ff903cbdc52259693389eea03b94918a2def2c30c3bf227ad88" +dependencies = [ + "bitflags 1.3.2", + "coreaudio-sys", +] + +[[package]] +name = "coreaudio-sys" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3120ebb80a9de008e638ad833d4127d50ea3d3a960ea23ea69bc66d9358a028" +dependencies = [ + "bindgen", +] + +[[package]] +name = "cpal" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74117836a5124f3629e4b474eed03e479abaf98988b4bb317e29f08cfe0e4116" +dependencies = [ + "alsa", + "core-foundation-sys", + "coreaudio-rs", + "jni", + "js-sys", + "lazy_static", + "libc", + "mach", + "ndk", + "ndk-glue", + "nix", + "oboe", + "parking_lot 0.11.2", + "stdweb", + "thiserror", + "web-sys", + "winapi", +] + [[package]] name = "cpufeatures" version = "0.2.11" @@ -400,6 +503,76 @@ dependencies = [ "cipher 0.2.5", ] +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core 0.13.4", + "darling_macro 0.13.4", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core 0.13.4", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core 0.14.4", + "quote", + "syn 1.0.109", +] + [[package]] name = "dashmap" version = "5.5.3" @@ -410,7 +583,7 @@ dependencies = [ "hashbrown 0.14.2", "lock_api", "once_cell", - "parking_lot_core", + "parking_lot_core 0.9.9", "serde", ] @@ -502,9 +675,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" dependencies = [ "humantime", "is-terminal", @@ -521,9 +694,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e" +checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" dependencies = [ "libc", "windows-sys", @@ -727,9 +900,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "h2" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", @@ -737,7 +910,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -824,9 +997,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -910,7 +1083,7 @@ dependencies = [ "futures-util", "http", "hyper", - "rustls 0.21.8", + "rustls 0.21.9", "tokio", "tokio-rustls 0.24.1", ] @@ -938,6 +1111,12 @@ dependencies = [ "cc", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.4.0" @@ -978,6 +1157,15 @@ dependencies = [ "hashbrown 0.14.2", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + [[package]] name = "ipnet" version = "2.9.0" @@ -1001,6 +1189,35 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.65" @@ -1017,10 +1234,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] -name = "levenshtein" -version = "1.0.5" +name = "lazycell" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "lewton" @@ -1039,6 +1256,16 @@ version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + [[package]] name = "libm" version = "0.2.8" @@ -1213,6 +1440,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5190a0b9bcc7f70ee4196a6b4a1c731d405ca130d4a6fcd4c561cfdde8b7cfb7" dependencies = [ "byteorder", + "cpal", "futures-executor", "futures-util", "lewton", @@ -1221,9 +1449,10 @@ dependencies = [ "librespot-metadata", "log", "ogg", - "parking_lot", + "parking_lot 0.12.1", "rand", "rand_distr", + "rodio", "shell-words", "thiserror", "tokio", @@ -1287,6 +1516,15 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + [[package]] name = "match_cfg" version = "0.1.0" @@ -1333,6 +1571,12 @@ dependencies = [ "unicase", ] +[[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.7.1" @@ -1371,6 +1615,62 @@ dependencies = [ "getrandom", ] +[[package]] +name = "ndk" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" +dependencies = [ + "bitflags 1.3.2", + "jni-sys", + "ndk-sys", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-glue" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d0c4a7b83860226e6b4183edac21851f05d5a51756e97a1144b7f5a6b63e65f" +dependencies = [ + "lazy_static", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-macro", + "ndk-sys", +] + +[[package]] +name = "ndk-macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c" +dependencies = [ + "darling 0.13.4", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ndk-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" +dependencies = [ + "jni-sys", +] + [[package]] name = "nix" version = "0.23.2" @@ -1384,6 +1684,16 @@ dependencies = [ "memoffset", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1406,6 +1716,17 @@ dependencies = [ "rand", ] +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -1445,6 +1766,27 @@ dependencies = [ "libc", ] +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "object" version = "0.32.1" @@ -1454,6 +1796,29 @@ dependencies = [ "memchr", ] +[[package]] +name = "oboe" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f63c358b4fa0fbcfefd7c8be5cfc39c08ce2389f5325687e7762a48d30a5c1" +dependencies = [ + "jni", + "ndk", + "ndk-context", + "num-derive", + "num-traits 0.2.17", + "oboe-sys", +] + +[[package]] +name = "oboe-sys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3370abb7372ed744232c12954d920d1a40f1c4686de9e79e800021ef492294bd" +dependencies = [ + "cc", +] + [[package]] name = "ogg" version = "0.8.0" @@ -1490,6 +1855,17 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + [[package]] name = "parking_lot" version = "0.12.1" @@ -1497,7 +1873,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.9", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", ] [[package]] @@ -1510,7 +1900,7 @@ dependencies = [ "cfg-if", "libc", "petgraph", - "redox_syscall", + "redox_syscall 0.4.1", "smallvec", "thread-id", "windows-targets", @@ -1526,6 +1916,12 @@ dependencies = [ "hmac", ] +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + [[package]] name = "percent-encoding" version = "2.3.0" @@ -1607,6 +2003,37 @@ dependencies = [ "pnet_base", ] +[[package]] +name = "poise" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d104e4b5847283b2fbd6a7ec19fb6a8af328e2145623d056b66d750a30073fdf" +dependencies = [ + "async-trait", + "derivative", + "futures-core", + "futures-util", + "log", + "once_cell", + "parking_lot 0.12.1", + "poise_macros", + "regex", + "serenity", + "tokio", +] + +[[package]] +name = "poise_macros" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb516a8cf4e4ae4bd7ef5819d08c6ca408976461a9bea3ee3eec5138ac070c1" +dependencies = [ + "darling 0.14.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "poly1305" version = "0.7.2" @@ -1640,6 +2067,16 @@ dependencies = [ "indexmap 1.9.3", ] +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.69" @@ -1736,6 +2173,15 @@ dependencies = [ "url", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -1813,7 +2259,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls 0.21.8", + "rustls 0.21.9", "rustls-pemfile", "serde", "serde_json", @@ -1861,6 +2307,15 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "rodio" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0939e9f626e6c6f1989adb6226a039c855ca483053f0ee7c98b90e41cf731e" +dependencies = [ + "cpal", +] + [[package]] name = "rpassword" version = "6.0.1" @@ -1879,6 +2334,12 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.4.0" @@ -1890,9 +2351,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.21" +version = "0.38.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +checksum = "9ad981d6c340a49cdc40a1028d9c6084ec7e9fa33fcb839cab656a267071e234" dependencies = [ "bitflags 2.4.1", "errno", @@ -1915,9 +2376,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.8" +version = "0.21.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" +checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" dependencies = [ "log", "ring 0.17.5", @@ -1966,6 +2427,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "samplerate" version = "0.2.4" @@ -2079,26 +2549,24 @@ dependencies = [ "bitflags 1.3.2", "bytes", "cfg-if", - "command_attr", + "chrono", "dashmap", "flate2", "futures", - "levenshtein", "mime", "mime_guess", - "parking_lot", + "parking_lot 0.12.1", "percent-encoding", "reqwest", + "rustversion", "serde", "serde-value", "serde_json", - "static_assertions", "time", "tokio", "tracing", "typemap_rev", "url", - "uwl", ] [[package]] @@ -2173,6 +2641,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +[[package]] +name = "shlex" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -2232,7 +2706,7 @@ dependencies = [ "discortp", "flume", "futures", - "parking_lot", + "parking_lot 0.12.1", "pin-project", "rand", "serde", @@ -2267,33 +2741,45 @@ dependencies = [ [[package]] name = "spoticord" -version = "2.1.3" +version = "2.2.0" dependencies = [ "anyhow", "dotenvy", - "env_logger 0.10.0", + "env_logger 0.10.1", "hex", "lazy_static", "librespot", "log", + "poise", "protobuf", "redis", "reqwest", "samplerate", "serde", "serde_json", - "serenity", "songbird", + "spoticord_audio", "thiserror", "tokio", - "zerocopy 0.7.25", + "zerocopy 0.7.26", ] [[package]] -name = "static_assertions" -version = "1.1.0" +name = "spoticord_audio" +version = "2.2.0" +dependencies = [ + "librespot", + "samplerate", + "songbird", + "tokio", + "zerocopy 0.7.26", +] + +[[package]] +name = "stdweb" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" [[package]] name = "streamcatcher" @@ -2306,6 +2792,12 @@ dependencies = [ "loom", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "subtle" version = "2.4.1" @@ -2376,16 +2868,16 @@ checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", + "redox_syscall 0.4.1", "rustix", "windows-sys", ] [[package]] name = "termcolor" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" dependencies = [ "winapi-util", ] @@ -2485,7 +2977,7 @@ dependencies = [ "libc", "mio", "num_cpus", - "parking_lot", + "parking_lot 0.12.1", "pin-project-lite", "signal-hook-registry", "socket2 0.5.5", @@ -2521,7 +3013,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.21.8", + "rustls 0.21.9", "tokio", ] @@ -2550,6 +3042,23 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.1.0", + "toml_datetime", + "winnow", +] + [[package]] name = "tower-service" version = "0.3.2" @@ -2601,9 +3110,9 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.4" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ "log", "once_cell", @@ -2612,9 +3121,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", @@ -2761,12 +3270,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "uwl" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4bf03e0ca70d626ecc4ba6b0763b934b6f2976e8c744088bb3c1d646fbb1ad0" - [[package]] name = "valuable" version = "0.1.0" @@ -2790,6 +3293,16 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -3034,6 +3547,15 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "winnow" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" @@ -3070,12 +3592,12 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.25" +version = "0.7.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd369a67c0edfef15010f980c3cbe45d7f651deac2cd67ce097cd801de16557" +checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0" dependencies = [ "byteorder", - "zerocopy-derive 0.7.25", + "zerocopy-derive 0.7.26", ] [[package]] @@ -3091,9 +3613,9 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.7.25" +version = "0.7.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f140bda219a26ccc0cdb03dba58af72590c53b22642577d88a927bc5c87d6b" +checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 0dba2c5..53b124c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,35 +1,40 @@ [package] name = "spoticord" -version = "2.1.3" +version = "2.2.0" edition = "2021" -rust-version = "1.65.0" +rust-version = "1.67.0" [[bin]] name = "spoticord" path = "src/main.rs" +[workspace] + [features] stats = ["redis"] +[dependencies.spoticord_audio] +path = "./spoticord_audio" + [dependencies] anyhow = "1.0.75" dotenvy = "0.15.7" -env_logger = "0.10.0" +env_logger = "0.10.1" hex = "0.4.3" lazy_static = "1.4.0" librespot = { version = "0.4.2", default-features = false } log = "0.4.20" +poise = "0.5.7" protobuf = "2.28.0" redis = { version = "0.23.3", optional = true, default-features = false } reqwest = { version = "0.11.22", default-features = false } samplerate = "0.2.4" serde = "1.0.192" serde_json = "1.0.108" -serenity = { version = "0.11.7", features = ["framework", "cache", "standard_framework", "rustls_backend", "gateway"], default-features = false } songbird = { version = "0.3.2", features = ["driver", "serenity-rustls"], default-features = false } thiserror = "1.0.50" tokio = { version = "1.34.0", features = ["rt", "full"] } -zerocopy = "0.7.25" +zerocopy = "0.7.26" [profile.release] opt-level = 3 diff --git a/Dockerfile b/Dockerfile index 38e72a2..a1245cf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Builder -FROM --platform=linux/amd64 rust:1.72.1-buster as builder +FROM --platform=linux/amd64 rust:1.74.0-buster as builder WORKDIR /app diff --git a/spoticord_audio/.gitignore b/spoticord_audio/.gitignore new file mode 100644 index 0000000..c41cc9e --- /dev/null +++ b/spoticord_audio/.gitignore @@ -0,0 +1 @@ +/target \ No newline at end of file diff --git a/spoticord_audio/Cargo.lock b/spoticord_audio/Cargo.lock new file mode 100644 index 0000000..bc3e57e --- /dev/null +++ b/spoticord_audio/Cargo.lock @@ -0,0 +1,3483 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aead" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +dependencies = [ + "generic-array", + "rand_core", +] + +[[package]] +name = "aes" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" +dependencies = [ + "aes-soft", + "aesni", + "cipher 0.2.5", +] + +[[package]] +name = "aes-ctr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7729c3cde54d67063be556aeac75a81330d802f0259500ca40cb52967f975763" +dependencies = [ + "aes-soft", + "aesni", + "cipher 0.2.5", + "ctr", +] + +[[package]] +name = "aes-soft" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" +dependencies = [ + "cipher 0.2.5", + "opaque-debug", +] + +[[package]] +name = "aesni" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" +dependencies = [ + "cipher 0.2.5", + "opaque-debug", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "alsa" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5915f52fe2cf65e83924d037b6c5290b7cee097c6b5c8700746e6168a343fd6b" +dependencies = [ + "alsa-sys", + "bitflags 1.3.2", + "libc", + "nix", +] + +[[package]] +name = "alsa-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "async-trait" +version = "0.1.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "async-tungstenite" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1b71b31561643aa8e7df3effe284fa83ab1a840e52294c5f4bd7bfd8b2becbb" +dependencies = [ + "futures-io", + "futures-util", + "log", + "pin-project-lite", + "tokio", + "tokio-rustls 0.23.4", + "tungstenite", + "webpki-roots 0.22.6", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "audiopus" +version = "0.3.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab55eb0e56d7c6de3d59f544e5db122d7725ec33be6a276ee8241f3be6473955" +dependencies = [ + "audiopus_sys", +] + +[[package]] +name = "audiopus_sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62314a1546a2064e033665d658e88c620a62904be945f8147e6b16c3db9f8651" +dependencies = [ + "cmake", + "log", + "pkg-config", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + +[[package]] +name = "bindgen" +version = "0.69.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ffcebc3849946a7170a05992aac39da343a90676ab392c51a4280981d6379c2" +dependencies = [ + "bitflags 2.4.1", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.39", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "bytemuck" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cesu8" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits 0.2.17", + "wasm-bindgen", + "windows-targets", +] + +[[package]] +name = "cipher" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array", +] + +[[package]] +name = "clang-sys" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "cmake" +version = "0.1.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +dependencies = [ + "cc", +] + +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "coreaudio-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11894b20ebfe1ff903cbdc52259693389eea03b94918a2def2c30c3bf227ad88" +dependencies = [ + "bitflags 1.3.2", + "coreaudio-sys", +] + +[[package]] +name = "coreaudio-sys" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3120ebb80a9de008e638ad833d4127d50ea3d3a960ea23ea69bc66d9358a028" +dependencies = [ + "bindgen", +] + +[[package]] +name = "cpal" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74117836a5124f3629e4b474eed03e479abaf98988b4bb317e29f08cfe0e4116" +dependencies = [ + "alsa", + "core-foundation-sys", + "coreaudio-rs", + "jni", + "js-sys", + "lazy_static", + "libc", + "mach", + "ndk", + "ndk-glue", + "nix", + "oboe", + "parking_lot 0.11.2", + "stdweb", + "thiserror", + "web-sys", + "winapi", +] + +[[package]] +name = "cpufeatures" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" +dependencies = [ + "cipher 0.2.5", +] + +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.2", + "lock_api", + "once_cell", + "parking_lot_core 0.9.9", +] + +[[package]] +name = "deranged" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", +] + +[[package]] +name = "discortp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb66017646a48220b5ea30d63ac18bb5952f647f1a41ed755880895125d26972" +dependencies = [ + "pnet_macros", + "pnet_macros_support", +] + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enum_primitive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" +dependencies = [ + "num-traits 0.1.43", +] + +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.10.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" +dependencies = [ + "futures-core", + "futures-sink", + "nanorand", + "pin-project", + "spin 0.9.8", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" + +[[package]] +name = "futures-executor" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" + +[[package]] +name = "futures-macro" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "futures-sink" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" + +[[package]] +name = "futures-task" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" + +[[package]] +name = "futures-util" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generator" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" +dependencies = [ + "cc", + "libc", + "log", + "rustversion", + "windows", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "h2" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 2.1.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" + +[[package]] +name = "headers" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" +dependencies = [ + "base64 0.21.5", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + +[[package]] +name = "http" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.4.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-proxy" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca815a891b24fdfb243fa3239c86154392b0953ee584aa1a2a1f66d20cbe75cc" +dependencies = [ + "bytes", + "futures", + "headers", + "http", + "hyper", + "tokio", + "tower-service", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http", + "hyper", + "rustls 0.21.9", + "tokio", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "if-addrs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbc0fa01ffc752e9dbc72818cdb072cd028b86be5e09dd04c5a643704fe101a9" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown 0.14.2", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "lewton" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030" +dependencies = [ + "byteorder", + "ogg", + "tinyvec", +] + +[[package]] +name = "libc" +version = "0.2.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libmdns" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b04ae6b56b3b19ade26f0e7e7c1360a1713514f326c5ed0797cf2c109c9e010" +dependencies = [ + "byteorder", + "futures-util", + "hostname", + "if-addrs", + "log", + "multimap", + "nix", + "rand", + "socket2 0.4.10", + "thiserror", + "tokio", + "winapi", +] + +[[package]] +name = "librespot" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea4c9952ef48968f8184a4a87f8576982426ebe623342d5a28f7d9c4978e4a44" +dependencies = [ + "base64 0.13.1", + "env_logger", + "futures-util", + "getopts", + "hex", + "hyper", + "librespot-audio", + "librespot-connect", + "librespot-core", + "librespot-discovery", + "librespot-metadata", + "librespot-playback", + "librespot-protocol", + "log", + "rpassword", + "sha-1 0.9.8", + "thiserror", + "tokio", + "url", +] + +[[package]] +name = "librespot-audio" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c176a31355e1ea8e0b9c4ced19df4947bfe4770661c25c142b6fba2365940d9d" +dependencies = [ + "aes-ctr", + "byteorder", + "bytes", + "futures-util", + "librespot-core", + "log", + "tempfile", + "tokio", +] + +[[package]] +name = "librespot-connect" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ffafb6a443e9445ccb3d5d591573b5b1da3c89a9b8846c63ba2c3710210d3ec" +dependencies = [ + "form_urlencoded", + "futures-util", + "librespot-core", + "librespot-discovery", + "librespot-playback", + "librespot-protocol", + "log", + "protobuf", + "rand", + "serde", + "serde_json", + "tokio", + "tokio-stream", +] + +[[package]] +name = "librespot-core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046349f25888e644bf02d9c5de0164b2a493d29aa4ce18e1ad0b756da9b55d6d" +dependencies = [ + "aes", + "base64 0.13.1", + "byteorder", + "bytes", + "form_urlencoded", + "futures-core", + "futures-util", + "hmac", + "http", + "httparse", + "hyper", + "hyper-proxy", + "librespot-protocol", + "log", + "num-bigint", + "num-integer", + "num-traits 0.2.17", + "once_cell", + "pbkdf2", + "priority-queue", + "protobuf", + "rand", + "serde", + "serde_json", + "sha-1 0.9.8", + "shannon", + "thiserror", + "tokio", + "tokio-stream", + "tokio-util", + "url", + "uuid 1.5.0", + "vergen", +] + +[[package]] +name = "librespot-discovery" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aa877d18f6150364012cb4be5682d62d7c712c88bae2d0d01720fd7c15e2f06" +dependencies = [ + "aes-ctr", + "base64 0.13.1", + "form_urlencoded", + "futures-core", + "hmac", + "hyper", + "libmdns", + "librespot-core", + "log", + "rand", + "serde_json", + "sha-1 0.9.8", + "thiserror", + "tokio", +] + +[[package]] +name = "librespot-metadata" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b80361fcbcb5092056fd47c08c34d5d51b08385d8efb6941c0d3e46d032c21c" +dependencies = [ + "async-trait", + "byteorder", + "librespot-core", + "librespot-protocol", + "log", + "protobuf", +] + +[[package]] +name = "librespot-playback" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5190a0b9bcc7f70ee4196a6b4a1c731d405ca130d4a6fcd4c561cfdde8b7cfb7" +dependencies = [ + "byteorder", + "cpal", + "futures-executor", + "futures-util", + "lewton", + "librespot-audio", + "librespot-core", + "librespot-metadata", + "log", + "ogg", + "parking_lot 0.12.1", + "rand", + "rand_distr", + "rodio", + "shell-words", + "thiserror", + "tokio", + "zerocopy 0.6.5", +] + +[[package]] +name = "librespot-protocol" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d6d3ac6196ac0ea67bbe039f56d6730a5d8b31502ef9bce0f504ed729dcb39f" +dependencies = [ + "glob", + "protobuf", + "protobuf-codegen-pure", +] + +[[package]] +name = "libsamplerate-sys" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28853b399f78f8281cd88d333b54a63170c4275f6faea66726a2bea5cca72e0d" +dependencies = [ + "cmake", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "loom" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "serde", + "serde_json", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[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.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" +dependencies = [ + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" +dependencies = [ + "serde", +] + +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom", +] + +[[package]] +name = "ndk" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" +dependencies = [ + "bitflags 1.3.2", + "jni-sys", + "ndk-sys", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-glue" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d0c4a7b83860226e6b4183edac21851f05d5a51756e97a1144b7f5a6b63e65f" +dependencies = [ + "lazy_static", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-macro", + "ndk-sys", +] + +[[package]] +name = "ndk-macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c" +dependencies = [ + "darling", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ndk-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "nix" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" +dependencies = [ + "bitflags 1.3.2", + "cc", + "cfg-if", + "libc", + "memoffset", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits 0.2.17", + "rand", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits 0.2.17", +] + +[[package]] +name = "num-traits" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" +dependencies = [ + "num-traits 0.2.17", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.3", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + +[[package]] +name = "oboe" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f63c358b4fa0fbcfefd7c8be5cfc39c08ce2389f5325687e7762a48d30a5c1" +dependencies = [ + "jni", + "ndk", + "ndk-context", + "num-derive", + "num-traits 0.2.17", + "oboe-sys", +] + +[[package]] +name = "oboe-sys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3370abb7372ed744232c12954d920d1a40f1c4686de9e79e800021ef492294bd" +dependencies = [ + "cc", +] + +[[package]] +name = "ogg" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6951b4e8bf21c8193da321bcce9c9dd2e13c858fe078bf9054a288b419ae5d6e" +dependencies = [ + "byteorder", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits 0.2.17", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.9", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "backtrace", + "cfg-if", + "libc", + "petgraph", + "redox_syscall 0.4.1", + "smallvec", + "thread-id", + "windows-targets", +] + +[[package]] +name = "pbkdf2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" +dependencies = [ + "crypto-mac", + "hmac", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap 2.1.0", +] + +[[package]] +name = "pin-project" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "pnet_base" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25488cd551a753dcaaa6fffc9f69a7610a412dd8954425bf7ffad5f7d1156fb8" + +[[package]] +name = "pnet_macros" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30490e0852e58402b8fae0d39897b08a24f493023a4d6cf56b2e30f31ed57548" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", +] + +[[package]] +name = "pnet_macros_support" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4714e10f30cab023005adce048f2d30dd4ac4f093662abf2220855655ef8f90" +dependencies = [ + "pnet_base", +] + +[[package]] +name = "poly1305" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "priority-queue" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff39edfcaec0d64e8d0da38564fad195d2d51b680940295fcc307366e101e61" +dependencies = [ + "autocfg", + "indexmap 1.9.3", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "protobuf" +version = "2.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" + +[[package]] +name = "protobuf-codegen" +version = "2.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "033460afb75cf755fcfc16dfaed20b86468082a2ea24e05ac35ab4a099a017d6" +dependencies = [ + "protobuf", +] + +[[package]] +name = "protobuf-codegen-pure" +version = "2.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a29399fc94bcd3eeaa951c715f7bea69409b2445356b00519740bcd6ddd865" +dependencies = [ + "protobuf", + "protobuf-codegen", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits 0.2.17", + "rand", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "reqwest" +version = "0.11.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +dependencies = [ + "base64 0.21.5", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "log", + "mime", + "mime_guess", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.21.9", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "system-configuration", + "tokio", + "tokio-rustls 0.24.1", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots 0.25.2", + "winreg", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + +[[package]] +name = "ring" +version = "0.17.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys", +] + +[[package]] +name = "rodio" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0939e9f626e6c6f1989adb6226a039c855ca483053f0ee7c98b90e41cf731e" +dependencies = [ + "cpal", +] + +[[package]] +name = "rpassword" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf099a1888612545b683d2661a1940089f6c2e5a8e38979b2159da876bfd956" +dependencies = [ + "libc", + "serde", + "serde_json", + "winapi", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ad981d6c340a49cdc40a1028d9c6084ec7e9fa33fcb839cab656a267071e234" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustls" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" +dependencies = [ + "log", + "ring 0.16.20", + "sct", + "webpki", +] + +[[package]] +name = "rustls" +version = "0.21.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" +dependencies = [ + "log", + "ring 0.17.5", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.5", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring 0.17.5", + "untrusted 0.9.0", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "salsa20" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0fbb5f676da676c260ba276a8f43a8dc67cf02d1438423aeb1c677a7212686" +dependencies = [ + "cipher 0.3.0", + "zeroize", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "samplerate" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e032b2b24715c4f982f483ea3abdb3c9ba444d9f63e87b2843d6f998f5ba2698" +dependencies = [ + "libsamplerate-sys", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring 0.17.5", + "untrusted 0.9.0", +] + +[[package]] +name = "semver" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" + +[[package]] +name = "serde" +version = "1.0.192" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.192" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "serde_json" +version = "1.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serenity" +version = "0.11.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a7a89cef23483fc9d4caf2df41e6d3928e18aada84c56abd237439d929622c6" +dependencies = [ + "async-trait", + "async-tungstenite", + "base64 0.21.5", + "bitflags 1.3.2", + "bytes", + "cfg-if", + "flate2", + "futures", + "mime", + "mime_guess", + "percent-encoding", + "reqwest", + "serde", + "serde-value", + "serde_json", + "time", + "tokio", + "tracing", + "typemap_rev", + "url", +] + +[[package]] +name = "serenity-voice-model" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be3aec8849ca2fde1e8a5dfbed96fbd68e9b5f4283fbe277d8694ce811d4952" +dependencies = [ + "bitflags 1.3.2", + "enum_primitive", + "serde", + "serde_json", + "serde_repr", +] + +[[package]] +name = "sha-1" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha-1" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "shannon" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ea5b41c9427b56caa7b808cb548a04fb50bb5b9e98590b53f28064ff4174561" +dependencies = [ + "byteorder", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + +[[package]] +name = "shlex" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "songbird" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f686a0fd771939de1da3e43cee45169fafe1595770b94680572cf18bdef288" +dependencies = [ + "async-trait", + "async-tungstenite", + "audiopus", + "byteorder", + "dashmap", + "derivative", + "discortp", + "flume", + "futures", + "parking_lot 0.12.1", + "pin-project", + "rand", + "serde", + "serde_json", + "serenity", + "serenity-voice-model", + "streamcatcher", + "symphonia-core", + "tokio", + "tracing", + "tracing-futures", + "typemap_rev", + "url", + "uuid 0.8.2", + "xsalsa20poly1305", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spoticord_audio" +version = "0.1.0" +dependencies = [ + "librespot", + "samplerate", + "songbird", + "tokio", + "zerocopy 0.7.26", +] + +[[package]] +name = "stdweb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" + +[[package]] +name = "streamcatcher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71664755c349abb0758fda6218fb2d2391ca2a73f9302c03b145491db4fcea29" +dependencies = [ + "crossbeam-utils", + "futures-util", + "loom", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "symphonia-core" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c73eb88fee79705268cc7b742c7bc93a7b76e092ab751d0833866970754142" +dependencies = [ + "arrayvec", + "bitflags 1.3.2", + "bytemuck", + "lazy_static", + "log", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.4.1", + "rustix", + "windows-sys", +] + +[[package]] +name = "termcolor" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "thread-id" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0ec81c46e9eb50deaa257be2f148adf052d1fb7701cfd55ccfab2525280b70b" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +dependencies = [ + "deranged", + "itoa", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +dependencies = [ + "time-core", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot 0.12.1", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.5.5", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls 0.20.9", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.9", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.1.0", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] +name = "tungstenite" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" +dependencies = [ + "base64 0.13.1", + "byteorder", + "bytes", + "http", + "httparse", + "log", + "rand", + "rustls 0.20.9", + "sha-1 0.10.1", + "thiserror", + "url", + "utf-8", + "webpki", +] + +[[package]] +name = "typemap_rev" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5b74f0a24b5454580a79abb6994393b09adf0ab8070f15827cb666255de155" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "universal-hash" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "uuid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" +dependencies = [ + "getrandom", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vergen" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7141e445af09c8919f1d5f8a20dae0b20c3b57a45dee0d5823c6ed5d237f15a" +dependencies = [ + "bitflags 1.3.2", + "chrono", + "rustc_version", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.39", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" + +[[package]] +name = "wasm-streams" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" +dependencies = [ + "ring 0.17.5", + "untrusted 0.9.0", +] + +[[package]] +name = "webpki-roots" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +dependencies = [ + "webpki", +] + +[[package]] +name = "webpki-roots" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "winnow" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys", +] + +[[package]] +name = "xsalsa20poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e68bcb965d6c650091450b95cea12f07dcd299a01c15e2f9433b0813ea3c0886" +dependencies = [ + "aead", + "poly1305", + "rand_core", + "salsa20", + "subtle", + "zeroize", +] + +[[package]] +name = "zerocopy" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96f8f25c15a0edc9b07eb66e7e6e97d124c0505435c382fde1ab7ceb188aa956" +dependencies = [ + "byteorder", + "zerocopy-derive 0.6.5", +] + +[[package]] +name = "zerocopy" +version = "0.7.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0" +dependencies = [ + "byteorder", + "zerocopy-derive 0.7.26", +] + +[[package]] +name = "zerocopy-derive" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "855e0f6af9cd72b87d8a6c586f3cb583f5cdcc62c2c80869d8cd7e96fdf7ee20" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "zeroize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" diff --git a/spoticord_audio/Cargo.toml b/spoticord_audio/Cargo.toml new file mode 100644 index 0000000..854eae7 --- /dev/null +++ b/spoticord_audio/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "spoticord_audio" +version = "2.2.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +librespot = "0.4.2" +samplerate = "0.2.4" +songbird = "0.3.2" +tokio = { version = "1.34.0", features = ["sync"], default-features = false } +zerocopy = "0.7.26" diff --git a/src/audio/mod.rs b/spoticord_audio/src/lib.rs similarity index 93% rename from src/audio/mod.rs rename to spoticord_audio/src/lib.rs index b038491..83b9df2 100644 --- a/src/audio/mod.rs +++ b/spoticord_audio/src/lib.rs @@ -5,7 +5,6 @@ use self::stream::Stream; use librespot::playback::audio_backend::{Sink, SinkAsBytes, SinkError, SinkResult}; use librespot::playback::convert::Converter; use librespot::playback::decoder::AudioPacket; -use log::error; use std::io::Write; use tokio::sync::mpsc::UnboundedSender; @@ -30,7 +29,6 @@ impl Sink for StreamSink { if let Err(why) = self.sender.send(SinkEvent::Start) { // WARNING: Returning an error causes librespot-playback to exit the process with status 1 - error!("Failed to send start playback event: {why}"); return Err(SinkError::ConnectionRefused(why.to_string())); } @@ -41,7 +39,6 @@ impl Sink for StreamSink { if let Err(why) = self.sender.send(SinkEvent::Stop) { // WARNING: Returning an error causes librespot-playback to exit the process with status 1 - error!("Failed to send start playback event: {why}"); return Err(SinkError::ConnectionRefused(why.to_string())); } diff --git a/src/audio/stream.rs b/spoticord_audio/src/stream.rs similarity index 95% rename from src/audio/stream.rs rename to spoticord_audio/src/stream.rs index f8d2468..49df66a 100644 --- a/src/audio/stream.rs +++ b/spoticord_audio/src/stream.rs @@ -10,16 +10,14 @@ use songbird::input::reader::MediaSource; /// Too low of a value results in unpredictable audio const MAX_SIZE: usize = 32 * 1024; -#[derive(Clone)] +#[derive(Clone, Default)] pub struct Stream { inner: Arc<(Mutex>, Condvar)>, } impl Stream { pub fn new() -> Self { - Self { - inner: Arc::new((Mutex::new(Vec::new()), Condvar::new())), - } + Self::default() } } diff --git a/src/bot/commands/core/help.rs b/src/bot/commands/core/help.rs index 531da30..c1892da 100644 --- a/src/bot/commands/core/help.rs +++ b/src/bot/commands/core/help.rs @@ -1,40 +1,27 @@ -use serenity::{ - builder::CreateApplicationCommand, - model::prelude::interaction::application_command::ApplicationCommandInteraction, - prelude::Context, -}; +use poise::serenity_prelude::Error; -use crate::{ - bot::commands::{respond_message, CommandOutput}, - utils::embed::{EmbedBuilder, Status}, -}; +use crate::{bot::Context, utils::embed::Color}; -pub const NAME: &str = "help"; +/// Shows the help message +#[poise::command(slash_command)] +pub async fn help(ctx: Context<'_>) -> Result<(), Error> { + ctx + .send(|b| { + b.embed(|f| { + f.title("Spoticord Help") + .author(|a| a.icon_url("https://spoticord.com/logo-standard.webp")) + .description("**Welcome to Spoticord** + It seems you have requested some help. Not to worry, we can help you out.\n + **Not sure how the bot works?** + **[Click here](https://spoticord.com/#how-to)** for a quick overview about how to set up Spoticord and how to use it.\n + **Which commands are there?** + You can find all **[the commands](https://spoticord.com/#commands)** on the website. You may also just type `/` in Discord and see which commands are available there.\n + **Need more help?** + If you still need some help, whether you are having issues with the bot or you just want to give us some feedback, you can join our **[Discord server](https://discord.gg/wRCyhVqBZ5)**.") + .color(Color::Info) + }) + }) + .await?; -pub fn command(ctx: Context, command: ApplicationCommandInteraction) -> CommandOutput { - Box::pin(async move { - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .title("Spoticord Help") - .icon_url("https://spoticord.com/logo-standard.webp") - .description("**Welcome to Spoticord** - It seems you have requested some help. Not to worry, we can help you out.\n - **Not sure how the bot works?** - **[Click here](https://spoticord.com/#how-to)** for a quick overview about how to set up Spoticord and how to use it.\n - **Which commands are there?** - You can find all **[the commands](https://spoticord.com/#commands)** on the website. You may also just type `/` in Discord and see which commands are available there.\n - **Need more help?** - If you still need some help, whether you are having issues with the bot or you just want to give us some feedback, you can join our **[Discord server](https://discord.gg/wRCyhVqBZ5)**.".to_string()) - .status(Status::Info) - .build(), - false, - ) - .await; - }) -} - -pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand { - command.name(NAME).description("Shows the help message") + Ok(()) } diff --git a/src/bot/commands/core/link.rs b/src/bot/commands/core/link.rs index bf606d6..5f63ed7 100644 --- a/src/bot/commands/core/link.rs +++ b/src/bot/commands/core/link.rs @@ -1,159 +1,97 @@ +use crate::{bot::Context, consts::SPOTICORD_ACCOUNTS_URL, utils::embed::Color}; use log::error; -use reqwest::StatusCode; -use serenity::{ - builder::CreateApplicationCommand, - model::prelude::interaction::application_command::ApplicationCommandInteraction, - prelude::Context, -}; - -use crate::{ - bot::commands::{respond_message, CommandOutput}, - consts::SPOTICORD_ACCOUNTS_URL, - database::{Database, DatabaseError}, - utils::embed::{EmbedBuilder, Status}, -}; +use poise::serenity_prelude::Error; + +/// Link your Spotify account to Spoticord +#[poise::command(slash_command)] +pub async fn link(ctx: Context<'_>) -> Result<(), Error> { + let db = &ctx.data().database; + + if db + .get_user_account(ctx.author().id.to_string()) + .await + .is_ok() + { + ctx + .send(|b| { + b.embed(|e| { + e.description("You have already linked your Spotify account") + .color(Color::Error) + }) + .ephemeral(true) + }) + .await?; + + return Ok(()); + } + + macro_rules! send_link_message { + ($token:expr) => { + let link = format!("{}/spotify/{}", SPOTICORD_ACCOUNTS_URL.as_str(), $token); + + ctx + .send(|b| { + b.embed(|e| { + e.author(|a| { + a.name("Link your Spotify account") + .url(&link) + .icon_url("https://spoticord.com/spotify-logo.png") + }) + .description(format!( + "Go to [this link]({}) to connect your Spotify account.", + link + )) + .color(Color::Info) + }) + .ephemeral(true) + }) + .await?; + }; + } + + macro_rules! send_error_message { + () => { + ctx + .send(|b| { + b.embed(|e| { + e.description("Something went wrong while trying to link your Spotify account.") + .color(Color::Error) + }) + .ephemeral(true) + }) + .await?; + + return Ok(()); + }; + } -pub const NAME: &str = "link"; + if let Ok(request) = db.get_user_request(ctx.author().id.to_string()).await { + send_link_message!(request.token); -pub fn command(ctx: Context, command: ApplicationCommandInteraction) -> CommandOutput { - Box::pin(async move { - let data = ctx.data.read().await; - let database = data.get::().expect("to contain a value"); + return Ok(()); + } - if database - .get_user_account(command.user.id.to_string()) - .await - .is_ok() - { - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .description("You have already linked your Spotify account.") - .status(Status::Error) - .build(), - true, - ) - .await; + // Check if user exists, if not, create them + let user = match db.get_or_create_user(ctx.author().id.to_string()).await { + Ok(user) => user, + Err(why) => { + error!("Error fetching user: {why:?}"); - return; + send_error_message!(); } + }; - if let Ok(request) = database.get_user_request(command.user.id.to_string()).await { - let link = format!( - "{}/spotify/{}", - SPOTICORD_ACCOUNTS_URL.as_str(), - request.token - ); - - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .title("Link your Spotify account") - .title_url(&link) - .icon_url("https://spoticord.com/spotify-logo.png") - .description(format!( - "Go to [this link]({}) to connect your Spotify account.", - link - )) - .status(Status::Info) - .build(), - true, - ) - .await; - - return; + match db.create_user_request(user.id).await { + Ok(request) => { + send_link_message!(request.token); } - // Check if user exists, if not, create them - if let Err(why) = database.get_user(command.user.id.to_string()).await { - match why { - DatabaseError::InvalidStatusCode(StatusCode::NOT_FOUND) => { - if let Err(why) = database.create_user(command.user.id.to_string()).await { - error!("Error creating user: {:?}", why); - - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .description("Something went wrong while trying to link your Spotify account.") - .status(Status::Error) - .build(), - true, - ) - .await; - - return; - } - } + Err(why) => { + error!("Error creating user request: {why:?}"); - _ => { - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .description("Something went wrong while trying to link your Spotify account.") - .status(Status::Error) - .build(), - true, - ) - .await; - - return; - } - } + send_error_message!(); } + } - match database - .create_user_request(command.user.id.to_string()) - .await - { - Ok(request) => { - let link = format!( - "{}/spotify/{}", - SPOTICORD_ACCOUNTS_URL.as_str(), - request.token - ); - - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .title("Link your Spotify account") - .title_url(&link) - .icon_url("https://spoticord.com/spotify-logo.png") - .description(format!( - "Go to [this link]({}) to connect your Spotify account.", - link - )) - .status(Status::Info) - .build(), - true, - ) - .await; - } - - Err(why) => { - error!("Error creating user request: {:?}", why); - - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .description("An error occurred while serving your request. Please try again later.") - .status(Status::Error) - .build(), - true, - ) - .await; - } - }; - }) -} - -pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand { - command - .name(NAME) - .description("Link your Spotify account to Spoticord") + Ok(()) } diff --git a/src/bot/commands/core/mod.rs b/src/bot/commands/core/mod.rs index 39aa8fd..85708ca 100644 --- a/src/bot/commands/core/mod.rs +++ b/src/bot/commands/core/mod.rs @@ -3,3 +3,9 @@ pub mod link; pub mod rename; pub mod unlink; pub mod version; + +pub use help::*; +pub use link::*; +pub use rename::*; +pub use unlink::*; +pub use version::*; diff --git a/src/bot/commands/core/rename.rs b/src/bot/commands/core/rename.rs index 36f1d5a..f3d662d 100644 --- a/src/bot/commands/core/rename.rs +++ b/src/bot/commands/core/rename.rs @@ -1,165 +1,69 @@ -use log::error; -use reqwest::StatusCode; -use serenity::{ - builder::CreateApplicationCommand, - model::prelude::{ - command::CommandOptionType, interaction::application_command::ApplicationCommandInteraction, - }, - prelude::Context, -}; - use crate::{ - bot::commands::{respond_message, CommandOutput}, - database::{Database, DatabaseError}, - utils::{ - self, - embed::{EmbedBuilder, Status}, - }, + bot::Context, + utils::{self, embed::Color}, }; - -pub const NAME: &str = "rename"; - -pub fn command(ctx: Context, command: ApplicationCommandInteraction) -> CommandOutput { - Box::pin(async move { - let data = ctx.data.read().await; - let database = data.get::().expect("to contain a value"); - - // Check if user exists, if not, create them - if let Err(why) = database.get_user(command.user.id.to_string()).await { - match why { - DatabaseError::InvalidStatusCode(StatusCode::NOT_FOUND) => { - if let Err(why) = database.create_user(command.user.id.to_string()).await { - error!("Error creating user: {:?}", why); - - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .description("Something went wrong while trying to rename your Spoticord device.") - .status(Status::Error) - .build(), - true, - ) - .await; - - return; - } - } - - _ => { - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .description("Something went wrong while trying to rename your Spoticord device.") - .status(Status::Error) - .build(), - true, - ) - .await; - - return; - } - } - } - - let device_name = match command.data.options.get(0) { - Some(option) => match option.value { - Some(ref value) => value.as_str().expect("to be a string").to_string(), - None => { - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .description("You need to provide a name for your Spoticord device.") - .status(Status::Error) - .build(), - true, - ) - .await; - - return; - } - }, - None => { - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .description("You need to provide a name for your Spoticord device.") - .status(Status::Error) - .build(), - true, - ) - .await; - - return; - } - }; - - if let Err(why) = database - .update_user_device_name(command.user.id.to_string(), &device_name) - .await - { - if let DatabaseError::InvalidInputBody(_) = why { - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .description( - "Your device name must not exceed 16 characters and be at least 1 character long.", - ) - .status(Status::Error) - .build(), - true, - ) - .await; - - return; - } - - error!("Error updating user device name: {:?}", why); - - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .description("Something went wrong while trying to rename your Spoticord device.") - .status(Status::Error) - .build(), - true, - ) - .await; - - return; +use log::error; +use poise::serenity_prelude::Error; + +/// Set a new device name that is displayed in Spotify +#[poise::command(slash_command)] +pub async fn rename( + ctx: Context<'_>, + + #[description = "The new device name"] + #[max_length = 16] + #[min_length = 1] + name: String, +) -> Result<(), Error> { + let db = &ctx.data().database; + + let user = match db.get_or_create_user(ctx.author().id.to_string()).await { + Ok(user) => user, + Err(why) => { + error!("Error fetching user: {why:?}"); + + ctx + .send(|b| { + b.embed(|e| { + e.description("Something went wrong while trying to rename your Spoticord device.") + .color(Color::Error) + }) + .ephemeral(true) + }) + .await?; + + return Ok(()); } - - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .description(format!( + }; + + if let Err(why) = db.update_user_device_name(user.id, &name).await { + error!("Error updating user device name: {why:?}"); + + ctx + .send(|b| { + b.embed(|e| { + e.description("Something went wrong while trying to rename your Spoticord device.") + .color(Color::Error) + }) + .ephemeral(true) + }) + .await?; + + return Ok(()); + } + + ctx + .send(|b| { + b.embed(|e| { + e.description(format!( "Successfully changed the Spotify device name to **{}**", - utils::discord::escape(device_name) + utils::discord::escape(name) )) - .status(Status::Success) - .build(), - true, - ) - .await; - }) -} - -pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand { - command - .name(NAME) - .description("Set a new device name that is displayed in Spotify") - .create_option(|option| { - option - .name("name") - .description("The new device name") - .kind(CommandOptionType::String) - .max_length(16) - .required(true) + .color(Color::Success) + }) + .ephemeral(true) }) + .await?; + + Ok(()) } diff --git a/src/bot/commands/core/unlink.rs b/src/bot/commands/core/unlink.rs index 99362d2..fe79f25 100644 --- a/src/bot/commands/core/unlink.rs +++ b/src/bot/commands/core/unlink.rs @@ -1,83 +1,61 @@ +use crate::{bot::Context, database::DatabaseError, utils::embed::Color}; use log::error; -use serenity::{ - builder::CreateApplicationCommand, - model::prelude::interaction::application_command::ApplicationCommandInteraction, - prelude::Context, -}; - -use crate::{ - bot::commands::{respond_message, CommandOutput}, - database::{Database, DatabaseError}, - session::manager::SessionManager, - utils::embed::{EmbedBuilder, Status}, -}; - -pub const NAME: &str = "unlink"; - -pub fn command(ctx: Context, command: ApplicationCommandInteraction) -> CommandOutput { - Box::pin(async move { - let data = ctx.data.read().await; - let database = data.get::().expect("to contain a value"); - let session_manager = data.get::().expect("to contain a value"); - - // Disconnect session if user has any - if let Some(session) = session_manager.find(command.user.id).await { - session.disconnect().await; - } - - // Check if user exists in the first place - if let Err(why) = database - .delete_user_account(command.user.id.to_string()) - .await - { - if let DatabaseError::InvalidStatusCode(status) = why { - if status == 404 { - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .description("You cannot unlink your Spotify account if you haven't linked one.") - .status(Status::Error) - .build(), - true, - ) - .await; - - return; - } +use poise::serenity_prelude::Error; +use reqwest::StatusCode; + +/// Unlink your Spotify account from Spoticord +#[poise::command(slash_command)] +pub async fn unlink(ctx: Context<'_>) -> Result<(), Error> { + let db = &ctx.data().database; + let sm = &ctx.data().session_manager; + + // Disconnect session if user has any + if let Some(session) = sm.find(ctx.author().id).await { + session.disconnect().await; + } + + // Check if user exists in the first place + if let Err(why) = db.delete_user_account(ctx.author().id.to_string()).await { + match why { + DatabaseError::InvalidStatusCode(StatusCode::NOT_FOUND) => { + ctx + .send(|b| { + b.embed(|e| { + e.description("You cannot unlink your Spotify account if you haven't linked one.") + .color(Color::Error) + }) + .ephemeral(true) + }) + .await?; } - error!("Error deleting user account: {:?}", why); - - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .description("An unexpected error has occured while trying to unlink your account. Please try again later.") - .status(Status::Error) - .build(), - true, - ) - .await; - - return; + _ => { + error!("Error deleting user account: {why:?}"); + + ctx + .send(|b| { + b.embed(|e| { + e.description("An unexpected error has occured while trying to unlink your account. Please try again later.") + .color(Color::Error) + }) + .ephemeral(true) + }) + .await?; + } } - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .description("Successfully unlinked your Spotify account from Spoticord") - .status(Status::Success) - .build(), - true, - ) - .await; - }) -} + return Ok(()); + } + + ctx + .send(|b| { + b.embed(|e| { + e.description("Successfully unlinked your Spotify account from Spoticord") + .color(Color::Success) + }) + .ephemeral(true) + }) + .await?; -pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand { - command - .name(NAME) - .description("Unlink your Spotify account from Spoticord") + Ok(()) } diff --git a/src/bot/commands/core/version.rs b/src/bot/commands/core/version.rs index b6e4861..b734ffa 100644 --- a/src/bot/commands/core/version.rs +++ b/src/bot/commands/core/version.rs @@ -1,46 +1,28 @@ -use log::error; -use serenity::{ - builder::CreateApplicationCommand, - model::prelude::interaction::{ - application_command::ApplicationCommandInteraction, InteractionResponseType, - }, - prelude::Context, -}; +use crate::{bot::Context, consts::VERSION, utils::embed::Color}; +use poise::serenity_prelude::Error; -use crate::{bot::commands::CommandOutput, consts::VERSION, utils::embed::Status}; +const IMAGE_URL: &str = "https://cdn.discordapp.com/avatars/389786424142200835/6bfe3840b0aa6a1baf432bb251b70c9f.webp?size=128"; -pub const NAME: &str = "version"; +/// Shows the current running version of Spoticord +#[poise::command(slash_command)] +pub async fn version(ctx: Context<'_>) -> Result<(), Error> { + // Had to pull this from the builder as rustfmt refused to format the file + let description = format!("Current version: {}\n\nSpoticord is open source, check out [our GitHub](https://github.com/SpoticordMusic)", VERSION); -pub fn command(ctx: Context, command: ApplicationCommandInteraction) -> CommandOutput { - Box::pin(async move { - if let Err(why) = command - .create_interaction_response(&ctx.http, |response| { - response - .kind(InteractionResponseType::ChannelMessageWithSource) - .interaction_response_data(|message| { - message.embed(|embed| { - embed - .title("Spoticord Version") - .author(|author| { - author - .name("Maintained by: DaXcess (@rodabafilms)") - .url("https://github.com/DaXcess") - .icon_url("https://cdn.discordapp.com/avatars/389786424142200835/6bfe3840b0aa6a1baf432bb251b70c9f.webp?size=128") - }) - .description(format!("Current version: {}\n\nSpoticord is open source, check out [our GitHub](https://github.com/SpoticordMusic)", VERSION)) - .color(Status::Info as u64) - }) + ctx + .send(|b| { + b.embed(|e| { + e.title("Spoticord Version") + .author(|a| { + a.name("Maintained by: DaXcess (@rodabafilms)") + .url("https://github.com/DaXcess") + .icon_url(IMAGE_URL) }) + .description(description) + .color(Color::Info) }) - .await - { - error!("Error sending message: {:?}", why); - } - }) -} + }) + .await?; -pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand { - command - .name(NAME) - .description("Shows the current running version of Spoticord") + Ok(()) } diff --git a/src/bot/commands/mod.rs b/src/bot/commands/mod.rs index d065a0f..b77a84b 100644 --- a/src/bot/commands/mod.rs +++ b/src/bot/commands/mod.rs @@ -1,23 +1,5 @@ -use std::{collections::HashMap, future::Future, pin::Pin}; - -use log::{debug, error}; -use serenity::{ - builder::{CreateApplicationCommand, CreateApplicationCommands}, - model::application::command::Command, - model::prelude::{ - interaction::{ - application_command::ApplicationCommandInteraction, - message_component::MessageComponentInteraction, InteractionResponseType, - }, - GuildId, - }, - prelude::{Context, TypeMapKey}, -}; - -use crate::utils::embed::{make_embed_message, EmbedMessageOptions}; - -mod core; -mod music; +pub mod core; +pub mod music; #[cfg(debug_assertions)] mod ping; @@ -25,285 +7,5 @@ mod ping; #[cfg(debug_assertions)] mod token; -pub async fn respond_message( - ctx: &Context, - command: &ApplicationCommandInteraction, - options: EmbedMessageOptions, - ephemeral: bool, -) { - if let Err(why) = command - .create_interaction_response(&ctx.http, |response| { - response - .kind(InteractionResponseType::ChannelMessageWithSource) - .interaction_response_data(|message| { - message - .embed(|embed| make_embed_message(embed, options)) - .ephemeral(ephemeral) - }) - }) - .await - { - error!("Error sending message: {:?}", why); - } -} - -pub async fn respond_component_message( - ctx: &Context, - component: &MessageComponentInteraction, - options: EmbedMessageOptions, - ephemeral: bool, -) { - if let Err(why) = component - .create_interaction_response(&ctx.http, |response| { - response - .kind(InteractionResponseType::ChannelMessageWithSource) - .interaction_response_data(|message| { - message - .embed(|embed| make_embed_message(embed, options)) - .ephemeral(ephemeral) - }) - }) - .await - { - error!("Error sending message: {:?}", why); - } -} - -pub async fn update_message( - ctx: &Context, - command: &ApplicationCommandInteraction, - options: EmbedMessageOptions, -) { - if let Err(why) = command - .edit_original_interaction_response(&ctx.http, |message| { - message.embed(|embed| make_embed_message(embed, options)) - }) - .await - { - error!("Error sending message: {:?}", why); - } -} - -pub async fn defer_message( - ctx: &Context, - command: &ApplicationCommandInteraction, - ephemeral: bool, -) { - if let Err(why) = command - .create_interaction_response(&ctx.http, |response| { - response - .kind(InteractionResponseType::DeferredChannelMessageWithSource) - .interaction_response_data(|message| message.ephemeral(ephemeral)) - }) - .await - { - error!("Error deferring message: {:?}", why); - } -} - -pub type CommandOutput = Pin + Send>>; -pub type CommandExecutor = fn(Context, ApplicationCommandInteraction) -> CommandOutput; -pub type ComponentExecutor = fn(Context, MessageComponentInteraction) -> CommandOutput; - -#[derive(Clone)] -pub struct CommandManager { - commands: HashMap, -} - -#[derive(Clone)] -pub struct CommandInfo { - pub name: String, - pub command_executor: CommandExecutor, - pub component_executor: Option, - pub register: fn(&mut CreateApplicationCommand) -> &mut CreateApplicationCommand, -} - -impl CommandManager { - pub fn new() -> Self { - let mut instance = Self { - commands: HashMap::new(), - }; - - // Debug-only commands - #[cfg(debug_assertions)] - { - instance.insert(ping::NAME, ping::register, ping::command, None); - instance.insert(token::NAME, token::register, token::command, None); - } - - // Core commands - instance.insert( - core::help::NAME, - core::help::register, - core::help::command, - None, - ); - instance.insert( - core::version::NAME, - core::version::register, - core::version::command, - None, - ); - instance.insert( - core::link::NAME, - core::link::register, - core::link::command, - None, - ); - instance.insert( - core::unlink::NAME, - core::unlink::register, - core::unlink::command, - None, - ); - instance.insert( - core::rename::NAME, - core::rename::register, - core::rename::command, - None, - ); - - // Music commands - instance.insert( - music::join::NAME, - music::join::register, - music::join::command, - None, - ); - instance.insert( - music::leave::NAME, - music::leave::register, - music::leave::command, - None, - ); - instance.insert( - music::playing::NAME, - music::playing::register, - music::playing::command, - Some(music::playing::component), - ); - - instance - } - - pub fn insert( - &mut self, - name: impl Into, - register: fn(&mut CreateApplicationCommand) -> &mut CreateApplicationCommand, - command_executor: CommandExecutor, - component_executor: Option, - ) { - let name = name.into(); - - self.commands.insert( - name.clone(), - CommandInfo { - name, - register, - command_executor, - component_executor, - }, - ); - } - - pub async fn register(&self, ctx: &Context) { - let cmds = &self.commands; - - debug!( - "Registering {} command{}", - cmds.len(), - if cmds.len() == 1 { "" } else { "s" } - ); - - fn _register_commands<'a>( - cmds: &HashMap, - mut commands: &'a mut CreateApplicationCommands, - ) -> &'a mut CreateApplicationCommands { - for command_info in cmds.values() { - commands = commands.create_application_command(|command| (command_info.register)(command)); - } - - commands - } - - if let Ok(guild_id) = std::env::var("GUILD_ID") { - if let Ok(guild_id) = guild_id.parse::() { - let guild_id = GuildId(guild_id); - guild_id - .set_application_commands(&ctx.http, |command| _register_commands(cmds, command)) - .await - .expect("Failed to create guild commands"); - - return; - } - } - - Command::set_global_application_commands(&ctx.http, |command| { - _register_commands(cmds, command) - }) - .await - .expect("Failed to create global commands"); - } - - // On slash command interaction - pub async fn execute_command(&self, ctx: &Context, interaction: ApplicationCommandInteraction) { - let command = self.commands.get(&interaction.data.name); - - if let Some(command) = command { - (command.command_executor)(ctx.clone(), interaction.clone()).await; - } else { - // Command does not exist - if let Err(why) = interaction - .create_interaction_response(&ctx.http, |response| { - response - .kind(InteractionResponseType::ChannelMessageWithSource) - .interaction_response_data(|message| { - message - .content("Woops, that command doesn't exist") - .ephemeral(true) - }) - }) - .await - { - error!("Failed to respond to command: {}", why); - } - } - } - - // On message component interaction (e.g. button) - pub async fn execute_component(&self, ctx: &Context, interaction: MessageComponentInteraction) { - let command = match interaction.data.custom_id.split("::").next() { - Some(command) => command, - None => return, - }; - - let command = self.commands.get(command); - - if let Some(command) = command { - if let Some(executor) = command.component_executor { - executor(ctx.clone(), interaction.clone()).await; - - return; - } - } - - if let Err(why) = interaction - .create_interaction_response(&ctx.http, |response| { - response - .kind(InteractionResponseType::ChannelMessageWithSource) - .interaction_response_data(|message| { - message - .content("Woops, that interaction doesn't exist") - .ephemeral(true) - }) - }) - .await - { - error!("Failed to respond to interaction: {}", why); - } - } -} - -impl TypeMapKey for CommandManager { - type Value = CommandManager; -} +pub use ping::ping; +pub use token::token; diff --git a/src/bot/commands/music/join.rs b/src/bot/commands/music/join.rs index e3cda26..14105bd 100644 --- a/src/bot/commands/music/join.rs +++ b/src/bot/commands/music/join.rs @@ -1,339 +1,305 @@ use log::error; -use serenity::{ - builder::CreateApplicationCommand, - model::prelude::{interaction::application_command::ApplicationCommandInteraction, Channel}, - prelude::Context, -}; +use poise::serenity_prelude::{model::prelude::Channel, Error}; use crate::{ - bot::commands::{defer_message, respond_message, update_message, CommandOutput}, - consts::SPOTICORD_ACCOUNTS_URL, - session::manager::{SessionCreateError, SessionManager}, - utils::embed::{EmbedBuilder, Status}, + bot::Context, consts::SPOTICORD_ACCOUNTS_URL, session::manager::SessionCreateError, + utils::embed::Color, }; -pub const NAME: &str = "join"; - -pub fn command(ctx: Context, command: ApplicationCommandInteraction) -> CommandOutput { - Box::pin(async move { - let guild = ctx - .cache - .guild(command.guild_id.expect("to contain a value")) - .expect("to be present"); - - // Get the voice channel id of the calling user - let channel_id = match guild - .voice_states - .get(&command.user.id) - .and_then(|state| state.channel_id) - { - Some(channel_id) => channel_id, - None => { - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .title("Cannot join voice channel") +/// Request the bot to join the current voice channel +#[poise::command(slash_command)] +pub async fn join(ctx: Context<'_>) -> Result<(), Error> { + let Some(guild) = ctx.guild() else { + ctx + .send(|b| { + b.embed(|e| { + e.description("You can only execute this command inside of a server") + .color(Color::Error) + }) + }) + .await?; + + return Ok(()); + }; + + let Some(channel) = guild + .voice_states + .get(&ctx.author().id) + .and_then(|state| state.channel_id) + else { + ctx + .send(|b| { + b.embed(|e| { + e.title("Cannot join voice channel") .description("You need to connect to a voice channel") - .status(Status::Error) - .build(), - true, - ) - .await; + .color(Color::Error) + }) + .ephemeral(true) + }) + .await?; + + return Ok(()); + }; + + // Check for Voice Channel permissions + { + let channel = match channel.to_channel(&ctx).await { + Ok(Channel::Guild(channel)) => channel, + Ok(_) => { + ctx + .send(|b| { + b.embed(|e| { + e.title("Cannot join voice channel") + .description("The voice channel you are in is not supported") + .color(Color::Error) + }) + .ephemeral(true) + }) + .await?; - return; + return Ok(()); + } + + Err(why) => { + error!("Failed to get channel: {why}"); + + ctx + .send(|b| { + b.embed(|e| { + e.title("Cannot join voice channel") + .description("The voice channel you are in is not available.\nI might not the permission to see this channel.") + .color(Color::Error) + }) + .ephemeral(true) + }) + .await?; + + return Ok(()); } }; - // Check for Voice Channel permissions + if let Ok(permissions) = + channel.permissions_for_user(ctx.cache(), ctx.cache().current_user_id()) { - let channel = match channel_id.to_channel(&ctx).await { - Ok(channel) => match channel { - Channel::Guild(channel) => channel, - _ => { - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .title("Cannot join voice channel") - .description("The voice channel you are in is not supported") - .status(Status::Error) - .build(), - true, - ) - .await; - - return; - } - }, - Err(why) => { - error!("Failed to get channel: {}", why); - - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .title("Cannot join voice channel") - .description("The voice channel you are in is not available.\nI might not the permission to see this channel.") - .status(Status::Error) - .build(), - true, - ) - .await; - - return; - } - }; - - if let Ok(permissions) = channel.permissions_for_user(&ctx.cache, ctx.cache.current_user_id()) - { - if !permissions.view_channel() || !permissions.connect() || !permissions.speak() { - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .title("Cannot join voice channel") - .description("I do not have the permissions to connect to that voice channel") - .status(Status::Error) - .build(), - true, - ) - .await; - - return; - } + if !permissions.view_channel() || !permissions.connect() || !permissions.speak() { + ctx + .send(|b| { + b.embed(|e| { + e.title("Cannot join voice channel") + .description("I do not have the permissions to connect to that voice channel") + .color(Color::Error) + }) + .ephemeral(true) + }) + .await?; + + return Ok(()); } } + } + + // Check for Text Channel permissions + { + let channel = match ctx.channel_id().to_channel(&ctx).await { + Ok(Channel::Guild(channel)) => channel, + Ok(_) => { + ctx + .send(|b| { + b.embed(|e| { + e.title("Cannot join voice channel") + .description("The voice channel you are in is not supported") + .color(Color::Error) + }) + .ephemeral(true) + }) + .await?; - // Check for Text Channel permissions - { - let channel = match command.channel_id.to_channel(&ctx).await { - Ok(channel) => match channel { - Channel::Guild(channel) => channel, - _ => { - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .title("Cannot join voice channel") - .description("The text channel you are in is not supported") - .status(Status::Error) - .build(), - true, - ) - .await; - - return; - } - }, - Err(why) => { - error!("Failed to get channel: {}", why); - - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .title("Cannot join voice channel") - .description("The text channel you are in is not available.\nI might not have the permission to see this channel.") - .status(Status::Error) - .build(), - true, - ) - .await; - - return; - } - }; - - if let Ok(permissions) = channel.permissions_for_user(&ctx.cache, ctx.cache.current_user_id()) - { - if !permissions.view_channel() || !permissions.send_messages() || !permissions.embed_links() - { - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .title("Cannot join voice channel") - .description( - "I do not have the permissions to send messages / links in this text channel", - ) - .status(Status::Error) - .build(), - true, - ) - .await; - - return; - } + return Ok(()); } - } + Err(why) => { + error!("Failed to get channel: {why}"); - let data = ctx.data.read().await; - let session_manager = data - .get::() - .expect("to contain a value") - .clone(); - - // Check if another session is already active in this server - let mut session_opt = session_manager.get_session(&guild.id).await; - - if let Some(session) = &session_opt { - if let Some(owner) = session.owner().await { - let msg = if owner == command.user.id { - "You are already controlling the bot" - } else { - "The bot is currently being controlled by someone else" - }; - - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .title("Cannot join voice channel") - .description(msg) - .status(Status::Error) - .build(), - true, - ) - .await; - - return; + ctx + .send(|b| { + b.embed(|e| { + e.title("Cannot join voice channel") + .description("The voice channel you are in is not available.\nI might not the permission to see this channel.") + .color(Color::Error) + }) + .ephemeral(true) + }) + .await?; + + return Ok(()); } }; - // Prevent duplicate Spotify sessions - if let Some(session) = session_manager.find(command.user.id).await { - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .title("Cannot join voice channel") - .description( - format!( - "You are already playing music in another server ({}).\nStop playing in that server first before joining this one.", - ctx.cache.guild(session.guild_id().await).expect("to be present").name - )).status(Status::Error).build(), - true, - ) - .await; - - return; + if let Ok(permissions) = + channel.permissions_for_user(ctx.cache(), ctx.cache().current_user_id()) + { + if !permissions.view_channel() || !permissions.send_messages() || !permissions.embed_links() { + ctx + .send(|b| { + b.embed(|e| { + e.title("Cannot join voice channel") + .description( + "I do not have the permissions to send messages / links in this text channel", + ) + .color(Color::Error) + }) + .ephemeral(true) + }) + .await?; + + return Ok(()); + } } + } - defer_message(&ctx, &command, false).await; + let sm = &ctx.data().session_manager; - if let Some(session) = &session_opt { - if session.channel_id().await != channel_id { - session.disconnect().await; - session_opt = None; + // Check if another session is already active in this server + let mut session_opt = sm.get_session(&guild.id).await; - // Give serenity/songbird some time to register the disconnect - tokio::time::sleep(std::time::Duration::from_secs(1)).await; - } + if let Some(session) = &session_opt { + if let Some(owner) = session.owner().await { + let msg = if owner == ctx.author().id { + "You are already controlling the bot" + } else { + "The bot is currently being controlled by someone else" + }; + + ctx + .send(|b| { + b.embed(|e| { + e.title("Cannot join voice channel") + .description(msg) + .color(Color::Error) + }) + .ephemeral(true) + }) + .await?; + + return Ok(()); + } + } + + // Prevent duplicate Spotify sessions + if let Some(session) = sm.find(ctx.author().id).await { + let message = format!("You are already playing music in another server ({}).\nStop playing in that server first before using the bot in this server.",ctx.cache().guild(session.guild_id().await).map(|g| g.name).unwrap_or(" { + match $why { + // User has not linked their account + SessionCreateError::NoSpotify => { + ctx + .send(|b| { + b.embed(|e| { + e.title("Cannot join voice channel") + .description(format!("You need to link your Spotify account. Use or go to [the accounts website]({}) to get started.", SPOTICORD_ACCOUNTS_URL.as_str())) + .color(Color::Error) + }) + }) + .await?; + } - macro_rules! report_error { - ($why:ident) => { - match $why { - // User has not linked their account - SessionCreateError::NoSpotify => { - update_message( - &ctx, - &command, - EmbedBuilder::new() - .title("Cannot join voice channel") - .description(format!("You need to link your Spotify account. Use or go to [the accounts website]({}) to get started.", SPOTICORD_ACCOUNTS_URL.as_str())) - .status(Status::Error) - .build(), - ) - .await; - } - - // Spotify credentials have expired or are invalid - SessionCreateError::SpotifyExpired => { - update_message( - &ctx, - &command, - EmbedBuilder::new() - .title("Cannot join voice channel") - .description(format!("Spoticord no longer has access to your Spotify account. Use or go to [the accounts website]({}) to relink your Spotify account.", SPOTICORD_ACCOUNTS_URL.as_str())) - .status(Status::Error) - .build(), - ).await; - } - - // Songbird error - SessionCreateError::JoinError(why) => { - update_message( - &ctx, - &command, - EmbedBuilder::new() - .title("Cannot join voice channel") - .description(format!( - "An error occured while joining the channel. Please try running again.\n\nError details: `{why}`" - )) - .status(Status::Error) - .build(), - ) - .await; - } - - // Any other error - _ => { - update_message( - &ctx, - &command, - EmbedBuilder::new() - .title("Cannot join voice channel") - .description("An error occured while joining the channel. Please try again later.") - .status(Status::Error) - .build(), - ) - .await; - } + SessionCreateError::SpotifyExpired => { + ctx + .send(|b| { + b.embed(|e| { + e.title("Cannot join voice channel") + .description(format!("Spoticord no longer has access to your Spotify account. Use or go to [the accounts website]({}) to relink your Spotify account.", SPOTICORD_ACCOUNTS_URL.as_str())) + .color(Color::Error) + }) + }) + .await?; } - return; - }; - } + SessionCreateError::JoinError(why) => { + ctx + .send(|b| { + b.embed(|e| { + e.title("Cannot join voice channel") + .description(format!( + "An error occured while joining the channel. Please try running again.\n\nError details: `{why}`" + )) + .color(Color::Error) + }) + }) + .await?; + } - if let Some(session) = session_opt.as_mut() { - if let Err(why) = session.update_owner(&ctx, command.user.id).await { - report_error!(why); + _ => { + ctx + .send(|b| { + b.embed(|e| { + e.title("Cannot join voice channel") + .description( + "An error occured while joining the channel. Please try again later.", + ) + .color(Color::Error) + }) + }) + .await?; + } } - } else { - // Create the session, and handle potential errors - if let Err(why) = session_manager - .create_session( - &ctx, - guild.id, - channel_id, - command.channel_id, - command.user.id, - ) - .await - { - report_error!(why); - }; - } - - update_message( - &ctx, - &command, - EmbedBuilder::new() - .title("Connected to voice channel") - .icon_url("https://spoticord.com/speaker.png") - .description(format!("Come listen along in <#{}>", channel_id)) - .footer("You must manually go to Spotify and select your device") - .status(Status::Info) - .build(), - ) - .await; - }) -} + }; + } -pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand { - command - .name(NAME) - .description("Request the bot to join the current voice channel") + if let Some(session) = session_opt.as_mut() { + if let Err(why) = session.update_owner(&ctx, ctx.author().id).await { + report_error!(why); + } + } else { + // Create the session, and handle potential errors + if let Err(why) = sm + .create_session(&ctx, guild.id, channel, ctx.channel_id(), ctx.author().id) + .await + { + report_error!(why); + }; + } + + ctx + .send(|b| { + b.embed(|e| { + e.author(|a| { + a.name("Connected to voice channel") + .icon_url("https://spoticord.com/speaker.png") + }) + .description(format!("Come listen along in <#{}>", channel)) + .footer(|f| f.text("You must manually go to Spotify and select your device")) + .color(Color::Info) + }) + }) + .await?; + + Ok(()) } diff --git a/src/bot/commands/music/leave.rs b/src/bot/commands/music/leave.rs index 1e834fe..e14fe19 100644 --- a/src/bot/commands/music/leave.rs +++ b/src/bot/commands/music/leave.rs @@ -1,82 +1,53 @@ -use serenity::{ - builder::CreateApplicationCommand, - model::prelude::interaction::application_command::ApplicationCommandInteraction, - prelude::Context, -}; - -use crate::{ - bot::commands::{respond_message, CommandOutput}, - session::manager::SessionManager, - utils::embed::{EmbedBuilder, Status}, -}; - -pub const NAME: &str = "leave"; - -pub fn command(ctx: Context, command: ApplicationCommandInteraction) -> CommandOutput { - Box::pin(async move { - let data = ctx.data.read().await; - let session_manager = data - .get::() - .expect("to contain a value") - .clone(); - - let session = match session_manager - .get_session(&command.guild_id.expect("to contain a value")) - .await - { - Some(session) => session, - None => { - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .title("Cannot disconnect bot") +use poise::serenity_prelude::Error; + +use crate::{bot::Context, utils::embed::Color}; + +/// Request the bot to leave the current voice channel +#[poise::command(slash_command)] +pub async fn leave(ctx: Context<'_>) -> Result<(), Error> { + let sm = &ctx.data().session_manager; + + let Some(session) = sm + .get_session(&ctx.guild_id().expect("to contain a value")) + .await + else { + ctx + .send(|b| { + b.embed(|f| { + f.title("Cannot disconnect bot") .description("I'm currently not connected to any voice channel") - .status(Status::Error) - .build(), - true, - ) - .await; - - return; - } - }; - - if let Some(owner) = session.owner().await { - if owner != command.user.id { - // This message was generated by AI, and I love it. - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .description("You are not the one who summoned me") - .status(Status::Error) - .build(), - true, - ) - .await; - - return; - }; + .color(Color::Error) + }) + .ephemeral(true) + }) + .await?; + return Ok(()); + }; + + if let Some(owner) = session.owner().await { + if owner != ctx.author().id { + ctx + .send(|b| { + b.embed(|f| { + f.description("You are not the one who summoned me") + .color(Color::Error) + }) + .ephemeral(true) + }) + .await?; } + } - session.disconnect().await; + session.disconnect().await; - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .description("I have left the voice channel, goodbye for now") - .status(Status::Info) - .build(), - false, - ) - .await; - }) -} + ctx + .send(|b| { + b.embed(|f| { + f.description("I have left the voice channel, goodbye for now") + .color(Color::Info) + }) + }) + .await?; -pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand { - command - .name(NAME) - .description("Request the bot to leave the current voice channel") + Ok(()) } diff --git a/src/bot/commands/music/mod.rs b/src/bot/commands/music/mod.rs index 88ecafd..a699b9a 100644 --- a/src/bot/commands/music/mod.rs +++ b/src/bot/commands/music/mod.rs @@ -1,3 +1,7 @@ pub mod join; pub mod leave; pub mod playing; + +pub use join::*; +pub use leave::*; +pub use playing::*; diff --git a/src/bot/commands/music/playing.rs b/src/bot/commands/music/playing.rs index 7023442..6b775a8 100644 --- a/src/bot/commands/music/playing.rs +++ b/src/bot/commands/music/playing.rs @@ -1,410 +1,101 @@ -use std::time::Duration; - use librespot::core::spotify_id::SpotifyId; use log::error; -use serenity::{ - builder::{CreateApplicationCommand, CreateButton, CreateComponents, CreateEmbed}, - model::{ - prelude::{ - component::ButtonStyle, - interaction::{ - application_command::ApplicationCommandInteraction, - message_component::MessageComponentInteraction, InteractionResponseType, - }, - }, - user::User, - }, - prelude::Context, -}; +use poise::serenity_prelude::{builder::CreateEmbed, Error, User}; use crate::{ - bot::commands::{respond_component_message, respond_message, CommandOutput}, - session::{manager::SessionManager, pbi::PlaybackInfo}, - utils::{ - self, - embed::{EmbedBuilder, Status}, - }, + bot::Context, + session::pbi::PlaybackInfo, + utils::{self, embed::Color}, }; -pub const NAME: &str = "playing"; - -pub fn command(ctx: Context, command: ApplicationCommandInteraction) -> CommandOutput { - Box::pin(async move { - macro_rules! not_playing { - () => { - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .title("Cannot get track info") - .icon_url("https://spoticord.com/forbidden.png") - .description("I'm currently not playing any music in this server") - .status(Status::Error) - .build(), - true, - ) - .await; - }; - } - - let data = ctx.data.read().await; - let session_manager = data - .get::() - .expect("to contain a value") - .clone(); - - let Some(session) = session_manager - .get_session(&command.guild_id.expect("to contain a value")) - .await - else { - not_playing!(); - - return; - }; - - let Some(owner) = session.owner().await else { - not_playing!(); - - return; - }; - - // Get Playback Info from session - let Some(pbi) = session.playback_info().await else { - not_playing!(); - - return; - }; - - // Get owner of session - let Some(owner) = utils::discord::get_user(&ctx, owner).await else { - // This shouldn't happen - - error!("Could not find user with ID: {owner}"); - - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .title("[INTERNAL ERROR] Cannot get track info") - .description(format!( - "Could not find user with ID `{}`\nThis is an issue with the bot!", - owner - )) - .status(Status::Error) - .build(), - true, - ) - .await; - - return; - }; - - // Get metadata - let (title, description, thumbnail) = get_metadata(&pbi); - - if let Err(why) = command - .create_interaction_response(&ctx.http, |response| { - response - .kind(InteractionResponseType::ChannelMessageWithSource) - .interaction_response_data(|message| { - message - .set_embed(build_playing_embed( - title, - pbi.get_type(), - pbi.spotify_id, - description, - owner, - thumbnail, - )) - .components(|components| create_button(components, pbi.is_playing)) - }) - }) - .await - { - error!("Error sending message: {why:?}"); - } - }) -} - -pub fn component(ctx: Context, mut interaction: MessageComponentInteraction) -> CommandOutput { - Box::pin(async move { - let error_message = |title: &'static str, description: &'static str| async { - respond_component_message( - &ctx, - &interaction, - EmbedBuilder::new() - .title(title.to_string()) - .icon_url("https://spoticord.com/forbidden.png") - .description(description.to_string()) - .status(Status::Error) - .build(), - true, - ) - .await; - }; - - let error_edit = |title: &'static str, description: &'static str| { - let mut interaction = interaction.clone(); - let ctx = ctx.clone(); - - async move { - interaction.defer(&ctx.http).await.ok(); - - if let Err(why) = interaction - .message - .edit(&ctx, |message| { - message.embed(|embed| { - embed - .description(description) - .author(|author| { - author - .name(title) - .icon_url("https://spoticord.com/forbidden.png") - }) - .color(Status::Error) +/// Display which song is currently being played +#[poise::command(slash_command)] +pub async fn playing(ctx: Context<'_>) -> Result<(), Error> { + macro_rules! not_playing { + () => { + ctx + .send(|b| { + b.embed(|e| { + e.author(|a| { + a.name("Cannot get track info") + .icon_url("https://spoticord.com/forbidden.png") }) + .description("I'm currently not playing any music in this server") + .color(Color::Error) }) - .await - { - error!("Failed to update playing message: {why}"); - } - } - }; - - let data = ctx.data.read().await; - let session_manager = data - .get::() - .expect("to contain a value") - .clone(); - - // Check if session still exists - let Some(mut session) = session_manager - .get_session(&interaction.guild_id.expect("to contain a value")) - .await - else { - error_edit( - "Cannot perform action", - "I'm currently not playing any music in this server", - ) - .await; - - return; - }; - - // Check if the session contains an owner - let Some(owner) = session.owner().await else { - error_edit( - "Cannot change playback state", - "I'm currently not playing any music in this server", - ) - .await; - - return; - }; - - // Get Playback Info from session - let Some(pbi) = session.playback_info().await else { - error_edit( - "Cannot change playback state", - "I'm currently not playing any music in this server", - ) - .await; - - return; - }; - - // Check if the user is the owner of the session - if owner != interaction.user.id { - error_message( - "Cannot change playback state", - "You must be the host to use the media buttons", - ) - .await; - - return; - } - - // Get owner of session - let Some(owner) = utils::discord::get_user(&ctx, owner).await else { - // This shouldn't happen - - error!("Could not find user with ID: {owner}"); - - respond_component_message( - &ctx, - &interaction, - EmbedBuilder::new() - .title("[INTERNAL ERROR] Cannot get track info") - .description(format!( - "Could not find user with ID `{}`\nThis is an issue with the bot!", - owner - )) - .status(Status::Error) - .build(), - true, - ) - .await; - - return; - }; - - // Send the desired command to the session - match interaction.data.custom_id.as_str() { - "playing::btn_pause_play" => { - if pbi.is_playing { - session.pause().await - } else { - session.resume().await - } - } - - "playing::btn_previous_track" => session.previous().await, - - "playing::btn_next_track" => session.next().await, + .ephemeral(true) + }) + .await?; - _ => { - error!("Unknown custom_id: {}", interaction.data.custom_id); - } + return Ok(()); }; + } - interaction.defer(&ctx.http).await.ok(); - tokio::time::sleep(Duration::from_millis( - if interaction.data.custom_id == "playing::btn_pause_play" { - 0 - } else { - 2500 - }, - )) - .await; - update_embed(&mut interaction, &ctx, owner).await; - }) -} - -pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand { - command - .name(NAME) - .description("Display which song is currently being played") -} - -fn create_button(components: &mut CreateComponents, playing: bool) -> &mut CreateComponents { - let mut prev_btn = CreateButton::default(); - prev_btn - .style(ButtonStyle::Primary) - .label("<<") - .custom_id("playing::btn_previous_track"); - - let mut toggle_btn = CreateButton::default(); - toggle_btn - .style(ButtonStyle::Secondary) - .label(if playing { "Pause" } else { "Play" }) - .custom_id("playing::btn_pause_play"); - - let mut next_btn = CreateButton::default(); - next_btn - .style(ButtonStyle::Primary) - .label(">>") - .custom_id("playing::btn_next_track"); - - components.create_action_row(|ar| { - ar.add_button(prev_btn) - .add_button(toggle_btn) - .add_button(next_btn) - }) -} - -async fn update_embed(interaction: &mut MessageComponentInteraction, ctx: &Context, owner: User) { - let error_edit = |title: &'static str, description: &'static str| { - let mut interaction = interaction.clone(); - let ctx = ctx.clone(); - - async move { - interaction.defer(&ctx.http).await.ok(); - - if let Err(why) = interaction - .message - .edit(&ctx, |message| { - message.embed(|embed| { - embed - .description(description) - .author(|author| { - author - .name(title) - .icon_url("https://spoticord.com/forbidden.png") - }) - .color(Status::Error) - }) + let Some(guild) = ctx.guild() else { + ctx + .send(|b| { + b.embed(|e| { + e.description("You can only execute this command inside of a server") + .color(Color::Error) }) - .await - { - error!("Failed to update playing message: {why}"); - } - } + }) + .await?; + + return Ok(()); }; - let data = ctx.data.read().await; - let session_manager = data - .get::() - .expect("to contain a value") - .clone(); + let sm = &ctx.data().session_manager; - // Check if session still exists - let Some(session) = session_manager - .get_session(&interaction.guild_id.expect("to contain a value")) - .await - else { - error_edit( - "Cannot perform action", - "I'm currently not playing any music in this server", - ) - .await; + let Some(session) = sm.get_session(&guild.id).await else { + not_playing!(); + }; - return; + let Some(owner) = session.owner().await else { + not_playing!(); }; - // Get Playback Info from session + // Get playback Info from session let Some(pbi) = session.playback_info().await else { - error_edit( - "Cannot change playback state", - "I'm currently not playing any music in this server", - ) - .await; - - return; + not_playing!(); }; + // Get owner of session as User + let owner = owner.to_user(&ctx).await?; + + // Get metadata let (title, description, thumbnail) = get_metadata(&pbi); - if let Err(why) = interaction - .message - .edit(&ctx, |message| { - message - .set_embed(build_playing_embed( + if let Err(why) = ctx + .send(|b| { + b.embed(|e| { + build_playing_embed( + e, title, pbi.get_type(), pbi.spotify_id, description, owner, thumbnail, - )) - .components(|components| create_button(components, pbi.is_playing)); - - message + ) + }) }) .await { - error!("Failed to update playing message: {why}"); + error!("Error sending message: {why}"); } + + Ok(()) } fn build_playing_embed( + embed: &mut CreateEmbed, title: impl Into, audio_type: impl Into, spotify_id: SpotifyId, description: impl Into, owner: User, thumbnail: impl Into, -) -> CreateEmbed { - let mut embed = CreateEmbed::default(); +) -> &mut CreateEmbed { embed .author(|author| { author @@ -422,7 +113,7 @@ fn build_playing_embed( .description(description.into()) .footer(|footer| footer.text(&owner.name).icon_url(owner.face())) .thumbnail(thumbnail.into()) - .color(Status::Info); + .color(Color::Info); embed } diff --git a/src/bot/commands/ping.rs b/src/bot/commands/ping.rs index 1807889..bf7982e 100644 --- a/src/bot/commands/ping.rs +++ b/src/bot/commands/ping.rs @@ -1,33 +1,12 @@ +use crate::bot::Context; use log::info; -use serenity::{ - builder::CreateApplicationCommand, - model::prelude::interaction::{ - application_command::ApplicationCommandInteraction, InteractionResponseType, - }, - prelude::Context, -}; +use poise::serenity_prelude::Error; -use super::CommandOutput; +/// Check if the bot is alive +#[poise::command(slash_command)] +pub async fn ping(ctx: Context<'_>) -> Result<(), Error> { + info!("Pong!"); + ctx.send(|reply| reply.content("Pong!").reply(true)).await?; -pub const NAME: &str = "ping"; - -pub fn command(ctx: Context, command: ApplicationCommandInteraction) -> CommandOutput { - Box::pin(async move { - info!("Pong!"); - - command - .create_interaction_response(&ctx.http, |response| { - response - .kind(InteractionResponseType::ChannelMessageWithSource) - .interaction_response_data(|message| message.content("Pong!")) - }) - .await - .ok(); - }) -} - -pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand { - command - .name("ping") - .description("Check if the bot is alive") + Ok(()) } diff --git a/src/bot/commands/token.rs b/src/bot/commands/token.rs index 6c6977c..95a03a5 100644 --- a/src/bot/commands/token.rs +++ b/src/bot/commands/token.rs @@ -1,42 +1,21 @@ -use serenity::{ - builder::CreateApplicationCommand, - model::prelude::interaction::{ - application_command::ApplicationCommandInteraction, InteractionResponseType, - }, - prelude::Context, -}; - -use crate::database::Database; - -use super::CommandOutput; - -pub const NAME: &str = "token"; - -pub fn command(ctx: Context, command: ApplicationCommandInteraction) -> CommandOutput { - Box::pin(async move { - let data = ctx.data.read().await; - let db = data.get::().expect("to contain a value"); - - let token = db.get_access_token(command.user.id.to_string()).await; - - let content = match token { - Ok(token) => format!("Your token is: {}", token), - Err(why) => format!("You don't have a token yet. (Real: {})", why), - }; - - command - .create_interaction_response(&ctx.http, |response| { - response - .kind(InteractionResponseType::ChannelMessageWithSource) - .interaction_response_data(|message| message.content(content).ephemeral(true)) - }) - .await - .ok(); - }) -} - -pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand { - command - .name("token") - .description("Get your Spotify access token") +use crate::bot::Context; +use poise::serenity_prelude::Error; + +/// Get your Spotify access token +#[poise::command(slash_command)] +pub async fn token(ctx: Context<'_>) -> Result<(), Error> { + let token = ctx + .data() + .database + .get_access_token(ctx.author().id.to_string()) + .await; + + let content = match token { + Ok(token) => format!("Your token is: {}", token), + Err(why) => format!("You don't have a token yet. (Real: {})", why), + }; + + ctx.send(|b| b.content(content).ephemeral(true)).await?; + + Ok(()) } diff --git a/src/bot/events.rs b/src/bot/events.rs deleted file mode 100644 index f70639a..0000000 --- a/src/bot/events.rs +++ /dev/null @@ -1,136 +0,0 @@ -/* This file implements all events for the Discord gateway */ - -use super::commands::CommandManager; -use crate::consts::MOTD; -use log::*; -use serenity::{ - async_trait, - model::prelude::{ - interaction::{ - application_command::ApplicationCommandInteraction, - message_component::MessageComponentInteraction, Interaction, - }, - Activity, GuildId, Ready, - }, - prelude::{Context, EventHandler}, -}; - -// If the GUILD_ID environment variable is set, only allow commands from that guild -macro_rules! enforce_guild { - ($interaction:ident) => { - if let Ok(guild_id) = std::env::var("GUILD_ID") { - if let Ok(guild_id) = guild_id.parse::() { - let guild_id = GuildId(guild_id); - - if let Some(interaction_guild_id) = $interaction.guild_id { - if guild_id != interaction_guild_id { - return; - } - } - } - } - }; -} - -// Handler struct with a command parameter, an array of dictionary which takes a string and function -pub struct Handler; - -#[async_trait] -impl EventHandler for Handler { - // READY event, emitted when the bot/shard starts up - async fn ready(&self, ctx: Context, ready: Ready) { - let data = ctx.data.read().await; - let command_manager = data.get::().expect("to contain a value"); - - debug!("Ready received, logged in as {}", ready.user.name); - - command_manager.register(&ctx).await; - - ctx.set_activity(Activity::listening(MOTD)).await; - - info!("{} has come online", ready.user.name); - } - - // INTERACTION_CREATE event, emitted when the bot receives an interaction (slash command, button, etc.) - async fn interaction_create(&self, ctx: Context, interaction: Interaction) { - match interaction { - Interaction::ApplicationCommand(command) => handle_command(ctx, command).await, - Interaction::MessageComponent(component) => handle_component(ctx, component).await, - _ => {} - } - } -} - -async fn handle_command(ctx: Context, command: ApplicationCommandInteraction) { - enforce_guild!(command); - - // Commands must only be executed inside of guilds - - let guild_id = match command.guild_id { - Some(guild_id) => guild_id, - None => { - if let Err(why) = command - .create_interaction_response(&ctx.http, |response| { - response - .kind(serenity::model::prelude::interaction::InteractionResponseType::ChannelMessageWithSource) - .interaction_response_data(|message| { - message.content("You can only execute commands inside of a server") - }) - }) - .await { - error!("Failed to send run-in-guild-only error message: {}", why); - } - - return; - } - }; - - trace!( - "Received command interaction: command={} user={} guild={}", - command.data.name, - command.user.id, - guild_id - ); - - let data = ctx.data.read().await; - let command_manager = data.get::().expect("to contain a value"); - - command_manager.execute_command(&ctx, command).await; -} - -async fn handle_component(ctx: Context, component: MessageComponentInteraction) { - enforce_guild!(component); - - // Components can only be interacted with inside of guilds - - let guild_id = match component.guild_id { - Some(guild_id) => guild_id, - None => { - if let Err(why) = component - .create_interaction_response(&ctx.http, |response| { - response - .kind(serenity::model::prelude::interaction::InteractionResponseType::ChannelMessageWithSource) - .interaction_response_data(|message| { - message.content("You can only interact with components inside of a server") - }) - }) - .await { - error!("Failed to send run-in-guild-only error message: {}", why); - } - - return; - } - }; - - trace!( - "Received component interaction: command={} user={} guild={}", - component.data.custom_id, - component.user.id, - guild_id - ); - - let data = ctx.data.read().await; - let command_manager = data.get::().expect("to contain a value"); - - command_manager.execute_component(&ctx, component).await; -} diff --git a/src/bot/mod.rs b/src/bot/mod.rs index 2bddc4f..dcb35c9 100644 --- a/src/bot/mod.rs +++ b/src/bot/mod.rs @@ -1,2 +1,132 @@ pub mod commands; -pub mod events; + +use crate::{consts::MOTD, database::Database, session::manager::SessionManager}; +use log::{debug, info}; +use poise::{ + serenity_prelude::{Activity, Error, GatewayIntents, ShardManager}, + FrameworkOptions, +}; +use std::{any::Any, sync::Arc}; +use tokio::sync::Mutex; + +#[cfg(feature = "stats")] +use crate::stats::StatsManager; + +#[cfg(feature = "stats")] +use log::error; + +#[cfg(unix)] +use tokio::signal::unix::SignalKind; + +pub type Context<'a> = poise::ApplicationContext<'a, Data, Error>; + +pub struct Data { + pub database: Database, + pub session_manager: SessionManager, +} + +pub fn get_framework_intents() -> GatewayIntents { + GatewayIntents::GUILDS | GatewayIntents::GUILD_VOICE_STATES +} + +pub fn get_framework_opts() -> FrameworkOptions { + poise::FrameworkOptions { + commands: vec![ + #[cfg(debug_assertions)] + commands::ping(), + #[cfg(debug_assertions)] + commands::token(), + commands::core::help(), + commands::core::link(), + commands::core::rename(), + commands::core::unlink(), + commands::core::version(), + commands::music::join(), + commands::music::leave(), + commands::music::playing(), + ], + event_handler: |_ctx, event, _framework, _data| { + Box::pin(event_handler(_ctx, event, _framework, _data)) + }, + ..Default::default() + } +} + +pub async fn background_loop( + session_manager: SessionManager, + #[cfg(feature = "stats")] stats_manager: StatsManager, + shard_manager: Arc>, +) { + #[cfg(unix)] + let mut term: Option> = Some(Box::new( + tokio::signal::unix::signal(SignalKind::terminate()) + .expect("to be able to create the signal stream"), + )); + + #[cfg(not(unix))] + let term: Option> = None; + + loop { + tokio::select! { + _ = tokio::time::sleep(std::time::Duration::from_secs(60)) => { + #[cfg(feature = "stats")] + { + let active_count = session_manager.get_active_session_count().await; + + if let Err(why) = stats_manager.set_active_count(active_count) { + error!("Failed to update active count: {why}"); + } + } + } + + _ = tokio::signal::ctrl_c() => { + info!("Received interrupt signal, shutting down..."); + + session_manager.shutdown().await; + shard_manager.lock().await.shutdown_all().await; + + break; + } + + _ = async { + #[cfg(unix)] + match term { + Some(ref mut term) => { + let term = term.downcast_mut::().expect("to be able to downcast"); + + term.recv().await + } + + _ => None + } + }, if term.is_some() => { + info!("Received terminate signal, shutting down..."); + + session_manager.shutdown().await; + shard_manager.lock().await.shutdown_all().await; + + break; + } + } + } +} + +async fn event_handler( + ctx: &poise::serenity_prelude::Context, + event: &poise::Event<'_>, + _framework: poise::FrameworkContext<'_, Data, poise::serenity_prelude::Error>, + _data: &Data, +) -> Result<(), poise::serenity_prelude::Error> { + if let poise::Event::Ready { + data_about_bot: ready, + } = event + { + debug!("Ready received, logged in as {}", ready.user.name); + + ctx.set_activity(Activity::listening(MOTD)).await; + + info!("{} has come online", ready.user.name); + } + + Ok(()) +} diff --git a/src/database.rs b/src/database.rs index a433894..c5d95f3 100644 --- a/src/database.rs +++ b/src/database.rs @@ -4,7 +4,6 @@ use log::trace; use reqwest::{header::HeaderMap, Client, Error, Response, StatusCode}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde_json::{json, Value}; -use serenity::prelude::TypeMapKey; use crate::utils; @@ -68,14 +67,14 @@ struct RequestOptions { } #[derive(Debug, Clone)] -#[allow(dead_code)] +#[allow(unused)] enum Body { Json(Value), Text(String), } #[derive(Debug, Clone)] -#[allow(dead_code)] +#[allow(unused)] enum Method { Get, Post, @@ -199,52 +198,54 @@ impl Database { impl Database { // Get Spoticord user - pub async fn get_user(&self, user_id: impl Into) -> Result { - let path = format!("/user/{}", user_id.into()); + pub async fn get_user(&self, user_id: impl AsRef) -> Result { + let path = format!("/user/{}", user_id.as_ref()); self.simple_get(path).await } + pub async fn get_or_create_user(&self, user_id: impl AsRef) -> Result { + let user_id = user_id.as_ref(); + + let result = self.get_user(user_id).await; + if let Err(DatabaseError::InvalidStatusCode(StatusCode::NOT_FOUND)) = result { + return self.create_user(user_id).await; + } + + result + } + // Get the Spotify access token for a user - pub async fn get_access_token( - &self, - user_id: impl Into + Send, - ) -> Result { + pub async fn get_access_token(&self, user_id: impl AsRef) -> Result { let body: GetAccessTokenResponse = self - .simple_get(format!("/user/{}/spotify/access_token", user_id.into())) + .simple_get(format!("/user/{}/spotify/access_token", user_id.as_ref())) .await?; Ok(body.access_token) } // Get the Spotify account for a user - pub async fn get_user_account( - &self, - user_id: impl Into + Send, - ) -> Result { + pub async fn get_user_account(&self, user_id: impl AsRef) -> Result { let body: Account = self - .simple_get(format!("/account/{}/spotify", user_id.into())) + .simple_get(format!("/account/{}/spotify", user_id.as_ref())) .await?; Ok(body) } // Get the Request for a user - pub async fn get_user_request( - &self, - user_id: impl Into + Send, - ) -> Result { + pub async fn get_user_request(&self, user_id: impl AsRef) -> Result { let body: Request = self - .simple_get(format!("/request/by-user/{}", user_id.into())) + .simple_get(format!("/request/by-user/{}", user_id.as_ref())) .await?; Ok(body) } // Create a Spoticord user - pub async fn create_user(&self, user_id: impl Into) -> Result { + pub async fn create_user(&self, user_id: impl AsRef) -> Result { let body = json!({ - "id": user_id.into(), + "id": user_id.as_ref(), }); let user: User = self.json_post(body, "/user/new").await?; @@ -288,14 +289,11 @@ impl Database { Ok(body) } - pub async fn delete_user_account( - &self, - user_id: impl Into + Send, - ) -> Result<(), DatabaseError> { + pub async fn delete_user_account(&self, user_id: impl AsRef) -> Result<(), DatabaseError> { let response = match self .request(RequestOptions { method: Method::Delete, - path: format!("/account/{}/spotify", user_id.into()), + path: format!("/account/{}/spotify", user_id.as_ref()), body: None, headers: None, }) @@ -315,10 +313,10 @@ impl Database { pub async fn update_user_device_name( &self, - user_id: impl Into, - name: impl Into, + user_id: impl AsRef, + name: impl AsRef, ) -> Result<(), DatabaseError> { - let device_name: String = name.into(); + let device_name = name.as_ref(); if device_name.len() > 16 || device_name.is_empty() { return Err(DatabaseError::InvalidInputBody( @@ -331,7 +329,7 @@ impl Database { let response = match self .request(RequestOptions { method: Method::Patch, - path: format!("/user/{}", user_id.into()), + path: format!("/user/{}", user_id.as_ref()), body: Some(Body::Json(body)), headers: None, }) @@ -349,7 +347,3 @@ impl Database { } } } - -impl TypeMapKey for Database { - type Value = Database; -} diff --git a/src/main.rs b/src/main.rs index 8f5e025..dd06daf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,23 +1,18 @@ -use dotenvy::dotenv; - #[cfg(feature = "stats")] use crate::consts::KV_URL; use crate::{ - bot::commands::CommandManager, + bot::Data, consts::{DATABASE_URL, DISCORD_TOKEN, MOTD}, database::Database, session::manager::SessionManager, }; +use dotenvy::dotenv; use log::*; -use serenity::{framework::StandardFramework, prelude::GatewayIntents, Client}; +use poise::FrameworkBuilder; use songbird::SerenityInit; -use std::{any::Any, process::exit}; +use std::process::exit; -#[cfg(unix)] -use tokio::signal::unix::SignalKind; - -mod audio; mod bot; mod consts; mod database; @@ -64,89 +59,38 @@ async fn main() { #[cfg(feature = "stats")] let stats_manager = StatsManager::new(KV_URL.as_str()).expect("Failed to connect to redis"); - let session_manager = SessionManager::new(); + let database = Database::new(DATABASE_URL.as_str(), None); // Create client - let mut client = Client::builder( - DISCORD_TOKEN.as_str(), - GatewayIntents::GUILDS | GatewayIntents::GUILD_VOICE_STATES, - ) - .event_handler(crate::bot::events::Handler) - .framework(StandardFramework::new()) - .register_songbird() - .await - .expect("to create a client"); - - { - let mut data = client.data.write().await; - - data.insert::(Database::new(DATABASE_URL.as_str(), None)); - data.insert::(CommandManager::new()); - data.insert::(session_manager.clone()); - } - - let shard_manager = client.shard_manager.clone(); - - #[cfg(unix)] - let mut term: Option> = Some(Box::new( - tokio::signal::unix::signal(SignalKind::terminate()) - .expect("to be able to create the signal stream"), - )); - - #[cfg(not(unix))] - let term: Option> = None; - - // Background tasks - tokio::spawn(async move { - loop { - tokio::select! { - _ = tokio::time::sleep(std::time::Duration::from_secs(60)) => { + let client = FrameworkBuilder::default() + .token(DISCORD_TOKEN.as_str()) + .client_settings(|client| client.register_songbird()) + .intents(bot::get_framework_intents()) + .options(bot::get_framework_opts()) + .setup(move |_ctx, _ready, framework| { + // This runs after the first shard has connected successfully + + Box::pin(async move { + let shard_manager = framework.shard_manager().clone(); + + tokio::spawn(bot::background_loop( + session_manager.clone(), #[cfg(feature = "stats")] - { - let active_count = session_manager.get_active_session_count().await; + stats_manager, + shard_manager, + )); - if let Err(why) = stats_manager.set_active_count(active_count) { - error!("Failed to update active count: {why}"); - } - } - } - - _ = tokio::signal::ctrl_c() => { - info!("Received interrupt signal, shutting down..."); - - session_manager.shutdown().await; - shard_manager.lock().await.shutdown_all().await; - - break; - } - - _ = async { - #[cfg(unix)] - match term { - Some(ref mut term) => { - let term = term.downcast_mut::().expect("to be able to downcast"); - - term.recv().await - } - - _ => None - } - }, if term.is_some() => { - info!("Received terminate signal, shutting down..."); - - session_manager.shutdown().await; - shard_manager.lock().await.shutdown_all().await; - - break; - } - } - } - }); + Ok(Data { + database, + session_manager, + }) + }) + }); // Start the bot - if let Err(why) = client.start_autosharded().await { - error!("FATAL Error in bot: {:?}", why); + if let Err(why) = client.run_autosharded().await { + error!("[FATAL] Error while running bot: {why}"); exit(1); } } diff --git a/src/player/mod.rs b/src/player/mod.rs index ef03233..03dbd4f 100644 --- a/src/player/mod.rs +++ b/src/player/mod.rs @@ -19,6 +19,7 @@ use librespot::{ use log::error; use protobuf::Message; use songbird::tracks::TrackHandle; +use spoticord_audio::{stream::Stream, SinkEvent, StreamSink}; use tokio::sync::{ broadcast::{Receiver, Sender}, mpsc::UnboundedReceiver, @@ -26,7 +27,6 @@ use tokio::sync::{ }; use crate::{ - audio::{stream::Stream, SinkEvent, StreamSink}, librespot_ext::discovery::CredentialsExt, session::pbi::{CurrentTrack, PlaybackInfo}, utils, diff --git a/src/session/manager.rs b/src/session/manager.rs index 7ebe009..1532085 100644 --- a/src/session/manager.rs +++ b/src/session/manager.rs @@ -1,12 +1,11 @@ use std::{collections::HashMap, sync::Arc}; -use serenity::{ - model::prelude::{ChannelId, GuildId, UserId}, - prelude::{Context, TypeMapKey}, -}; +use poise::serenity_prelude::model::prelude::{ChannelId, GuildId, UserId}; use songbird::error::JoinError; use thiserror::Error; +use crate::bot::Context; + use super::Session; #[derive(Debug, Error)] @@ -33,10 +32,6 @@ pub enum SessionCreateError { #[derive(Clone)] pub struct SessionManager(Arc>); -impl TypeMapKey for SessionManager { - type Value = SessionManager; -} - pub struct InnerSessionManager { sessions: HashMap, owner_map: HashMap, @@ -53,7 +48,7 @@ impl SessionManager { /// Creates a new session for the given user in the given guild. pub async fn create_session( &self, - ctx: &Context, + ctx: &Context<'_>, guild_id: GuildId, channel_id: ChannelId, text_channel_id: ChannelId, diff --git a/src/session/mod.rs b/src/session/mod.rs index f7ea489..8fa6204 100644 --- a/src/session/mod.rs +++ b/src/session/mod.rs @@ -6,26 +6,27 @@ use self::{ pbi::PlaybackInfo, }; use crate::{ - audio::stream::Stream, + bot::Context, consts::DISCONNECT_TIME, - database::{Database, DatabaseError}, + database::DatabaseError, player::{Player, PlayerEvent}, - utils::embed::Status, + utils::embed::Color, }; use log::*; -use reqwest::StatusCode; -use serenity::{ +use poise::serenity_prelude::{ async_trait, http::Http, model::prelude::{ChannelId, GuildId, UserId}, - prelude::{Context, RwLock}, + prelude::RwLock, }; +use reqwest::StatusCode; use songbird::{ create_player, input::{Codec, Container, Input, Reader}, tracks::TrackHandle, Call, Event, EventContext, EventHandler, }; +use spoticord_audio::stream::Stream; use std::{ sync::{Arc, Weak}, time::Duration, @@ -67,21 +68,20 @@ struct SessionInner { impl Session { pub async fn new( - ctx: &Context, + ctx: &Context<'_>, guild_id: GuildId, channel_id: ChannelId, text_channel_id: ChannelId, owner_id: UserId, ) -> Result { // Get the Spotify token of the owner - let data = ctx.data.read().await; - let session_manager = data - .get::() - .expect("to contain a value") - .clone(); + let session_manager = &ctx.data().session_manager; // Join the voice channel - let songbird = songbird::get(ctx).await.expect("to be present").clone(); + let songbird = songbird::get(ctx.serenity_context()) + .await + .expect("to be present") + .clone(); let (call, result) = songbird.join(guild_id, channel_id).await; @@ -95,7 +95,7 @@ impl Session { guild_id, channel_id, text_channel_id, - http: ctx.http.clone(), + http: ctx.serenity_context().http.clone(), session_manager: session_manager.clone(), call: call.clone(), track: None, @@ -129,15 +129,11 @@ impl Session { pub async fn update_owner( &mut self, - ctx: &Context, + ctx: &Context<'_>, owner_id: UserId, ) -> Result<(), SessionCreateError> { // Get the Spotify token of the owner - let data = ctx.data.read().await; - let session_manager = data - .get::() - .expect("to contain a value") - .clone(); + let session_manager = &ctx.data().session_manager; { let mut inner = self.0.write().await; @@ -156,6 +152,7 @@ impl Session { } /// Advance to the next track + #[allow(unused)] pub async fn next(&mut self) { if let Some(ref player) = self.0.read().await.player { player.next(); @@ -163,6 +160,7 @@ impl Session { } /// Rewind to the previous track + #[allow(unused)] pub async fn previous(&mut self) { if let Some(ref player) = self.0.read().await.player { player.prev(); @@ -170,6 +168,7 @@ impl Session { } /// Pause the current track + #[allow(unused)] pub async fn pause(&mut self) { if let Some(ref player) = self.0.read().await.player { player.pause(); @@ -177,20 +176,20 @@ impl Session { } /// Resume the current track + #[allow(unused)] pub async fn resume(&mut self) { if let Some(ref player) = self.0.read().await.player { player.play(); } } - async fn create_player(&mut self, ctx: &Context) -> Result<(), SessionCreateError> { + async fn create_player(&mut self, ctx: &Context<'_>) -> Result<(), SessionCreateError> { let owner_id = match self.owner().await { Some(owner_id) => owner_id, None => return Err(SessionCreateError::NoOwner), }; - let data = ctx.data.read().await; - let database = data.get::().expect("to contain a value"); + let database = &ctx.data().database; let token = match database.get_access_token(owner_id.to_string()).await { Ok(token) => token, @@ -406,7 +405,7 @@ impl Session { message.embed(|embed| { embed.title("Disconnected from voice channel"); embed.description(content); - embed.color(Status::Warning as u64); + embed.color(Color::Warning as u64); embed }) @@ -444,7 +443,7 @@ impl Session { } /// Get the channel id - #[allow(dead_code)] + #[allow(unused)] pub async fn text_channel_id(&self) -> ChannelId { self.0.read().await.text_channel_id } @@ -461,7 +460,7 @@ impl Session { self.0.read().await.call.clone() } - #[allow(dead_code)] + #[allow(unused)] pub async fn http(&self) -> Arc { self.0.read().await.http.clone() } diff --git a/src/utils/discord.rs b/src/utils/discord.rs index e0068e5..ea59d63 100644 --- a/src/utils/discord.rs +++ b/src/utils/discord.rs @@ -1,27 +1,13 @@ -use serenity::{ - model::{prelude::UserId, user::User}, - prelude::Context, -}; - pub fn escape(text: impl Into) -> String { let text: String = text.into(); text .replace('\\', "\\\\") + .replace('/', "\\/") .replace('*', "\\*") .replace('_', "\\_") .replace('~', "\\~") .replace('`', "\\`") -} - -pub async fn get_user(ctx: &Context, id: UserId) -> Option { - let user = match ctx.cache.user(id) { - Some(user) => user, - None => match ctx.http.get_user(id.0).await { - Ok(user) => user, - Err(_) => return None, - }, - }; - - Some(user) + .replace('[', "\\[") + .replace(']', "\\]") } diff --git a/src/utils/embed.rs b/src/utils/embed.rs index 839cc45..2477486 100644 --- a/src/utils/embed.rs +++ b/src/utils/embed.rs @@ -1,6 +1,4 @@ -use serenity::builder::CreateEmbed; - -pub enum Status { +pub enum Color { Info = 0x0773D6, Success = 0x3BD65D, Warning = 0xF0D932, @@ -8,97 +6,8 @@ pub enum Status { None = 0, } -impl From for serenity::utils::Colour { - fn from(value: Status) -> Self { +impl From for poise::serenity_prelude::utils::Colour { + fn from(value: Color) -> Self { Self(value as u32) } } - -#[derive(Default)] -pub struct EmbedMessageOptions { - pub title: Option, - pub title_url: Option, - pub icon_url: Option, - pub description: String, - pub status: Option, - pub footer: Option, -} - -pub struct EmbedBuilder { - embed: EmbedMessageOptions, -} - -impl EmbedBuilder { - pub fn new() -> Self { - Self { - embed: EmbedMessageOptions::default(), - } - } - - pub fn title(mut self, title: impl Into) -> Self { - self.embed.title = Some(title.into()); - self - } - - pub fn title_url(mut self, title_url: impl Into) -> Self { - self.embed.title_url = Some(title_url.into()); - self - } - - pub fn icon_url(mut self, icon_url: impl Into) -> Self { - self.embed.icon_url = Some(icon_url.into()); - self - } - - pub fn description(mut self, description: impl Into) -> Self { - self.embed.description = description.into(); - self - } - - pub fn status(mut self, status: Status) -> Self { - self.embed.status = Some(status); - self - } - - pub fn footer(mut self, footer: impl Into) -> Self { - self.embed.footer = Some(footer.into()); - self - } - - /// Build the embed - pub fn build(self) -> EmbedMessageOptions { - self.embed - } -} - -pub fn make_embed_message( - embed: &'_ mut CreateEmbed, - options: EmbedMessageOptions, -) -> &'_ mut CreateEmbed { - let status = options.status.unwrap_or(Status::None); - - embed.author(|author| { - if let Some(title) = options.title { - author.name(title); - } - - if let Some(title_url) = options.title_url { - author.url(title_url); - } - - if let Some(icon_url) = options.icon_url { - author.icon_url(icon_url); - } - - author - }); - - if let Some(text) = options.footer { - embed.footer(|footer| footer.text(text)); - } - - embed.description(options.description); - embed.color(status as u32); - - embed -}