Skip to content
This repository was archived by the owner on Mar 12, 2025. It is now read-only.

Commit 0521e67

Browse files
committed
fix: wip awful voice chat please god someone save me I feel my bones they're melting oh gOD HELP ME
1 parent df0b8df commit 0521e67

File tree

13 files changed

+1770
-40
lines changed

13 files changed

+1770
-40
lines changed

Cargo.lock

Lines changed: 1172 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,9 @@ reqwest = { version = "0.12.9", features = ["json"] }
2323
fastrand = "2.3.0"
2424
lru = "0.12.5"
2525
serde_json = "1.0"
26+
songbird = { version = "0.4", features = ["receive", "gateway"] }
27+
dashmap = "6.1.0"
28+
29+
[dependencies.symphonia]
30+
version = "0.5.2"
31+
features = ["wav", "mp3"]

extra/recording-start.mp3

13.6 KB
Binary file not shown.

extra/recording-voice.wav

36.4 KB
Binary file not shown.

src/databases.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@ use crate::database::Database;
22
use crate::modules::{
33
lorax::database::LoraxDatabase, modrinth::database::ModrinthDatabase,
44
stats::database::StatsDatabase, testing::database::TestingDatabase,
5+
recording::database::RecordingDatabase,
56
};
7+
use std::fs;
68

79
#[derive(Debug)]
810
pub struct Databases {
911
pub lorax: Database<LoraxDatabase>,
1012
pub stats: Database<StatsDatabase>,
1113
pub testing: Database<TestingDatabase>,
1214
pub modrinth: Database<ModrinthDatabase>,
15+
pub recording: Database<RecordingDatabase>,
1316
}
1417

1518
impl Default for Databases {
@@ -20,11 +23,15 @@ impl Default for Databases {
2023

2124
impl Databases {
2225
pub async fn default() -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
26+
// Create data directory if it doesn't exist
27+
fs::create_dir_all("data")?;
28+
2329
Ok(Self {
2430
lorax: Database::new("data/lorax.db").await?,
2531
stats: Database::new("data/stats.db").await?,
2632
testing: Database::new("data/testing.db").await?,
27-
modrinth: Database::new("modrinth.json").await?,
33+
modrinth: Database::new("data/modrinth.json").await?,
34+
recording: Database::new("data/recording.json").await?,
2835
})
2936
}
3037
}

src/events.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ use async_trait::async_trait;
22
use futures::stream::{FuturesUnordered, StreamExt};
33
use poise::serenity_prelude::{Context, FullEvent};
44
use std::fmt::Debug;
5+
use std::sync::Arc;
56
use tokio::sync::Mutex;
7+
use crate::{Data, modules::recording::handler::RecordingHandler};
68

79
#[async_trait]
810
pub trait EventHandler: Send + Sync + Debug {
@@ -33,6 +35,11 @@ impl EventManager {
3335
}
3436
}
3537

38+
pub async fn init(&self, data: &Arc<Data>) {
39+
let mut handlers = self.handlers.lock().await;
40+
handlers.push(Box::new(RecordingHandler::new(data.dbs.recording.clone())));
41+
}
42+
3643
pub async fn add_handler(&self, handler: impl EventHandler + 'static) {
3744
self.handlers.lock().await.push(Box::new(handler));
3845
}

src/main.rs

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ use databases::Databases;
33
use modules::{
44
lorax::{commands::lorax, task::LoraxEventTask},
55
modrinth::modrinth,
6+
recording::recording,
67
stats::{stats, task::StatsTask},
7-
system::events::ReadyHandler,
88
testing::{task::TestingTask, testing},
99
utils::server_costs,
1010
};
1111
use poise::serenity_prelude::{self as serenity, CreateAllowedMentions};
12+
use songbird::SerenityInit;
1213
use std::sync::Arc;
1314
use tasks::TaskManager;
1415
use tracing::{error, info, trace};
@@ -80,12 +81,20 @@ async fn main() {
8081
info!("starting prometheus");
8182

8283
let token = std::env::var("DISCORD_TOKEN").expect("missing DISCORD_TOKEN");
83-
let intents = serenity::GatewayIntents::non_privileged();
84+
let intents = serenity::GatewayIntents::all();
8485

8586
let framework = poise::Framework::builder()
8687
.options(poise::FrameworkOptions::<Data, Error> {
8788
allowed_mentions: Some(CreateAllowedMentions::new().empty_roles().empty_users()),
88-
commands: vec![register(), lorax(), stats(), testing(), modrinth(), server_costs()],
89+
commands: vec![
90+
register(),
91+
lorax(),
92+
stats(),
93+
testing(),
94+
modrinth(),
95+
server_costs(),
96+
recording(),
97+
],
8998
pre_command: |ctx| {
9099
Box::pin(async move {
91100
trace!(
@@ -143,23 +152,27 @@ async fn main() {
143152
let event_manager = Arc::new(events::EventManager::new());
144153
let master_key = std::env::var("MASTER_KEY").expect("missing MASTER_KEY");
145154

146-
event_manager.add_handler(ReadyHandler).await;
147-
148-
let data = Data {
149-
dbs,
150-
task_manager,
151-
event_manager,
155+
let data = Arc::new(Data {
156+
dbs: dbs.clone(),
157+
task_manager: task_manager.clone(),
158+
event_manager: event_manager.clone(),
152159
config: Config { master_key },
153-
};
160+
});
161+
162+
event_manager.init(&data).await;
154163
data.init_tasks(ctx).await;
155164

156-
Ok(data)
165+
Ok((*data).clone())
157166
})
158167
})
159168
.build();
160169

170+
let songbird = songbird::Songbird::serenity();
171+
songbird.set_config(songbird::Config::default().decode_mode(songbird::driver::DecodeMode::Decode));
172+
161173
let client = serenity::ClientBuilder::new(token, intents)
162174
.framework(framework)
175+
.register_songbird_with(songbird)
163176
.await;
164177

165178
client.unwrap().start().await.unwrap();

src/modules/lorax/commands/settings.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub async fn config(_ctx: Context<'_>) -> Result<(), Error> {
1717
}
1818

1919
/// Set the announcement channel
20-
#[command(slash_command, guild_only)]
20+
#[command(slash_command, guild_only, required_permissions = "MANAGE_GUILD")]
2121
pub async fn channel(
2222
ctx: Context<'_>,
2323
#[description = "Channel for Lorax announcements"] channel: serenity::Channel,
@@ -85,7 +85,7 @@ pub async fn channel(
8585
}
8686

8787
/// Configure role settings
88-
#[command(slash_command, guild_only)]
88+
#[command(slash_command, guild_only, required_permissions = "MANAGE_GUILD")]
8989
pub async fn roles(
9090
ctx: Context<'_>,
9191
#[description = "Role to mention for events"] event_role: Option<serenity::Role>,
@@ -157,7 +157,7 @@ pub async fn roles(
157157
}
158158

159159
/// Set event phase durations
160-
#[command(slash_command, guild_only)]
160+
#[command(slash_command, guild_only, required_permissions = "MANAGE_GUILD")]
161161
pub async fn durations(
162162
ctx: Context<'_>,
163163
#[description = "Minutes for submissions"] submission: Option<u64>,
@@ -205,7 +205,7 @@ pub async fn durations(
205205
}
206206

207207
/// View current Lorax settings
208-
#[command(slash_command, guild_only)]
208+
#[command(slash_command, guild_only, required_permissions = "MANAGE_GUILD")]
209209
pub async fn view(ctx: Context<'_>) -> Result<(), Error> {
210210
let guild_id = ctx.guild_id().unwrap().get();
211211

src/modules/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pub mod lorax;
22
pub mod modrinth;
3+
pub mod recording; // Add this
34
pub mod stats;
45
pub mod system;
56
pub mod testing;

src/modules/recording/commands.rs

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
use crate::Context;
2+
use poise::command;
3+
use poise::serenity_prelude::{ChannelId, ChannelType};
4+
use super::database::RecordingChannel;
5+
6+
/// Enable voice channel recording
7+
#[command(slash_command, guild_only)]
8+
pub async fn enable(
9+
ctx: Context<'_>,
10+
#[description = "Voice channel to record"] voice_channel: ChannelId,
11+
) -> Result<(), crate::Error> {
12+
let guild_id = ctx.guild_id().unwrap();
13+
14+
// Verify channel is voice channel
15+
let voice_channel_info = voice_channel.to_channel(&ctx).await?;
16+
17+
if voice_channel_info.guild().map(|c| c.kind) != Some(ChannelType::Voice) {
18+
ctx.say("The specified channel must be a voice channel!").await?;
19+
return Ok(());
20+
}
21+
22+
// Get database
23+
let db = &ctx.data().dbs.recording;
24+
25+
// Check if guild already has a recording channel
26+
if db.read(|data| {
27+
data.channels.contains_key(&guild_id.get())
28+
}).await {
29+
ctx.say("This guild already has a recording channel set up! Use `/recording disable` first.").await?;
30+
return Ok(());
31+
}
32+
33+
// Add recording channel
34+
db.transaction(|data| {
35+
data.channels.insert(
36+
guild_id.get(),
37+
RecordingChannel {
38+
guild_id: guild_id.get(),
39+
voice_channel_id: voice_channel.get(),
40+
is_recording: false,
41+
last_activity: None,
42+
},
43+
);
44+
Ok(())
45+
})
46+
.await?;
47+
48+
ctx.say("Voice channel recording enabled!").await?;
49+
Ok(())
50+
}
51+
52+
/// Disable voice channel recording
53+
#[command(slash_command, guild_only)]
54+
pub async fn disable(
55+
ctx: Context<'_>,
56+
) -> Result<(), crate::Error> {
57+
let guild_id = ctx.guild_id().unwrap();
58+
let db = &ctx.data().dbs.recording;
59+
60+
db.transaction(|data| {
61+
if data.channels.remove(&guild_id.get()).is_some() {
62+
Ok(())
63+
} else {
64+
Err("No recording channel configured for this guild.".into())
65+
}
66+
})
67+
.await?;
68+
69+
ctx.say("Voice channel recording disabled!").await?;
70+
Ok(())
71+
}
72+
73+
/// List recording channels
74+
#[command(slash_command, guild_only)]
75+
pub async fn list(ctx: Context<'_>) -> Result<(), crate::Error> {
76+
let guild_id = ctx.guild_id().unwrap();
77+
let db = &ctx.data().dbs.recording;
78+
79+
let channel = db.read(|data| {
80+
data.channels.get(&guild_id.get()).cloned()
81+
}).await;
82+
83+
match channel {
84+
Some(channel) => {
85+
let voice_name = ChannelId::new(channel.voice_channel_id)
86+
.to_channel(&ctx)
87+
.await?
88+
.guild()
89+
.map(|c| c.name().to_string())
90+
.unwrap_or_else(|| "Unknown".to_string());
91+
92+
ctx.say(format!(
93+
"Recording configuration:\nVoice Channel: {}\nCurrently Recording: {}\nLast Activity: {}",
94+
voice_name,
95+
if channel.is_recording { "Yes" } else { "No" },
96+
channel.last_activity.map(|t| t.to_rfc3339()).unwrap_or_else(|| "Never".to_string())
97+
)).await?;
98+
}
99+
None => {
100+
ctx.say("No recording channel configured for this guild.").await?;
101+
}
102+
}
103+
104+
Ok(())
105+
}
106+
107+
/// Toggle voice recording for a channel
108+
#[command(slash_command, guild_only)]
109+
pub async fn toggle(
110+
ctx: Context<'_>,
111+
#[description = "Voice channel to record (leave empty to disable)"] voice_channel: Option<ChannelId>,
112+
) -> Result<(), crate::Error> {
113+
let guild_id = ctx.guild_id().unwrap();
114+
let db = &ctx.data().dbs.recording;
115+
116+
match voice_channel {
117+
Some(channel) => {
118+
// Verify channel is voice channel
119+
let channel_info = channel.to_channel(&ctx).await?;
120+
121+
// Check channel type first
122+
if channel_info.clone().guild().map(|c| c.kind) != Some(ChannelType::Voice) {
123+
ctx.say("The specified channel must be a voice channel!").await?;
124+
return Ok(());
125+
}
126+
127+
// Update or create recording configuration
128+
db.transaction(|data| {
129+
data.channels.insert(
130+
guild_id.get(),
131+
RecordingChannel {
132+
guild_id: guild_id.get(),
133+
voice_channel_id: channel.get(),
134+
is_recording: false,
135+
last_activity: None,
136+
},
137+
);
138+
Ok(())
139+
})
140+
.await?;
141+
142+
let channel_name = channel_info.guild().map(|c| c.name().to_string())
143+
.unwrap_or_else(|| "Unknown".to_string());
144+
ctx.say(format!("Voice recording configured for channel: {}", channel_name)).await?;
145+
}
146+
None => {
147+
// Disable recording if it exists
148+
db.transaction(|data| {
149+
if data.channels.remove(&guild_id.get()).is_some() {
150+
Ok(())
151+
} else {
152+
Err("No recording channel was configured for this guild.".into())
153+
}
154+
})
155+
.await?;
156+
157+
ctx.say("Voice recording disabled!").await?;
158+
}
159+
}
160+
161+
Ok(())
162+
}

0 commit comments

Comments
 (0)