From 3288f7aa75be86c99f55bc49ad86b261c517bccd Mon Sep 17 00:00:00 2001 From: Andrew Lalis Date: Sat, 24 Jun 2017 16:20:40 +0200 Subject: [PATCH 1/4] Cleaned up the command handler. --- README.md | 2 +- pom.xml | 25 +++ src/main/java/META-INF/MANIFEST.MF | 3 + src/main/java/handiebot/HandieBot.java | 5 + .../handiebot/command/CommandHandler.java | 154 ++++++++++-------- .../command/commands/InfoCommand.java | 30 ++++ .../command/commands/SetPrefixCommand.java | 32 ++++ .../commands/music/PlaylistCommand.java | 12 +- .../command/commands/music/QueueCommand.java | 2 +- .../handiebot/lavaplayer/MusicPlayer.java | 2 +- .../handiebot/lavaplayer/TrackScheduler.java | 2 - src/main/java/handiebot/utils/FileUtil.java | 61 +++++++ src/main/java/handiebot/view/View.java | 52 +++++- 13 files changed, 296 insertions(+), 86 deletions(-) create mode 100644 src/main/java/META-INF/MANIFEST.MF create mode 100644 src/main/java/handiebot/command/commands/InfoCommand.java create mode 100644 src/main/java/handiebot/command/commands/SetPrefixCommand.java create mode 100644 src/main/java/handiebot/utils/FileUtil.java diff --git a/README.md b/README.md index 29e7f22..feee5e1 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Because the play command is defined as `play [URL]`, and the queue command is de * `skip` - If a song is playing, the bot will skip it and play the next song in the queue. -* `queue [all]` - Lists up to the first 10 items on the queue, if no argument is given. If you add `all`, the bot will upload a list to [PasteBin](http://pastebin.com) of the entire queue, and give you +* `queue [all]` - Lists up to the first 10 items on the queue, if no argument is given. If you add `all`, the bot will upload a list to [PasteBin](http://pastebin.com) of the entire queue, provided it is greater than 10 elements, and give you a link which expires in 10 minutes. * `repeat [true|false]` - Sets the bot to repeat the playlist, as in once a song is removed from the queue to be played, it is added back to the end of the playlist. diff --git a/pom.xml b/pom.xml index dea48d3..321f66d 100644 --- a/pom.xml +++ b/pom.xml @@ -17,6 +17,31 @@ 1.8 + + org.apache.maven.plugins + maven-assembly-plugin + 3.0.0 + + 1.8 + 1.8 + + jar-with-dependencies + + + + handiebot.HandieBot + + + + + + package + + single + + + + jar diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 0000000..e9e1ba4 --- /dev/null +++ b/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: handiebot.HandieBot + diff --git a/src/main/java/handiebot/HandieBot.java b/src/main/java/handiebot/HandieBot.java index 7e4ca6e..a92be94 100644 --- a/src/main/java/handiebot/HandieBot.java +++ b/src/main/java/handiebot/HandieBot.java @@ -2,6 +2,7 @@ package handiebot; import handiebot.command.CommandHandler; import handiebot.lavaplayer.MusicPlayer; +import handiebot.utils.DisappearingMessage; import handiebot.view.BotLog; import handiebot.view.BotWindow; import handiebot.view.View; @@ -10,6 +11,7 @@ import sx.blah.discord.api.IDiscordClient; import sx.blah.discord.api.events.EventSubscriber; import sx.blah.discord.handle.impl.events.ReadyEvent; import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent; +import sx.blah.discord.handle.obj.IGuild; import sx.blah.discord.util.DiscordException; import sx.blah.discord.util.RateLimitException; @@ -40,6 +42,9 @@ public class HandieBot { @EventSubscriber public void onReady(ReadyEvent event){ log.log(BotLog.TYPE.INFO, "HandieBot initialized."); + for (IGuild guild : client.getGuilds()){ + DisappearingMessage.deleteMessageAfter(5000, musicPlayer.getChatChannel(guild).sendMessage("HandieBot initialized.")); + } //client.changeAvatar(Image.forStream("png", getClass().getClassLoader().getResourceAsStream("avatarIcon.png"))); } diff --git a/src/main/java/handiebot/command/CommandHandler.java b/src/main/java/handiebot/command/CommandHandler.java index a4a14b2..3b78cd5 100644 --- a/src/main/java/handiebot/command/CommandHandler.java +++ b/src/main/java/handiebot/command/CommandHandler.java @@ -1,21 +1,25 @@ package handiebot.command; -import com.sun.istack.internal.NotNull; -import handiebot.command.commands.music.PlayCommand; -import handiebot.command.commands.music.PlaylistCommand; -import handiebot.command.commands.music.RepeatCommand; -import handiebot.command.commands.music.ShuffleCommand; +import handiebot.command.commands.HelpCommand; +import handiebot.command.commands.InfoCommand; +import handiebot.command.commands.SetPrefixCommand; +import handiebot.command.commands.music.*; import handiebot.utils.DisappearingMessage; +import handiebot.utils.FileUtil; import handiebot.view.BotLog; -import handiebot.view.actions.QuitAction; -import handiebot.view.actions.music.QueueListAction; -import handiebot.view.actions.music.SkipAction; import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent; -import sx.blah.discord.handle.obj.*; -import sx.blah.discord.util.EmbedBuilder; +import sx.blah.discord.handle.obj.IChannel; +import sx.blah.discord.handle.obj.IGuild; +import sx.blah.discord.handle.obj.IMessage; +import sx.blah.discord.handle.obj.IUser; -import java.awt.*; +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import static handiebot.HandieBot.client; import static handiebot.HandieBot.log; /** @@ -24,7 +28,8 @@ import static handiebot.HandieBot.log; */ public class CommandHandler { - public static String PREFIX = "!"; + public static final String DEFAULT_PREFIX = "!"; + public static Map PREFIXES = loadGuildPrefixes(); /** * Main method to handle user messages. * @param event The event generated by the message. @@ -32,49 +37,53 @@ public class CommandHandler { public static void handleCommand(MessageReceivedEvent event){ IMessage message = event.getMessage(); IUser user = event.getAuthor(); + //Exit immediately if the user is a bot; avoids bot spam chat. + if (user.isBot()){ + return; + } IChannel channel = event.getChannel(); IGuild guild = event.getGuild(); + //Check if the guild already has a prefix assigned, and if not, give it the default. + if (!PREFIXES.containsKey(guild)){ + PREFIXES.put(guild, DEFAULT_PREFIX); + } String command = extractCommand(message); String[] args = extractArgs(message); + //Create a context to give to each command's execution, so it knows what channel to reply on, etc. CommandContext context = new CommandContext(user, channel, guild, args); if (guild != null && command != null){ DisappearingMessage.deleteMessageAfter(1000, message); - if (command.equals("play")){ - //Play or queue a song. - new PlayCommand().execute(context); - } else if (command.equals("skip") && args.length == 0){ - //Skip the current song. - new SkipAction(guild).actionPerformed(null); - } else if (command.equals("help")){ - //Send a PM to the user with help info. - sendHelpInfo(user);//TODO finish the help command and fill in with new descriptions each time. - } else if (command.equals("queue")){ - //Display the first few items of the queue. - new QueueListAction(guild, (args.length == 1) && args[0].equals("all")).actionPerformed(null); - } else if (command.equals("repeat")) { - //Toggle repeat. - new RepeatCommand().execute(context); - } else if (command.equals("shuffle")){ - new ShuffleCommand().execute(context); - } else if (command.equals("clear")){ - //TODO clear command. - } else if (command.equals("quit")){ - //Quit the application. - new QuitAction(guild).actionPerformed(null); - } else if (command.equals("playlist")){ - //Do playlist actions. - new PlaylistCommand().execute(context); - } else if (command.equals("prefix") && args.length == 1){ - //Set the prefix to the first argument. - if (args[0].length() != 1){ - new DisappearingMessage(channel, "You may only set the prefix to 1 character. To do otherwise is simply foolish.", 3000); - } else { - new DisappearingMessage(channel, "Command prefix set to "+PREFIX, 10000); - log.log(BotLog.TYPE.INFO, guild, "Prefix set to "+PREFIX); - setPrefix(args[0]); - } - } else { - log.log(BotLog.TYPE.ERROR, guild, "Invalid command: "+command+" issued by "+user.getName()); + switch (command){ + //Music commands. + case ("play"): + new PlayCommand().execute(context); + break; + case ("skip"): + new SkipCommand().execute(context); + break; + case ("queue"): + new QueueCommand().execute(context); + break; + case ("repeat"): + new RepeatCommand().execute(context); + break; + case ("shuffle"): + new ShuffleCommand().execute(context); + break; + case ("playlist"): + new PlaylistCommand().execute(context); + break; + //Other commands. + case ("help"): + new HelpCommand().execute(context); + break; + case ("info"): + new InfoCommand().execute(context); + break; + case ("setprefix"): + new SetPrefixCommand().execute(context); + default: + log.log(BotLog.TYPE.ERROR, guild, "Invalid command: "+command+" issued by "+user.getName()); } } } @@ -86,8 +95,8 @@ public class CommandHandler { */ private static String extractCommand(IMessage message){ String[] words = message.getContent().split(" "); - if (words[0].startsWith(PREFIX)){ - return words[0].replaceFirst(PREFIX, "").toLowerCase(); + if (words[0].startsWith(PREFIXES.get(message.getGuild()))){ + return words[0].replaceFirst(PREFIXES.get(message.getGuild()), "").toLowerCase(); } return null; } @@ -97,10 +106,9 @@ public class CommandHandler { * @param message The message to parse. * @return A list of strings representing args. */ - @NotNull private static String[] extractArgs(IMessage message){ String[] words = message.getContent().split(" "); - if (words[0].startsWith(PREFIX)){ + if (words[0].startsWith(PREFIXES.get(message.getGuild()))){ String[] args = new String[words.length-1]; for (int i = 0; i < words.length-1; i++){ args[i] = words[i+1]; @@ -111,30 +119,34 @@ public class CommandHandler { } /** - * Method to send a useful list of commands to any user if they desire. - * @param user The user to send the message to. + * Loads a persistent list of prefixes for guilds from a file called guildPrefixes.txt + * @return The mapping of guild to prefix. */ - private static void sendHelpInfo(IUser user){ - IPrivateChannel pm = user.getOrCreatePMChannel(); - EmbedBuilder builder = new EmbedBuilder(); - - builder.withAuthorName("HandieBot"); - builder.withAuthorUrl("https://github.com/andrewlalis/HandieBot"); - builder.withAuthorIcon("https://github.com/andrewlalis/HandieBot/blob/master/src/main/resources/icon.png"); - - builder.withColor(new Color(255, 0, 0)); - builder.withDescription("I'm a discord bot that can manage music, as well as some other important functions which will be implemented later on. Some commands are shown below."); - builder.appendField("Commands:", "play, skip, help", false); - - pm.sendMessage(builder.build()); + private static Map loadGuildPrefixes(){ + File prefixFile = new File(FileUtil.getDataDirectory()+"guildPrefixes.txt"); + Map prefixes = new HashMap<>(); + if (prefixFile.exists()){ + List lines = FileUtil.getLinesFromFile(prefixFile); + for (String line : lines){ + String[] words = line.split(" / "); + prefixes.put(client.getGuildByID(Long.parseLong(words[0])), words[1]); + } + } + log.log(BotLog.TYPE.INFO, "Loaded prefixes."); + return prefixes; } /** - * Sets the prefix used to identify commands. - * @param prefix The prefix appended to the beginning of commands. + * Saves the list of prefixes to a file. */ - public static void setPrefix(String prefix){ - PREFIX = prefix; + public static void saveGuildPrefixes(){ + File prefixFile = new File(FileUtil.getDataDirectory()+"guildPrefixes.txt"); + List lines = new ArrayList<>(); + for (Map.Entry entry : PREFIXES.entrySet()){ + lines.add(Long.toString(entry.getKey().getLongID())+" / "+entry.getValue()); + } + FileUtil.writeLinesToFile(lines, prefixFile); + log.log(BotLog.TYPE.INFO, "Saved prefixes."); } } diff --git a/src/main/java/handiebot/command/commands/InfoCommand.java b/src/main/java/handiebot/command/commands/InfoCommand.java new file mode 100644 index 0000000..229814d --- /dev/null +++ b/src/main/java/handiebot/command/commands/InfoCommand.java @@ -0,0 +1,30 @@ +package handiebot.command.commands; + +import handiebot.command.CommandContext; +import handiebot.command.CommandHandler; +import handiebot.command.types.ContextCommand; +import handiebot.utils.DisappearingMessage; +import sx.blah.discord.util.EmbedBuilder; + +import java.awt.*; + +/** + * @author Andrew Lalis + * Command to display information about the bot, and some common commands. + */ +public class InfoCommand extends ContextCommand { + + public InfoCommand() { + super("info"); + } + + @Override + public void execute(CommandContext context) { + EmbedBuilder builder = new EmbedBuilder(); + builder.withColor(new Color(255, 0, 0)); + builder.withDescription("HandieBot is a Discord bot created by Andrew Lalis. It can play music, manage playlists, and provide other assistance to users. Some useful commands are shown below."); + builder.appendField("`"+ CommandHandler.PREFIXES.get(context.getGuild())+"help`", "Receive a message with a detailed list of all commands and how to use them.", false); + builder.appendField("`"+CommandHandler.PREFIXES.get(context.getGuild())+"setprefix`", "Changed the prefix used at the beginning of each command.", false); + DisappearingMessage.deleteMessageAfter(10000, context.getChannel().sendMessage(builder.build())); + } +} diff --git a/src/main/java/handiebot/command/commands/SetPrefixCommand.java b/src/main/java/handiebot/command/commands/SetPrefixCommand.java new file mode 100644 index 0000000..a68e1e0 --- /dev/null +++ b/src/main/java/handiebot/command/commands/SetPrefixCommand.java @@ -0,0 +1,32 @@ +package handiebot.command.commands; + +import handiebot.command.CommandContext; +import handiebot.command.CommandHandler; +import handiebot.command.types.ContextCommand; +import handiebot.utils.DisappearingMessage; +import handiebot.view.BotLog; + +import static handiebot.HandieBot.log; + +/** + * @author Andrew Lalis + * Command to set the prefix used for a particular server. + */ +public class SetPrefixCommand extends ContextCommand { + + public SetPrefixCommand() { + super("setprefix"); + } + + @Override + public void execute(CommandContext context) { + if (context.getArgs().length == 1) { + CommandHandler.PREFIXES.put(context.getGuild(), context.getArgs()[0]); + CommandHandler.saveGuildPrefixes(); + new DisappearingMessage(context.getChannel(), "Changed command prefix to \""+context.getArgs()[0]+"\"", 6000); + log.log(BotLog.TYPE.INFO, "Changed command prefix to \""+context.getArgs()[0]+"\""); + } else { + new DisappearingMessage(context.getChannel(), "You must provide a new prefix.", 3000); + } + } +} diff --git a/src/main/java/handiebot/command/commands/music/PlaylistCommand.java b/src/main/java/handiebot/command/commands/music/PlaylistCommand.java index 37e505b..cdc9fa9 100644 --- a/src/main/java/handiebot/command/commands/music/PlaylistCommand.java +++ b/src/main/java/handiebot/command/commands/music/PlaylistCommand.java @@ -86,7 +86,7 @@ public class PlaylistCommand extends ContextCommand { } playlist.save(); log.log(BotLog.TYPE.INFO, "Created playlist: "+playlist.getName()+" with "+playlist.getTrackCount()+" new tracks."); - new DisappearingMessage(context.getChannel(), "Your playlist *"+playlist.getName()+"* has been created.\nType `"+ CommandHandler.PREFIX+"playlist play "+playlist.getName()+"` to play it.", 5000); + new DisappearingMessage(context.getChannel(), "Your playlist *"+playlist.getName()+"* has been created.\nType `"+ CommandHandler.PREFIXES.get(context.getGuild())+"playlist play "+playlist.getName()+"` to play it.", 5000); } else { new DisappearingMessage(context.getChannel(), "You must specify a name for the new playlist.", 3000); } @@ -109,7 +109,7 @@ public class PlaylistCommand extends ContextCommand { new DisappearingMessage(context.getChannel(), "The playlist was not able to be deleted.", 3000); } } else { - new DisappearingMessage(context.getChannel(), "The name you entered is not a playlist.\nType `"+CommandHandler.PREFIX+"playlist show` to list the playlists available.", 5000); + new DisappearingMessage(context.getChannel(), "The name you entered is not a playlist.\nType `"+CommandHandler.PREFIXES.get(context.getGuild())+"playlist show` to list the playlists available.", 5000); } } else { new DisappearingMessage(context.getChannel(), "You must specify the name of a playlist to delete.", 3000); @@ -128,7 +128,7 @@ public class PlaylistCommand extends ContextCommand { IMessage message = context.getChannel().sendMessage(playlist.toString()); DisappearingMessage.deleteMessageAfter(6000, message); } else { - new DisappearingMessage(context.getChannel(), "The playlist you specified does not exist.\nUse `"+CommandHandler.PREFIX+"playlist show` to view available playlists.", 5000); + new DisappearingMessage(context.getChannel(), "The playlist you specified does not exist.\nUse `"+CommandHandler.PREFIXES.get(context.getGuild())+"playlist show` to view available playlists.", 5000); } } else { List playlists = Playlist.getAvailablePlaylists(); @@ -163,7 +163,7 @@ public class PlaylistCommand extends ContextCommand { DisappearingMessage.deleteMessageAfter(6000, message); } else { if (context.getArgs().length == 1){ - new DisappearingMessage(context.getChannel(), "You must provide the name of a playlist to add a URL to.\nUse '"+CommandHandler.PREFIX+"playlist show` to view available playlists.", 5000); + new DisappearingMessage(context.getChannel(), "You must provide the name of a playlist to add a URL to.\nUse '"+CommandHandler.PREFIXES.get(context.getGuild())+"playlist show` to view available playlists.", 5000); } else { new DisappearingMessage(context.getChannel(), "You must provide at least one URL to add.", 3000); } @@ -187,7 +187,7 @@ public class PlaylistCommand extends ContextCommand { log.log(BotLog.TYPE.INFO, "Loaded playlist ["+playlist.getName()+"]."); new DisappearingMessage(context.getChannel(), "Now playing from playlist: *"+playlist.getName()+"*.", 6000); } else { - new DisappearingMessage(context.getChannel(), "You must provide a playlist to play.\nUse '"+CommandHandler.PREFIX+"playlist show` to view available playlists.", 3000); + new DisappearingMessage(context.getChannel(), "You must provide a playlist to play.\nUse '"+CommandHandler.PREFIXES.get(context.getGuild())+"playlist show` to view available playlists.", 3000); } } @@ -265,7 +265,7 @@ public class PlaylistCommand extends ContextCommand { } catch (NumberFormatException e){ new DisappearingMessage(context.getChannel(), "You must enter two integer values for the song indices.", 5000); } - UnloadedTrack track = null; + UnloadedTrack track; if (oldIndex > -1 && oldIndex < playlist.getTrackCount()){ track = playlist.getTracks().remove(oldIndex); if (newIndex > -1 && newIndex <= playlist.getTrackCount()){ diff --git a/src/main/java/handiebot/command/commands/music/QueueCommand.java b/src/main/java/handiebot/command/commands/music/QueueCommand.java index 85b8919..ebcae20 100644 --- a/src/main/java/handiebot/command/commands/music/QueueCommand.java +++ b/src/main/java/handiebot/command/commands/music/QueueCommand.java @@ -15,7 +15,7 @@ public class QueueCommand extends ContextCommand { @Override public void execute(CommandContext context) { - HandieBot.musicPlayer.showQueueList(context.getGuild(), (context.getArgs() != null && context.getArgs()[0].equals("all"))); + HandieBot.musicPlayer.showQueueList(context.getGuild(), (context.getArgs().length == 1 && context.getArgs()[0].equals("all"))); } } diff --git a/src/main/java/handiebot/lavaplayer/MusicPlayer.java b/src/main/java/handiebot/lavaplayer/MusicPlayer.java index 977aab1..7e9438d 100644 --- a/src/main/java/handiebot/lavaplayer/MusicPlayer.java +++ b/src/main/java/handiebot/lavaplayer/MusicPlayer.java @@ -150,7 +150,7 @@ public class MusicPlayer { public void showQueueList(IGuild guild, boolean showAll) { List tracks = getMusicManager(guild).scheduler.queueList(); if (tracks.size() == 0) { - new DisappearingMessage(getChatChannel(guild), "The queue is empty. Use **"+ CommandHandler.PREFIX+"play** *URL* to add songs.", 3000); + new DisappearingMessage(getChatChannel(guild), "The queue is empty. Use **"+ CommandHandler.PREFIXES.get(guild)+"play** *URL* to add songs.", 3000); } else { if (tracks.size() > 10 && showAll) { String result = Pastebin.paste("Current queue for discord server: "+guild.getName()+".", getMusicManager(guild).scheduler.getActivePlaylist().toString()); diff --git a/src/main/java/handiebot/lavaplayer/TrackScheduler.java b/src/main/java/handiebot/lavaplayer/TrackScheduler.java index f06d513..49be0cf 100644 --- a/src/main/java/handiebot/lavaplayer/TrackScheduler.java +++ b/src/main/java/handiebot/lavaplayer/TrackScheduler.java @@ -174,8 +174,6 @@ public class TrackScheduler extends AudioEventAdapter { } if (endReason.mayStartNext){ nextTrack(); - } else { - log.log(BotLog.TYPE.MUSIC, this.guild, "Unable to go to the next track. Reason: "+endReason.name()); } } diff --git a/src/main/java/handiebot/utils/FileUtil.java b/src/main/java/handiebot/utils/FileUtil.java new file mode 100644 index 0000000..5a01126 --- /dev/null +++ b/src/main/java/handiebot/utils/FileUtil.java @@ -0,0 +1,61 @@ +package handiebot.utils; + +import handiebot.view.BotLog; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; + +import static handiebot.HandieBot.log; + +/** + * @author Andrew Lalis + * Class to simplify file operations. + */ +public class FileUtil { + + public static String getDataDirectory(){ + return System.getProperty("user.home")+"/.handiebot/"; + } + + public static List getLinesFromFile(File file){ + try { + return Files.readAllLines(file.toPath()); + } catch (IOException e) { + e.printStackTrace(); + return new ArrayList<>(); + } + } + + public static void writeLinesToFile(List lines, File file){ + if (lines.size() == 0){ + return; + } + if (!file.exists()){ + try { + boolean success = file.createNewFile(); + if (!success) { + log.log(BotLog.TYPE.ERROR, "Unable to create file. "+file.getAbsolutePath()); + return; + } + } catch (IOException e) { + e.printStackTrace(); + log.log(BotLog.TYPE.ERROR, "Unable to create file. "+file.getAbsolutePath()); + return; + } + } + try (PrintWriter writer = new PrintWriter(file)){ + while (lines.size() > 0) { + writer.println(lines.remove(0)); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + log.log(BotLog.TYPE.ERROR, "Unable to write to file. "+file.getAbsolutePath()); + } + } + +} diff --git a/src/main/java/handiebot/view/View.java b/src/main/java/handiebot/view/View.java index 67580fe..13fe909 100644 --- a/src/main/java/handiebot/view/View.java +++ b/src/main/java/handiebot/view/View.java @@ -1,6 +1,7 @@ package handiebot.view; import javax.swing.*; +import java.awt.*; /** * @author Andrew Lalis @@ -10,12 +11,55 @@ public class View { private JTextPane outputArea; private JTextField commandField; - public View(){ + public View() { this.commandField.addKeyListener(new CommandLineListener()); } - public JTextPane getOutputArea(){ - return this.outputArea; - } + public JTextPane getOutputArea() { + return this.outputArea; + } + { +// GUI initializer generated by IntelliJ IDEA GUI Designer +// >>> IMPORTANT!! <<< +// DO NOT EDIT OR ADD ANY CODE HERE! + $$$setupUI$$$(); + } + + /** + * Method generated by IntelliJ IDEA GUI Designer + * >>> IMPORTANT!! <<< + * DO NOT edit this method OR call it in your code! + * + * @noinspection ALL + */ + private void $$$setupUI$$$() { + mainPanel = new JPanel(); + mainPanel.setLayout(new com.intellij.uiDesigner.core.GridLayoutManager(2, 1, new Insets(0, 0, 0, 0), -1, -1)); + final JScrollPane scrollPane1 = new JScrollPane(); + scrollPane1.setFont(new Font("Consolas", scrollPane1.getFont().getStyle(), 12)); + mainPanel.add(scrollPane1, new com.intellij.uiDesigner.core.GridConstraints(0, 0, 1, 1, com.intellij.uiDesigner.core.GridConstraints.ANCHOR_CENTER, com.intellij.uiDesigner.core.GridConstraints.FILL_BOTH, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_SHRINK | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_WANT_GROW, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_SHRINK | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false)); + outputArea = new JTextPane(); + outputArea.setEditable(false); + outputArea.setFont(new Font("Consolas", outputArea.getFont().getStyle(), 12)); + outputArea.setSelectedTextColor(new Color(-1)); + outputArea.setSelectionColor(new Color(-9843846)); + outputArea.setText(""); + scrollPane1.setViewportView(outputArea); + final JPanel panel1 = new JPanel(); + panel1.setLayout(new com.intellij.uiDesigner.core.GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); + mainPanel.add(panel1, new com.intellij.uiDesigner.core.GridConstraints(1, 0, 1, 1, com.intellij.uiDesigner.core.GridConstraints.ANCHOR_CENTER, com.intellij.uiDesigner.core.GridConstraints.FILL_BOTH, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_SHRINK | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_GROW, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_SHRINK | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + commandField = new JTextField(); + commandField.setFont(new Font("DialogInput", commandField.getFont().getStyle(), 16)); + commandField.setForeground(new Color(-16118999)); + commandField.setMargin(new Insets(0, 0, 0, 0)); + panel1.add(commandField, new com.intellij.uiDesigner.core.GridConstraints(0, 0, 1, 1, com.intellij.uiDesigner.core.GridConstraints.ANCHOR_WEST, com.intellij.uiDesigner.core.GridConstraints.FILL_HORIZONTAL, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_WANT_GROW, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false)); + } + + /** + * @noinspection ALL + */ + public JComponent $$$getRootComponent$$$() { + return mainPanel; + } } From e7283743fcc9f0d3b9789b415a0767ae417f24ff Mon Sep 17 00:00:00 2001 From: Andrew Lalis Date: Sun, 25 Jun 2017 00:31:10 +0200 Subject: [PATCH 2/4] Lots of minor bug fixes, added queue clear. --- README.md | 6 ++- .../handiebot/command/CommandHandler.java | 37 +------------------ src/main/java/handiebot/command/Commands.java | 27 ++++++++++++++ .../command/commands/HelpCommand.java | 2 +- .../commands/music/PlaylistCommand.java | 23 ++++++------ .../command/commands/music/QueueCommand.java | 12 +++++- .../handiebot/lavaplayer/MusicPlayer.java | 2 +- .../handiebot/lavaplayer/TrackScheduler.java | 10 ++++- .../lavaplayer/playlist/Playlist.java | 28 ++++++++++++-- 9 files changed, 91 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index feee5e1..0f5f1b8 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,11 @@ Because the play command is defined as `play [URL]`, and the queue command is de * `skip` - If a song is playing, the bot will skip it and play the next song in the queue. -* `queue [all]` - Lists up to the first 10 items on the queue, if no argument is given. If you add `all`, the bot will upload a list to [PasteBin](http://pastebin.com) of the entire queue, provided it is greater than 10 elements, and give you a link which expires in 10 minutes. +* `queue [all|clear]` - Lists up to the first 10 items on the queue, if no argument is given. + + * If you add `all`, the bot will upload a list to [PasteBin](http://pastebin.com) of the entire queue, provided it is greater than 10 elements, and give you a link which expires in 10 minutes. + + * If `clear` is used, the queue will be cleared and the current song will be stopped. * `repeat [true|false]` - Sets the bot to repeat the playlist, as in once a song is removed from the queue to be played, it is added back to the end of the playlist. diff --git a/src/main/java/handiebot/command/CommandHandler.java b/src/main/java/handiebot/command/CommandHandler.java index 3b78cd5..7e7df3a 100644 --- a/src/main/java/handiebot/command/CommandHandler.java +++ b/src/main/java/handiebot/command/CommandHandler.java @@ -1,9 +1,5 @@ package handiebot.command; -import handiebot.command.commands.HelpCommand; -import handiebot.command.commands.InfoCommand; -import handiebot.command.commands.SetPrefixCommand; -import handiebot.command.commands.music.*; import handiebot.utils.DisappearingMessage; import handiebot.utils.FileUtil; import handiebot.view.BotLog; @@ -53,38 +49,7 @@ public class CommandHandler { CommandContext context = new CommandContext(user, channel, guild, args); if (guild != null && command != null){ DisappearingMessage.deleteMessageAfter(1000, message); - switch (command){ - //Music commands. - case ("play"): - new PlayCommand().execute(context); - break; - case ("skip"): - new SkipCommand().execute(context); - break; - case ("queue"): - new QueueCommand().execute(context); - break; - case ("repeat"): - new RepeatCommand().execute(context); - break; - case ("shuffle"): - new ShuffleCommand().execute(context); - break; - case ("playlist"): - new PlaylistCommand().execute(context); - break; - //Other commands. - case ("help"): - new HelpCommand().execute(context); - break; - case ("info"): - new InfoCommand().execute(context); - break; - case ("setprefix"): - new SetPrefixCommand().execute(context); - default: - log.log(BotLog.TYPE.ERROR, guild, "Invalid command: "+command+" issued by "+user.getName()); - } + Commands.executeCommand(command, context); } } diff --git a/src/main/java/handiebot/command/Commands.java b/src/main/java/handiebot/command/Commands.java index 67a1aba..2f87ae2 100644 --- a/src/main/java/handiebot/command/Commands.java +++ b/src/main/java/handiebot/command/Commands.java @@ -1,11 +1,18 @@ package handiebot.command; +import handiebot.command.commands.HelpCommand; +import handiebot.command.commands.InfoCommand; +import handiebot.command.commands.SetPrefixCommand; import handiebot.command.commands.music.*; import handiebot.command.types.Command; +import handiebot.command.types.ContextCommand; +import handiebot.view.BotLog; import java.util.ArrayList; import java.util.List; +import static handiebot.HandieBot.log; + /** * @author Andrew Lalis * Class to hold a list of commands, as static definitions that can be called upon by {@code CommandHandler}. @@ -22,6 +29,26 @@ public class Commands { commands.add(new RepeatCommand()); commands.add(new ShuffleCommand()); commands.add(new PlaylistCommand()); + //Other commands. + commands.add(new HelpCommand()); + commands.add(new InfoCommand()); + commands.add(new SetPrefixCommand()); + } + + /** + * Attempts to execute a command from a given command string. + * @param command The string representation of a main command, without prefix. + */ + public static void executeCommand(String command, CommandContext context){ + for (Command cmd : commands) { + if (cmd.getName().equals(command)){ + if (cmd instanceof ContextCommand){ + ((ContextCommand)cmd).execute(context); + return; + } + } + } + log.log(BotLog.TYPE.ERROR, context.getGuild(), "Invalid command: "+command+" issued by "+context.getUser().getName()); } } diff --git a/src/main/java/handiebot/command/commands/HelpCommand.java b/src/main/java/handiebot/command/commands/HelpCommand.java index 6142cf2..4050398 100644 --- a/src/main/java/handiebot/command/commands/HelpCommand.java +++ b/src/main/java/handiebot/command/commands/HelpCommand.java @@ -12,7 +12,7 @@ import java.awt.*; * Class for sending help/command info to a user if they so desire it. */ public class HelpCommand extends ContextCommand { - +//TODO: Finish the help class. public HelpCommand() { super("help"); } diff --git a/src/main/java/handiebot/command/commands/music/PlaylistCommand.java b/src/main/java/handiebot/command/commands/music/PlaylistCommand.java index cdc9fa9..0b82649 100644 --- a/src/main/java/handiebot/command/commands/music/PlaylistCommand.java +++ b/src/main/java/handiebot/command/commands/music/PlaylistCommand.java @@ -126,7 +126,7 @@ public class PlaylistCommand extends ContextCommand { Playlist playlist = new Playlist(context.getArgs()[1]); playlist.load(); IMessage message = context.getChannel().sendMessage(playlist.toString()); - DisappearingMessage.deleteMessageAfter(6000, message); + DisappearingMessage.deleteMessageAfter(12000, message); } else { new DisappearingMessage(context.getChannel(), "The playlist you specified does not exist.\nUse `"+CommandHandler.PREFIXES.get(context.getGuild())+"playlist show` to view available playlists.", 5000); } @@ -137,7 +137,7 @@ public class PlaylistCommand extends ContextCommand { sb.append(playlist).append('\n'); } IMessage message = context.getChannel().sendMessage(sb.toString()); - DisappearingMessage.deleteMessageAfter(6000, message); + DisappearingMessage.deleteMessageAfter(12000, message); } } @@ -228,9 +228,10 @@ public class PlaylistCommand extends ContextCommand { Playlist playlist = new Playlist(context.getArgs()[1]); playlist.load(); try{ - int index = Integer.parseInt(context.getArgs()[2]); + int index = Integer.parseInt(context.getArgs()[2]) - 1; UnloadedTrack track = playlist.getTracks().get(index); playlist.removeTrack(track); + playlist.save(); new DisappearingMessage(context.getChannel(), "Removed song: *"+track.getTitle()+"* from playlist **"+playlist.getName()+"**.", 6000); log.log(BotLog.TYPE.MUSIC, "Removed song: "+track.getTitle()+" from playlist ["+playlist.getName()+"]."); DisappearingMessage.deleteMessageAfter(6000, context.getChannel().sendMessage(playlist.toString())); @@ -266,17 +267,15 @@ public class PlaylistCommand extends ContextCommand { new DisappearingMessage(context.getChannel(), "You must enter two integer values for the song indices.", 5000); } UnloadedTrack track; - if (oldIndex > -1 && oldIndex < playlist.getTrackCount()){ + if ((oldIndex > -1 && oldIndex < playlist.getTrackCount()) && + (newIndex > -1 && newIndex <= playlist.getTrackCount())){ track = playlist.getTracks().remove(oldIndex); - if (newIndex > -1 && newIndex <= playlist.getTrackCount()){ - playlist.getTracks().add(newIndex, track); - new DisappearingMessage(context.getChannel(), "Moved song *"+track.getTitle()+"* from position "+(oldIndex+1)+" to position "+(newIndex+1), 6000); - log.log(BotLog.TYPE.MUSIC, "Moved song "+track.getTitle()+" from position "+(oldIndex+1)+" to position "+(newIndex+1)); - } else { - new DisappearingMessage(context.getChannel(), "The index of the song's new position is invalid. You entered "+newIndex, 5000); - } + playlist.getTracks().add(newIndex, track); + playlist.save(); + new DisappearingMessage(context.getChannel(), "Moved song *"+track.getTitle()+"* from position "+(oldIndex+1)+" to position "+(newIndex+1), 6000); + log.log(BotLog.TYPE.MUSIC, "Moved song "+track.getTitle()+" from position "+(oldIndex+1)+" to position "+(newIndex+1)); } else { - new DisappearingMessage(context.getChannel(), "The index of the song is invalid. You entered "+oldIndex, 5000); + new DisappearingMessage(context.getChannel(), "The song indices are invalid. You specified moving song "+oldIndex+" to position "+newIndex+". ", 5000); } } else { new DisappearingMessage(context.getChannel(), "You must provide a playlist name, followed by the song index, and a new index for that song.", 5000); diff --git a/src/main/java/handiebot/command/commands/music/QueueCommand.java b/src/main/java/handiebot/command/commands/music/QueueCommand.java index ebcae20..d5ab4b9 100644 --- a/src/main/java/handiebot/command/commands/music/QueueCommand.java +++ b/src/main/java/handiebot/command/commands/music/QueueCommand.java @@ -3,6 +3,7 @@ package handiebot.command.commands.music; import handiebot.HandieBot; import handiebot.command.CommandContext; import handiebot.command.types.ContextCommand; +import handiebot.utils.DisappearingMessage; /** * @author Andrew Lalis @@ -15,7 +16,16 @@ public class QueueCommand extends ContextCommand { @Override public void execute(CommandContext context) { - HandieBot.musicPlayer.showQueueList(context.getGuild(), (context.getArgs().length == 1 && context.getArgs()[0].equals("all"))); + if (context.getArgs().length == 1){ + if (context.getArgs()[0].equals("all")){ + HandieBot.musicPlayer.showQueueList(context.getGuild(), true); + } else if (context.getArgs()[0].equals("clear")){ + HandieBot.musicPlayer.getMusicManager(context.getGuild()).scheduler.clearQueue(); + new DisappearingMessage(context.getChannel(), "Cleared the queue.", 5000); + } + } else { + HandieBot.musicPlayer.showQueueList(context.getGuild(), false); + } } } diff --git a/src/main/java/handiebot/lavaplayer/MusicPlayer.java b/src/main/java/handiebot/lavaplayer/MusicPlayer.java index 7e9438d..95024a4 100644 --- a/src/main/java/handiebot/lavaplayer/MusicPlayer.java +++ b/src/main/java/handiebot/lavaplayer/MusicPlayer.java @@ -169,7 +169,7 @@ public class MusicPlayer { sb.append(tracks.get(i).getURL()).append(")"); sb.append(tracks.get(i).getFormattedDuration()).append('\n'); } - builder.appendField("Showing " + (tracks.size() <= 10 ? tracks.size() : "the first 10") + " track" + (tracks.size() > 1 ? "s" : "") + ".", sb.toString(), false); + builder.appendField("Showing " + (tracks.size() <= 10 ? tracks.size() : "the first 10") + " track" + (tracks.size() > 1 ? "s" : "") + " out of "+tracks.size()+".", sb.toString(), false); IMessage message = getChatChannel(guild).sendMessage(builder.build()); DisappearingMessage.deleteMessageAfter(6000, message); } diff --git a/src/main/java/handiebot/lavaplayer/TrackScheduler.java b/src/main/java/handiebot/lavaplayer/TrackScheduler.java index 49be0cf..98cd89c 100644 --- a/src/main/java/handiebot/lavaplayer/TrackScheduler.java +++ b/src/main/java/handiebot/lavaplayer/TrackScheduler.java @@ -50,13 +50,21 @@ public class TrackScheduler extends AudioEventAdapter { * @param playlist the playlist to load from. */ public void setPlaylist(Playlist playlist){ - this.activePlaylist = playlist; + this.activePlaylist.copy(playlist); } public Playlist getActivePlaylist(){ return this.activePlaylist; } + /** + * Clears the queue. + */ + public void clearQueue(){ + this.quit(); + this.activePlaylist.clear(); + } + /** * Sets whether or not songs get placed back into the queue once they're played. * @param value True if the playlist should repeat. diff --git a/src/main/java/handiebot/lavaplayer/playlist/Playlist.java b/src/main/java/handiebot/lavaplayer/playlist/Playlist.java index cee15e1..442e37a 100644 --- a/src/main/java/handiebot/lavaplayer/playlist/Playlist.java +++ b/src/main/java/handiebot/lavaplayer/playlist/Playlist.java @@ -56,6 +56,21 @@ public class Playlist { this.tracks.remove(track); } + /** + * Copies all the tracks from another playlist onto this one. + * @param playlist A playlist. + */ + public void copy(Playlist playlist){ + this.getTracks().clear(); + for (UnloadedTrack track : playlist.getTracks()){ + this.tracks.add(track.clone()); + } + } + + public void clear(){ + this.tracks.clear(); + } + /** * Loads and returns the audio track that's first on the list. * This removes that track from the playlist. @@ -63,6 +78,9 @@ public class Playlist { * @return The AudioTrack corresponding to the next UnloadedTrack in the list. */ public AudioTrack loadNextTrack(boolean shouldShuffle){ + if (this.getTrackCount() == 0){ + return null; + } if (shouldShuffle){ return this.tracks.remove(getShuffledIndex(this.tracks.size())).loadAudioTrack(); } else { @@ -188,9 +206,13 @@ public class Playlist { @Override public String toString(){ - StringBuilder sb = new StringBuilder("HandieBot Playlist: "+this.getName()+'\n'); - for (int i = 0; i < this.getTrackCount(); i++){ - sb.append(i+1).append(". ").append(this.tracks.get(i).getTitle()).append(" ").append(this.tracks.get(i).getFormattedDuration()).append("\n"); + StringBuilder sb = new StringBuilder("Playlist: "+this.getName()+'\n'); + if (this.getTrackCount() == 0){ + sb.append("There are no songs in this playlist."); + } else { + for (int i = 0; i < this.getTrackCount(); i++) { + sb.append(i + 1).append(". ").append(this.tracks.get(i).getTitle()).append(" ").append(this.tracks.get(i).getFormattedDuration()).append("\n"); + } } return sb.toString(); } From 7bf9c9ab3e17478ae7924ad942f760c48826683d Mon Sep 17 00:00:00 2001 From: Andrew Lalis Date: Sun, 25 Jun 2017 02:06:34 +0200 Subject: [PATCH 3/4] Added better command descriptions. Help does not work. --- README.md | 9 ++++++ src/main/java/handiebot/command/Commands.java | 15 ++++++++++ .../command/commands/HelpCommand.java | 22 ++++++++++++-- .../command/commands/InfoCommand.java | 12 +++++--- .../command/commands/SetPrefixCommand.java | 4 ++- .../command/commands/music/PlayCommand.java | 4 ++- .../commands/music/PlaylistCommand.java | 14 +++++++-- .../command/commands/music/QueueCommand.java | 10 ++++--- .../command/commands/music/RepeatCommand.java | 10 ++----- .../commands/music/ShuffleCommand.java | 10 ++----- .../command/commands/music/SkipCommand.java | 4 ++- .../command/commands/music/StopCommand.java | 23 +++++++++++++++ .../java/handiebot/command/types/Command.java | 14 ++++++++- .../command/types/ContextCommand.java | 15 ++++++++-- .../command/types/StaticCommand.java | 4 +-- .../handiebot/lavaplayer/MusicPlayer.java | 29 +++++++++++++------ .../handiebot/lavaplayer/TrackScheduler.java | 12 ++++---- .../handiebot/view/CommandLineListener.java | 2 +- .../handiebot/view/actions/QuitAction.java | 2 +- 19 files changed, 165 insertions(+), 50 deletions(-) create mode 100644 src/main/java/handiebot/command/commands/music/StopCommand.java diff --git a/README.md b/README.md index 0f5f1b8..706e82c 100644 --- a/README.md +++ b/README.md @@ -29,11 +29,20 @@ queue all Because the play command is defined as `play [URL]`, and the queue command is defined as `queue [all]`. +### General + +* `info` - Displays the most common commands, and some basic information about the bot. + +* `help` - Sends a private message to whoever issues this command. The message contains an in-depth list of all commands and their proper usage. + +* `setprefix ` - Sets the prefix for all commands. Be careful, as some values will cause irreversible damage, if for example, a prefix conflicts with another bot's prefix. ### Music * `play [URL]` - Starts playback from the queue, or if a URL is defined, then it will attempt to play that song, or add it to the queue, depending on if a song is already playing. If a song is already playing, you should receive an estimate of when your song should begin playing. +* `stop` - If music is playing, this will stop it. + * `skip` - If a song is playing, the bot will skip it and play the next song in the queue. * `queue [all|clear]` - Lists up to the first 10 items on the queue, if no argument is given. diff --git a/src/main/java/handiebot/command/Commands.java b/src/main/java/handiebot/command/Commands.java index 2f87ae2..f3cdc73 100644 --- a/src/main/java/handiebot/command/Commands.java +++ b/src/main/java/handiebot/command/Commands.java @@ -24,6 +24,7 @@ public class Commands { static { //Music commands. commands.add(new PlayCommand()); + commands.add(new StopCommand()); commands.add(new QueueCommand()); commands.add(new SkipCommand()); commands.add(new RepeatCommand()); @@ -51,4 +52,18 @@ public class Commands { log.log(BotLog.TYPE.ERROR, context.getGuild(), "Invalid command: "+command+" issued by "+context.getUser().getName()); } + /** + * Attempts to get a command object, given the name of a command. + * @param command The name of the command to get. + * @return Either a command, or null. + */ + public Command get(String command){ + for (Command cmd : commands){ + if (cmd.getName().equals(command)){ + return cmd; + } + } + return null; + } + } diff --git a/src/main/java/handiebot/command/commands/HelpCommand.java b/src/main/java/handiebot/command/commands/HelpCommand.java index 4050398..a4d2e7d 100644 --- a/src/main/java/handiebot/command/commands/HelpCommand.java +++ b/src/main/java/handiebot/command/commands/HelpCommand.java @@ -1,6 +1,8 @@ package handiebot.command.commands; import handiebot.command.CommandContext; +import handiebot.command.Commands; +import handiebot.command.types.Command; import handiebot.command.types.ContextCommand; import sx.blah.discord.handle.obj.IPrivateChannel; import sx.blah.discord.util.EmbedBuilder; @@ -14,7 +16,9 @@ import java.awt.*; public class HelpCommand extends ContextCommand { //TODO: Finish the help class. public HelpCommand() { - super("help"); + super("help", + "", + "Displays a list of commands and what they do."); } @Override @@ -28,7 +32,21 @@ public class HelpCommand extends ContextCommand { builder.withColor(new Color(255, 0, 0)); builder.withDescription("I'm a discord bot that can manage music, as well as some other important functions which will be implemented later on. Some commands are shown below."); - builder.appendField("Commands:", "play, skip, help", false); + + //Music Commands: + + StringBuilder sb = new StringBuilder(); + for (Command cmd : Commands.commands){ + sb.append('`'); + if (cmd instanceof ContextCommand){ + sb.append(((ContextCommand)cmd).getUsage(context.getGuild())); + } else { + sb.append(cmd.getUsage()); + } + sb.append("`\n").append(cmd.getDescription()).append('\n'); + } + + builder.appendField("Commands:", sb.toString(), false); pm.sendMessage(builder.build()); } diff --git a/src/main/java/handiebot/command/commands/InfoCommand.java b/src/main/java/handiebot/command/commands/InfoCommand.java index 229814d..6d10564 100644 --- a/src/main/java/handiebot/command/commands/InfoCommand.java +++ b/src/main/java/handiebot/command/commands/InfoCommand.java @@ -1,7 +1,8 @@ package handiebot.command.commands; import handiebot.command.CommandContext; -import handiebot.command.CommandHandler; +import handiebot.command.commands.music.PlayCommand; +import handiebot.command.commands.music.QueueCommand; import handiebot.command.types.ContextCommand; import handiebot.utils.DisappearingMessage; import sx.blah.discord.util.EmbedBuilder; @@ -15,7 +16,9 @@ import java.awt.*; public class InfoCommand extends ContextCommand { public InfoCommand() { - super("info"); + super("info", + "", + "Displays some common commands and information about the bot."); } @Override @@ -23,8 +26,9 @@ public class InfoCommand extends ContextCommand { EmbedBuilder builder = new EmbedBuilder(); builder.withColor(new Color(255, 0, 0)); builder.withDescription("HandieBot is a Discord bot created by Andrew Lalis. It can play music, manage playlists, and provide other assistance to users. Some useful commands are shown below."); - builder.appendField("`"+ CommandHandler.PREFIXES.get(context.getGuild())+"help`", "Receive a message with a detailed list of all commands and how to use them.", false); - builder.appendField("`"+CommandHandler.PREFIXES.get(context.getGuild())+"setprefix`", "Changed the prefix used at the beginning of each command.", false); + builder.appendField("`"+new HelpCommand().getUsage(context.getGuild())+"`", "Receive a message with a detailed list of all commands and how to use them.", false); + builder.appendField("`"+new PlayCommand().getUsage(context.getGuild())+"`", "Play a song, or add it to the queue if one is already playing. A URL can be a YouTube or SoundCloud link.", false); + builder.appendField("`"+new QueueCommand().getUsage(context.getGuild())+"`", "Show a list of songs that will soon be played.", false); DisappearingMessage.deleteMessageAfter(10000, context.getChannel().sendMessage(builder.build())); } } diff --git a/src/main/java/handiebot/command/commands/SetPrefixCommand.java b/src/main/java/handiebot/command/commands/SetPrefixCommand.java index a68e1e0..e5b3012 100644 --- a/src/main/java/handiebot/command/commands/SetPrefixCommand.java +++ b/src/main/java/handiebot/command/commands/SetPrefixCommand.java @@ -15,7 +15,9 @@ import static handiebot.HandieBot.log; public class SetPrefixCommand extends ContextCommand { public SetPrefixCommand() { - super("setprefix"); + super("setprefix", + "", + "Sets the prefix for commands."); } @Override diff --git a/src/main/java/handiebot/command/commands/music/PlayCommand.java b/src/main/java/handiebot/command/commands/music/PlayCommand.java index 1d961ec..567468f 100644 --- a/src/main/java/handiebot/command/commands/music/PlayCommand.java +++ b/src/main/java/handiebot/command/commands/music/PlayCommand.java @@ -13,7 +13,9 @@ import handiebot.utils.DisappearingMessage; public class PlayCommand extends ContextCommand { public PlayCommand() { - super("play"); + super("play", + "[URL]", + "Plays a song, or adds it to the queue."); } @Override diff --git a/src/main/java/handiebot/command/commands/music/PlaylistCommand.java b/src/main/java/handiebot/command/commands/music/PlaylistCommand.java index 0b82649..7e620d7 100644 --- a/src/main/java/handiebot/command/commands/music/PlaylistCommand.java +++ b/src/main/java/handiebot/command/commands/music/PlaylistCommand.java @@ -23,7 +23,17 @@ import static handiebot.HandieBot.log; public class PlaylistCommand extends ContextCommand { public PlaylistCommand(){ - super("playlist"); + super("playlist", + " [PLAYLIST]", + "Do something with a playlist.\n" + + "\tcreate - Creates a playlist.\n" + + "\tdelete - Deletes a playlist.\n" + + "\tshow [PLAYLIST] - If a playlist given, show that, otherwise show a list of playlists.\n" + + "\tadd [URL]... - Adds one or more songs to a playlist.\n" + + "\tremove - Removes a song from a playlist.\n" + + "\trename - Renames a playlist.\n" + + "\tmove - Moves a song from one index to another.\n" + + "\tplay - Queues all songs from a playlist."); } @Override @@ -69,7 +79,7 @@ public class PlaylistCommand extends ContextCommand { * @param channel The channel to show the error message in. */ private void incorrectMainArg(IChannel channel){ - new DisappearingMessage(channel, "Please use one of the following actions: \n``", 5000); + new DisappearingMessage(channel, "To use the playlist command: \n"+this.getUsage(channel.getGuild()), 5000); } /** diff --git a/src/main/java/handiebot/command/commands/music/QueueCommand.java b/src/main/java/handiebot/command/commands/music/QueueCommand.java index d5ab4b9..60d864e 100644 --- a/src/main/java/handiebot/command/commands/music/QueueCommand.java +++ b/src/main/java/handiebot/command/commands/music/QueueCommand.java @@ -3,7 +3,6 @@ package handiebot.command.commands.music; import handiebot.HandieBot; import handiebot.command.CommandContext; import handiebot.command.types.ContextCommand; -import handiebot.utils.DisappearingMessage; /** * @author Andrew Lalis @@ -11,7 +10,11 @@ import handiebot.utils.DisappearingMessage; */ public class QueueCommand extends ContextCommand { public QueueCommand() { - super("queue"); + super("queue", + "[all|clear]", + "Shows the first 10 songs in the queue.\n" + + "\tall - Shows all songs.\n" + + "\tclear - Clears the queue and stops playing."); } @Override @@ -20,8 +23,7 @@ public class QueueCommand extends ContextCommand { if (context.getArgs()[0].equals("all")){ HandieBot.musicPlayer.showQueueList(context.getGuild(), true); } else if (context.getArgs()[0].equals("clear")){ - HandieBot.musicPlayer.getMusicManager(context.getGuild()).scheduler.clearQueue(); - new DisappearingMessage(context.getChannel(), "Cleared the queue.", 5000); + HandieBot.musicPlayer.clearQueue(context.getGuild()); } } else { HandieBot.musicPlayer.showQueueList(context.getGuild(), false); diff --git a/src/main/java/handiebot/command/commands/music/RepeatCommand.java b/src/main/java/handiebot/command/commands/music/RepeatCommand.java index 25e0793..aa0b735 100644 --- a/src/main/java/handiebot/command/commands/music/RepeatCommand.java +++ b/src/main/java/handiebot/command/commands/music/RepeatCommand.java @@ -3,10 +3,6 @@ package handiebot.command.commands.music; import handiebot.HandieBot; import handiebot.command.CommandContext; import handiebot.command.types.ContextCommand; -import handiebot.utils.DisappearingMessage; -import handiebot.view.BotLog; - -import static handiebot.HandieBot.log; /** * @author Andrew Lalis @@ -15,7 +11,9 @@ import static handiebot.HandieBot.log; public class RepeatCommand extends ContextCommand { public RepeatCommand(){ - super("repeat"); + super("repeat", + "[true|false]", + "Sets repeating."); } @Override @@ -26,7 +24,5 @@ public class RepeatCommand extends ContextCommand { } else { HandieBot.musicPlayer.toggleRepeat(context.getGuild()); } - log.log(BotLog.TYPE.MUSIC, context.getGuild(), "Set repeat to "+HandieBot.musicPlayer.getMusicManager(context.getGuild()).scheduler.isRepeating()); - new DisappearingMessage(context.getChannel(), "Set repeat to "+HandieBot.musicPlayer.getMusicManager(context.getGuild()).scheduler.isRepeating(), 3000); } } diff --git a/src/main/java/handiebot/command/commands/music/ShuffleCommand.java b/src/main/java/handiebot/command/commands/music/ShuffleCommand.java index c4f5ebf..1618909 100644 --- a/src/main/java/handiebot/command/commands/music/ShuffleCommand.java +++ b/src/main/java/handiebot/command/commands/music/ShuffleCommand.java @@ -3,10 +3,6 @@ package handiebot.command.commands.music; import handiebot.HandieBot; import handiebot.command.CommandContext; import handiebot.command.types.ContextCommand; -import handiebot.utils.DisappearingMessage; -import handiebot.view.BotLog; - -import static handiebot.HandieBot.log; /** * @author Andrew Lalis @@ -15,7 +11,9 @@ import static handiebot.HandieBot.log; public class ShuffleCommand extends ContextCommand { public ShuffleCommand(){ - super("shuffle"); + super("shuffle", + "[true|false]", + "Sets shuffling."); } @Override @@ -26,7 +24,5 @@ public class ShuffleCommand extends ContextCommand { } else { HandieBot.musicPlayer.toggleShuffle(context.getGuild()); } - log.log(BotLog.TYPE.MUSIC, context.getGuild(), "Set shuffle to "+Boolean.toString(HandieBot.musicPlayer.getMusicManager(context.getGuild()).scheduler.isShuffling())); - new DisappearingMessage(context.getChannel(), "Set shuffle to "+Boolean.toString(HandieBot.musicPlayer.getMusicManager(context.getGuild()).scheduler.isShuffling()), 3000); } } diff --git a/src/main/java/handiebot/command/commands/music/SkipCommand.java b/src/main/java/handiebot/command/commands/music/SkipCommand.java index 69ed235..8129444 100644 --- a/src/main/java/handiebot/command/commands/music/SkipCommand.java +++ b/src/main/java/handiebot/command/commands/music/SkipCommand.java @@ -11,7 +11,9 @@ import handiebot.command.types.ContextCommand; public class SkipCommand extends ContextCommand { public SkipCommand() { - super("skip"); + super("skip", + "", + "Skips the current song."); } @Override diff --git a/src/main/java/handiebot/command/commands/music/StopCommand.java b/src/main/java/handiebot/command/commands/music/StopCommand.java new file mode 100644 index 0000000..6ab231d --- /dev/null +++ b/src/main/java/handiebot/command/commands/music/StopCommand.java @@ -0,0 +1,23 @@ +package handiebot.command.commands.music; + +import handiebot.HandieBot; +import handiebot.command.CommandContext; +import handiebot.command.types.ContextCommand; + +/** + * @author Andrew Lalis + * Command to stop playback of music on a server. + */ +public class StopCommand extends ContextCommand { + + public StopCommand(){ + super("stop", + "", + "Stops playing music."); + } + + @Override + public void execute(CommandContext context) { + HandieBot.musicPlayer.stop(context.getGuild()); + } +} diff --git a/src/main/java/handiebot/command/types/Command.java b/src/main/java/handiebot/command/types/Command.java index 7f6ca26..4d69991 100644 --- a/src/main/java/handiebot/command/types/Command.java +++ b/src/main/java/handiebot/command/types/Command.java @@ -7,13 +7,25 @@ package handiebot.command.types; public abstract class Command { private String name; + private String usage; + private String description; - public Command(String name){ + public Command(String name, String usage, String description){ this.name = name; + this.usage = usage; + this.description = description; } public String getName(){ return this.name; }; + public String getUsage() { + return this.name+" "+this.usage; + }; + + public String getDescription() { + return this.description; + } + } diff --git a/src/main/java/handiebot/command/types/ContextCommand.java b/src/main/java/handiebot/command/types/ContextCommand.java index 6ac4e91..e059bab 100644 --- a/src/main/java/handiebot/command/types/ContextCommand.java +++ b/src/main/java/handiebot/command/types/ContextCommand.java @@ -1,6 +1,8 @@ package handiebot.command.types; import handiebot.command.CommandContext; +import handiebot.command.CommandHandler; +import sx.blah.discord.handle.obj.IGuild; /** * @author Andrew Lalis @@ -8,10 +10,19 @@ import handiebot.command.CommandContext; */ public abstract class ContextCommand extends Command { - public ContextCommand(String s) { - super(s); + public ContextCommand(String name, String usage, String description) { + super(name, usage, description); } public abstract void execute(CommandContext context); + /** + * Gets the usage of a command, including the guild, so that the prefix is known. + * @param guild The guild the command should be used on. + * @return A string representing the usage for this command. + */ + public String getUsage(IGuild guild){ + return CommandHandler.PREFIXES.get(guild)+this.getUsage(); + } + } diff --git a/src/main/java/handiebot/command/types/StaticCommand.java b/src/main/java/handiebot/command/types/StaticCommand.java index 60274dc..351e61f 100644 --- a/src/main/java/handiebot/command/types/StaticCommand.java +++ b/src/main/java/handiebot/command/types/StaticCommand.java @@ -6,8 +6,8 @@ package handiebot.command.types; */ public abstract class StaticCommand extends Command { - public StaticCommand(String s) { - super(s); + public StaticCommand(String name, String usage, String description) { + super(name, usage, description); } public abstract void execute(); diff --git a/src/main/java/handiebot/lavaplayer/MusicPlayer.java b/src/main/java/handiebot/lavaplayer/MusicPlayer.java index 95024a4..d944c39 100644 --- a/src/main/java/handiebot/lavaplayer/MusicPlayer.java +++ b/src/main/java/handiebot/lavaplayer/MusicPlayer.java @@ -3,6 +3,7 @@ package handiebot.lavaplayer; import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager; import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers; +import handiebot.HandieBot; import handiebot.command.CommandHandler; import handiebot.lavaplayer.playlist.UnloadedTrack; import handiebot.utils.DisappearingMessage; @@ -25,6 +26,7 @@ import static handiebot.HandieBot.log; * @author Andrew Lalis * This class is a container for all the music related functions, and contains methods for easy playback and queue * management. + * The goal is to abstract all functions to this layer, rather than have the bot interact directly with any schedulers. */ public class MusicPlayer { @@ -113,8 +115,7 @@ public class MusicPlayer { * @param guild The guild to repeat for. */ public void toggleRepeat(IGuild guild){ - GuildMusicManager musicManager = this.getMusicManager(guild); - musicManager.scheduler.setRepeat(!musicManager.scheduler.isRepeating()); + setRepeat(guild, !getMusicManager(guild).scheduler.isRepeating()); } /** @@ -124,6 +125,8 @@ public class MusicPlayer { */ public void setRepeat(IGuild guild, boolean value){ getMusicManager(guild).scheduler.setRepeat(value); + log.log(BotLog.TYPE.MUSIC, guild, "Set repeat to "+getMusicManager(guild).scheduler.isRepeating()); + new DisappearingMessage(getChatChannel(guild), "Set repeat to "+getMusicManager(guild).scheduler.isRepeating(), 3000); } /** @@ -131,8 +134,7 @@ public class MusicPlayer { * @param guild The guild to toggle shuffling for. */ public void toggleShuffle(IGuild guild){ - GuildMusicManager musicManager = this.getMusicManager(guild); - musicManager.scheduler.setShuffle(!musicManager.scheduler.isShuffling()); + setShuffle(guild, !getMusicManager(guild).scheduler.isShuffling()); } /** @@ -142,6 +144,8 @@ public class MusicPlayer { */ public void setShuffle(IGuild guild, boolean value){ getMusicManager(guild).scheduler.setShuffle(value); + log.log(BotLog.TYPE.MUSIC, guild, "Set shuffle to "+Boolean.toString(HandieBot.musicPlayer.getMusicManager(guild).scheduler.isShuffling())); + new DisappearingMessage(getChatChannel(guild), "Set shuffle to "+Boolean.toString(HandieBot.musicPlayer.getMusicManager(guild).scheduler.isShuffling()), 3000); } /** @@ -217,6 +221,11 @@ public class MusicPlayer { getMusicManager(guild).scheduler.nextTrack(); } + public void clearQueue(IGuild guild){ + getMusicManager(guild).scheduler.clearQueue(); + new DisappearingMessage(getChatChannel(guild), "Cleared the queue.", 5000); + } + /** * Skips the current track. */ @@ -228,18 +237,20 @@ public class MusicPlayer { /** * Stops playback and disconnects from the voice channel, to cease music actions. - * @param guild The guild to quit from. + * @param guild The guild to stop from. */ - public void quit(IGuild guild){ - getMusicManager(guild).scheduler.quit(); + public void stop(IGuild guild){ + getMusicManager(guild).scheduler.stop(); + new DisappearingMessage(getChatChannel(guild), "Stopped playing music.", 5000); + log.log(BotLog.TYPE.MUSIC, guild, "Stopped playing music."); } /** - * Performs the same functions as quit, but with every guild. + * Performs the same functions as stop, but with every guild. */ public void quitAll(){ this.musicManagers.forEach((guild, musicManager) -> { - musicManager.scheduler.quit(); + musicManager.scheduler.stop(); }); this.playerManager.shutdown(); } diff --git a/src/main/java/handiebot/lavaplayer/TrackScheduler.java b/src/main/java/handiebot/lavaplayer/TrackScheduler.java index 98cd89c..edf3b9c 100644 --- a/src/main/java/handiebot/lavaplayer/TrackScheduler.java +++ b/src/main/java/handiebot/lavaplayer/TrackScheduler.java @@ -61,7 +61,7 @@ public class TrackScheduler extends AudioEventAdapter { * Clears the queue. */ public void clearQueue(){ - this.quit(); + this.stop(); this.activePlaylist.clear(); } @@ -149,19 +149,21 @@ public class TrackScheduler extends AudioEventAdapter { } player.startTrack(track, false); } else { - this.quit(); + this.stop(); } } /** - * If the user wishes to quit, stop the currently played track. + * If the user wishes to stop, stop the currently played track. */ - public void quit(){ + public void stop(){ IVoiceChannel voiceChannel = HandieBot.musicPlayer.getVoiceChannel(this.guild); if (voiceChannel.isConnected()){ voiceChannel.leave(); } - this.player.stopTrack(); + if (this.player.getPlayingTrack() != null) { + this.player.stopTrack(); + } } @Override diff --git a/src/main/java/handiebot/view/CommandLineListener.java b/src/main/java/handiebot/view/CommandLineListener.java index 0179497..e43502a 100644 --- a/src/main/java/handiebot/view/CommandLineListener.java +++ b/src/main/java/handiebot/view/CommandLineListener.java @@ -41,7 +41,7 @@ public class CommandLineListener implements KeyListener { * @param args The list of arguments for the command. */ private void executeCommand(String command, String[] args){ - if (command.equals("quit")){ + if (command.equals("stop")){ new QuitAction().actionPerformed(null); } } diff --git a/src/main/java/handiebot/view/actions/QuitAction.java b/src/main/java/handiebot/view/actions/QuitAction.java index 23d9089..03f4c74 100644 --- a/src/main/java/handiebot/view/actions/QuitAction.java +++ b/src/main/java/handiebot/view/actions/QuitAction.java @@ -24,7 +24,7 @@ public class QuitAction implements ActionListener { public void actionPerformed(ActionEvent e) { if (guild != null){ HandieBot.musicPlayer.getChatChannel(this.guild).sendMessage("Quiting HandieBot"); - HandieBot.musicPlayer.quit(this.guild); + HandieBot.musicPlayer.stop(this.guild); } else { HandieBot.quit(); } From fdeb1a20597c390dec1e733750c6d171a8dee0f8 Mon Sep 17 00:00:00 2001 From: Andrew Lalis Date: Sun, 25 Jun 2017 11:51:19 +0200 Subject: [PATCH 4/4] Fixed help command, improved aesthetics, added time to playing song. Added framework for reaction voting. --- README.md | 10 +++--- src/main/java/handiebot/HandieBot.java | 10 ++++-- .../command/commands/HelpCommand.java | 34 +++++++------------ .../commands/music/PlaylistCommand.java | 16 ++++----- .../command/commands/music/QueueCommand.java | 21 +++++++++--- .../command/types/ReactionHandler.java | 19 +++++++++++ .../handiebot/lavaplayer/MusicPlayer.java | 23 +++++++++++-- .../handiebot/lavaplayer/TrackScheduler.java | 16 +++++++-- .../lavaplayer/playlist/Playlist.java | 4 +++ 9 files changed, 110 insertions(+), 43 deletions(-) create mode 100644 src/main/java/handiebot/command/types/ReactionHandler.java diff --git a/README.md b/README.md index 706e82c..e763802 100644 --- a/README.md +++ b/README.md @@ -45,12 +45,14 @@ Because the play command is defined as `play [URL]`, and the queue command is de * `skip` - If a song is playing, the bot will skip it and play the next song in the queue. -* `queue [all|clear]` - Lists up to the first 10 items on the queue, if no argument is given. +* `queue [all|clear|save]` - Lists up to the first 10 items on the queue, if no argument is given. - * If you add `all`, the bot will upload a list to [PasteBin](http://pastebin.com) of the entire queue, provided it is greater than 10 elements, and give you a link which expires in 10 minutes. + * `all` - The bot will upload a list to [PasteBin](http://pastebin.com) of the entire queue, provided it is greater than 10 elements, and give you a link which expires in 10 minutes. + + * `clear` - The queue will be cleared and the current song will be stopped. + + * `save ` - The queue will be saved as a playlist with the given name. - * If `clear` is used, the queue will be cleared and the current song will be stopped. - * `repeat [true|false]` - Sets the bot to repeat the playlist, as in once a song is removed from the queue to be played, it is added back to the end of the playlist. * `shuffle [true|false]` - Sets the bot to shuffle the playlist, as in pull a random song from the playlist, with some filters to prevent repeating songs. diff --git a/src/main/java/handiebot/HandieBot.java b/src/main/java/handiebot/HandieBot.java index a92be94..3f13e77 100644 --- a/src/main/java/handiebot/HandieBot.java +++ b/src/main/java/handiebot/HandieBot.java @@ -1,6 +1,7 @@ package handiebot; import handiebot.command.CommandHandler; +import handiebot.command.types.ReactionHandler; import handiebot.lavaplayer.MusicPlayer; import handiebot.utils.DisappearingMessage; import handiebot.view.BotLog; @@ -11,6 +12,7 @@ import sx.blah.discord.api.IDiscordClient; import sx.blah.discord.api.events.EventSubscriber; import sx.blah.discord.handle.impl.events.ReadyEvent; import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent; +import sx.blah.discord.handle.impl.events.guild.channel.message.reaction.ReactionEvent; import sx.blah.discord.handle.obj.IGuild; import sx.blah.discord.util.DiscordException; import sx.blah.discord.util.RateLimitException; @@ -31,12 +33,16 @@ public class HandieBot { private static BotWindow window; public static BotLog log; - private static CommandHandler commandHandler; public static MusicPlayer musicPlayer; @EventSubscriber public void onMessageReceived(MessageReceivedEvent event) { - commandHandler.handleCommand(event); + CommandHandler.handleCommand(event); + } + + @EventSubscriber + public void onReactionReceived(ReactionEvent event){ + ReactionHandler.handleReaction(event); } @EventSubscriber diff --git a/src/main/java/handiebot/command/commands/HelpCommand.java b/src/main/java/handiebot/command/commands/HelpCommand.java index a4d2e7d..bd1c5c9 100644 --- a/src/main/java/handiebot/command/commands/HelpCommand.java +++ b/src/main/java/handiebot/command/commands/HelpCommand.java @@ -5,9 +5,6 @@ import handiebot.command.Commands; import handiebot.command.types.Command; import handiebot.command.types.ContextCommand; import sx.blah.discord.handle.obj.IPrivateChannel; -import sx.blah.discord.util.EmbedBuilder; - -import java.awt.*; /** * @author Andrew Lalis @@ -24,30 +21,25 @@ public class HelpCommand extends ContextCommand { @Override public void execute(CommandContext context) { IPrivateChannel pm = context.getUser().getOrCreatePMChannel(); - EmbedBuilder builder = new EmbedBuilder(); - builder.withAuthorName("HandieBot"); - builder.withAuthorUrl("https://github.com/andrewlalis/HandieBot"); - builder.withAuthorIcon("https://github.com/andrewlalis/HandieBot/blob/master/src/main/resources/icon.png"); - - builder.withColor(new Color(255, 0, 0)); - builder.withDescription("I'm a discord bot that can manage music, as well as some other important functions which will be implemented later on. Some commands are shown below."); - - //Music Commands: - - StringBuilder sb = new StringBuilder(); + StringBuilder sb = new StringBuilder("HandieBot Commands:\n"); for (Command cmd : Commands.commands){ - sb.append('`'); + StringBuilder commandText = new StringBuilder(); + commandText.append("- `"); if (cmd instanceof ContextCommand){ - sb.append(((ContextCommand)cmd).getUsage(context.getGuild())); + commandText.append(((ContextCommand)cmd).getUsage(context.getGuild())); } else { - sb.append(cmd.getUsage()); + commandText.append(cmd.getUsage()); + } + commandText.append("`\n").append(cmd.getDescription()).append("\n\n"); + if (sb.length() + commandText.length() > 2000){ + pm.sendMessage(sb.toString()); + sb = commandText; + } else { + sb.append(commandText); } - sb.append("`\n").append(cmd.getDescription()).append('\n'); } - builder.appendField("Commands:", sb.toString(), false); - - pm.sendMessage(builder.build()); + pm.sendMessage(sb.toString()); } } diff --git a/src/main/java/handiebot/command/commands/music/PlaylistCommand.java b/src/main/java/handiebot/command/commands/music/PlaylistCommand.java index 7e620d7..336ab70 100644 --- a/src/main/java/handiebot/command/commands/music/PlaylistCommand.java +++ b/src/main/java/handiebot/command/commands/music/PlaylistCommand.java @@ -26,14 +26,14 @@ public class PlaylistCommand extends ContextCommand { super("playlist", " [PLAYLIST]", "Do something with a playlist.\n" + - "\tcreate - Creates a playlist.\n" + - "\tdelete - Deletes a playlist.\n" + - "\tshow [PLAYLIST] - If a playlist given, show that, otherwise show a list of playlists.\n" + - "\tadd [URL]... - Adds one or more songs to a playlist.\n" + - "\tremove - Removes a song from a playlist.\n" + - "\trename - Renames a playlist.\n" + - "\tmove - Moves a song from one index to another.\n" + - "\tplay - Queues all songs from a playlist."); + "\t`create ` - Creates a playlist.\n" + + "\t`delete ` - Deletes a playlist.\n" + + "\t`show [PLAYLIST]` - If a playlist given, show that, otherwise show a list of playlists.\n" + + "\t`add [URL]...` - Adds one or more songs to a playlist.\n" + + "\t`remove ` - Removes a song from a playlist.\n" + + "\t`rename ` - Renames a playlist.\n" + + "\t`move ` - Moves a song from one index to another.\n" + + "\t`play ` - Queues all songs from a playlist."); } @Override diff --git a/src/main/java/handiebot/command/commands/music/QueueCommand.java b/src/main/java/handiebot/command/commands/music/QueueCommand.java index 60d864e..6e982a7 100644 --- a/src/main/java/handiebot/command/commands/music/QueueCommand.java +++ b/src/main/java/handiebot/command/commands/music/QueueCommand.java @@ -3,6 +3,11 @@ package handiebot.command.commands.music; import handiebot.HandieBot; import handiebot.command.CommandContext; import handiebot.command.types.ContextCommand; +import handiebot.lavaplayer.playlist.Playlist; +import handiebot.utils.DisappearingMessage; +import handiebot.view.BotLog; + +import static handiebot.HandieBot.log; /** * @author Andrew Lalis @@ -11,19 +16,27 @@ import handiebot.command.types.ContextCommand; public class QueueCommand extends ContextCommand { public QueueCommand() { super("queue", - "[all|clear]", + "[all|clear|save]", "Shows the first 10 songs in the queue.\n" + - "\tall - Shows all songs.\n" + - "\tclear - Clears the queue and stops playing."); + "\t`all` - Shows all songs.\n" + + "\t`clear` - Clears the queue and stops playing.\n" + + "\t`save ` - Saves the queue to a playlist."); } @Override public void execute(CommandContext context) { - if (context.getArgs().length == 1){ + if (context.getArgs().length > 0){ if (context.getArgs()[0].equals("all")){ HandieBot.musicPlayer.showQueueList(context.getGuild(), true); } else if (context.getArgs()[0].equals("clear")){ HandieBot.musicPlayer.clearQueue(context.getGuild()); + log.log(BotLog.TYPE.MUSIC, context.getGuild(), "Cleared queue."); + } else if (context.getArgs()[0].equals("save") && context.getArgs().length == 2){ + Playlist p = HandieBot.musicPlayer.getAllSongsInQueue(context.getGuild()); + p.setName(context.getArgs()[1]); + p.save(); + new DisappearingMessage(context.getChannel(), "Saved "+p.getTrackCount()+" tracks to playlist **"+p.getName()+"**.", 6000); + log.log(BotLog.TYPE.INFO, "Saved queue to playlist ["+p.getName()+"]."); } } else { HandieBot.musicPlayer.showQueueList(context.getGuild(), false); diff --git a/src/main/java/handiebot/command/types/ReactionHandler.java b/src/main/java/handiebot/command/types/ReactionHandler.java new file mode 100644 index 0000000..808b556 --- /dev/null +++ b/src/main/java/handiebot/command/types/ReactionHandler.java @@ -0,0 +1,19 @@ +package handiebot.command.types; + +import sx.blah.discord.handle.impl.events.guild.channel.message.reaction.ReactionEvent; + +/** + * @author Andrew Lalis + * Class which handles user reactions to songs and performs necessary actions. + */ +public class ReactionHandler { + + /** + * Processes a reaction. + * @param event The reaction event to process. + */ + public static void handleReaction(ReactionEvent event){ + + } + +} diff --git a/src/main/java/handiebot/lavaplayer/MusicPlayer.java b/src/main/java/handiebot/lavaplayer/MusicPlayer.java index d944c39..12e488b 100644 --- a/src/main/java/handiebot/lavaplayer/MusicPlayer.java +++ b/src/main/java/handiebot/lavaplayer/MusicPlayer.java @@ -5,6 +5,7 @@ import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager; import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers; import handiebot.HandieBot; import handiebot.command.CommandHandler; +import handiebot.lavaplayer.playlist.Playlist; import handiebot.lavaplayer.playlist.UnloadedTrack; import handiebot.utils.DisappearingMessage; import handiebot.utils.Pastebin; @@ -204,8 +205,10 @@ public class MusicPlayer { TimeUnit.MILLISECONDS.toSeconds(timeUntilPlay) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeUntilPlay)) )); } - IMessage message = getChatChannel(guild).sendMessage(sb.toString()); - DisappearingMessage.deleteMessageAfter(3000, message); + if (sb.length() > 0) { + IMessage message = getChatChannel(guild).sendMessage(sb.toString()); + DisappearingMessage.deleteMessageAfter(3000, message); + } } } @@ -245,6 +248,22 @@ public class MusicPlayer { log.log(BotLog.TYPE.MUSIC, guild, "Stopped playing music."); } + /** + * Returns a playlist of all songs either in the queue or being played now. + * @param guild The guild to get songs from. + * @return A list of songs in the form of a playlist. + */ + public Playlist getAllSongsInQueue(IGuild guild){ + GuildMusicManager musicManager = getMusicManager(guild); + Playlist p = new Playlist("Active Queue"); + p.copy(musicManager.scheduler.getActivePlaylist()); + UnloadedTrack track = musicManager.scheduler.getPlayingTrack(); + if (track != null){ + p.addTrack(track); + } + return p; + } + /** * Performs the same functions as stop, but with every guild. */ diff --git a/src/main/java/handiebot/lavaplayer/TrackScheduler.java b/src/main/java/handiebot/lavaplayer/TrackScheduler.java index edf3b9c..525699b 100644 --- a/src/main/java/handiebot/lavaplayer/TrackScheduler.java +++ b/src/main/java/handiebot/lavaplayer/TrackScheduler.java @@ -113,6 +113,18 @@ public class TrackScheduler extends AudioEventAdapter { return t; } + /** + * Returns the currently playing track, in unloaded form. + * @return The currently playing track, or null. + */ + public UnloadedTrack getPlayingTrack(){ + AudioTrack track = this.player.getPlayingTrack(); + if (track == null){ + return null; + } + return new UnloadedTrack(track); + } + /** * Returns a list of tracks in the queue. * @return A list of tracks in the queue. @@ -171,9 +183,9 @@ public class TrackScheduler extends AudioEventAdapter { log.log(BotLog.TYPE.MUSIC, this.guild, "Started audio track: "+track.getInfo().title); List channels = this.guild.getChannelsByName(MusicPlayer.CHANNEL_NAME.toLowerCase()); if (channels.size() > 0){ - IMessage message = channels.get(0).sendMessage("Now playing: **"+track.getInfo().title+"**\n"+track.getInfo().uri); + IMessage message = channels.get(0).sendMessage("Now playing: **"+track.getInfo().title+"** "+new UnloadedTrack(track).getFormattedDuration()+"\n"+track.getInfo().uri); RequestBuffer.request(() -> {message.addReaction(":thumbsup:");}).get(); - RequestBuffer.request(() -> {message.addReaction(":thumbsdown:");}); + RequestBuffer.request(() -> {message.addReaction(":thumbsdown:");}).get(); } } diff --git a/src/main/java/handiebot/lavaplayer/playlist/Playlist.java b/src/main/java/handiebot/lavaplayer/playlist/Playlist.java index 442e37a..4ad89fe 100644 --- a/src/main/java/handiebot/lavaplayer/playlist/Playlist.java +++ b/src/main/java/handiebot/lavaplayer/playlist/Playlist.java @@ -40,6 +40,10 @@ public class Playlist { return this.name; } + public void setName(String name){ + this.name = name; + } + public int getTrackCount(){ return this.tracks.size(); }