Skip to main content

voice/
voice.rs

1use fluxer::prelude::*;
2use tokio::sync::Mutex;
3use tokio::task::AbortHandle;
4
5const PREFIX: &str = "!";
6const AUDIO_FILE: &str = "audio/audio.mp3";
7
8struct Handler {
9    playback: Mutex<Option<AbortHandle>>,
10    voice: Mutex<Option<FluxerVoiceConnection>>,
11}
12
13fn parse_command(content: &str) -> Option<(&str, &str)> {
14    let trimmed = content.strip_prefix(PREFIX)?;
15    match trimmed.find(' ') {
16        Some(pos) => Some((&trimmed[..pos], trimmed[pos + 1..].trim())),
17        None => Some((trimmed, "")),
18    }
19}
20
21#[async_trait]
22impl EventHandler for Handler {
23    async fn on_ready(&self, _ctx: Context, ready: Ready) {
24        println!("Logged in as {}", ready.user.username);
25    }
26
27    async fn on_message(&self, ctx: Context, msg: Message) {
28        if msg.author.bot.unwrap_or(false) {
29            return;
30        }
31
32        let content = match msg.content.as_deref() {
33            Some(c) => c,
34            None => return,
35        };
36
37        let channel_id = msg.channel_id.as_deref().unwrap_or_default();
38        let guild_id = match msg.guild_id.as_deref() {
39            Some(id) => id,
40            None => return,
41        };
42
43        let (cmd, args) = match parse_command(content) {
44            Some(v) => v,
45            None => return,
46        };
47
48        match cmd {
49            "join" => {
50                if args.is_empty() {
51                    let _ = ctx.http.send_message(channel_id, "`!join <voice_channel_id>`").await;
52                    return;
53                }
54
55                match ctx.join_voice(guild_id, args).await {
56                    Ok(conn) => {
57                        *self.voice.lock().await = Some(conn);
58                        let _ = ctx.http.send_message(channel_id, "Joined.").await;
59                    }
60                    Err(e) => {
61                        let _ = ctx.http.send_message(channel_id, &format!("Failed: {}", e)).await;
62                    }
63                }
64            }
65
66            "leave" => {
67                if let Some(handle) = self.playback.lock().await.take() {
68                    handle.abort();
69                }
70                *self.voice.lock().await = None;
71                let _ = ctx.leave_voice(guild_id).await;
72                let _ = ctx.http.send_message(channel_id, "Left.").await;
73            }
74
75            "play" => {
76                let conn = self.voice.lock().await;
77                let conn = match conn.as_ref() {
78                    Some(c) => c,
79                    None => {
80                        let _ = ctx.http.send_message(channel_id, "Not in a voice channel.").await;
81                        return;
82                    }
83                };
84
85                if let Some(handle) = self.playback.lock().await.take() {
86                    handle.abort();
87                }
88
89                match conn.play_music(AUDIO_FILE, ctx.http.clone(), channel_id.to_string()).await {
90                    Ok(handle) => {
91                        *self.playback.lock().await = Some(handle);
92                        let _ = ctx.http.send_message(channel_id, &format!("Playing `{}`.", AUDIO_FILE)).await;
93                    }
94                    Err(e) => {
95                        let _ = ctx.http.send_message(channel_id, &format!("Failed: {}", e)).await;
96                    }
97                }
98            }
99
100            "stop" => {
101                if let Some(handle) = self.playback.lock().await.take() {
102                    handle.abort();
103                    let _ = ctx.http.send_message(channel_id, "Stopped.").await;
104                } else {
105                    let _ = ctx.http.send_message(channel_id, "Nothing is playing.").await;
106                }
107            }
108
109            _ => {}
110        }
111    }
112}
113
114#[tokio::main]
115async fn main() {
116    let token = std::env::var("FLUXER_TOKEN")
117        .expect("Set FLUXER_TOKEN to your bot token");
118
119    let handler = Handler {
120        playback: Mutex::new(None),
121        voice: Mutex::new(None),
122    };
123
124    let mut client = Client::builder(&token)
125        // .api_url("http://localhost:48763/api/v1") this is for self hosted instances
126        .event_handler(handler)
127        .build();
128
129    if let Err(e) = client.start().await {
130        eprintln!("Error: {}", e);
131    }
132}