Change queue command to accept query and display an embed

The queue command now displays an embed with pagination and
allows for songs to be queried by providing arguments. Each argument
is interpreted as a keyword that is searched for.

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/11/head
trivernis 3 years ago
parent 0f47c5b942
commit a98f401fbe
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -7,6 +7,7 @@ use serenity::model::channel::Reaction;
/// Shows the next page in the menu
pub async fn next_page(ctx: &Context, menu: &mut Menu<'_>, _: Reaction) -> SerenityUtilsResult<()> {
log::debug!("Showing next page");
menu.current_page = (menu.current_page + 1) % menu.pages.len();
display_page(ctx, menu).await?;
@ -19,6 +20,7 @@ pub async fn previous_page(
menu: &mut Menu<'_>,
_: Reaction,
) -> SerenityUtilsResult<()> {
log::debug!("Showing previous page");
if menu.current_page == 0 {
menu.current_page = menu.pages.len() - 1;
} else {
@ -35,6 +37,7 @@ pub async fn close_menu(
menu: &mut Menu<'_>,
_: Reaction,
) -> SerenityUtilsResult<()> {
log::debug!("Closing menu");
menu.close(ctx.http()).await?;
let listeners = get_listeners_from_context(&ctx).await?;
let mut listeners_lock = listeners.lock().await;
@ -46,6 +49,7 @@ pub async fn close_menu(
/// Displays the menu page
async fn display_page(ctx: &Context, menu: &mut Menu<'_>) -> SerenityUtilsResult<()> {
log::debug!("Displaying page {}", menu.current_page);
let page = menu
.pages
.get(menu.current_page)
@ -59,6 +63,7 @@ async fn display_page(ctx: &Context, menu: &mut Menu<'_>) -> SerenityUtilsResult
e
})
.await?;
log::debug!("Page displayed");
Ok(())
}

@ -8,6 +8,7 @@ use serenity::model::channel::Message;
#[command]
#[description("Displays a list of all gifs used by the bot")]
#[bucket("general")]
#[only_in(guilds)]
async fn gifs(ctx: &Context, msg: &Message) -> CommandResult {
let database = get_database_from_context(ctx).await;
let gifs = database.get_all_gifs().await?;

@ -10,7 +10,7 @@ use crate::commands::music::{get_queue_for_guild, is_dj};
#[only_in(guilds)]
#[description("Clears the queue")]
#[usage("")]
#[aliases("cl")]
#[aliases("cq", "clear-queue", "clearqueue")]
#[bucket("general")]
async fn clear_queue(ctx: &Context, msg: &Message) -> CommandResult {
let guild = msg.guild(&ctx.cache).await.unwrap();

@ -7,7 +7,7 @@ use serenity::model::channel::Message;
use crate::commands::common::handle_autodelete;
use crate::commands::music::get_queue_for_guild;
use crate::messages::music::create_now_playing_msg;
use crate::messages::music::now_playing::create_now_playing_msg;
#[command]
#[only_in(guilds)]

@ -31,7 +31,7 @@ use save_playlist::SAVE_PLAYLIST_COMMAND;
use shuffle::SHUFFLE_COMMAND;
use skip::SKIP_COMMAND;
use crate::messages::music::update_now_playing_msg;
use crate::messages::music::now_playing::update_now_playing_msg;
use crate::providers::music::queue::{MusicQueue, Song};
use crate::providers::music::youtube_dl;
use crate::providers::settings::{get_setting, Setting};

@ -5,7 +5,7 @@ use serenity::prelude::*;
use crate::commands::common::handle_autodelete;
use crate::commands::music::{get_queue_for_guild, is_dj};
use crate::messages::music::update_now_playing_msg;
use crate::messages::music::now_playing::update_now_playing_msg;
#[command]
#[only_in(guilds)]

@ -1,30 +1,49 @@
use std::cmp::min;
use serenity::client::Context;
use serenity::framework::standard::macros::command;
use serenity::framework::standard::CommandResult;
use serenity::framework::standard::{Args, CommandResult};
use serenity::model::channel::Message;
use crate::commands::common::handle_autodelete;
use crate::commands::music::get_queue_for_guild;
use crate::messages::music::queue::create_queue_menu;
use crate::providers::music::queue::Song;
#[command]
#[only_in(guilds)]
#[description("Shows the song queue")]
#[usage("")]
#[usage("(<query...>)")]
#[aliases("q")]
#[bucket("general")]
async fn queue(ctx: &Context, msg: &Message) -> CommandResult {
async fn queue(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
let guild = msg.guild(&ctx.cache).await.unwrap();
log::trace!("Displaying queue for guild {}", guild.id);
let query = args
.iter::<String>()
.map(|s| s.unwrap().to_lowercase())
.collect::<Vec<String>>();
let queue = get_queue_for_guild(ctx, &guild.id).await?;
let queue_lock = queue.lock().await;
let songs: Vec<(usize, String)> = queue_lock
let songs: Vec<(usize, Song)> = queue_lock
.entries()
.into_iter()
.map(|s| s.title().clone())
.enumerate()
.filter(|(i, s)| {
if query.is_empty() {
return true;
}
for kw in &query {
if s.title().to_lowercase().contains(kw)
|| s.author().to_lowercase().contains(kw)
|| &i.to_string() == kw
{
return true;
}
}
false
})
.map(|(i, s)| (i, s.clone()))
.collect();
log::trace!("Songs are {:?}", songs);
@ -37,26 +56,8 @@ async fn queue(ctx: &Context, msg: &Message) -> CommandResult {
return Ok(());
}
create_queue_menu(ctx, msg.channel_id, songs).await?;
let mut song_list = Vec::new();
for i in 0..min(10, songs.len() - 1) {
song_list.push(format!("{:0>3} - {}", songs[i].0 + 1, songs[i].1))
}
if songs.len() > 10 {
song_list.push("...".to_string());
let last = songs.last().unwrap();
song_list.push(format!("{:0>3} - {}", last.0 + 1, last.1))
}
log::trace!("Song list is {:?}", song_list);
msg.channel_id
.send_message(ctx, |m| {
m.embed(|e| {
e.title("Queue")
.description(format!("```\n{}\n```", song_list.join("\n")))
})
})
.await?;
handle_autodelete(ctx, msg).await?;
Ok(())

@ -0,0 +1,2 @@
pub mod now_playing;
pub mod queue;

@ -0,0 +1,45 @@
use crate::providers::music::queue::Song;
use crate::utils::error::BotResult;
use bot_serenityutils::menu::{MenuBuilder, Page};
use serenity::builder::CreateMessage;
use serenity::client::Context;
use serenity::model::id::ChannelId;
use std::time::Duration;
/// Creates a new queue menu
pub async fn create_queue_menu(
ctx: &Context,
channel_id: ChannelId,
songs: Vec<(usize, Song)>,
) -> BotResult<()> {
let page_count = (songs.len() as f32 / 10.0).ceil() as usize;
let pages: Vec<Page<'static>> = songs
.chunks(10)
.enumerate()
.map(|(i, entries)| create_songs_page(page_count, i + 1, entries.to_vec()))
.collect();
MenuBuilder::new_paginator()
.add_pages(pages)
.timeout(Duration::from_secs(120))
.build(ctx, channel_id)
.await?;
Ok(())
}
/// Creates a new page with songs
fn create_songs_page(total_pages: usize, page: usize, songs: Vec<(usize, Song)>) -> Page<'static> {
let mut message = CreateMessage::default();
let description_entries: Vec<String> = songs
.into_iter()
.map(|(i, s)| format!("{:0>3}. {} - {}", i, s.author(), s.title()))
.collect();
message.embed(|e| {
e.title("Queue")
.description(format!("```md\n{}\n```", description_entries.join("\n")))
.footer(|f| f.text(format!("Page {} of {}", page, total_pages)))
});
Page::new_static(message)
}
Loading…
Cancel
Save