diff --git a/src/main/java/moe/nekojimi/chords/Main.java b/src/main/java/moe/nekojimi/chords/Main.java index 4d3d3e5..2adc300 100644 --- a/src/main/java/moe/nekojimi/chords/Main.java +++ b/src/main/java/moe/nekojimi/chords/Main.java @@ -6,15 +6,10 @@ package moe.nekojimi.chords; import java.io.File; -import java.net.MalformedURLException; import java.net.URL; import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; import javax.security.auth.login.LoginException; -import moe.nekojimi.chords.commands.Command; -import moe.nekojimi.chords.commands.JoinCommand; -import moe.nekojimi.musicsearcher.Query; +import moe.nekojimi.chords.commands.*; import moe.nekojimi.musicsearcher.Result; import moe.nekojimi.musicsearcher.providers.MetaSearcher; import moe.nekojimi.musicsearcher.providers.Searcher; @@ -35,8 +30,6 @@ import net.dv8tion.jda.api.utils.cache.CacheFlag; public class Main extends ListenerAdapter { - private static final double SEARCH_SCORE_THRESHOLD_AUTOPLAY = 9999; // disable autoplay it sucks - private static final double SEARCH_SCORE_THRESHOLD_DISPLAY = 0.6; private MusicHandler musicHandler; private final Downloader downloader; @@ -44,11 +37,10 @@ public class Main extends ListenerAdapter private JDA jda; private final Map commands = new HashMap<>(); + private final Command helpCommand; private VoiceChannel currentVoiceChannel = null; - private List lastSearchResults; - private int trackNumber = 1; /** @@ -111,6 +103,14 @@ public class Main extends ListenerAdapter searcher = MetaSearcher.loadYAML(new File("searchproviders.yml")); addCommand(new JoinCommand(this)); + addCommand(new LeaveCommand(this)); + addCommand(new PlayCommand(this)); + addCommand(new QueueCommand(this)); + addCommand(new RemoveCommand(this)); + addCommand(new RestartCommand(this)); + addCommand(new SkipCommand(this)); + helpCommand = new HelpCommand(this); + addCommand(helpCommand); } private void addCommand(Command command) @@ -157,176 +157,15 @@ public class Main extends ListenerAdapter { Command command = commands.get(cmd); command.call(event, List.of(arg)); - } - - // else if (content.startsWith("!join ")) - // onJoinCommand(event, guild, arg); - else if (content.equals("!leave")) - onLeaveCommand(event); -// else if (content.equals("!join")) -// onJoinCommand(event); - else if (content.startsWith("!play ")) - onPlayCommand(event, guild, arg); - else if (content.startsWith("!queue")) - onQueueCommand(event, guild); - else if (content.startsWith("!remove ")) - onRemoveCommand(event, guild, arg); - else if (content.startsWith("!restart")) - onRestartCommand(event); - else if (content.startsWith("!skip")) - onSkipCommand(event); - else if (content.startsWith("!")) - onHelpCommand(event); + } else + helpCommand.call(event, List.of(arg)); } catch (Exception ex) { event.getChannel().sendMessage("Error in command! " + ex.getMessage()).queue(); } } - /** - * Handle command without arguments. - * - * @param event - * The event for this command - */ -// private void onJoinCommand(GuildMessageReceivedEvent event) -// { -// // Note: None of these can be null due to our configuration with the JDABuilder! -// Member member = event.getMember(); // Member is the context of the user for the specific guild, containing voice state and roles -// GuildVoiceState voiceState = member.getVoiceState(); // Check the current voice state of the user -// VoiceChannel channel = voiceState.getChannel(); // Use the channel the user is currently connected to -//// if (channel != null) -//// { -//// connectTo(channel); // Join the channel of the user -//// onConnecting(channel, event.getChannel()); // Tell the user about our success -//// } else -//// onUnknownChannel(event.getChannel(), "your voice channel"); // Tell the user about our failure -// onJoinCommand(event, member.getGuild(), channel.getName()); -// } - - /** - * Handle command with arguments. - * - * @param event - * The event for this command - * @param guild - * The guild where its happening - * @param arg - * The input argument - */ -// private void onJoinCommand(GuildMessageReceivedEvent event, Guild guild, String arg) -// { -// boolean isNumber = arg.matches("\\d+"); // This is a regular expression that ensures the input consists of digits -// VoiceChannel channel = null; -// if (isNumber) // The input is an id? -// channel = guild.getVoiceChannelById(arg); -// if (channel == null) // Then the input must be a name? -// { -// List channels = guild.getVoiceChannelsByName(arg, true); -// if (!channels.isEmpty()) // Make sure we found at least one exact match -// channel = channels.get(0); // We found a channel! This cannot be null. -// } -// -// TextChannel textChannel = event.getChannel(); -// if (channel == null) // I have no idea what you want mr user -// { -// onUnknownChannel(textChannel, arg); // Let the user know about our failure -// return; -// } -// connectTo(channel); // We found a channel to connect to! -// onConnecting(channel, textChannel); // Let the user know, we were successful! -// } - - private void onLeaveCommand(GuildMessageReceivedEvent event) - { - if (currentVoiceChannel != null) - { - disconnect(); - } - } - - private void onPlayCommand(GuildMessageReceivedEvent event, Guild guild, String arg) - { - try - { - final URL url = new URL(arg); - queueDownload(url, event); - - } catch (MalformedURLException mux) - { - // not a URL, try parsing it as a search result - if (lastSearchResults != null && !lastSearchResults.isEmpty()) - { - try - { - int index = Integer.parseInt(arg); - int size = lastSearchResults.size(); - if (index >= 1 && index <= size) - { - Result res = lastSearchResults.get(index - 1); - queueDownload(res, event); -// event.getChannel().sendMessage("Song removed.").queue(); - } else if (size > 1) - event.getChannel().sendMessage("That's not a number between 1 and " + size + "!").queue(); - else if (size == 1) - event.getChannel().sendMessage("There's only one song and that's not one of them!").queue(); - - return; - } catch (NumberFormatException nfx) - { -// event.getChannel().sendMessage(arg + " isn't a number!").queue(); - } - } - - // otherwise, try searching - CompletableFuture> search = searcher.search(Query.fullText(arg)); - event.getChannel().sendMessage("Searching for \"" + arg + "\" ...").queue(); - search.orTimeout(30, TimeUnit.SECONDS).whenCompleteAsync((List results, Throwable exec) -> - { - if (exec != null) - { - event.getChannel().sendMessage("Failed to search! Reason: " + exec.getMessage()).queue(); - return; - } - - lastSearchResults = results; - - if (results.isEmpty()) - { - event.getChannel().sendMessage("Found nothing! :(").queue(); - return; - } - - if (results.get(0).getScore() >= SEARCH_SCORE_THRESHOLD_AUTOPLAY) - { - queueDownload(results.get(0).getLink(), event); - return; - } - - String resultString = ">>> :mag: __Search results:__\n"; - int i = 1; - for (Result result : results) - { - if (result.getScore() <= SEARCH_SCORE_THRESHOLD_DISPLAY && i > 5) - break; - if (i > 10) - break; - resultString += "**" + i + ":** " - + "[" + result.getSourceAbbr() + "] " - + "*" + result.getTitle() + "* " - + "by " + (result.getArtist() != null ? result.getArtist().trim() : "unknown") + " " - // + (result.getAlbum() != null ? "from the album *" + result.getAlbum().trim() + "*" : "") - + "\n"; - i++; - } - resultString += "Type eg. `!play 1` to select"; - event.getChannel().sendMessage(resultString).queue(); - }); -// event.getChannel().sendMessage("That's not a valid URL you idiot! " + ex.getMessage()).queue(); - } - } - - private Song queueDownload(final URL url, GuildMessageReceivedEvent event) + public Song queueDownload(final URL url, GuildMessageReceivedEvent event) { Song song = new Song(url); song.setRequestedBy(event.getAuthor().getName()); @@ -337,7 +176,7 @@ public class Main extends ListenerAdapter return song; } - private Song queueDownload(Result res, GuildMessageReceivedEvent event) + public Song queueDownload(Result res, GuildMessageReceivedEvent event) { Song song = queueDownload(res.getLink(), event); song.setArtist(res.getArtist()); @@ -346,101 +185,6 @@ public class Main extends ListenerAdapter return song; } - private void onRestartCommand(GuildMessageReceivedEvent event) - { - // TODO: this needs to clear the current data queue - boolean ok = musicHandler.restartSong(); - if (ok) - event.getChannel().sendMessage("Restarted current song!").queue(); - else - event.getChannel().sendMessage("Cannot restart!").queue(); - } - - private void onSkipCommand(GuildMessageReceivedEvent event) - { - boolean ok = musicHandler.nextSong(true); - if (ok) - event.getChannel().sendMessage("Skipped to next song!").queue(); - else - event.getChannel().sendMessage("There's no more songs!").queue(); - } - - private void onQueueCommand(GuildMessageReceivedEvent event, Guild guild) - { - String message = ">>> "; - int i = 1; - - final Song currentSong = musicHandler.getCurrentSong(); - if (currentSong != null) - message += ":notes: **Now playing: " + currentSong + "**\n"; - else - message += ":mute: **Not playing anything right now.**\n"; - - final Queue songQueue = musicHandler.getSongQueue(); - if (!songQueue.isEmpty()) - { - message += "__Ready to play:__\n"; - for (Song song : songQueue) - { - message += ":bread: **" + (i) + ":** " + song + "\n"; - i++; - } - } - - final List downloadQueue = downloader.getDownloadQueue(); - if (!downloadQueue.isEmpty()) - { - message += "__Downloading:__\n"; - for (Song song : downloadQueue) - { - message += ":inbox_tray: **" + (i) + ":** " + song + "\n"; - i++; - } - } - - if (downloadQueue.isEmpty() && songQueue.isEmpty()) - message += ":mailbox_with_no_mail: The track queue is empty."; - // :inbox_tray: - event.getChannel().sendMessage(message).queue(); - } - - private void onRemoveCommand(GuildMessageReceivedEvent event, Guild guild, String arg) - { - try - { - int i = Integer.parseInt(arg); - boolean removed = musicHandler.removeSong(i - 1); - final int size = musicHandler.getSongQueue().size(); - if (removed) - event.getChannel().sendMessage("Song removed.").queue(); - else if (size > 1) - event.getChannel().sendMessage("That's not a number between 1 and " + size + "!").queue(); - else if (size == 1) - event.getChannel().sendMessage("There's only one song to remove and that's not one of them!").queue(); - - } catch (NumberFormatException ex) - { - event.getChannel().sendMessage(arg + " isn't a number!").queue(); - } - } - - private void onHelpCommand(GuildMessageReceivedEvent event) - { - String help = "Commands available:\n" - + "!join - Joins a voice channel\n" - + "!leave - Leaves the current voice channel\n" - + "!play - Downloads the track at that URL and adds it to the queue.\n" - + "!play - Searches for a track and displays a selection menu.\n" - + "!queue - Show the songs currently playing and the current queue.\n" - + "!remove - Remove the song at position from the queue.\n" - + "!skip - Skip the current song and play the next one.\n" - + "!restart - Try playing the current song again in case it goes wrong.\n"; -// for (String key: commands.keySet()) -// { -// help += "!" + key + ":" -// } - event.getChannel().sendMessage(help).queue(); - } /** * Connect to requested channel and start echo handler * @@ -505,10 +249,6 @@ public class Main extends ListenerAdapter return currentVoiceChannel; } - public List getLastSearchResults() - { - return lastSearchResults; - } public int getTrackNumber() { diff --git a/src/main/java/moe/nekojimi/chords/commands/HelpCommand.java b/src/main/java/moe/nekojimi/chords/commands/HelpCommand.java new file mode 100644 index 0000000..f0d3e6f --- /dev/null +++ b/src/main/java/moe/nekojimi/chords/commands/HelpCommand.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2022 jimj316 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package moe.nekojimi.chords.commands; + +import java.util.List; +import moe.nekojimi.chords.Main; +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; + +public class HelpCommand extends Command +{ + + public HelpCommand(Main bot) + { + super(bot, "help"); + } + + @Override + public void call(GuildMessageReceivedEvent event, List arg) + { + String help = "Commands available:\n" + + "!join - Joins a voice channel\n" + + "!leave - Leaves the current voice channel\n" + + "!play - Downloads the track at that URL and adds it to the queue.\n" + + "!play - Searches for a track and displays a selection menu.\n" + + "!queue - Show the songs currently playing and the current queue.\n" + + "!remove - Remove the song at position from the queue.\n" + + "!skip - Skip the current song and play the next one.\n" + + "!restart - Try playing the current song again in case it goes wrong.\n"; +// for (String key: commands.keySet()) +// { +// help += "!" + key + ":" +// } + event.getChannel().sendMessage(help).queue(); + } + +} diff --git a/src/main/java/moe/nekojimi/chords/commands/PlayCommand.java b/src/main/java/moe/nekojimi/chords/commands/PlayCommand.java new file mode 100644 index 0000000..1ff4031 --- /dev/null +++ b/src/main/java/moe/nekojimi/chords/commands/PlayCommand.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2022 jimj316 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package moe.nekojimi.chords.commands; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import moe.nekojimi.chords.Main; +import moe.nekojimi.musicsearcher.Query; +import moe.nekojimi.musicsearcher.Result; +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; + +/** + * + * @author jimj316 + */ +public class PlayCommand extends Command +{ + private static final double SEARCH_SCORE_THRESHOLD_DISPLAY = 0.6; + private static final double SEARCH_SCORE_THRESHOLD_AUTOPLAY = 9999; // disable autoplay it sucks + + private List lastSearchResults; + + public PlayCommand(Main main) + { + super(main, "play"); + } + + @Override + public void call(GuildMessageReceivedEvent event, List arg) + { + try + { + final URL url = new URL(arg.get(0)); + bot.queueDownload(url, event); + + } catch (MalformedURLException mux) + { + // not a URL, try parsing it as a search result + if (lastSearchResults != null && !lastSearchResults.isEmpty()) + { + try + { + int index = Integer.parseInt(arg.get(0)); + int size = lastSearchResults.size(); + if (index >= 1 && index <= size) + { + Result res = lastSearchResults.get(index - 1); + bot.queueDownload(res, event); +// event.getChannel().sendMessage("Song removed.").queue(); + } else if (size > 1) + event.getChannel().sendMessage("That's not a number between 1 and " + size + "!").queue(); + else if (size == 1) + event.getChannel().sendMessage("There's only one song and that's not one of them!").queue(); + + return; + } catch (NumberFormatException nfx) + { +// event.getChannel().sendMessage(arg + " isn't a number!").queue(); + } + } + + // otherwise, try searching + CompletableFuture> search = bot.getSearcher().search(Query.fullText(arg.stream().reduce((t, u) -> t + " " + u).get())); + event.getChannel().sendMessage("Searching for \"" + arg + "\" ...").queue(); + search.orTimeout(30, TimeUnit.SECONDS).whenCompleteAsync((List results, Throwable exec) -> + { + if (exec != null) + { + event.getChannel().sendMessage("Failed to search! Reason: " + exec.getMessage()).queue(); + return; + } + + lastSearchResults = results; + + if (results.isEmpty()) + { + event.getChannel().sendMessage("Found nothing! :(").queue(); + return; + } + + if (results.get(0).getScore() >= SEARCH_SCORE_THRESHOLD_AUTOPLAY) + { + bot.queueDownload(results.get(0).getLink(), event); + return; + } + + String resultString = ">>> :mag: __Search results:__\n"; + int i = 1; + for (Result result : results) + { + if (result.getScore() <= SEARCH_SCORE_THRESHOLD_DISPLAY && i > 5) + break; + if (i > 10) + break; + resultString += "**" + i + ":** " + + "[" + result.getSourceAbbr() + "] " + + "*" + result.getTitle() + "* " + + "by " + (result.getArtist() != null ? result.getArtist().trim() : "unknown") + " " + // + (result.getAlbum() != null ? "from the album *" + result.getAlbum().trim() + "*" : "") + + "\n"; + i++; + } + resultString += "Type eg. `!play 1` to select"; + event.getChannel().sendMessage(resultString).queue(); + }); +// event.getChannel().sendMessage("That's not a valid URL you idiot! " + ex.getMessage()).queue(); + } + } + +} diff --git a/src/main/java/moe/nekojimi/chords/commands/QueueCommand.java b/src/main/java/moe/nekojimi/chords/commands/QueueCommand.java new file mode 100644 index 0000000..a2811e5 --- /dev/null +++ b/src/main/java/moe/nekojimi/chords/commands/QueueCommand.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2022 jimj316 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package moe.nekojimi.chords.commands; + +import java.util.List; +import java.util.Queue; +import moe.nekojimi.chords.Main; +import moe.nekojimi.chords.Song; +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; + +public class QueueCommand extends Command +{ + + public QueueCommand(Main bot) + { + super(bot, "queue"); + } + + @Override + public void call(GuildMessageReceivedEvent event, List arg) + { + String message = ">>> "; + int i = 1; + + final Song currentSong = bot.getMusicHandler().getCurrentSong(); + if (currentSong != null) + message += ":notes: **Now playing: " + currentSong + "**\n"; + else + message += ":mute: **Not playing anything right now.**\n"; + + final Queue songQueue = bot.getMusicHandler().getSongQueue(); + if (!songQueue.isEmpty()) + { + message += "__Ready to play:__\n"; + for (Song song : songQueue) + { + message += ":bread: **" + (i) + ":** " + song + "\n"; + i++; + } + } + + final List downloadQueue = bot.getDownloader().getDownloadQueue(); + if (!downloadQueue.isEmpty()) + { + message += "__Downloading:__\n"; + for (Song song : downloadQueue) + { + message += ":inbox_tray: **" + (i) + ":** " + song + "\n"; + i++; + } + } + + if (downloadQueue.isEmpty() && songQueue.isEmpty()) + message += ":mailbox_with_no_mail: The track queue is empty."; + // :inbox_tray: + event.getChannel().sendMessage(message).queue(); + } + +} diff --git a/src/main/java/moe/nekojimi/chords/commands/RemoveCommand.java b/src/main/java/moe/nekojimi/chords/commands/RemoveCommand.java new file mode 100644 index 0000000..40679a0 --- /dev/null +++ b/src/main/java/moe/nekojimi/chords/commands/RemoveCommand.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2022 jimj316 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package moe.nekojimi.chords.commands; + +import java.util.List; +import moe.nekojimi.chords.Main; +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; + +public class RemoveCommand extends Command +{ + + public RemoveCommand(Main bot) + { + super(bot, "remove"); + } + + @Override + public void call(GuildMessageReceivedEvent event, List arg) + { + try + { + int i = Integer.parseInt(arg.get(0)); + boolean removed = bot.getMusicHandler().removeSong(i - 1); + final int size = bot.getMusicHandler().getSongQueue().size(); + if (removed) + event.getChannel().sendMessage("Song removed.").queue(); + else if (size > 1) + event.getChannel().sendMessage("That's not a number between 1 and " + size + "!").queue(); + else if (size == 1) + event.getChannel().sendMessage("There's only one song to remove and that's not one of them!").queue(); + + } catch (NumberFormatException ex) + { + event.getChannel().sendMessage(arg + " isn't a number!").queue(); + } + } + +} diff --git a/src/main/java/moe/nekojimi/chords/commands/RestartCommand.java b/src/main/java/moe/nekojimi/chords/commands/RestartCommand.java new file mode 100644 index 0000000..5cdac33 --- /dev/null +++ b/src/main/java/moe/nekojimi/chords/commands/RestartCommand.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022 jimj316 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package moe.nekojimi.chords.commands; + +import java.util.List; +import moe.nekojimi.chords.Main; +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; + +public class RestartCommand extends Command +{ + + public RestartCommand(Main bot) + { + super(bot, "restart"); + } + + @Override + public void call(GuildMessageReceivedEvent event, List arg) + { + // TODO: this needs to clear the current data queue + boolean ok = bot.getMusicHandler().restartSong(); + if (ok) + event.getChannel().sendMessage("Restarted current song!").queue(); + else + event.getChannel().sendMessage("Cannot restart!").queue(); + } + +} diff --git a/src/main/java/moe/nekojimi/chords/commands/SkipCommand.java b/src/main/java/moe/nekojimi/chords/commands/SkipCommand.java new file mode 100644 index 0000000..6cfe5fc --- /dev/null +++ b/src/main/java/moe/nekojimi/chords/commands/SkipCommand.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2022 jimj316 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package moe.nekojimi.chords.commands; + +import java.util.List; +import moe.nekojimi.chords.Main; +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; + +public class SkipCommand extends Command +{ + + public SkipCommand(Main bot) + { + super(bot, "skip"); + } + + @Override + public void call(GuildMessageReceivedEvent event, List arg) + { + boolean ok = bot.getMusicHandler().nextSong(true); + if (ok) + event.getChannel().sendMessage("Skipped to next song!").queue(); + else + event.getChannel().sendMessage("There's no more songs!").queue(); + } + +}