feat: started to impl queue system
This commit is contained in:
parent
a16d8a6b60
commit
a06299fb6f
9 changed files with 134 additions and 54 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -1338,12 +1338,6 @@ dependencies = [
|
||||||
"unicase",
|
"unicase",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "queues"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1475abae4f8ad4998590fe3acfe20104f0a5d48fc420c817cd2c09c3f56151f0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.35"
|
version = "1.0.35"
|
||||||
|
@ -1567,8 +1561,6 @@ dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"confy",
|
"confy",
|
||||||
"futures",
|
"futures",
|
||||||
"once_cell",
|
|
||||||
"queues",
|
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "rustendo"
|
name = "rustendo"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["moonleay <contact@moonleay.net>"]
|
authors = ["moonleay <contact@moonleay.net>", "migueldamota <miguel@damota.de>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
@ -21,5 +21,3 @@ tracing = "0.1.40"
|
||||||
tracing-subscriber = "0.3.18"
|
tracing-subscriber = "0.3.18"
|
||||||
tracing-futures = "0.2.5"
|
tracing-futures = "0.2.5"
|
||||||
futures = "0.3.1"
|
futures = "0.3.1"
|
||||||
queues = "1"
|
|
||||||
once_cell = "1"
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::music::music_manager;
|
||||||
|
|
||||||
use crate::util::embed::Embed;
|
use crate::util::embed::Embed;
|
||||||
|
|
||||||
pub async fn run(ctx: &Context, command: &CommandInteraction) -> CreateEmbed {
|
pub async unsafe fn run(ctx: &Context, command: &CommandInteraction) -> CreateEmbed {
|
||||||
let username = command.user.name.as_str();
|
let username = command.user.name.as_str();
|
||||||
let options = &command.data.options;
|
let options = &command.data.options;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ use serenity::builder::{CreateCommand, CreateEmbed};
|
||||||
use crate::music::music_manager;
|
use crate::music::music_manager;
|
||||||
use crate::util::embed::Embed;
|
use crate::util::embed::Embed;
|
||||||
|
|
||||||
pub async fn run(ctx: &Context, command: &CommandInteraction) -> CreateEmbed {
|
pub async unsafe fn run(ctx: &Context, command: &CommandInteraction) -> CreateEmbed {
|
||||||
let username = command.user.name.as_str();
|
let username = command.user.name.as_str();
|
||||||
|
|
||||||
let guild_id = match &command.guild_id {
|
let guild_id = match &command.guild_id {
|
||||||
|
|
26
src/main.rs
26
src/main.rs
|
@ -29,20 +29,22 @@ struct Handler;
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl EventHandler for Handler {
|
impl EventHandler for Handler {
|
||||||
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
|
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
|
||||||
if let Interaction::Command(command) = interaction {
|
unsafe {
|
||||||
let _ = &command.defer(&ctx.http()).await.expect("Cannot defer");
|
if let Interaction::Command(command) = interaction {
|
||||||
|
let _ = &command.defer(&ctx.http()).await.expect("Cannot defer");
|
||||||
|
|
||||||
let content = Some(match command.data.name.as_str() {
|
let content = Some(match command.data.name.as_str() {
|
||||||
"info" => commands::info::run(&ctx, &command).await,
|
"info" => commands::info::run(&ctx, &command).await,
|
||||||
"play" => commands::play::run(&ctx, &command).await,
|
"play" => commands::play::run(&ctx, &command).await,
|
||||||
"stop" => commands::stop::run(&ctx, &command).await,
|
"stop" => commands::stop::run(&ctx, &command).await,
|
||||||
_ => respond_with_error(&ctx, &command).await,
|
_ => respond_with_error(&ctx, &command).await,
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(embed) = content {
|
if let Some(embed) = content {
|
||||||
let followup = CreateInteractionResponseFollowup::new().embed(embed);
|
let followup = CreateInteractionResponseFollowup::new().embed(embed);
|
||||||
if let Err(why) = command.create_followup(&ctx.http, followup).await {
|
if let Err(why) = command.create_followup(&ctx.http, followup).await {
|
||||||
println!("Cannot followup to slash command: {why}")
|
println!("Cannot followup to slash command: {why}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
pub mod music_manager;
|
pub mod music_manager;
|
||||||
pub mod music_events;
|
pub mod music_events;
|
||||||
|
mod music_queue;
|
|
@ -1,9 +1,8 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use queues::IsQueue;
|
|
||||||
use serenity::all::{ChannelId, GuildId, Http};
|
use serenity::all::{ChannelId, GuildId, Http};
|
||||||
use serenity::async_trait;
|
use serenity::async_trait;
|
||||||
use songbird::{Event, EventContext, EventHandler};
|
use songbird::{Event, EventContext, EventHandler};
|
||||||
use crate::music::music_manager;
|
use crate::music::{music_manager, music_queue};
|
||||||
|
|
||||||
pub struct TrackEndNotifier {
|
pub struct TrackEndNotifier {
|
||||||
pub guild_id: GuildId,
|
pub guild_id: GuildId,
|
||||||
|
@ -18,8 +17,10 @@ impl EventHandler for TrackEndNotifier {
|
||||||
unsafe { // TODO: Does this need to be unsafe?
|
unsafe { // TODO: Does this need to be unsafe?
|
||||||
if let EventContext::Track(track_list) = ctx {
|
if let EventContext::Track(track_list) = ctx {
|
||||||
println!("The track ended!");
|
println!("The track ended!");
|
||||||
let queue = music_manager::get_queue(&self.guild_id);
|
let music_queue = music_queue::get_queue(&self.guild_id);
|
||||||
if queue.size() == 0 {
|
let q = &music_queue.queue;
|
||||||
|
if q.len() == 0 {
|
||||||
|
// No more songs in queue, exit the vc
|
||||||
let stopped = match music_manager::stop(&self.cmdctx, &self.guild_id).await {
|
let stopped = match music_manager::stop(&self.cmdctx, &self.guild_id).await {
|
||||||
Ok(stopped) => stopped,
|
Ok(stopped) => stopped,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -34,6 +35,19 @@ impl EventHandler for TrackEndNotifier {
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
let head = music_queue::get_head(&self.guild_id);
|
||||||
|
if head.is_none() {
|
||||||
|
println!("Cannot get head of queue");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let head = head.unwrap();
|
||||||
|
/*let started = match music_manager::play(&self.cmdctx, &self.guild_id, &head).await {
|
||||||
|
Ok(started) => started,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Cannot play: {:?}", e);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}; */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,28 +1,16 @@
|
||||||
use std::collections::{HashMap};
|
use std::sync::{Arc};
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
use queues::Queue;
|
|
||||||
use serenity::all::{Context, CreateEmbed, GuildId, UserId};
|
use serenity::all::{Context, CreateEmbed, GuildId, UserId};
|
||||||
use songbird::{Event, TrackEvent};
|
use songbird::{Event, TrackEvent};
|
||||||
use songbird::error::JoinError;
|
use songbird::error::JoinError;
|
||||||
use songbird::input::{Compose, YoutubeDl};
|
use songbird::input::{Compose, YoutubeDl};
|
||||||
use crate::HttpKey;
|
use crate::HttpKey;
|
||||||
use crate::music::music_events;
|
use crate::music::{music_events, music_queue};
|
||||||
use crate::util::embed::Embed;
|
use crate::util::embed::Embed;
|
||||||
use crate::util::user_util;
|
use crate::util::user_util;
|
||||||
use crate::util::user_util::get_vc_id;
|
use crate::util::user_util::get_vc_id;
|
||||||
|
|
||||||
/// pub static mut MUSIC_QUEUE: HashMap<GuildId, Queue<String>> = HashMap::new();
|
pub async unsafe fn attempt_to_queue_song(ctx: &Context, guild_id: &GuildId, user_id: &UserId, username: &str, query: &str) -> CreateEmbed {
|
||||||
pub static mut MUSIC_QUEUE: Lazy<Mutex<HashMap<GuildId, Queue<String>>>> = Lazy::new(|| {
|
|
||||||
Mutex::new(HashMap::new())
|
|
||||||
}); // TODO: This does not work and this is not the way to do it. This is a placeholder for now.
|
|
||||||
|
|
||||||
pub unsafe fn get_queue(guild_id: &GuildId) -> &Queue<String> {
|
|
||||||
MUSIC_QUEUE.lock().unwrap().entry(*guild_id).or_insert_with(Queue::new)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn attempt_to_queue_song(ctx: &Context, guild_id: &GuildId, user_id: &UserId, username: &str, query: &str) -> CreateEmbed {
|
|
||||||
if !user_util::is_user_connected_to_vc(ctx, guild_id, user_id).await {
|
if !user_util::is_user_connected_to_vc(ctx, guild_id, user_id).await {
|
||||||
return Embed::create(username, "You are not connected to a VC", "Connect to my VC to control the music.");
|
return Embed::create(username, "You are not connected to a VC", "Connect to my VC to control the music.");
|
||||||
}
|
}
|
||||||
|
@ -35,7 +23,7 @@ pub async fn attempt_to_queue_song(ctx: &Context, guild_id: &GuildId, user_id: &
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let manager = &songbird::get(ctx)
|
let manager = &songbird::get(ctx) // TODO match
|
||||||
.await
|
.await
|
||||||
.expect("Cannot get Songbird.")
|
.expect("Cannot get Songbird.")
|
||||||
.clone();
|
.clone();
|
||||||
|
@ -65,6 +53,16 @@ pub async fn attempt_to_queue_song(ctx: &Context, guild_id: &GuildId, user_id: &
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let currently_playing = music_queue::get_now_playing(&guild_id);
|
||||||
|
music_queue::add_to_queue(&guild_id, query.to_string());
|
||||||
|
if currently_playing != "".to_string() {
|
||||||
|
// Add to queue
|
||||||
|
return Embed::create(username, "Added to queue", "The song was added to the queue.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let query = music_queue::get_head(&guild_id).expect("Cannot get head of queue");
|
||||||
|
music_queue::set_now_playing(&guild_id, query.clone());
|
||||||
|
|
||||||
// Get query
|
// Get query
|
||||||
let do_search = !query.starts_with("http");
|
let do_search = !query.starts_with("http");
|
||||||
let http_client = {
|
let http_client = {
|
||||||
|
@ -83,13 +81,13 @@ pub async fn attempt_to_queue_song(ctx: &Context, guild_id: &GuildId, user_id: &
|
||||||
let handler_lock = match manager.get(*guild_id) {
|
let handler_lock = match manager.get(*guild_id) {
|
||||||
Some(handler) => handler,
|
Some(handler) => handler,
|
||||||
None => {
|
None => {
|
||||||
return Embed::create(username, "Error", "Cannot get handler");
|
return Embed::create("", "Error", "Cannot get handler");
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Start playing
|
// Start playing
|
||||||
let mut handler = handler_lock.lock().await;
|
let mut handler = handler_lock.lock().await;
|
||||||
let track_handle = handler.play_input(src.clone().into()); // TODO: Add event handlers
|
let _ = handler.play_input(src.clone().into()); // TODO: Add event handlers
|
||||||
handler.add_global_event(
|
handler.add_global_event(
|
||||||
Event::Track(TrackEvent::End),
|
Event::Track(TrackEvent::End),
|
||||||
music_events::TrackEndNotifier {
|
music_events::TrackEndNotifier {
|
||||||
|
@ -113,8 +111,11 @@ pub async fn attempt_to_queue_song(ctx: &Context, guild_id: &GuildId, user_id: &
|
||||||
.thumbnail(thumbnail)
|
.thumbnail(thumbnail)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async unsafe fn play() {
|
||||||
|
|
||||||
pub async fn attempt_to_stop(ctx: &Context, guild_id: &GuildId, user_id: &UserId, username: &str) -> CreateEmbed {
|
}
|
||||||
|
|
||||||
|
pub async unsafe fn attempt_to_stop(ctx: &Context, guild_id: &GuildId, user_id: &UserId, username: &str) -> CreateEmbed {
|
||||||
if !user_util::is_self_connected_to_vc(ctx, guild_id).await {
|
if !user_util::is_self_connected_to_vc(ctx, guild_id).await {
|
||||||
// Bot is not connectd to vc; no need to dc
|
// Bot is not connectd to vc; no need to dc
|
||||||
return Embed::create(
|
return Embed::create(
|
||||||
|
@ -143,17 +144,24 @@ pub async fn attempt_to_stop(ctx: &Context, guild_id: &GuildId, user_id: &UserId
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if !stopped {
|
return if !stopped {
|
||||||
return Embed::create(username, "Can't stop, what ain't running.", "I am not connected. I cant stop doing something, when I'm not doing it".to_string());
|
Embed::create(username, "Can't stop, what ain't running.", "I am not connected. I cant stop doing something, when I'm not doing it".to_string())
|
||||||
} else {
|
} else {
|
||||||
return Embed::create(
|
music_queue::delete_queue(guild_id); // Clear queue
|
||||||
|
|
||||||
|
Embed::create(
|
||||||
username,
|
username,
|
||||||
"I stopped and left",
|
"I stopped and left",
|
||||||
"Just like your girlfriend.",
|
"Just like your girlfriend.",
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// pub async unsafe fn play_song(ctx: &Context, guild_id: &GuildId, query: String) -> Result<bool, JoinError> {
|
||||||
|
|
||||||
|
/// }
|
||||||
|
|
||||||
|
|
||||||
// Make the bot leave the voice channel. Returns Ok(true) if bot was connected, returns Ok(false) if bot was not connected. Returns Err if something went wrong.
|
// Make the bot leave the voice channel. Returns Ok(true) if bot was connected, returns Ok(false) if bot was not connected. Returns Err if something went wrong.
|
||||||
pub async fn stop(ctx: &Context, guild_id: &GuildId) -> Result<bool, JoinError> {
|
pub async fn stop(ctx: &Context, guild_id: &GuildId) -> Result<bool, JoinError> {
|
||||||
let manager = songbird::get(ctx)
|
let manager = songbird::get(ctx)
|
||||||
|
|
65
src/music/music_queue.rs
Normal file
65
src/music/music_queue.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
use serenity::all::GuildId;
|
||||||
|
|
||||||
|
pub struct MusicQueue { // God this sucks. This needs to be reprogrammed properly.
|
||||||
|
guild_id: GuildId,
|
||||||
|
pub queue: Vec<String>,
|
||||||
|
pub now_playing: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
static mut MUSIC_QUEUE: Vec<MusicQueue> = Vec::new();
|
||||||
|
|
||||||
|
pub unsafe fn get_queue(guild_id: &GuildId) -> &MusicQueue {
|
||||||
|
let queue = MUSIC_QUEUE.iter().find(|q| q.guild_id == *guild_id);
|
||||||
|
match queue {
|
||||||
|
Some(queue) => queue,
|
||||||
|
None => {
|
||||||
|
let new_queue = MusicQueue {
|
||||||
|
guild_id: *guild_id,
|
||||||
|
queue: Vec::new(),
|
||||||
|
now_playing: "".to_string(),
|
||||||
|
};
|
||||||
|
MUSIC_QUEUE.push(new_queue);
|
||||||
|
MUSIC_QUEUE.iter().find(|q| q.guild_id == *guild_id).expect("Cannot get queue")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn update_queue(guild_id: &GuildId, queue: Vec<String>, now_playing: String) {
|
||||||
|
let index = MUSIC_QUEUE.iter().position(|q| q.guild_id == *guild_id).expect("Cannot get index");
|
||||||
|
MUSIC_QUEUE[index] = MusicQueue{
|
||||||
|
guild_id: *guild_id,
|
||||||
|
queue,
|
||||||
|
now_playing,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn delete_queue(guild_id: &GuildId) {
|
||||||
|
let index = MUSIC_QUEUE.iter().position(|q| q.guild_id == *guild_id).expect("Cannot get index");
|
||||||
|
MUSIC_QUEUE.remove(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn add_to_queue(guild_id: &GuildId, input: String) {
|
||||||
|
let queue = get_queue(guild_id);
|
||||||
|
let mut new_queue = queue.queue.clone();
|
||||||
|
new_queue.push(input);
|
||||||
|
update_queue(guild_id, new_queue, queue.now_playing.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn get_head(guild_id: &GuildId) -> Option<String> {
|
||||||
|
let queue = get_queue(guild_id);
|
||||||
|
let mut q = queue.queue.clone();
|
||||||
|
let result = q.first().map(|s| s.clone());
|
||||||
|
q.remove(0);
|
||||||
|
update_queue(guild_id, q, queue.now_playing.clone());
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn set_now_playing(guild_id: &GuildId, now_playing: String) {
|
||||||
|
let queue = get_queue(guild_id);
|
||||||
|
update_queue(guild_id, queue.queue.clone(), now_playing);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn get_now_playing(guild_id: &GuildId) -> String {
|
||||||
|
let queue = get_queue(guild_id);
|
||||||
|
queue.now_playing.clone()
|
||||||
|
}
|
Loading…
Reference in a new issue