Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8fefbddffd | |||
| 7dea731cbf | |||
| ff9a46c05c | |||
| 6169e6065d | |||
| 0ae38b0e01 | |||
| b2059a76c6 |
Generated
+396
-3
@@ -4,8 +4,15 @@ version = 4
|
||||
|
||||
[[package]]
|
||||
name = "RhythmWorks"
|
||||
version = "0.2.0"
|
||||
version = "0.5.1"
|
||||
dependencies = [
|
||||
"dialoguer",
|
||||
"keyring",
|
||||
"opentelemetry 0.27.1",
|
||||
"opentelemetry-otlp",
|
||||
"opentelemetry-proto",
|
||||
"opentelemetry-semantic-conventions",
|
||||
"opentelemetry_sdk",
|
||||
"reqwest",
|
||||
"semver",
|
||||
"serde",
|
||||
@@ -14,6 +21,10 @@ dependencies = [
|
||||
"songbird",
|
||||
"symphonia",
|
||||
"tokio",
|
||||
"tonic",
|
||||
"tracing",
|
||||
"tracing-opentelemetry",
|
||||
"tracing-subscriber",
|
||||
"yt-dlp",
|
||||
]
|
||||
|
||||
@@ -82,6 +93,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
version = "1.4.2"
|
||||
@@ -100,6 +117,28 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476"
|
||||
dependencies = [
|
||||
"async-stream-impl",
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream-impl"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.89"
|
||||
@@ -152,6 +191,53 @@ version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.7.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum-core",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"itoa",
|
||||
"matchit",
|
||||
"memchr",
|
||||
"mime",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"serde",
|
||||
"sync_wrapper",
|
||||
"tower 0.5.2",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-core"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"mime",
|
||||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"sync_wrapper",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
@@ -360,6 +446,19 @@ dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.16.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03e45a4a8926227e4197636ba97a9fc9b00477e9f4bd711395687c5f0734bec4"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"unicode-width",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.9.6"
|
||||
@@ -693,6 +792,18 @@ dependencies = [
|
||||
"syn 2.0.111",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dialoguer"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25f104b501bf2364e78d0d3974cbc774f738f5865306ed128e1e0d7499c0ad96"
|
||||
dependencies = [
|
||||
"console",
|
||||
"shell-words",
|
||||
"tempfile",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
@@ -747,6 +858,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.33"
|
||||
@@ -1243,6 +1360,12 @@ version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
||||
|
||||
[[package]]
|
||||
name = "httpdate"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.8.1"
|
||||
@@ -1257,6 +1380,7 @@ dependencies = [
|
||||
"http",
|
||||
"http-body",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
@@ -1275,6 +1399,7 @@ dependencies = [
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"rustls 0.23.35",
|
||||
"rustls-native-certs",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-rustls 0.26.4",
|
||||
@@ -1282,6 +1407,19 @@ dependencies = [
|
||||
"webpki-roots 1.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-timeout"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0"
|
||||
dependencies = [
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-tls"
|
||||
version = "0.6.0"
|
||||
@@ -1515,6 +1653,15 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.16"
|
||||
@@ -1541,6 +1688,19 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "keyring"
|
||||
version = "3.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eebcc3aff044e5944a8fbaf69eb277d11986064cba30c468730e8b9909fb551c"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"linux-keyutils",
|
||||
"log",
|
||||
"windows-sys 0.60.2",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
@@ -1605,6 +1765,16 @@ dependencies = [
|
||||
"zlib-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-keyutils"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "761e49ec5fd8a5a463f9b84e877c373d888935b71c6be78f3767fe2ae6bed18e"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.11.0"
|
||||
@@ -1683,6 +1853,12 @@ dependencies = [
|
||||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matchit"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
|
||||
|
||||
[[package]]
|
||||
name = "md-5"
|
||||
version = "0.10.6"
|
||||
@@ -1937,6 +2113,108 @@ dependencies = [
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry"
|
||||
version = "0.27.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab70038c28ed37b97d8ed414b6429d343a8bbf44c9f79ec854f3a643029ba6d7"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"js-sys",
|
||||
"pin-project-lite",
|
||||
"thiserror 1.0.69",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"js-sys",
|
||||
"pin-project-lite",
|
||||
"thiserror 2.0.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-http"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10a8a7f5f6ba7c1b286c2fbca0454eaba116f63bbe69ed250b642d36fbb04d80"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
"http",
|
||||
"opentelemetry 0.27.1",
|
||||
"reqwest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-otlp"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91cf61a1868dacc576bf2b2a1c3e9ab150af7272909e80085c3173384fe11f76"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures-core",
|
||||
"http",
|
||||
"opentelemetry 0.27.1",
|
||||
"opentelemetry-http",
|
||||
"opentelemetry-proto",
|
||||
"opentelemetry_sdk",
|
||||
"prost",
|
||||
"reqwest",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
"tonic",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-proto"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6e05acbfada5ec79023c85368af14abd0b307c015e9064d249b2a950ef459a6"
|
||||
dependencies = [
|
||||
"hex",
|
||||
"opentelemetry 0.27.1",
|
||||
"opentelemetry_sdk",
|
||||
"prost",
|
||||
"serde",
|
||||
"tonic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-semantic-conventions"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc1b6902ff63b32ef6c489e8048c5e253e2e4a803ea3ea7e783914536eb15c52"
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry_sdk"
|
||||
version = "0.27.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "231e9d6ceef9b0b2546ddf52335785ce41252bc7474ee8ba05bfad277be13ab8"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures-channel",
|
||||
"futures-executor",
|
||||
"futures-util",
|
||||
"glob",
|
||||
"opentelemetry 0.27.1",
|
||||
"percent-encoding",
|
||||
"rand 0.8.5",
|
||||
"serde_json",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "2.10.1"
|
||||
@@ -2195,6 +2473,29 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost"
|
||||
version = "0.13.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-derive"
|
||||
version = "0.13.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pulldown-cmark"
|
||||
version = "0.9.6"
|
||||
@@ -2442,6 +2743,7 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
"quinn",
|
||||
"rustls 0.23.35",
|
||||
"rustls-native-certs",
|
||||
"rustls-pki-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -2451,7 +2753,7 @@ dependencies = [
|
||||
"tokio-native-tls",
|
||||
"tokio-rustls 0.26.4",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
"tower 0.5.2",
|
||||
"tower-http",
|
||||
"tower-service",
|
||||
"url",
|
||||
@@ -2581,6 +2883,7 @@ version = "0.23.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
@@ -2601,6 +2904,15 @@ dependencies = [
|
||||
"security-framework 3.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.13.2"
|
||||
@@ -2983,6 +3295,12 @@ dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shell-words"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
@@ -3963,6 +4281,59 @@ dependencies = [
|
||||
"tokio-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tonic"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"async-trait",
|
||||
"axum",
|
||||
"base64",
|
||||
"bytes",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-timeout",
|
||||
"hyper-util",
|
||||
"percent-encoding",
|
||||
"pin-project",
|
||||
"prost",
|
||||
"rustls-native-certs",
|
||||
"rustls-pemfile",
|
||||
"socket2 0.5.10",
|
||||
"tokio",
|
||||
"tokio-rustls 0.26.4",
|
||||
"tokio-stream",
|
||||
"tower 0.4.13",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"indexmap 1.9.3",
|
||||
"pin-project",
|
||||
"pin-project-lite",
|
||||
"rand 0.8.5",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.5.2"
|
||||
@@ -3991,7 +4362,7 @@ dependencies = [
|
||||
"http-body",
|
||||
"iri-string",
|
||||
"pin-project-lite",
|
||||
"tower",
|
||||
"tower 0.5.2",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
@@ -4062,6 +4433,22 @@ dependencies = [
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-opentelemetry"
|
||||
version = "0.32.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ac28f2d093c6c477eaa76b23525478f38de514fa9aeb1285738d4b97a9552fc"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"opentelemetry 0.31.0",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
"tracing-subscriber",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.22"
|
||||
@@ -4265,6 +4652,12 @@ version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
|
||||
|
||||
[[package]]
|
||||
name = "universal-hash"
|
||||
version = "0.5.1"
|
||||
|
||||
+12
-1
@@ -1,9 +1,16 @@
|
||||
[package]
|
||||
name = "RhythmWorks"
|
||||
version = "0.2.0"
|
||||
version = "0.5.1"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
dialoguer = "0.12.0"
|
||||
keyring = { version = "3.6.3", features = ["linux-native", "windows-native"] }
|
||||
opentelemetry = { version = "0.27.0", features = ["logs", "metrics", "trace"] }
|
||||
opentelemetry-otlp = { version = "0.27.0", features = ["trace", "metrics", "grpc-tonic", "http-proto", "tls", "reqwest-client", "reqwest-rustls"] }
|
||||
opentelemetry-proto = "0.27.0"
|
||||
opentelemetry-semantic-conventions = "0.27.0"
|
||||
opentelemetry_sdk = { version = "0.27.0", features = ["rt-tokio", "trace"] }
|
||||
reqwest = { version = "0.12.28", features = ["blocking", "json"] }
|
||||
semver = "1.0.27"
|
||||
serde = "1.0.228"
|
||||
@@ -12,6 +19,10 @@ serenity = { version = "0.12.5", features = ["client", "gateway", "voice"] }
|
||||
songbird = { version = "0.5.0", features = ["builtin-queue", "driver", "serenity"] }
|
||||
symphonia = { version = "0.5.5", features = ["aac", "alac", "isomp4", "mp3"] }
|
||||
tokio = "1.48.0"
|
||||
tonic = { version = "0.12.3", features = ["tls-roots"] }
|
||||
tracing = "0.1.41"
|
||||
tracing-opentelemetry = "0.32.0"
|
||||
tracing-subscriber = "0.3.20"
|
||||
yt-dlp = "1.4.7"
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
cargo clean
|
||||
cargo fmt
|
||||
cargo clippy --fix --all-targets --allow-dirty
|
||||
cargo build --release
|
||||
cargo build --release --target x86_64-pc-windows-gnu
|
||||
+277
-59
@@ -1,25 +1,65 @@
|
||||
use dialoguer::Select;
|
||||
use dialoguer::theme::ColorfulTheme;
|
||||
use modules::*;
|
||||
use opentelemetry::KeyValue;
|
||||
use opentelemetry::global;
|
||||
use opentelemetry::trace::Status;
|
||||
use opentelemetry::trace::TraceContextExt;
|
||||
use opentelemetry::trace::Tracer;
|
||||
use serenity::all::ChannelId;
|
||||
use serenity::async_trait;
|
||||
use serenity::model::channel::Message;
|
||||
use serenity::model::gateway::Ready;
|
||||
use serenity::prelude::*;
|
||||
use songbird::Event;
|
||||
use songbird::EventContext;
|
||||
use songbird::SerenityInit;
|
||||
use songbird::events::EventHandler as VoiceEventHandler;
|
||||
use songbird::get;
|
||||
use songbird::input::HlsRequest;
|
||||
use songbird::input::Input;
|
||||
use songbird::tracks::TrackHandle;
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::env;
|
||||
use std::process::Command;
|
||||
use std::process::Stdio;
|
||||
use std::sync::Arc;
|
||||
pub mod modules;
|
||||
|
||||
type TrackMap = Arc<Mutex<HashMap<u64, TrackHandle>>>;
|
||||
struct Handler {
|
||||
track_map: TrackMap,
|
||||
struct TrackTraceHandler {
|
||||
otel_ctx: opentelemetry::Context,
|
||||
guild_id: String,
|
||||
track_url: String,
|
||||
hls_url: String,
|
||||
event_name: &'static str,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl VoiceEventHandler for TrackTraceHandler {
|
||||
async fn act(&self, ctx: &EventContext<'_>) -> Option<Event> {
|
||||
let tracer = global::tracer("RhythmWorks");
|
||||
let track_status = if let EventContext::Track(track_list) = ctx {
|
||||
track_list.first().map(|state| format!("{:?}", state.0))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
tracer.in_span(self.event_name, |cx| {
|
||||
cx.span()
|
||||
.set_attribute(KeyValue::new("Guild_ID", self.guild_id.clone()));
|
||||
cx.span()
|
||||
.set_attribute(KeyValue::new("Youtube_URL", self.track_url.clone()));
|
||||
cx.span()
|
||||
.set_attribute(KeyValue::new("Stream_URL", self.hls_url.clone()));
|
||||
cx.span().add_event(
|
||||
self.event_name,
|
||||
vec![KeyValue::new(
|
||||
"track_status",
|
||||
track_status.unwrap().to_string(),
|
||||
)],
|
||||
);
|
||||
});
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
struct Handler;
|
||||
fn get_user_voice_channel(ctx: &Context, msg: &Message) -> Option<ChannelId> {
|
||||
let guild_id = msg.guild_id?;
|
||||
let guild = ctx.cache.guild(guild_id)?;
|
||||
@@ -38,13 +78,50 @@ impl EventHandler for Handler {
|
||||
println!("Error sending message: {why:?}");
|
||||
}
|
||||
if msg.content == "!join" {
|
||||
let tracer = global::tracer("RhythmWorks");
|
||||
let span = tracer.start("Join Message Received");
|
||||
let cx = opentelemetry::Context::current_with_span(span);
|
||||
let guild_id = match msg.guild_id {
|
||||
Some(g) => g,
|
||||
None => return,
|
||||
};
|
||||
let channel_id = match get_user_voice_channel(&ctx, &msg) {
|
||||
Some(c) => c,
|
||||
Some(g) => {
|
||||
cx.span().add_event(
|
||||
"Received Guild ID",
|
||||
vec![KeyValue::new("Server ID", g.to_string())],
|
||||
);
|
||||
cx.span().set_status(opentelemetry::trace::Status::Ok);
|
||||
cx.span()
|
||||
.set_attribute(KeyValue::new("Guild_ID", g.to_string()));
|
||||
g
|
||||
}
|
||||
None => {
|
||||
cx.span().add_event(
|
||||
"Failed to Retreive Guild ID",
|
||||
vec![KeyValue::new("Server ID", "None")],
|
||||
);
|
||||
cx.span()
|
||||
.set_status(opentelemetry::trace::Status::error("Failed"));
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let channel_id = match get_user_voice_channel(&ctx, &msg) {
|
||||
Some(c) => {
|
||||
cx.span().add_event(
|
||||
"Received Channel ID",
|
||||
vec![KeyValue::new("Channel ID", c.to_string())],
|
||||
);
|
||||
cx.span().set_status(Status::Ok);
|
||||
c
|
||||
}
|
||||
None => {
|
||||
cx.span().add_event(
|
||||
"Failed to Retreive Channel ID",
|
||||
vec![KeyValue::new("Channel ID", "None")],
|
||||
);
|
||||
cx.span()
|
||||
.set_status(opentelemetry::trace::Status::error(format!(
|
||||
"{} not in Voice Channel",
|
||||
msg.author
|
||||
)));
|
||||
let _ = msg
|
||||
.channel_id
|
||||
.say(&ctx.http, "You must be in a voice channel")
|
||||
@@ -52,7 +129,6 @@ impl EventHandler for Handler {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let manager = get(&ctx).await.expect("Songbird not initialized").clone();
|
||||
|
||||
let _ = manager.join(guild_id, channel_id).await;
|
||||
@@ -61,6 +137,11 @@ impl EventHandler for Handler {
|
||||
.channel_id
|
||||
.say(&ctx.http, "Joined your voice channel!")
|
||||
.await;
|
||||
cx.span().add_event(
|
||||
"Joined Voice Channel",
|
||||
vec![KeyValue::new("Voice Channel", msg.channel_id.to_string())],
|
||||
);
|
||||
cx.span().set_status(Status::Ok);
|
||||
}
|
||||
if msg.content == "!leave" {
|
||||
let guild_id = match msg.guild_id {
|
||||
@@ -77,61 +158,168 @@ impl EventHandler for Handler {
|
||||
}
|
||||
}
|
||||
if msg.content.starts_with("!play") {
|
||||
let mut url = msg
|
||||
let tracer = global::tracer("RhythmWorks");
|
||||
let span = tracer.start("Play Message Received");
|
||||
let mut yt_url = msg
|
||||
.content
|
||||
.strip_prefix("!play ")
|
||||
.unwrap_or("")
|
||||
.trim()
|
||||
.to_string();
|
||||
let separator = "&";
|
||||
if let Some(offset) = url.find(separator) {
|
||||
url.truncate(offset);
|
||||
if let Some(offset) = yt_url.find('&') {
|
||||
yt_url.truncate(offset);
|
||||
}
|
||||
if url.is_empty() {
|
||||
if yt_url.is_empty() {
|
||||
let _ = msg.reply(&ctx, "Please provide a YouTube URL.").await;
|
||||
return;
|
||||
}
|
||||
let guild_id = msg.guild_id.unwrap();
|
||||
let manager = songbird::get(&ctx)
|
||||
.await
|
||||
.expect("Songbird Voice client placed in at initialisation.")
|
||||
.clone();
|
||||
let handler_lock = if let Some(handler) = manager.get(guild_id) {
|
||||
handler
|
||||
} else {
|
||||
let channel_id = get_user_voice_channel(&ctx, &msg);
|
||||
match channel_id {
|
||||
Some(c) => manager.join(guild_id, c).await.unwrap(),
|
||||
let cx = opentelemetry::Context::current_with_span(span);
|
||||
cx.span()
|
||||
.set_attribute(KeyValue::new("Youtube_URL", yt_url.to_string()));
|
||||
let guild_id = match msg.guild_id {
|
||||
Some(g) => {
|
||||
cx.span().add_event(
|
||||
"Received Guild ID",
|
||||
vec![KeyValue::new("Server ID", g.to_string())],
|
||||
);
|
||||
cx.span().set_status(opentelemetry::trace::Status::Ok);
|
||||
cx.span()
|
||||
.set_attribute(KeyValue::new("Guild_ID", g.to_string()));
|
||||
g
|
||||
}
|
||||
None => {
|
||||
let _ = msg.reply(&ctx, "Join a voice channel first!").await;
|
||||
cx.span().add_event(
|
||||
"Failed to Retreive Guild ID",
|
||||
vec![KeyValue::new("Server ID", "None")],
|
||||
);
|
||||
cx.span()
|
||||
.set_status(opentelemetry::trace::Status::error("Failed"));
|
||||
return;
|
||||
}
|
||||
};
|
||||
let manager = songbird::get(&ctx).await.unwrap().clone();
|
||||
let handler_lock = if let Some(call) = manager.get(guild_id) {
|
||||
call
|
||||
} else {
|
||||
let channel_id = match get_user_voice_channel(&ctx, &msg) {
|
||||
Some(c) => c,
|
||||
None => {
|
||||
cx.span().add_event(
|
||||
"Failed to Retreive Channel ID",
|
||||
vec![KeyValue::new("Channel ID", "None")],
|
||||
);
|
||||
cx.span()
|
||||
.set_status(opentelemetry::trace::Status::error(format!(
|
||||
"{} not in Voice Channel",
|
||||
msg.author
|
||||
)));
|
||||
let _ = msg
|
||||
.channel_id
|
||||
.say(&ctx.http, "You must be in a voice channel")
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
};
|
||||
let output = Command::new("./yt-dlp")
|
||||
.args(["-f", "bestaudio", "-g", &url])
|
||||
manager.join(guild_id, channel_id).await.unwrap()
|
||||
};
|
||||
let output = match Command::new("./yt-dlp")
|
||||
.args(["-f", "bestaudio", "-g", "--no-playlist", &yt_url])
|
||||
.stdout(Stdio::piped())
|
||||
.output()
|
||||
.expect("Failed");
|
||||
let url_bytes = output.stdout;
|
||||
let url = String::from_utf8(url_bytes).expect("Failed");
|
||||
let mut handler = handler_lock.lock().await;
|
||||
let input = Input::from(HlsRequest::new(reqwest::Client::new(), url.to_string()));
|
||||
let track_handle = handler.play_input(input);
|
||||
let _ = track_handle.play();
|
||||
self.track_map
|
||||
.lock()
|
||||
.await
|
||||
.insert(guild_id.into(), track_handle);
|
||||
let _ = msg.channel_id.say(&ctx.http, "🎶 Playing...").await;
|
||||
{
|
||||
Ok(output) => {
|
||||
cx.span().add_event(
|
||||
"Retreiving Youtube Information",
|
||||
vec![KeyValue::new("Success", yt_url.to_string())],
|
||||
);
|
||||
output
|
||||
}
|
||||
Err(e) => {
|
||||
cx.span().add_event(
|
||||
"Retreiving Youtube Information",
|
||||
vec![KeyValue::new("Failed", e.to_string())],
|
||||
);
|
||||
cx.span().set_status(Status::error("Failed"));
|
||||
eprintln!("{}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let stream_url = String::from_utf8(output.stdout)
|
||||
.expect("Invalid UTF-8")
|
||||
.trim()
|
||||
.to_string();
|
||||
let telemetry_stream_url = stream_url.clone();
|
||||
let mut call = handler_lock.lock().await;
|
||||
let input = Input::from(HlsRequest::new(reqwest::Client::new(), stream_url));
|
||||
let track_handle = call.enqueue_input(input).await;
|
||||
let otel_ctx = opentelemetry::Context::current();
|
||||
let position = call.queue().len();
|
||||
let response = if position == 1 {
|
||||
cx.span().add_event(
|
||||
"Starting Playback",
|
||||
vec![KeyValue::new("Status", "Playing".to_string())],
|
||||
);
|
||||
"🎶 Now playing!".to_string()
|
||||
} else {
|
||||
cx.span().add_event(
|
||||
"Starting Playback",
|
||||
vec![KeyValue::new("Status", "Added to Queue".to_string())],
|
||||
);
|
||||
format!("🎶 Added Song to Queue: #{}", position)
|
||||
};
|
||||
let _ = msg.channel_id.say(&ctx.http, response).await;
|
||||
let _ = track_handle.add_event(
|
||||
Event::Track(songbird::events::TrackEvent::Play),
|
||||
TrackTraceHandler {
|
||||
otel_ctx: otel_ctx.clone(),
|
||||
guild_id: guild_id.to_string().clone(),
|
||||
track_url: yt_url.clone(),
|
||||
hls_url: telemetry_stream_url.clone(),
|
||||
event_name: "Track Started Playing",
|
||||
},
|
||||
);
|
||||
let _ = track_handle.add_event(
|
||||
Event::Track(songbird::events::TrackEvent::End),
|
||||
TrackTraceHandler {
|
||||
otel_ctx: otel_ctx.clone(),
|
||||
guild_id: guild_id.to_string().clone(),
|
||||
track_url: yt_url.clone(),
|
||||
hls_url: telemetry_stream_url.clone(),
|
||||
event_name: "Track Finished",
|
||||
},
|
||||
);
|
||||
let _ = track_handle.add_event(
|
||||
Event::Track(songbird::events::TrackEvent::Error),
|
||||
TrackTraceHandler {
|
||||
otel_ctx: otel_ctx.clone(),
|
||||
guild_id: guild_id.to_string().clone(),
|
||||
track_url: yt_url.clone(),
|
||||
hls_url: telemetry_stream_url.clone(),
|
||||
event_name: "Playback had an error",
|
||||
},
|
||||
);
|
||||
}
|
||||
if msg.content == "!skip" {
|
||||
let guild_id = match msg.guild_id {
|
||||
Some(g) => g,
|
||||
None => return,
|
||||
};
|
||||
let manager = songbird::get(&ctx).await.unwrap();
|
||||
if let Some(call) = manager.get(guild_id) {
|
||||
let call = call.lock().await;
|
||||
let _ = call.queue().skip();
|
||||
let _ = msg.channel_id.say(&ctx.http, "Skipped").await;
|
||||
}
|
||||
}
|
||||
if msg.content == "!pause" {
|
||||
let guild_id = match msg.guild_id {
|
||||
Some(g) => g,
|
||||
None => return,
|
||||
};
|
||||
if let Some(handle) = self.track_map.lock().await.get(&guild_id.into()) {
|
||||
let _ = handle.pause();
|
||||
let manager = songbird::get(&ctx).await.unwrap();
|
||||
if let Some(call) = manager.get(guild_id) {
|
||||
let call = call.lock().await;
|
||||
let _ = call.queue().pause();
|
||||
}
|
||||
}
|
||||
if msg.content == "!resume" {
|
||||
@@ -139,8 +327,10 @@ impl EventHandler for Handler {
|
||||
Some(g) => g,
|
||||
None => return,
|
||||
};
|
||||
if let Some(handle) = self.track_map.lock().await.get(&guild_id.into()) {
|
||||
let _ = handle.play();
|
||||
let manager = songbird::get(&ctx).await.unwrap();
|
||||
if let Some(call) = manager.get(guild_id) {
|
||||
let call = call.lock().await;
|
||||
let _ = call.queue().resume();
|
||||
}
|
||||
}
|
||||
if msg.content == "!stop" {
|
||||
@@ -148,8 +338,10 @@ impl EventHandler for Handler {
|
||||
Some(g) => g,
|
||||
None => return,
|
||||
};
|
||||
if let Some(handle) = self.track_map.lock().await.get(&guild_id.into()) {
|
||||
let _ = handle.stop();
|
||||
let manager = songbird::get(&ctx).await.unwrap();
|
||||
if let Some(call) = manager.get(guild_id) {
|
||||
let call = call.lock().await;
|
||||
let _ = call.queue().stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -157,28 +349,54 @@ impl EventHandler for Handler {
|
||||
println!("{} is connected!", ready.user.name);
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
println!("RhythmWorks Copyright (C) 2025 James Brotosky\n
|
||||
println!(
|
||||
"RhythmWorks Copyright (C) 2025 James Brotosky\n
|
||||
This program comes with ABSOLUTELY NO WARRANTY\n
|
||||
This is free software, and you are welcome to redistribute it under certain conditions.");
|
||||
updator::update().await;
|
||||
println!("Please paste in your bot token");
|
||||
let mut input = String::new();
|
||||
io::stdin().read_line(&mut input).expect("Failed to read line");
|
||||
let token = input.trim();
|
||||
This is free software, and you are welcome to redistribute it under certain conditions."
|
||||
);
|
||||
let tracer_provider = telemetry::init_telemetry();
|
||||
global::set_tracer_provider(tracer_provider.clone());
|
||||
let tracer: global::BoxedTracer = global::tracer("tracer");
|
||||
tracer
|
||||
.in_span("Checking for Updates", |_cx| updator::update())
|
||||
.await;
|
||||
let service_name = "RhythmWorks";
|
||||
let username = env::var("USER").or_else(|_| env::var("USERNAME")).unwrap();
|
||||
loop {
|
||||
let token = credentialmanager::get_token(service_name, &username);
|
||||
let options: Vec<&'static str> = vec!["- Start Bot", "- Change Token", "- Delete Token"];
|
||||
let selection = Select::with_theme(&ColorfulTheme::default())
|
||||
.with_prompt("Choose an Option")
|
||||
.default(0)
|
||||
.items(&options)
|
||||
.interact()
|
||||
.unwrap();
|
||||
match selection {
|
||||
0 => {
|
||||
let intents = GatewayIntents::GUILD_MESSAGES
|
||||
| GatewayIntents::GUILDS
|
||||
| GatewayIntents::DIRECT_MESSAGES
|
||||
| GatewayIntents::MESSAGE_CONTENT
|
||||
| GatewayIntents::GUILD_VOICE_STATES;
|
||||
let track_map: TrackMap = Arc::new(Mutex::new(HashMap::new()));
|
||||
let mut client = Client::builder(&token, intents)
|
||||
.event_handler(Handler { track_map })
|
||||
.event_handler(Handler)
|
||||
.register_songbird()
|
||||
.await
|
||||
.expect("Err creating client");
|
||||
if let Err(why) = client.start().await {
|
||||
println!("Client error: {why:?}");
|
||||
}
|
||||
}
|
||||
1 => {
|
||||
credentialmanager::change_token(service_name, &username);
|
||||
}
|
||||
2 => {
|
||||
credentialmanager::remove_token(service_name, &username);
|
||||
}
|
||||
_ => println!("Invalid Option"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
use dialoguer::{Input, theme::ColorfulTheme};
|
||||
use keyring::Entry;
|
||||
|
||||
pub fn get_token<'a>(service: &str, username: &str) -> String {
|
||||
let entry = Entry::new(service, username).expect("Failed to get keyring entry");
|
||||
match entry.get_password() {
|
||||
Ok(token) => token,
|
||||
Err(_) => {
|
||||
let token: String = Input::with_theme(&ColorfulTheme::default())
|
||||
.with_prompt("Enter your bot token")
|
||||
.interact_text()
|
||||
.unwrap();
|
||||
match entry.set_password(&token) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
println!("Failed to set token: {}", e);
|
||||
std::process::abort()
|
||||
}
|
||||
};
|
||||
token
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn change_token(service: &str, username: &str) {
|
||||
let entry = Entry::new(service, username).expect("Failed to get keyring entry");
|
||||
let new_token: String = Input::with_theme(&ColorfulTheme::default())
|
||||
.with_prompt("New Token")
|
||||
.interact_text()
|
||||
.unwrap();
|
||||
let _ = entry.set_password(&new_token);
|
||||
}
|
||||
|
||||
pub fn remove_token(service: &str, username: &str) {
|
||||
let entry = Entry::new(service, username).expect("Failed to get keyring entry");
|
||||
let _ = entry.delete_credential();
|
||||
}
|
||||
@@ -1 +1,3 @@
|
||||
pub mod credentialmanager;
|
||||
pub mod telemetry;
|
||||
pub mod updator;
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
use opentelemetry::KeyValue;
|
||||
use opentelemetry_otlp::{WithExportConfig, WithTonicConfig};
|
||||
use opentelemetry_sdk::{Resource, runtime};
|
||||
use tonic::transport::{Channel, ClientTlsConfig};
|
||||
|
||||
pub fn init_telemetry() -> opentelemetry_sdk::trace::TracerProvider {
|
||||
let endpoint = "https://signoz.racooncity.org".to_string();
|
||||
let channel = Channel::from_shared(endpoint.clone())
|
||||
.unwrap()
|
||||
.tls_config(ClientTlsConfig::new().with_native_roots())
|
||||
.unwrap()
|
||||
.connect_lazy();
|
||||
let exporter = opentelemetry_otlp::SpanExporter::builder()
|
||||
.with_tonic()
|
||||
.with_endpoint(endpoint.clone())
|
||||
.with_channel(channel)
|
||||
.build()
|
||||
.expect("Failed to Build Exporter");
|
||||
opentelemetry_sdk::trace::TracerProvider::builder()
|
||||
.with_batch_exporter(exporter, runtime::Tokio)
|
||||
.with_resource(Resource::new(vec![KeyValue::new(
|
||||
"service.name",
|
||||
"RhythmWorks",
|
||||
)]))
|
||||
.build()
|
||||
}
|
||||
+10
-7
@@ -1,15 +1,22 @@
|
||||
use std::thread;
|
||||
|
||||
use serde::Deserialize;
|
||||
use semver::Version;
|
||||
use reqwest;
|
||||
use semver::Version;
|
||||
use serde::Deserialize;
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct Release {
|
||||
tag_name: String,
|
||||
}
|
||||
|
||||
pub async fn update() {
|
||||
let body = reqwest::get("https://git.racooncity.org/api/v1/repos/brotoskyj/RhythmWorks/releases/latest").await.unwrap().text().await.unwrap();
|
||||
let body = reqwest::get(
|
||||
"https://git.racooncity.org/api/v1/repos/brotoskyj/RhythmWorks/releases/latest",
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
.text()
|
||||
.await
|
||||
.unwrap();
|
||||
let release_info: Release = serde_json::from_str(&body).unwrap();
|
||||
let latest_version = Version::parse(&release_info.tag_name).unwrap();
|
||||
let current_version = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
|
||||
@@ -18,9 +25,5 @@ pub async fn update() {
|
||||
println!("URL: https://git.racooncity.org/brotoskyj/RhythmWorks/releases");
|
||||
thread::sleep(std::time::Duration::from_secs(10));
|
||||
std::process::exit(1);
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user