Fix API and Voice

This commit is contained in:
Joey Hines 2026-05-03 18:38:06 -06:00
parent 26eabbe275
commit fa4863bfb3
Signed by: joeyahines
GPG Key ID: E99D8FB14855100E
6 changed files with 78 additions and 54 deletions

50
Cargo.lock generated
View File

@ -1425,6 +1425,7 @@ dependencies = [
"regex", "regex",
"reqwest 0.13.3", "reqwest 0.13.3",
"rust-dsn-parser", "rust-dsn-parser",
"rustls 0.23.40",
"serde", "serde",
"serde_json", "serde_json",
"sha3", "sha3",
@ -4375,6 +4376,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b"
dependencies = [ dependencies = [
"aws-lc-rs", "aws-lc-rs",
"log",
"once_cell", "once_cell",
"ring", "ring",
"rustls-pki-types", "rustls-pki-types",
@ -5208,9 +5210,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]] [[package]]
name = "symphonia" name = "symphonia"
version = "0.5.4" version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "815c942ae7ee74737bb00f965fa5b5a2ac2ce7b6c01c0cc169bbeaf7abd5f5a9" checksum = "5773a4c030a19d9bfaa090f49746ff35c75dfddfa700df7a5939d5e076a57039"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"symphonia-bundle-flac", "symphonia-bundle-flac",
@ -5227,9 +5229,9 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-bundle-flac" name = "symphonia-bundle-flac"
version = "0.5.4" version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72e34f34298a7308d4397a6c7fbf5b84c5d491231ce3dd379707ba673ab3bd97" checksum = "c91565e180aea25d9b80a910c546802526ffd0072d0b8974e3ebe59b686c9976"
dependencies = [ dependencies = [
"log", "log",
"symphonia-core", "symphonia-core",
@ -5239,9 +5241,9 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-bundle-mp3" name = "symphonia-bundle-mp3"
version = "0.5.4" version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c01c2aae70f0f1fb096b6f0ff112a930b1fb3626178fba3ae68b09dce71706d4" checksum = "4872dd6bb56bf5eac799e3e957aa1981086c3e613b27e0ac23b176054f7c57ed"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"log", "log",
@ -5251,9 +5253,9 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-codec-adpcm" name = "symphonia-codec-adpcm"
version = "0.5.4" version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c94e1feac3327cd616e973d5be69ad36b3945f16b06f19c6773fc3ac0b426a0f" checksum = "2dddc50e2bbea4cfe027441eece77c46b9f319748605ab8f3443350129ddd07f"
dependencies = [ dependencies = [
"log", "log",
"symphonia-core", "symphonia-core",
@ -5261,9 +5263,9 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-codec-pcm" name = "symphonia-codec-pcm"
version = "0.5.4" version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f395a67057c2ebc5e84d7bb1be71cce1a7ba99f64e0f0f0e303a03f79116f89b" checksum = "4e89d716c01541ad3ebe7c91ce4c8d38a7cf266a3f7b2f090b108fb0cb031d95"
dependencies = [ dependencies = [
"log", "log",
"symphonia-core", "symphonia-core",
@ -5271,9 +5273,9 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-codec-vorbis" name = "symphonia-codec-vorbis"
version = "0.5.4" version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a98765fb46a0a6732b007f7e2870c2129b6f78d87db7987e6533c8f164a9f30" checksum = "f025837c309cd69ffef572750b4a2257b59552c5399a5e49707cc5b1b85d1c73"
dependencies = [ dependencies = [
"log", "log",
"symphonia-core", "symphonia-core",
@ -5282,9 +5284,9 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-core" name = "symphonia-core"
version = "0.5.4" version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "798306779e3dc7d5231bd5691f5a813496dc79d3f56bf82e25789f2094e022c3" checksum = "ea00cc4f79b7f6bb7ff87eddc065a1066f3a43fe1875979056672c9ef948c2af"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"bitflags 1.3.2", "bitflags 1.3.2",
@ -5295,9 +5297,9 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-format-mkv" name = "symphonia-format-mkv"
version = "0.5.4" version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bb43471a100f7882dc9937395bd5ebee8329298e766250b15b3875652fe3d6f" checksum = "122d786d2c43a49beb6f397551b4a050d8229eaa54c7ddf9ee4b98899b8742d0"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"log", "log",
@ -5308,9 +5310,9 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-format-ogg" name = "symphonia-format-ogg"
version = "0.5.4" version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ada3505789516bcf00fc1157c67729eded428b455c27ca370e41f4d785bfa931" checksum = "2b4955c67c1ed3aa8ae8428d04ca8397fbef6a19b2b051e73b5da8b1435639cb"
dependencies = [ dependencies = [
"log", "log",
"symphonia-core", "symphonia-core",
@ -5320,9 +5322,9 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-format-riff" name = "symphonia-format-riff"
version = "0.5.4" version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f7be232f962f937f4b7115cbe62c330929345434c834359425e043bfd15f50" checksum = "c2d7c3df0e7d94efb68401d81906eae73c02b40d5ec1a141962c592d0f11a96f"
dependencies = [ dependencies = [
"extended", "extended",
"log", "log",
@ -5332,9 +5334,9 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-metadata" name = "symphonia-metadata"
version = "0.5.4" version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc622b9841a10089c5b18e99eb904f4341615d5aa55bbf4eedde1be721a4023c" checksum = "36306ff42b9ffe6e5afc99d49e121e0bd62fe79b9db7b9681d48e29fa19e6b16"
dependencies = [ dependencies = [
"encoding_rs", "encoding_rs",
"lazy_static", "lazy_static",
@ -5344,9 +5346,9 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-utils-xiph" name = "symphonia-utils-xiph"
version = "0.5.4" version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "484472580fa49991afda5f6550ece662237b00c6f562c7d9638d1b086ed010fe" checksum = "ee27c85ab799a338446b68eec77abf42e1a6f1bb490656e121c6e27bfbab9f16"
dependencies = [ dependencies = [
"symphonia-core", "symphonia-core",
"symphonia-metadata", "symphonia-metadata",

View File

@ -38,6 +38,7 @@ thousands = "0.2.0"
url = { version = "2.5.7", features = ["serde"] } url = { version = "2.5.7", features = ["serde"] }
convert_case = "0.11.0" convert_case = "0.11.0"
rust-dsn-parser = { version = "1.0.0", registry = "ahines"} rust-dsn-parser = { version = "1.0.0", registry = "ahines"}
rustls = "0.23.40"
[dependencies.tokio] [dependencies.tokio]
version = "1.35.1" version = "1.35.1"
@ -48,5 +49,5 @@ version = "0.6.0"
features = ["builtin-queue"] features = ["builtin-queue"]
[dependencies.symphonia] [dependencies.symphonia]
version = "0.5" version = "0.5.5"
features = ["mp3", "wav"] features = ["mp3", "wav"]

View File

@ -1,23 +1,29 @@
use std::sync::Arc;
use crate::config::GlobalData; use crate::config::GlobalData;
use crate::discord::voices::speak; use crate::discord::voices::speak;
use crate::models::api_key::Apikey; use crate::models::api_key::Apikey;
use axum::extract::State; use axum::extract::State;
use axum::{http::StatusCode, response::IntoResponse, routing::post, Json, Router}; use axum::{http::StatusCode, response::IntoResponse, routing::post, Json, Router};
use log::info;
use serde::Deserialize; use serde::Deserialize;
use serenity::prelude::Context;
pub async fn web_server(ctx: Context) { #[derive(Clone)]
let addr = { struct ApiContext {
let data = ctx.data.read().await; data: Arc<GlobalData>,
let global_data = data.get::<GlobalData>().unwrap(); ctx: poise::serenity_prelude::Context
global_data.cfg.api_addr }
};
pub async fn web_server(data: Arc<GlobalData>, ctx: poise::serenity_prelude::Context) {
let addr = data.cfg.api_addr;
let app = Router::new() let app = Router::new()
.route("/play", post(play_sound)) .route("/play", post(play_sound))
.with_state(ctx); .with_state(ApiContext {
data,
ctx
});
println!("Serving bot api on: {}", addr); info!("Serving bot api on: {}", addr);
let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
axum::serve(listener, app).await.unwrap(); axum::serve(listener, app).await.unwrap();
} }
@ -30,18 +36,17 @@ struct SoundPayload {
} }
async fn play_sound( async fn play_sound(
State(ctx): State<Context>, State(ctx): State<ApiContext>,
Json(payload): Json<SoundPayload>, Json(payload): Json<SoundPayload>,
) -> impl IntoResponse { ) -> impl IntoResponse {
let data = ctx.data.read().await;
let global_data = data.get::<GlobalData>().unwrap();
if let Some(api_key) = Apikey::find_key_from_secret(&global_data.db, &payload.api_key).unwrap() if let Some(api_key) = Apikey::find_key_from_secret(&ctx.data.db, &payload.api_key).unwrap()
{ && let Some(user_id) = api_key.user_id {
if let Some(user_id) = api_key.user_id { info!("Playing audio for {user_id}");
speak( speak(
&ctx, &ctx.ctx,
global_data.cfg.guild_id, &ctx.data,
ctx.data.cfg.guild_id,
user_id, user_id,
&payload.voice, &payload.voice,
&payload.phrase, &payload.phrase,
@ -49,7 +54,6 @@ async fn play_sound(
.await .await
.unwrap(); .unwrap();
} }
}
StatusCode::ACCEPTED StatusCode::ACCEPTED
} }

View File

@ -39,6 +39,7 @@ use songbird::SerenityInit;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use url::Url; use url::Url;
use crate::api::web_server;
pub type Context<'a> = poise::Context<'a, Arc<GlobalData>, Error>; pub type Context<'a> = poise::Context<'a, Arc<GlobalData>, Error>;
@ -54,15 +55,25 @@ async fn event_handler(
{ {
info!("Starting tasks handler..."); info!("Starting tasks handler...");
let data = data.clone(); let data_task = data.clone();
let ctx = ctx.clone(); let ctx_task = ctx.clone();
tokio::spawn(async move { tokio::spawn(async move {
let _ = Task::create_reoccurring_tasks(&data).await.is_ok(); let _ = Task::create_reoccurring_tasks(&data_task).await.is_ok();
loop { loop {
let _ = Task::run_tasks(&ctx, &data).await.is_ok(); let _ = Task::run_tasks(&ctx_task, &data_task).await.is_ok();
tokio::time::sleep(Duration::from_secs(5)).await; tokio::time::sleep(Duration::from_secs(5)).await;
} }
}); });
let data_web = data.clone();
let ctx_web = ctx.clone();
tokio::spawn(async move {
web_server(
data_web,
ctx_web
).await;
});
} }
} }
serenity::FullEvent::Message { new_message } => { serenity::FullEvent::Message { new_message } => {

View File

@ -14,6 +14,7 @@ use std::collections::HashMap;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::Arc; use std::sync::Arc;
use crate::config::GlobalData;
async fn get_voice_dictionary(path: &Path) -> Result<HashMap<String, PathBuf>, tokio::io::Error> { async fn get_voice_dictionary(path: &Path) -> Result<HashMap<String, PathBuf>, tokio::io::Error> {
let mut dir = tokio::fs::read_dir(path).await?; let mut dir = tokio::fs::read_dir(path).await?;
@ -124,15 +125,16 @@ impl EventHandler for LeaveHandler {
} }
pub async fn speak( pub async fn speak(
ctx: Context<'_>, ctx: &poise::serenity_prelude::Context,
data: &Arc<GlobalData>,
guild_id: GuildId, guild_id: GuildId,
user_id: UserId, user_id: UserId,
voice: &str, voice: &str,
phrase: &str, phrase: &str,
) -> Result<(), VoiceError> { ) -> Result<(), VoiceError> {
let _ = ctx.data().speak_lock.lock().await; let _ = data.speak_lock.lock().await;
let voice_path = match find_voice(&ctx.data().cfg.voice_path, voice).await.unwrap() { let voice_path = match find_voice(&data.cfg.voice_path, voice).await.unwrap() {
None => return Err(VoiceError::VoiceNotFound(voice.to_string())), None => return Err(VoiceError::VoiceNotFound(voice.to_string())),
Some(voice_path) => voice_path, Some(voice_path) => voice_path,
}; };
@ -170,7 +172,7 @@ pub async fn speak(
} }
let channel_id = { let channel_id = {
let guild = ctx.cache().guild(guild_id).unwrap(); let guild = guild_id.to_guild_cached(&ctx).unwrap();
guild guild
.voice_states .voice_states
@ -185,7 +187,7 @@ pub async fn speak(
} }
}; };
let manager = songbird::get(ctx.serenity_context()) let manager = songbird::get(ctx)
.await .await
.expect("Songbird not initialized") .expect("Songbird not initialized")
.clone(); .clone();
@ -215,7 +217,7 @@ pub async fn speak(
.add_event( .add_event(
Event::Track(TrackEvent::End), Event::Track(TrackEvent::End),
LeaveHandler { LeaveHandler {
guild: ctx.guild_id().unwrap(), guild: guild_id,
manager: manager.clone(), manager: manager.clone(),
}, },
) )
@ -238,7 +240,7 @@ pub async fn say(
) -> Result<(), Error> { ) -> Result<(), Error> {
let guild_id = ctx.guild_id().unwrap(); let guild_id = ctx.guild_id().unwrap();
if let Err(err) = speak(ctx, guild_id, ctx.author().id, &voice, &phrase).await { if let Err(err) = speak(ctx.serenity_context(), ctx.data(), guild_id, ctx.author().id, &voice, &phrase).await {
match err { match err {
VoiceError::VoiceNotFound(_) VoiceError::VoiceNotFound(_)
| VoiceError::WordNotFound(_) | VoiceError::WordNotFound(_)

View File

@ -9,12 +9,14 @@ mod migrations;
mod models; mod models;
mod music; mod music;
mod user; mod user;
mod api;
use crate::config::{Args, BotConfig, GlobalData}; use crate::config::{Args, BotConfig, GlobalData};
use crate::discord::run_bot; use crate::discord::run_bot;
use log::{error, info}; use log::{error, info};
use magick_rust::magick_wand_genesis; use magick_rust::magick_wand_genesis;
use std::sync::Once; use std::sync::Once;
use rustls::crypto;
use structopt::StructOpt; use structopt::StructOpt;
use tracing_core::LevelFilter; use tracing_core::LevelFilter;
use tracing_subscriber::EnvFilter; use tracing_subscriber::EnvFilter;
@ -25,6 +27,8 @@ static START: Once = Once::new();
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
crypto::aws_lc_rs::default_provider().install_default().expect("Unable to setup default Rustls provider");
let args: Args = Args::from_args(); let args: Args = Args::from_args();
tracing_subscriber::fmt() tracing_subscriber::fmt()
.with_env_filter( .with_env_filter(