Version 1: Basic functionality #1

Merged
andrewlalis merged 10 commits from development into master 2017-06-21 14:48:08 +00:00
12 changed files with 241 additions and 73 deletions
Showing only changes of commit b9b6c6277f - Show all commits

View File

@ -21,6 +21,10 @@
</build>
<packaging>jar</packaging>
<properties>
<pastebin4j.version>1.1.0</pastebin4j.version>
</properties>
<repositories>
<repository>
<id>jcenter</id>
@ -43,6 +47,11 @@
<artifactId>lavaplayer</artifactId>
<version>1.2.39</version>
</dependency>
<dependency>
<groupId>com.github.kennedyoliveira</groupId>
<artifactId>pastebin4j</artifactId>
<version>${pastebin4j.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -8,6 +8,7 @@ import handiebot.view.View;
import sx.blah.discord.api.ClientBuilder;
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.util.DiscordException;
import sx.blah.discord.util.RateLimitException;
@ -26,17 +27,17 @@ public class HandieBot {
private static BotWindow window;
public static BotLog log;
private CommandHandler commandHandler;
private static CommandHandler commandHandler;
public static MusicPlayer musicPlayer;
private HandieBot() {
this.commandHandler = new CommandHandler(this);
}
@EventSubscriber
public void onMessageReceived(MessageReceivedEvent event) {
this.commandHandler.handleCommand(event);
commandHandler.handleCommand(event);
}
@EventSubscriber
public void onReady(ReadyEvent event){
log.log(BotLog.TYPE.INFO, "HandieBot initialized.");
}
public static void main(String[] args) throws DiscordException, RateLimitException {
@ -47,7 +48,7 @@ public class HandieBot {
log = new BotLog(view.getOutputArea());
window = new BotWindow(view);
log.log(BotLog.TYPE.INFO, "Logging client in.");
log.log(BotLog.TYPE.INFO, "Logging client in...");
client = new ClientBuilder().withToken(TOKEN).build();
client.getDispatcher().registerListener(new HandieBot());
client.login();

View File

@ -1,14 +1,21 @@
package handiebot.command;
import com.sun.istack.internal.NotNull;
import handiebot.HandieBot;
import handiebot.utils.DisappearingMessage;
import handiebot.view.BotLog;
import handiebot.view.actions.QuitAction;
import handiebot.view.actions.music.PlayAction;
import handiebot.view.actions.music.QueueListAction;
import handiebot.view.actions.music.SkipAction;
import handiebot.view.actions.music.ToggleRepeatAction;
import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent;
import sx.blah.discord.handle.obj.*;
import sx.blah.discord.util.EmbedBuilder;
import java.awt.*;
import static handiebot.HandieBot.log;
/**
* @author Andrew Lalis
* Class to process commands.
@ -16,18 +23,11 @@ import java.awt.*;
public class CommandHandler {
public static String PREFIX = "!";
private final HandieBot bot;
public CommandHandler(HandieBot bot){
this.bot = bot;
}
/**
* Main method to handle user messages.
* @param event The event generated by the message.
*/
public void handleCommand(MessageReceivedEvent event){
public static void handleCommand(MessageReceivedEvent event){
IMessage message = event.getMessage();
IUser user = event.getAuthor();
IChannel channel = event.getChannel();
@ -38,29 +38,24 @@ public class CommandHandler {
DisappearingMessage.deleteMessageAfter(1000, message);
if (command.equals("play")){
//Play or queue a song.
if (args.length == 1) {
HandieBot.musicPlayer.loadToQueue(guild, args[0]);
} else if (args.length == 0){
HandieBot.musicPlayer.playQueue(guild);
}
new PlayAction(guild, args).actionPerformed(null);
} else if (command.equals("skip") && args.length == 0){
//Skip the current song.
HandieBot.musicPlayer.skipTrack(guild);
new SkipAction(guild).actionPerformed(null);
} else if (command.equals("help")){
//Send a PM to the user with help info.
this.sendHelpInfo(user);//TODO finish the help command and fill in with new descriptions each time.
} else if (command.equals("queue") && args.length == 0){
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.
HandieBot.musicPlayer.showQueueList(guild);
new QueueListAction(guild, (args.length == 1) && args[0].equals("all")).actionPerformed(null);
} else if (command.equals("repeat")){
//Toggle repeat.
HandieBot.musicPlayer.toggleRepeat(guild);
new ToggleRepeatAction(guild).actionPerformed(null);
} else if (command.equals("clear")){
//TODO clear command.
} else if (command.equals("quit")){
//Quit the application.
channel.sendMessage("Quitting HandieBot functions.");
HandieBot.musicPlayer.quit(guild);
new QuitAction(guild).actionPerformed(null);
} else if (command.equals("playlist")){
//Do playlist actions.
//TODO perform actions!
@ -69,8 +64,12 @@ public class CommandHandler {
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());
}
}
}
@ -80,7 +79,7 @@ public class CommandHandler {
* @param message The message to get a command from.
* @return The command word, minus the prefix, or null.
*/
private String extractCommand(IMessage message){
private static String extractCommand(IMessage message){
String[] words = message.getContent().split(" ");
if (words[0].startsWith(PREFIX)){
return words[0].replaceFirst(PREFIX, "").toLowerCase();
@ -94,7 +93,7 @@ public class CommandHandler {
* @return A list of strings representing args.
*/
@NotNull
private String[] extractArgs(IMessage message){
private static String[] extractArgs(IMessage message){
String[] words = message.getContent().split(" ");
if (words[0].startsWith(PREFIX)){
String[] args = new String[words.length-1];
@ -110,7 +109,7 @@ 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.
*/
private void sendHelpInfo(IUser user){
private static void sendHelpInfo(IUser user){
IPrivateChannel pm = user.getOrCreatePMChannel();
EmbedBuilder builder = new EmbedBuilder();

View File

@ -31,7 +31,8 @@ import static handiebot.HandieBot.log;
public class MusicPlayer {
//Name for the message and voice channels dedicated to this bot.
public static String CHANNEL_NAME = "HandieBotMusic";
static String CHANNEL_NAME = "HandieBotMusic";
private static String PASTEBIN_KEY = "769adc01154922ece448cabd7a33b57c";
private final AudioPlayerManager playerManager;
@ -74,7 +75,7 @@ public class MusicPlayer {
* @param guild The guild to get the channel from.
* @return A message channel on a particular guild that is specifically for music.
*/
private IChannel getChatChannel(IGuild guild){
public IChannel getChatChannel(IGuild guild){
if (!this.chatChannels.containsKey(guild)){
List<IChannel> channels = guild.getChannelsByName(CHANNEL_NAME.toLowerCase());
if (channels.isEmpty()){
@ -93,7 +94,7 @@ public class MusicPlayer {
* @param guild The guild to get the channel from.
* @return The voice channel on a guild that is for this bot.
*/
private IVoiceChannel getVoiceChannel(IGuild guild){
public IVoiceChannel getVoiceChannel(IGuild guild){
if (!this.voiceChannels.containsKey(guild)){
List<IVoiceChannel> channels = guild.getVoiceChannelsByName(CHANNEL_NAME);
if (channels.isEmpty()){
@ -119,32 +120,56 @@ public class MusicPlayer {
/**
* Sends a formatted message to the guild about the first few items in a queue.
*/
public void showQueueList(IGuild guild){
public void showQueueList(IGuild guild, boolean showAll){
List<AudioTrack> 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);
} else {
if (!showAll) {
EmbedBuilder builder = new EmbedBuilder();
builder.withColor(255, 0, 0);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < (tracks.size() <= 10 ? tracks.size() : 10); i++) {
sb.append(i+1);
sb.append(i + 1);
sb.append(". ");
sb.append('[');
sb.append(tracks.get(i).getInfo().title);
sb.append("](");
sb.append(tracks.get(i).getInfo().uri);
sb.append(")");
int seconds = (int) (tracks.get(i).getInfo().length/1000);
int seconds = (int) (tracks.get(i).getInfo().length / 1000);
int minutes = seconds / 60;
seconds = seconds % 60;
String time = String.format(" [%d:%02d]\n", minutes, seconds);
sb.append(time);
}
builder.withTimestamp(System.currentTimeMillis());
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" : "") + ".", sb.toString(), false);
IMessage message = getChatChannel(guild).sendMessage(builder.build());
DisappearingMessage.deleteMessageAfter(6000, message);
} else {
StringBuilder sb = new StringBuilder("Queue for Discord Server: "+guild.getName()+"\n");
for (int i = 0; i < tracks.size(); i++){
sb.append(i+1).append(". ").append(tracks.get(i).getInfo().title);
int seconds = (int) (tracks.get(i).getInfo().length / 1000);
int minutes = seconds / 60;
seconds = seconds % 60;
String time = String.format(" [%d:%02d]\n", minutes, seconds);
sb.append(time);
}
//TODO: get pastebin working.
/*
PasteBin pasteBin = new PasteBin(new AccountCredentials(PASTEBIN_KEY));
Paste paste = new Paste(PASTEBIN_KEY);
paste.setTitle("Music Queue for Discord Server: "+guild.getName());
paste.setContent(sb.toString());
paste.setExpiration(PasteExpiration.ONE_HOUR);
paste.setVisibility(PasteVisibility.PUBLIC);
final String pasteURL = pasteBin.createPaste(paste);
log.log(BotLog.TYPE.INFO, guild, "Uploaded full queue to "+pasteURL);
new DisappearingMessage(getChatChannel(guild), "You may view the full queue here. "+pasteURL, 60000);
*/
}
}
}
@ -188,7 +213,7 @@ public class MusicPlayer {
* Adds a track to the queue and sends a message to the appropriate channel notifying users.
* @param track The track to queue.
*/
public void addToQueue(IGuild guild, AudioTrack track){
private void addToQueue(IGuild guild, AudioTrack track){
IVoiceChannel voiceChannel = getVoiceChannel(guild);
if (voiceChannel != null){
if (!voiceChannel.isConnected()) {
@ -240,10 +265,6 @@ public class MusicPlayer {
*/
public void quit(IGuild guild){
getMusicManager(guild).scheduler.quit();
IVoiceChannel vc = this.getVoiceChannel(guild);
if (vc.isConnected()){
vc.leave();
}
}
/**
@ -252,10 +273,6 @@ public class MusicPlayer {
public void quitAll(){
this.musicManagers.forEach((guild, musicManager) -> {
musicManager.scheduler.quit();
IVoiceChannel vc = this.getVoiceChannel(guild);
if (vc.isConnected()){
vc.leave();
}
});
this.playerManager.shutdown();
}

View File

@ -6,10 +6,12 @@ import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter;
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason;
import handiebot.HandieBot;
import handiebot.view.BotLog;
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.IVoiceChannel;
import sx.blah.discord.util.RequestBuffer;
import java.util.List;
@ -113,11 +115,19 @@ public class TrackScheduler extends AudioEventAdapter {
* Starts the next track, stopping the current one if it's playing.
*/
public void nextTrack(){
AudioTrack currentTrack = this.player.getPlayingTrack();
if (currentTrack != null){
this.player.stopTrack();
}
AudioTrack track = (this.repeat ? this.activePlaylist.getNextTrackAndRequeue(this.shuffle) : this.activePlaylist.getNextTrackAndRemove(this.shuffle));
if (track != null) {
IVoiceChannel voiceChannel = HandieBot.musicPlayer.getVoiceChannel(this.guild);
if (!voiceChannel.isConnected()){
voiceChannel.join();
}
player.startTrack(track, false);
} else {
player.stopTrack();
this.quit();
}
}
@ -125,8 +135,11 @@ public class TrackScheduler extends AudioEventAdapter {
* If the user wishes to quit, stop the currently played track.
*/
public void quit(){
IVoiceChannel voiceChannel = HandieBot.musicPlayer.getVoiceChannel(this.guild);
if (voiceChannel.isConnected()){
voiceChannel.leave();
}
this.player.stopTrack();
this.player.destroy();
}
@Override
@ -134,7 +147,7 @@ public class TrackScheduler extends AudioEventAdapter {
log.log(BotLog.TYPE.MUSIC, this.guild, "Started audio track: "+track.getInfo().title);
List<IChannel> channels = this.guild.getChannelsByName(MusicPlayer.CHANNEL_NAME.toLowerCase());
if (channels.size() > 0){
IMessage message = channels.get(0).sendMessage("Now playing: **"+track.getInfo().title+"**.");
IMessage message = channels.get(0).sendMessage("Now playing: **"+track.getInfo().title+"**\n"+track.getInfo().uri);
RequestBuffer.request(() -> {message.addReaction(":thumbsup:");}).get();
RequestBuffer.request(() -> {message.addReaction(":thumbsdown:");});
}
@ -142,13 +155,10 @@ public class TrackScheduler extends AudioEventAdapter {
@Override
public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) {
System.out.println("Track ended.");
if (endReason.mayStartNext){
System.out.println("Moving to next track.");
nextTrack();
} else {
log.log(BotLog.TYPE.ERROR, this.guild, "Unable to go to the next track. Reason: "+endReason.name());
System.out.println(endReason.toString());
log.log(BotLog.TYPE.MUSIC, this.guild, "Unable to go to the next track. Reason: "+endReason.name());
}
}

View File

@ -21,6 +21,7 @@ public class CommandLineListener implements KeyListener {
//user wishes to submit command.
JTextField commandLine = (JTextField) e.getSource();
String[] words = commandLine.getText().trim().split(" ");
commandLine.setText(null);
String command = words[0];
String[] args = new String[words.length-1];
for (int i = 1; i < words.length; i++) {

View File

@ -1,6 +1,7 @@
package handiebot.view.actions;
import handiebot.HandieBot;
import sx.blah.discord.handle.obj.IGuild;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@ -10,8 +11,22 @@ import java.awt.event.ActionListener;
*/
public class QuitAction implements ActionListener {
private IGuild guild;
public QuitAction(){
}
public QuitAction(IGuild guild){
this.guild = guild;
}
@Override
public void actionPerformed(ActionEvent e) {
if (guild != null){
HandieBot.musicPlayer.getChatChannel(this.guild).sendMessage("Quiting HandieBot");
HandieBot.musicPlayer.quit(this.guild);
} else {
HandieBot.quit();
}
}
}

View File

@ -0,0 +1,18 @@
package handiebot.view.actions.music;
import sx.blah.discord.handle.obj.IGuild;
import java.awt.event.ActionListener;
/**
* @author Andrew Lalis
*/
public abstract class MusicAction implements ActionListener {
protected IGuild guild;
public MusicAction(IGuild guild) {
this.guild = guild;
}
}

View File

@ -0,0 +1,32 @@
package handiebot.view.actions.music;
import handiebot.HandieBot;
import sx.blah.discord.handle.obj.IGuild;
import java.awt.event.ActionEvent;
/**
* @author Andrew Lalis
*/
public class PlayAction extends MusicAction {
private String[] args = null;
public PlayAction(IGuild guild) {
super(guild);
}
public PlayAction(IGuild guild, String[] args){
super(guild);
this.args = args;
}
@Override
public void actionPerformed(ActionEvent e) {
if (this.args == null || this.args.length < 1){
HandieBot.musicPlayer.playQueue(this.guild);
} else {
HandieBot.musicPlayer.loadToQueue(this.guild, this.args[0]);
}
}
}

View File

@ -0,0 +1,24 @@
package handiebot.view.actions.music;
import handiebot.HandieBot;
import sx.blah.discord.handle.obj.IGuild;
import java.awt.event.ActionEvent;
/**
* @author Andrew Lalis
*/
public class QueueListAction extends MusicAction {
private boolean showAll = false;
public QueueListAction(IGuild guild, boolean showAll){
super(guild);
this.showAll = showAll;
}
@Override
public void actionPerformed(ActionEvent e) {
HandieBot.musicPlayer.showQueueList(this.guild, this.showAll);
}
}

View File

@ -0,0 +1,21 @@
package handiebot.view.actions.music;
import handiebot.HandieBot;
import sx.blah.discord.handle.obj.IGuild;
import java.awt.event.ActionEvent;
/**
* @author Andrew Lalis
*/
public class SkipAction extends MusicAction {
public SkipAction(IGuild guild) {
super(guild);
}
@Override
public void actionPerformed(ActionEvent e) {
HandieBot.musicPlayer.skipTrack(this.guild);
}
}

View File

@ -0,0 +1,21 @@
package handiebot.view.actions.music;
import handiebot.HandieBot;
import sx.blah.discord.handle.obj.IGuild;
import java.awt.event.ActionEvent;
/**
* @author Andrew Lalis
*/
public class ToggleRepeatAction extends MusicAction {
public ToggleRepeatAction(IGuild guild) {
super(guild);
}
@Override
public void actionPerformed(ActionEvent e) {
HandieBot.musicPlayer.toggleRepeat(this.guild);
}
}