Skip to content

Instantly share code, notes, and snippets.

@reactormonk
Created February 18, 2021 18:11
Show Gist options
  • Save reactormonk/e4e92973cab25318f3133b67dc0899c6 to your computer and use it in GitHub Desktop.
Save reactormonk/e4e92973cab25318f3133b67dc0899c6 to your computer and use it in GitHub Desktop.
use serenity::prelude::Mutex;
use songbird::Call;
use std::sync::Arc;
use songbird::Event;
use songbird::ffmpeg;
use songbird::SerenityInit;
use serenity::async_trait;
use serenity::client::{Client, Context, EventHandler};
use serenity::model::channel::Message;
use serenity::client::bridge::gateway::GatewayIntents;
use serenity::framework::standard::{
StandardFramework,
CommandResult,
macros::{
command,
group
}
};
use serenity::Result as SerenityResult;
use songbird::{
EventContext,
EventHandler as VoiceEventHandler,
TrackEvent,
};
use std::env;
#[group]
#[commands(ping)]
struct General;
struct Handler;
#[async_trait]
impl EventHandler for Handler {}
#[tokio::main]
async fn main() {
let framework = StandardFramework::new()
.configure(|c| c.prefix("~")) // set the bot's prefix to "~"
.group(&GENERAL_GROUP);
// Login with a bot token from the environment
let token = env::var("DISCORD_TOKEN").expect("token");
let mut client = Client::builder(token)
.event_handler(Handler)
.framework(framework)
.intents(GatewayIntents::non_privileged() | GatewayIntents::GUILDS | GatewayIntents::GUILD_VOICE_STATES)
.register_songbird()
.await
.expect("Error creating client");
// start listening for events by starting a single shard
if let Err(why) = client.start().await {
println!("An error occurred while running the client: {:?}", why);
}
}
#[command]
async fn ping(ctx: &Context, msg: &Message) -> CommandResult {
msg.reply(ctx, "Pong!").await?;
let guild = msg.guild(&ctx.cache).await;
match guild {
None => {},
Some(g) => {
let channel_id = g
.voice_states.get(&msg.author.id)
.and_then(|voice_state| voice_state.channel_id);
let connect_to = match channel_id {
Some(channel) => channel,
None => {
check_msg(msg.reply(ctx, "Not in a voice channel").await);
return Ok(());
}
};
let manager = songbird::serenity::get(ctx).await
.expect("Songbird Voice client placed in at initialisation.").clone();
let (call, _err) = manager.join(g.id, connect_to).await;
if let Some(handler_lock) = manager.get(g.id) {
let mut handler = handler_lock.lock().await;
let source = match ffmpeg("Rick Astley - Never Gonna Give You Up (Video)-dQw4w9WgXcQ.opus").await {
Ok(source) => source,
Err(why) => {
println!("Err starting source: {:?}", why);
check_msg(msg.channel_id.say(&ctx.http, "Error sourcing ffmpeg").await);
return Ok(());
},
};
let song = handler.play_only_source(source);
song.set_volume(0.3)?;
// This shows how to fire an event once an audio track completes,
// either due to hitting the end of the bytestream or stopped by user code.
let _ = song.add_event(
Event::Track(TrackEvent::End),
SongEndNotifier {
call,
},
);
}
}
}
Ok(())
}
fn check_msg(result: SerenityResult<Message>) {
if let Err(why) = result {
println!("Error sending message: {:?}", why);
}
}
struct SongEndNotifier {
call: Arc<Mutex<Call>>,
}
#[async_trait]
impl VoiceEventHandler for SongEndNotifier {
async fn act(&self, _ctx: &EventContext<'_>) -> Option<Event> {
if let Err(e) = (*self.call).lock().await.leave().await {
println!("Error sending message: {:?}", e);
}
None
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment