Compare commits
1 Commits
developmen
...
master
Author | SHA1 | Date |
---|---|---|
Andrew Lalis | d851482d94 |
|
@ -1,4 +1,4 @@
|
||||||
|
.idea/
|
||||||
|
modules/
|
||||||
src/test/
|
src/test/
|
||||||
target/
|
target/
|
||||||
modules/
|
|
||||||
.idea
|
|
||||||
|
|
BIN
avatarIcon.psd
BIN
avatarIcon.psd
Binary file not shown.
30
pom.xml
30
pom.xml
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
<groupId>com.github.andrewlalis</groupId>
|
<groupId>com.github.andrewlalis</groupId>
|
||||||
<artifactId>HandieBot</artifactId>
|
<artifactId>HandieBot</artifactId>
|
||||||
<version>1.6.0</version>
|
<version>1.4.0</version>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
@ -60,41 +60,17 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.austinv11</groupId>
|
<groupId>com.github.austinv11</groupId>
|
||||||
<artifactId>Discord4J</artifactId>
|
<artifactId>Discord4J</artifactId>
|
||||||
<version>2.9.2</version>
|
<version>2.8.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- Command Framework -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>de.btobastian.sdcf4j</groupId>
|
|
||||||
<artifactId>sdcf4j-core</artifactId>
|
|
||||||
<version>v1.0.9</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>de.btobastian.sdcf4j</groupId>
|
|
||||||
<artifactId>sdcf4j-discord4j</artifactId>
|
|
||||||
<version>v1.0.9</version>
|
|
||||||
</dependency>
|
|
||||||
<!-- Music Player -->
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.sedmelluq</groupId>
|
<groupId>com.sedmelluq</groupId>
|
||||||
<artifactId>lavaplayer</artifactId>
|
<artifactId>lavaplayer</artifactId>
|
||||||
<version>1.2.39</version>
|
<version>1.2.39</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- Tengwar Translator -->
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.andrewlalis</groupId>
|
<groupId>com.github.andrewlalis</groupId>
|
||||||
<artifactId>TengwarTranslatorLibrary</artifactId>
|
<artifactId>TengwarTranslatorLibrary</artifactId>
|
||||||
<version>1.3.1</version>
|
<version>1.3</version>
|
||||||
</dependency>
|
|
||||||
<!-- Google APIs -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.apis</groupId>
|
|
||||||
<artifactId>google-api-services-youtube</artifactId>
|
|
||||||
<version>v3-rev183-1.22.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.oauth-client</groupId>
|
|
||||||
<artifactId>google-oauth-client-jetty</artifactId>
|
|
||||||
<version>1.22.0</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ package handiebot;
|
||||||
import handiebot.command.CommandHandler;
|
import handiebot.command.CommandHandler;
|
||||||
import handiebot.command.ReactionHandler;
|
import handiebot.command.ReactionHandler;
|
||||||
import handiebot.lavaplayer.MusicPlayer;
|
import handiebot.lavaplayer.MusicPlayer;
|
||||||
import handiebot.utils.FileUtil;
|
|
||||||
import handiebot.view.BotLog;
|
import handiebot.view.BotLog;
|
||||||
import handiebot.view.BotWindow;
|
import handiebot.view.BotWindow;
|
||||||
import sx.blah.discord.api.ClientBuilder;
|
import sx.blah.discord.api.ClientBuilder;
|
||||||
|
@ -27,31 +26,44 @@ import java.util.*;
|
||||||
*/
|
*/
|
||||||
public class HandieBot {
|
public class HandieBot {
|
||||||
|
|
||||||
//Application name is the name of application as it appears on display window.
|
|
||||||
public static final String APPLICATION_NAME = "HandieBot";
|
public static final String APPLICATION_NAME = "HandieBot";
|
||||||
|
private static final String TOKEN = "MjgzNjUyOTg5MjEyNjg4Mzg0.C45A_Q.506b0G6my1FEFa7_YY39lxLBHUY";
|
||||||
//The token required for logging into Discord. This is secure and must not be in the source code on GitHub.
|
|
||||||
private static String TOKEN;
|
|
||||||
|
|
||||||
//Variable to enable or disable GUI.
|
|
||||||
private static boolean USE_GUI = true;
|
private static boolean USE_GUI = true;
|
||||||
|
|
||||||
//Settings for the bot. Tries to load the settings, or if that doesn't work, it will load defaults.
|
public static final ResourceBundle resourceBundle = ResourceBundle.getBundle("Strings");
|
||||||
public static Properties settings;
|
|
||||||
|
|
||||||
//Resource bundle for localized strings.
|
|
||||||
public static ResourceBundle resourceBundle;
|
|
||||||
|
|
||||||
//Discord client object.
|
//Discord client object.
|
||||||
public static IDiscordClient client;
|
public static IDiscordClient client;
|
||||||
|
|
||||||
//Display objects.
|
//Display objects.
|
||||||
public static BotWindow window;
|
private static BotWindow window;
|
||||||
public static BotLog log;
|
public static BotLog log;
|
||||||
|
|
||||||
//The cross-guild music player.
|
//The cross-guild music player.
|
||||||
public static MusicPlayer musicPlayer;
|
public static MusicPlayer musicPlayer;
|
||||||
|
|
||||||
|
//List of all permissions needed to operate this bot.
|
||||||
|
private static final int permissionsNumber;
|
||||||
|
static {
|
||||||
|
List<Permissions> requiredPermissions = new ArrayList<>();
|
||||||
|
requiredPermissions.add(Permissions.CHANGE_NICKNAME);
|
||||||
|
requiredPermissions.add(Permissions.ADD_REACTIONS);
|
||||||
|
requiredPermissions.add(Permissions.MANAGE_CHANNELS);
|
||||||
|
requiredPermissions.add(Permissions.EMBED_LINKS);
|
||||||
|
requiredPermissions.add(Permissions.ATTACH_FILES);
|
||||||
|
requiredPermissions.add(Permissions.MANAGE_EMOJIS);
|
||||||
|
requiredPermissions.add(Permissions.MANAGE_MESSAGES);
|
||||||
|
requiredPermissions.add(Permissions.MANAGE_PERMISSIONS);
|
||||||
|
requiredPermissions.add(Permissions.READ_MESSAGE_HISTORY);
|
||||||
|
requiredPermissions.add(Permissions.READ_MESSAGES);
|
||||||
|
requiredPermissions.add(Permissions.SEND_MESSAGES);
|
||||||
|
requiredPermissions.add(Permissions.VOICE_CONNECT);
|
||||||
|
requiredPermissions.add(Permissions.VOICE_MUTE_MEMBERS);
|
||||||
|
requiredPermissions.add(Permissions.VOICE_SPEAK);
|
||||||
|
requiredPermissions.add(Permissions.VOICE_USE_VAD);
|
||||||
|
permissionsNumber = Permissions.generatePermissionsNumber(EnumSet.copyOf(requiredPermissions));
|
||||||
|
}
|
||||||
|
|
||||||
@EventSubscriber
|
@EventSubscriber
|
||||||
public void onMessageReceived(MessageReceivedEvent event) {
|
public void onMessageReceived(MessageReceivedEvent event) {
|
||||||
CommandHandler.handleCommand(event);
|
CommandHandler.handleCommand(event);
|
||||||
|
@ -68,25 +80,8 @@ public class HandieBot {
|
||||||
//client.changeAvatar(Image.forStream("png", getClass().getClassLoader().getResourceAsStream("avatarIcon.png")));
|
//client.changeAvatar(Image.forStream("png", getClass().getClassLoader().getResourceAsStream("avatarIcon.png")));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up the basic functions of the bot.
|
|
||||||
*/
|
|
||||||
private static void init(){
|
|
||||||
TOKEN = FileUtil.readToken();
|
|
||||||
if (TOKEN.isEmpty()){
|
|
||||||
System.out.println("You do not have the token required to start the bot. Shutting down.");
|
|
||||||
System.exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
settings = FileUtil.loadSettings();
|
|
||||||
|
|
||||||
resourceBundle = ResourceBundle.getBundle("Strings", Locale.forLanguageTag(settings.getProperty("language")));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws DiscordException, RateLimitException {
|
public static void main(String[] args) throws DiscordException, RateLimitException {
|
||||||
|
|
||||||
init();
|
|
||||||
|
|
||||||
musicPlayer = new MusicPlayer();
|
musicPlayer = new MusicPlayer();
|
||||||
|
|
||||||
List<String> argsList = Arrays.asList(args);
|
List<String> argsList = Arrays.asList(args);
|
||||||
|
@ -126,7 +121,6 @@ public class HandieBot {
|
||||||
musicPlayer.quitAll();
|
musicPlayer.quitAll();
|
||||||
client.logout();
|
client.logout();
|
||||||
window.dispose();
|
window.dispose();
|
||||||
FileUtil.saveSettings(settings);
|
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package handiebot.command;
|
package handiebot.command;
|
||||||
|
|
||||||
|
import handiebot.utils.DisappearingMessage;
|
||||||
import handiebot.utils.FileUtil;
|
import handiebot.utils.FileUtil;
|
||||||
import handiebot.utils.MessageUtils;
|
|
||||||
import handiebot.view.BotLog;
|
import handiebot.view.BotLog;
|
||||||
import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent;
|
import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent;
|
||||||
import sx.blah.discord.handle.obj.IChannel;
|
import sx.blah.discord.handle.obj.IChannel;
|
||||||
|
@ -50,7 +50,7 @@ public class CommandHandler {
|
||||||
//Create a context to give to each command's execution, so it knows what channel to reply on, etc.
|
//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);
|
CommandContext context = new CommandContext(user, channel, guild, args);
|
||||||
if (guild != null && command != null){
|
if (guild != null && command != null){
|
||||||
MessageUtils.deleteMessageAfter(1000, message);
|
DisappearingMessage.deleteMessageAfter(1000, message);
|
||||||
Commands.executeCommand(command, context);
|
Commands.executeCommand(command, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
package handiebot.command;
|
package handiebot.command;
|
||||||
|
|
||||||
import handiebot.command.commands.admin.BroadcastCommand;
|
|
||||||
import handiebot.command.commands.admin.QuitCommand;
|
import handiebot.command.commands.admin.QuitCommand;
|
||||||
import handiebot.command.commands.admin.SetPrefixCommand;
|
import handiebot.command.commands.admin.SetPrefixCommand;
|
||||||
import handiebot.command.commands.misc.TengwarCommand;
|
import handiebot.command.commands.misc.TengwarCommand;
|
||||||
import handiebot.command.commands.music.*;
|
import handiebot.command.commands.music.*;
|
||||||
import handiebot.command.commands.support.HelpCommand;
|
import handiebot.command.commands.support.HelpCommand;
|
||||||
import handiebot.command.commands.support.InfoCommand;
|
import handiebot.command.commands.support.InfoCommand;
|
||||||
import handiebot.command.commands.support.ReportCommand;
|
|
||||||
import handiebot.command.types.Command;
|
import handiebot.command.types.Command;
|
||||||
import handiebot.command.types.ContextCommand;
|
import handiebot.command.types.ContextCommand;
|
||||||
import handiebot.command.types.StaticCommand;
|
import handiebot.command.types.StaticCommand;
|
||||||
|
@ -20,7 +18,6 @@ import java.util.List;
|
||||||
|
|
||||||
import static handiebot.HandieBot.log;
|
import static handiebot.HandieBot.log;
|
||||||
import static handiebot.HandieBot.resourceBundle;
|
import static handiebot.HandieBot.resourceBundle;
|
||||||
import static handiebot.utils.MessageUtils.sendMessage;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andrew Lalis
|
* @author Andrew Lalis
|
||||||
|
@ -33,7 +30,6 @@ public class Commands {
|
||||||
static {
|
static {
|
||||||
//Music commands.
|
//Music commands.
|
||||||
commands.add(new PlayCommand());
|
commands.add(new PlayCommand());
|
||||||
commands.add(new PlayNowCommand());
|
|
||||||
commands.add(new StopCommand());
|
commands.add(new StopCommand());
|
||||||
commands.add(new QueueCommand());
|
commands.add(new QueueCommand());
|
||||||
commands.add(new SkipCommand());
|
commands.add(new SkipCommand());
|
||||||
|
@ -43,10 +39,8 @@ public class Commands {
|
||||||
//Other commands.
|
//Other commands.
|
||||||
commands.add(new HelpCommand());
|
commands.add(new HelpCommand());
|
||||||
commands.add(new InfoCommand());
|
commands.add(new InfoCommand());
|
||||||
commands.add(new ReportCommand());
|
|
||||||
commands.add(new SetPrefixCommand());
|
commands.add(new SetPrefixCommand());
|
||||||
commands.add(new QuitCommand());
|
commands.add(new QuitCommand());
|
||||||
commands.add(new BroadcastCommand());
|
|
||||||
commands.add(new TengwarCommand());
|
commands.add(new TengwarCommand());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,14 +52,13 @@ public class Commands {
|
||||||
public static void executeCommand(String command, CommandContext context){
|
public static void executeCommand(String command, CommandContext context){
|
||||||
for (Command cmd : commands) {
|
for (Command cmd : commands) {
|
||||||
if (cmd.getName().equals(command)){
|
if (cmd.getName().equals(command)){
|
||||||
if (cmd instanceof StaticCommand &&
|
if (cmd instanceof StaticCommand){
|
||||||
((context != null && cmd.canUserExecute(context.getUser(), context.getGuild())) || context == null)){
|
|
||||||
log.log(BotLog.TYPE.COMMAND, command+" has been issued.");
|
log.log(BotLog.TYPE.COMMAND, command+" has been issued.");
|
||||||
((StaticCommand)cmd).execute();
|
((StaticCommand)cmd).execute();
|
||||||
return;
|
return;
|
||||||
} else if (!cmd.canUserExecute(context.getUser(), context.getGuild())){
|
} else if (!cmd.canUserExecute(context.getUser(), context.getGuild())){
|
||||||
log.log(BotLog.TYPE.COMMAND, context.getGuild(), MessageFormat.format(resourceBundle.getString("commands.noPermission.log"), context.getUser().getName(), cmd.getName()));
|
log.log(BotLog.TYPE.COMMAND, context.getGuild(), MessageFormat.format(resourceBundle.getString("commands.noPermission.log"), context.getUser().getName(), cmd.getName()));
|
||||||
sendMessage(MessageFormat.format(resourceBundle.getString("commands.noPermission.message"), command), context.getChannel());
|
context.getChannel().sendMessage(MessageFormat.format(resourceBundle.getString("commands.noPermission.message"), command));
|
||||||
return;
|
return;
|
||||||
} else if (cmd instanceof ContextCommand){
|
} else if (cmd instanceof ContextCommand){
|
||||||
log.log(BotLog.TYPE.COMMAND, context.getGuild(), context.getUser().getName()+" has issued the command: "+command);
|
log.log(BotLog.TYPE.COMMAND, context.getGuild(), context.getUser().getName()+" has issued the command: "+command);
|
||||||
|
@ -107,7 +100,7 @@ public class Commands {
|
||||||
(context.getUser().getLongID() == 235439851263098880L) ||
|
(context.getUser().getLongID() == 235439851263098880L) ||
|
||||||
(permission == 0);
|
(permission == 0);
|
||||||
if (!result){
|
if (!result){
|
||||||
sendMessage(resourceBundle.getString("commands.noPermission.subcommand"), context.getChannel());
|
context.getChannel().sendMessage(resourceBundle.getString("commands.noPermission.subcommand"));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,76 +1,68 @@
|
||||||
package handiebot.command;
|
package handiebot.command;
|
||||||
|
|
||||||
import handiebot.command.types.ReactionListener;
|
import handiebot.HandieBot;
|
||||||
|
import handiebot.view.BotLog;
|
||||||
import sx.blah.discord.handle.impl.events.guild.channel.message.reaction.ReactionEvent;
|
import sx.blah.discord.handle.impl.events.guild.channel.message.reaction.ReactionEvent;
|
||||||
import sx.blah.discord.util.RequestBuffer;
|
import sx.blah.discord.handle.obj.IMessage;
|
||||||
|
import sx.blah.discord.handle.obj.IReaction;
|
||||||
|
import sx.blah.discord.handle.obj.IUser;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static handiebot.HandieBot.log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andrew Lalis
|
* @author Andrew Lalis
|
||||||
* Class which handles user reactions to songs and performs necessary actions.
|
* Class which handles user reactions to songs and performs necessary actions.
|
||||||
*/
|
*/
|
||||||
public class ReactionHandler {
|
public class ReactionHandler {
|
||||||
|
|
||||||
private static List<ReactionListener> listeners = new ArrayList<>();
|
public static final String thumbsUp = "\uD83D\uDC4D";
|
||||||
//Flag to tell if the handler is iterating over the listeners.
|
public static final String thumbsDown = "\uD83D\uDC4E";
|
||||||
private static boolean iterating = false;
|
|
||||||
//Queue of listeners to remove after an iteration.
|
|
||||||
private static List<ReactionListener> listenersToRemove = new ArrayList<>();
|
|
||||||
//Flag that individual listeners can set to request the message be deleted after processing.
|
|
||||||
private static boolean deleteRequested = false;
|
|
||||||
/**
|
|
||||||
* Adds a listener, so that it is notified when reaction events are received.
|
|
||||||
* @param listener The listener to add.
|
|
||||||
*/
|
|
||||||
public static void addListener(ReactionListener listener){
|
|
||||||
listeners.add(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a listener from the list of reaction listeners.
|
|
||||||
* @param listener The listener to remove.
|
|
||||||
*/
|
|
||||||
public static void removeListener(ReactionListener listener){
|
|
||||||
if (iterating){
|
|
||||||
listenersToRemove.add(listener);
|
|
||||||
} else {
|
|
||||||
listeners.remove(listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Requests that the currently processing message should be deleted after the iteration.
|
|
||||||
*/
|
|
||||||
public static void requestMessageDeletion(){
|
|
||||||
deleteRequested = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notifies all listeners that a ReactionEvent has occurred, and calls each one's function.
|
|
||||||
* @param event The event that occurred.
|
|
||||||
*/
|
|
||||||
private static void notifyListeners(ReactionEvent event){
|
|
||||||
iterating = true;
|
|
||||||
for (ReactionListener listener : listeners){
|
|
||||||
listener.onReactionEvent(event);
|
|
||||||
}
|
|
||||||
iterating = false;
|
|
||||||
if (deleteRequested) {
|
|
||||||
RequestBuffer.request(event.getMessage()::delete);
|
|
||||||
}
|
|
||||||
deleteRequested = false;
|
|
||||||
listeners.removeAll(listenersToRemove);
|
|
||||||
listenersToRemove.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes a reaction.
|
* Processes a reaction.
|
||||||
* @param event The reaction event to process.
|
* @param event The reaction event to process.
|
||||||
*/
|
*/
|
||||||
public static void handleReaction(ReactionEvent event){
|
public static void handleReaction(ReactionEvent event){
|
||||||
notifyListeners(event);
|
IMessage message = event.getMessage();
|
||||||
|
IReaction reaction = event.getReaction();
|
||||||
|
CommandContext context = new CommandContext(event.getUser(), event.getChannel(), event.getGuild(), new String[]{});
|
||||||
|
if (reaction.toString().equals(thumbsDown)){
|
||||||
|
onDownvote(context, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* What to do if someone downvotes a song.
|
||||||
|
* If more than half of the people in the voice channel dislike the song, it will be skipped.
|
||||||
|
* If not, then the bot will tell how many more people need to downvote.
|
||||||
|
* @param context The context of the reaction.
|
||||||
|
* @param message The messages that received a reaction.
|
||||||
|
*/
|
||||||
|
private static void onDownvote(CommandContext context, IMessage message){
|
||||||
|
//Filter out reactions to previous messages.
|
||||||
|
if (message.getLongID() != HandieBot.musicPlayer.getMusicManager(context.getGuild()).scheduler.getPlayMessageId()){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<IUser> usersHere = HandieBot.musicPlayer.getVoiceChannel(context.getGuild()).getConnectedUsers();
|
||||||
|
//Remove the bot from the list of users in the voice channel.
|
||||||
|
usersHere.removeIf(user -> (user.getLongID() == HandieBot.client.getOurUser().getLongID()) ||
|
||||||
|
(user.getVoiceStateForGuild(context.getGuild()).isDeafened()) ||
|
||||||
|
(user.getVoiceStateForGuild(context.getGuild()).isSelfDeafened()));
|
||||||
|
|
||||||
|
int userCount = usersHere.size();
|
||||||
|
int userDownvotes = 0;
|
||||||
|
IReaction reaction = message.getReactionByUnicode(thumbsDown);
|
||||||
|
for (IUser user : reaction.getUsers()){
|
||||||
|
if (usersHere.contains(user)){
|
||||||
|
userDownvotes++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (userDownvotes > (userCount/2)){
|
||||||
|
log.log(BotLog.TYPE.MUSIC, context.getGuild(), "Users voted to skip the current song.");
|
||||||
|
HandieBot.musicPlayer.skipTrack(context.getGuild());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
package handiebot.command;
|
|
||||||
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.awt.event.MouseListener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Author: Zino Holwerda
|
|
||||||
* Date: 7/13/2017.
|
|
||||||
*/
|
|
||||||
public class SelectionController implements MouseListener {
|
|
||||||
|
|
||||||
|
|
||||||
public SelectionController() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseClicked(MouseEvent e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mousePressed(MouseEvent e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseReleased(MouseEvent e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseEntered(MouseEvent e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseExited(MouseEvent e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
package handiebot.command.commands.admin;
|
|
||||||
|
|
||||||
import handiebot.command.CommandContext;
|
|
||||||
import handiebot.command.types.CommandLineCommand;
|
|
||||||
import handiebot.command.types.ContextCommand;
|
|
||||||
import handiebot.utils.MessageUtils;
|
|
||||||
import sx.blah.discord.handle.obj.IGuild;
|
|
||||||
|
|
||||||
import static handiebot.HandieBot.*;
|
|
||||||
import static handiebot.utils.MessageUtils.sendMessage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrew Lalis
|
|
||||||
* Command to broadcast a message to all guilds the bot is connected to.
|
|
||||||
*/
|
|
||||||
public class BroadcastCommand extends ContextCommand implements CommandLineCommand {
|
|
||||||
|
|
||||||
public BroadcastCommand() {
|
|
||||||
super("broadcast",
|
|
||||||
"<message>",
|
|
||||||
resourceBundle.getString("commands.command.broadcast.description"),
|
|
||||||
8);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(CommandContext context) {
|
|
||||||
String message = MessageUtils.getTextFromArgs(context.getArgs(), 0);
|
|
||||||
for (IGuild guild : client.getGuilds()){
|
|
||||||
sendMessage(message, musicPlayer.getChatChannel(guild));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
package handiebot.command.commands.admin;
|
package handiebot.command.commands.admin;
|
||||||
|
|
||||||
import handiebot.HandieBot;
|
import handiebot.HandieBot;
|
||||||
import handiebot.command.types.CommandLineCommand;
|
|
||||||
import handiebot.command.types.StaticCommand;
|
import handiebot.command.types.StaticCommand;
|
||||||
|
|
||||||
import static handiebot.HandieBot.resourceBundle;
|
import static handiebot.HandieBot.resourceBundle;
|
||||||
|
@ -10,7 +9,7 @@ import static handiebot.HandieBot.resourceBundle;
|
||||||
* @author Andrew Lalis
|
* @author Andrew Lalis
|
||||||
* Command to quit the entire bot. This shuts down every guild's support, and the GUI.
|
* Command to quit the entire bot. This shuts down every guild's support, and the GUI.
|
||||||
*/
|
*/
|
||||||
public class QuitCommand extends StaticCommand implements CommandLineCommand {
|
public class QuitCommand extends StaticCommand {
|
||||||
|
|
||||||
public QuitCommand() {
|
public QuitCommand() {
|
||||||
super("quit",
|
super("quit",
|
||||||
|
|
|
@ -9,7 +9,6 @@ import java.text.MessageFormat;
|
||||||
|
|
||||||
import static handiebot.HandieBot.log;
|
import static handiebot.HandieBot.log;
|
||||||
import static handiebot.HandieBot.resourceBundle;
|
import static handiebot.HandieBot.resourceBundle;
|
||||||
import static handiebot.utils.MessageUtils.sendMessage;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andrew Lalis
|
* @author Andrew Lalis
|
||||||
|
@ -30,10 +29,10 @@ public class SetPrefixCommand extends ContextCommand {
|
||||||
CommandHandler.PREFIXES.put(context.getGuild(), context.getArgs()[0]);
|
CommandHandler.PREFIXES.put(context.getGuild(), context.getArgs()[0]);
|
||||||
CommandHandler.saveGuildPrefixes();
|
CommandHandler.saveGuildPrefixes();
|
||||||
String response = MessageFormat.format(resourceBundle.getString("commands.command.setPrefix.changed"), context.getArgs()[0]);
|
String response = MessageFormat.format(resourceBundle.getString("commands.command.setPrefix.changed"), context.getArgs()[0]);
|
||||||
sendMessage(response, context.getChannel());
|
context.getChannel().sendMessage(response);
|
||||||
log.log(BotLog.TYPE.INFO, response);
|
log.log(BotLog.TYPE.INFO, response);
|
||||||
} else {
|
} else {
|
||||||
sendMessage(resourceBundle.getString("commands.command.setPrefix.noPrefixError"), context.getChannel());
|
context.getChannel().sendMessage(resourceBundle.getString("commands.command.setPrefix.noPrefixError"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
package handiebot.command.commands.interfaceActions;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
|
|
||||||
import static handiebot.HandieBot.resourceBundle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Author: Zino Holwerda
|
|
||||||
* Date: 7/14/2017.
|
|
||||||
*/
|
|
||||||
public class PlaylistAction extends AbstractAction {
|
|
||||||
|
|
||||||
private static final String DEFAULT_SOURCE_CHOICE_LABEL = "Available Playlists";
|
|
||||||
|
|
||||||
public PlaylistAction() {
|
|
||||||
super(resourceBundle.getString("action.menu.playlist"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
JFrame editPlaylist = new JFrame(resourceBundle.getString("action.menu.playlist"));
|
|
||||||
editPlaylist.setLayout(new BorderLayout(5,5));
|
|
||||||
|
|
||||||
JPanel topSide = new JPanel(new FlowLayout());
|
|
||||||
|
|
||||||
JPanel leftSide = new JPanel(new BorderLayout(5,5));
|
|
||||||
JLabel sourceLabel = new JLabel(DEFAULT_SOURCE_CHOICE_LABEL);
|
|
||||||
JList<String> playlistList = new JList<>();
|
|
||||||
leftSide.add(sourceLabel, BorderLayout.NORTH);
|
|
||||||
JScrollPane scrollPane = new JScrollPane(playlistList);
|
|
||||||
scrollPane.setPreferredSize(new Dimension(200, 200));
|
|
||||||
leftSide.add(scrollPane, BorderLayout.SOUTH);
|
|
||||||
topSide.add(leftSide);
|
|
||||||
|
|
||||||
JPanel rightSide = new JPanel(new BorderLayout(5,5));
|
|
||||||
JButton addButton = new JButton(resourceBundle.getString("action.menu.playlist.add"));
|
|
||||||
rightSide.add(addButton, BorderLayout.NORTH);
|
|
||||||
addButton.addActionListener(null);
|
|
||||||
JButton deleteButton = new JButton(resourceBundle.getString("action.menu.playlist.delete"));
|
|
||||||
rightSide.add(deleteButton, BorderLayout.AFTER_LINE_ENDS);
|
|
||||||
deleteButton.addActionListener(null);
|
|
||||||
JButton editButton = new JButton(resourceBundle.getString("action.menu.playlist.edit"));
|
|
||||||
rightSide.add(editButton, BorderLayout.AFTER_LAST_LINE);
|
|
||||||
editButton.addActionListener(null);
|
|
||||||
topSide.add(rightSide);
|
|
||||||
editPlaylist.add(topSide, BorderLayout.PAGE_START);
|
|
||||||
|
|
||||||
JPanel bottomSide = new JPanel();
|
|
||||||
bottomSide.add(new JScrollPane(playlistList));
|
|
||||||
editPlaylist.add(bottomSide, BorderLayout.PAGE_END);
|
|
||||||
|
|
||||||
editPlaylist.pack();
|
|
||||||
editPlaylist.setLocationRelativeTo(null);
|
|
||||||
editPlaylist.setVisible(true);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
package handiebot.command.commands.interfaceActions.PlaylistActions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Author: Zino
|
|
||||||
* Date: 7/14/2017.
|
|
||||||
*/
|
|
||||||
public class DeletePlaylistAction {
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
package handiebot.command.commands.interfaceActions.PlaylistActions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Author: Zino
|
|
||||||
* Date: 7/14/2017.
|
|
||||||
*/
|
|
||||||
public class EditPlaylistAction {
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
package handiebot.command.commands.interfaceActions.PlaylistActions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Author: Zino
|
|
||||||
* Date: 7/14/2017.
|
|
||||||
*/
|
|
||||||
public class NewPlaylistAction {
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
package handiebot.command.commands.misc;
|
|
||||||
|
|
||||||
import handiebot.command.CommandContext;
|
|
||||||
import handiebot.command.types.ContextCommand;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrew Lalis
|
|
||||||
* Command to fetch rocket league stats and display them in a nice way.
|
|
||||||
*/
|
|
||||||
public class RLCommand extends ContextCommand {
|
|
||||||
//TODO Finish this command, and register it with the list of commands.
|
|
||||||
public RLCommand() {
|
|
||||||
super("rl",
|
|
||||||
"<stats|rank> <steamID> [PLAYLIST]",
|
|
||||||
"Get Rocket League stats or specific competitive playlists.",
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(CommandContext context) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,15 +2,12 @@ package handiebot.command.commands.misc;
|
||||||
|
|
||||||
import handiebot.command.CommandContext;
|
import handiebot.command.CommandContext;
|
||||||
import handiebot.command.types.ContextCommand;
|
import handiebot.command.types.ContextCommand;
|
||||||
import handiebot.utils.MessageUtils;
|
|
||||||
import net.agspace.TengwarImageGenerator;
|
import net.agspace.TengwarImageGenerator;
|
||||||
import net.agspace.Translator;
|
import net.agspace.Translator;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.io.FileNotFoundException;
|
||||||
|
|
||||||
import static handiebot.HandieBot.resourceBundle;
|
import static handiebot.HandieBot.resourceBundle;
|
||||||
import static handiebot.utils.MessageUtils.sendFile;
|
|
||||||
import static handiebot.utils.MessageUtils.sendMessage;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andrew Lalis
|
* @author Andrew Lalis
|
||||||
|
@ -27,27 +24,34 @@ public class TengwarCommand extends ContextCommand {
|
||||||
@Override
|
@Override
|
||||||
public void execute(CommandContext context) {
|
public void execute(CommandContext context) {
|
||||||
if (context.getArgs().length == 0){
|
if (context.getArgs().length == 0){
|
||||||
sendMessage(this.getUsage(context.getGuild()), context.getChannel());
|
context.getChannel().sendMessage(this.getUsage(context.getGuild()));
|
||||||
} else if (context.getArgs().length >= 2){
|
} else if (context.getArgs().length >= 2){
|
||||||
String input = MessageUtils.getTextFromArgs(context.getArgs(), 1);
|
String input = readTextFromArgs(context.getArgs());
|
||||||
if (context.getArgs()[0].equalsIgnoreCase("to")){
|
if (context.getArgs()[0].equalsIgnoreCase("to")){
|
||||||
String result = Translator.translateToTengwar(input);
|
String result = Translator.translateToTengwar(input);
|
||||||
sendFile(TengwarImageGenerator.generateImage(result,
|
try {
|
||||||
600,
|
context.getChannel().sendFile("Raw text: `" +result+'`', TengwarImageGenerator.generateImage(result,
|
||||||
24f,
|
600,
|
||||||
false,
|
24f,
|
||||||
false,
|
false,
|
||||||
System.getProperty("user.home")+"/.handiebot/tengwarTemp.png",
|
false,
|
||||||
Color.white,
|
System.getProperty("user.home")+"/.handiebot/tengwarTemp.png"));
|
||||||
Color.black),
|
} catch (FileNotFoundException e) {
|
||||||
"Raw text: `" +result+'`',
|
e.printStackTrace();
|
||||||
context.getChannel());
|
}
|
||||||
} else if (context.getArgs()[0].equalsIgnoreCase("from")){
|
} else if (context.getArgs()[0].equalsIgnoreCase("from")){
|
||||||
sendMessage(Translator.translateToEnglish(input), context.getChannel());
|
context.getChannel().sendMessage(Translator.translateToEnglish(input));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sendMessage(this.getUsage(context.getGuild()), context.getChannel());
|
context.getChannel().sendMessage(this.getUsage(context.getGuild()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String readTextFromArgs(String[] args){
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 1; i < args.length; i++){
|
||||||
|
sb.append(args[i]).append(' ');
|
||||||
|
}
|
||||||
|
return sb.toString().trim();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +1,13 @@
|
||||||
package handiebot.command.commands.music;
|
package handiebot.command.commands.music;
|
||||||
|
|
||||||
import com.google.api.services.youtube.model.Video;
|
|
||||||
import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler;
|
|
||||||
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
|
|
||||||
import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist;
|
|
||||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
|
||||||
import handiebot.HandieBot;
|
import handiebot.HandieBot;
|
||||||
import handiebot.command.CommandContext;
|
import handiebot.command.CommandContext;
|
||||||
import handiebot.command.Commands;
|
|
||||||
import handiebot.command.ReactionHandler;
|
|
||||||
import handiebot.command.reactionListeners.YoutubePlayListener;
|
|
||||||
import handiebot.command.types.ContextCommand;
|
import handiebot.command.types.ContextCommand;
|
||||||
import handiebot.lavaplayer.playlist.UnloadedTrack;
|
import handiebot.lavaplayer.playlist.UnloadedTrack;
|
||||||
import handiebot.utils.MessageUtils;
|
|
||||||
import handiebot.utils.YoutubeSearch;
|
|
||||||
import handiebot.view.BotLog;
|
|
||||||
import sx.blah.discord.handle.obj.IMessage;
|
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
|
|
||||||
import static handiebot.HandieBot.log;
|
|
||||||
import static handiebot.HandieBot.resourceBundle;
|
import static handiebot.HandieBot.resourceBundle;
|
||||||
import static handiebot.utils.MessageUtils.sendMessage;
|
|
||||||
import static handiebot.utils.YoutubeSearch.WATCH_URL;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andrew Lalis
|
* @author Andrew Lalis
|
||||||
|
@ -35,7 +17,7 @@ public class PlayCommand extends ContextCommand {
|
||||||
|
|
||||||
public PlayCommand() {
|
public PlayCommand() {
|
||||||
super("play",
|
super("play",
|
||||||
"[URL|QUERY]",
|
"[URL]",
|
||||||
resourceBundle.getString("commands.command.play.description"),
|
resourceBundle.getString("commands.command.play.description"),
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
@ -45,64 +27,11 @@ public class PlayCommand extends ContextCommand {
|
||||||
if (context.getArgs() == null || context.getArgs().length == 0){
|
if (context.getArgs() == null || context.getArgs().length == 0){
|
||||||
HandieBot.musicPlayer.playQueue(context.getGuild());
|
HandieBot.musicPlayer.playQueue(context.getGuild());
|
||||||
} else {
|
} else {
|
||||||
//Check if an actual URL is used, and if not, create a youtube request.
|
try {
|
||||||
if (context.getArgs()[0].startsWith("http")) {
|
HandieBot.musicPlayer.addToQueue(context.getGuild(), new UnloadedTrack(context.getArgs()[0]), context.getUser());
|
||||||
if (context.getArgs()[0].contains("list") && Commands.hasPermission(context, 8)){
|
} catch (Exception e) {
|
||||||
try {
|
context.getChannel().sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.play.songAddError"), context.getArgs()[0]));
|
||||||
HandieBot.musicPlayer.getPlayerManager().loadItem(context.getArgs()[0], new AudioLoadResultHandler() {
|
e.printStackTrace();
|
||||||
@Override
|
|
||||||
public void trackLoaded(AudioTrack track) {
|
|
||||||
//This should not happen.
|
|
||||||
HandieBot.log.log(BotLog.TYPE.ERROR, "Loaded song while attempting to load playlist.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void playlistLoaded(AudioPlaylist playlist) {
|
|
||||||
//This is expected to happen.
|
|
||||||
HandieBot.log.log(BotLog.TYPE.MUSIC, "Loading a playlist named: "+playlist.getName()+" with "+playlist.getTracks().size()+" tracks.");
|
|
||||||
MessageUtils.sendMessage("Songs from the playlist **"+playlist.getName()+"** have been added to the queue.", context.getChannel());
|
|
||||||
HandieBot.musicPlayer.getMusicManager(context.getGuild()).scheduler.clearQueue();
|
|
||||||
for (AudioTrack track : playlist.getTracks()){
|
|
||||||
HandieBot.log.log(BotLog.TYPE.MUSIC, "Added song from playlist: "+track.getInfo().title);
|
|
||||||
HandieBot.musicPlayer.getMusicManager(context.getGuild()).scheduler.getActivePlaylist().addTrack(new UnloadedTrack(track));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void noMatches() {
|
|
||||||
//Error that nothing was found.
|
|
||||||
HandieBot.log.log(BotLog.TYPE.ERROR, "No matches while loading playlist.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void loadFailed(FriendlyException exception) {
|
|
||||||
//Error that loading failed.
|
|
||||||
HandieBot.log.log(BotLog.TYPE.ERROR, "Loading failed while loading playlist.");
|
|
||||||
}
|
|
||||||
}).get();
|
|
||||||
HandieBot.musicPlayer.playQueue(context.getGuild());
|
|
||||||
} catch (InterruptedException | ExecutionException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
HandieBot.musicPlayer.addToQueue(context.getGuild(), new UnloadedTrack(context.getArgs()[0]), context.getUser());
|
|
||||||
} catch (Exception e) {
|
|
||||||
sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.play.songAddError"), context.getArgs()[0]), context.getChannel());
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//Construct a Youtube song choice.
|
|
||||||
List<Video> videos = YoutubeSearch.query(MessageUtils.getTextFromArgs(context.getArgs(), 0));
|
|
||||||
if (videos != null) {
|
|
||||||
List<String> urls = new ArrayList<>(videos.size());
|
|
||||||
videos.forEach((video) -> urls.add(WATCH_URL+video.getId()));
|
|
||||||
IMessage message = YoutubeSearch.displayChoicesDialog(videos, context.getChannel());
|
|
||||||
ReactionHandler.addListener(new YoutubePlayListener(message, context.getUser(), urls));
|
|
||||||
} else {
|
|
||||||
log.log(BotLog.TYPE.ERROR, "YouTube query returned a null list of videos.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
package handiebot.command.commands.music;
|
|
||||||
|
|
||||||
import com.google.api.services.youtube.model.Video;
|
|
||||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
|
|
||||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
|
||||||
import handiebot.HandieBot;
|
|
||||||
import handiebot.command.CommandContext;
|
|
||||||
import handiebot.command.ReactionHandler;
|
|
||||||
import handiebot.command.reactionListeners.YoutubeChoiceListener;
|
|
||||||
import handiebot.command.types.ContextCommand;
|
|
||||||
import handiebot.lavaplayer.TrackScheduler;
|
|
||||||
import handiebot.lavaplayer.playlist.UnloadedTrack;
|
|
||||||
import handiebot.utils.MessageUtils;
|
|
||||||
import handiebot.utils.YoutubeSearch;
|
|
||||||
import sx.blah.discord.handle.obj.IMessage;
|
|
||||||
import sx.blah.discord.handle.obj.IVoiceChannel;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static handiebot.HandieBot.resourceBundle;
|
|
||||||
import static handiebot.utils.MessageUtils.sendMessage;
|
|
||||||
import static handiebot.utils.YoutubeSearch.WATCH_URL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrew Lalis
|
|
||||||
* Command to make a song play immediately.
|
|
||||||
*/
|
|
||||||
public class PlayNowCommand extends ContextCommand {
|
|
||||||
//TODO: Externalize strings.
|
|
||||||
public PlayNowCommand() {
|
|
||||||
super("playnow",
|
|
||||||
"<URL,QUERY>",
|
|
||||||
resourceBundle.getString("commands.command.playnow.description"),
|
|
||||||
8);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(CommandContext context) {
|
|
||||||
if (context.getArgs().length < 1){
|
|
||||||
sendMessage("You must provide a URL or series of words to search.", context.getChannel());
|
|
||||||
}
|
|
||||||
if (context.getArgs()[0].startsWith("http")) {
|
|
||||||
//The user has given only a URL.
|
|
||||||
try {
|
|
||||||
playTrackNow(new UnloadedTrack(context.getArgs()[0]), context);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
sendMessage("Unable to load the song.", context.getChannel());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//The user has given a search query.
|
|
||||||
List<Video> videos = YoutubeSearch.query(MessageUtils.getTextFromArgs(context.getArgs(), 0));
|
|
||||||
if (videos != null) {
|
|
||||||
List<String> urls = new ArrayList<>(videos.size());
|
|
||||||
videos.forEach((video) -> urls.add(WATCH_URL+video.getId()));
|
|
||||||
IMessage message = YoutubeSearch.displayChoicesDialog(videos, context.getChannel());
|
|
||||||
ReactionHandler.addListener(new YoutubeChoiceListener(message, context.getUser(), urls) {
|
|
||||||
@Override
|
|
||||||
protected void onChoice(int choice) {
|
|
||||||
try {
|
|
||||||
playTrackNow(new UnloadedTrack(urls.get(choice)), context);
|
|
||||||
} catch (Exception e){
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Plays an unloaded track immediately.
|
|
||||||
* @param track The unloaded track.
|
|
||||||
* @param context The context of the action.
|
|
||||||
*/
|
|
||||||
private void playTrackNow(UnloadedTrack track, CommandContext context){
|
|
||||||
TrackScheduler scheduler = HandieBot.musicPlayer.getMusicManager(context.getGuild()).scheduler;
|
|
||||||
AudioPlayer player = HandieBot.musicPlayer.getMusicManager(context.getGuild()).player;
|
|
||||||
AudioTrack currentTrack = player.getPlayingTrack();
|
|
||||||
if (currentTrack != null){
|
|
||||||
player.stopTrack();
|
|
||||||
if (scheduler.isRepeating()){
|
|
||||||
scheduler.getActivePlaylist().addTrack(new UnloadedTrack(currentTrack));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AudioTrack aTrack = track.loadAudioTrack();
|
|
||||||
IVoiceChannel voiceChannel = HandieBot.musicPlayer.getVoiceChannel(context.getGuild());
|
|
||||||
if (!voiceChannel.isConnected()){
|
|
||||||
voiceChannel.join();
|
|
||||||
}
|
|
||||||
player.startTrack(aTrack, false);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +1,22 @@
|
||||||
package handiebot.command.commands.music;
|
package handiebot.command.commands.music;
|
||||||
|
|
||||||
import com.google.api.services.youtube.model.Video;
|
|
||||||
import handiebot.HandieBot;
|
import handiebot.HandieBot;
|
||||||
import handiebot.command.CommandContext;
|
import handiebot.command.CommandContext;
|
||||||
import handiebot.command.CommandHandler;
|
import handiebot.command.CommandHandler;
|
||||||
import handiebot.command.ReactionHandler;
|
|
||||||
import handiebot.command.reactionListeners.YoutubePlaylistAddListener;
|
|
||||||
import handiebot.command.types.ContextCommand;
|
import handiebot.command.types.ContextCommand;
|
||||||
import handiebot.lavaplayer.playlist.Playlist;
|
import handiebot.lavaplayer.playlist.Playlist;
|
||||||
import handiebot.lavaplayer.playlist.UnloadedTrack;
|
import handiebot.lavaplayer.playlist.UnloadedTrack;
|
||||||
import handiebot.utils.MessageUtils;
|
import handiebot.utils.DisappearingMessage;
|
||||||
import handiebot.utils.YoutubeSearch;
|
|
||||||
import handiebot.view.BotLog;
|
import handiebot.view.BotLog;
|
||||||
import sx.blah.discord.handle.obj.IChannel;
|
import sx.blah.discord.handle.obj.IChannel;
|
||||||
import sx.blah.discord.handle.obj.IMessage;
|
import sx.blah.discord.util.RequestBuffer;
|
||||||
import sx.blah.discord.util.EmbedBuilder;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static handiebot.HandieBot.*;
|
import static handiebot.HandieBot.log;
|
||||||
import static handiebot.utils.MessageUtils.sendMessage;
|
import static handiebot.HandieBot.resourceBundle;
|
||||||
import static handiebot.utils.YoutubeSearch.WATCH_URL;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andrew Lalis
|
* @author Andrew Lalis
|
||||||
|
@ -39,7 +31,7 @@ public class PlaylistCommand extends ContextCommand {
|
||||||
"\t`create <PLAYLIST>` - "+resourceBundle.getString("commands.command.playlist.description.create")+"\n" +
|
"\t`create <PLAYLIST>` - "+resourceBundle.getString("commands.command.playlist.description.create")+"\n" +
|
||||||
"\t`delete <PLAYLIST>` - "+resourceBundle.getString("commands.command.playlist.description.delete")+"\n" +
|
"\t`delete <PLAYLIST>` - "+resourceBundle.getString("commands.command.playlist.description.delete")+"\n" +
|
||||||
"\t`show [PLAYLIST]` - "+resourceBundle.getString("commands.command.playlist.description.show")+"\n" +
|
"\t`show [PLAYLIST]` - "+resourceBundle.getString("commands.command.playlist.description.show")+"\n" +
|
||||||
"\t`add <PLAYLIST> <URL URL...|SEARCHTEXT, SEARCHTEXT...>` - "+resourceBundle.getString("commands.command.playlist.description.add")+"\n" +
|
"\t`add <PLAYLIST> <URL> [URL]...` - "+resourceBundle.getString("commands.command.playlist.description.add")+"\n" +
|
||||||
"\t`remove <PLAYLIST> <SONGINDEX>` - "+resourceBundle.getString("commands.command.playlist.description.remove")+"\n" +
|
"\t`remove <PLAYLIST> <SONGINDEX>` - "+resourceBundle.getString("commands.command.playlist.description.remove")+"\n" +
|
||||||
"\t`rename <PLAYLIST> <NEWNAME>` - "+resourceBundle.getString("commands.command.playlist.description.rename")+"\n" +
|
"\t`rename <PLAYLIST> <NEWNAME>` - "+resourceBundle.getString("commands.command.playlist.description.rename")+"\n" +
|
||||||
"\t`move <PLAYLIST> <OLDINDEX> <NEWINDEX>` - "+resourceBundle.getString("commands.command.playlist.description.move")+"\n" +
|
"\t`move <PLAYLIST> <OLDINDEX> <NEWINDEX>` - "+resourceBundle.getString("commands.command.playlist.description.move")+"\n" +
|
||||||
|
@ -90,8 +82,7 @@ public class PlaylistCommand extends ContextCommand {
|
||||||
* @param channel The channel to show the error message in.
|
* @param channel The channel to show the error message in.
|
||||||
*/
|
*/
|
||||||
private void incorrectMainArg(IChannel channel){
|
private void incorrectMainArg(IChannel channel){
|
||||||
IMessage message = sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.error.incorrectMainArg"), this.getUsage(channel.getGuild())), channel);
|
new DisappearingMessage(channel, MessageFormat.format(resourceBundle.getString("commands.command.playlist.error.incorrectMainArg"), this.getUsage(channel.getGuild())), 5000);
|
||||||
MessageUtils.deleteMessageAfter(5000, message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -102,18 +93,15 @@ public class PlaylistCommand extends ContextCommand {
|
||||||
if (context.getArgs().length >= 2) {
|
if (context.getArgs().length >= 2) {
|
||||||
Playlist playlist = new Playlist(context.getArgs()[1]);
|
Playlist playlist = new Playlist(context.getArgs()[1]);
|
||||||
playlist.save();
|
playlist.save();
|
||||||
if (context.getArgs().length > 2) {
|
for (int i = 2; i < context.getArgs().length; i++){
|
||||||
for (int i = 2; i < context.getArgs().length; i++) {
|
String url = context.getArgs()[i];
|
||||||
String url = context.getArgs()[i];
|
playlist.loadTrack(url);
|
||||||
playlist.loadTrack(url);
|
|
||||||
}
|
|
||||||
playlist.save();
|
|
||||||
}
|
}
|
||||||
|
playlist.save();
|
||||||
log.log(BotLog.TYPE.INFO, MessageFormat.format(resourceBundle.getString("commands.command.playlist.createdPlaylist.log"), playlist.getName(), playlist.getTrackCount()));
|
log.log(BotLog.TYPE.INFO, MessageFormat.format(resourceBundle.getString("commands.command.playlist.createdPlaylist.log"), playlist.getName(), playlist.getTrackCount()));
|
||||||
sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.createdPlaylist.message"), playlist.getName(), this.getPrefixedName(context.getGuild()), playlist.getName()), context.getChannel());
|
context.getChannel().sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.createdPlaylist.message"), playlist.getName(), this.getPrefixedName(context.getGuild()), playlist.getName()));
|
||||||
window.updatePlaylistNames();//Refresh the list of names in the GUI.
|
|
||||||
} else {
|
} else {
|
||||||
sendMessage(resourceBundle.getString("commands.command.playlist.error.createPlaylistName"), context.getChannel());
|
context.getChannel().sendMessage(resourceBundle.getString("commands.command.playlist.error.createPlaylistName"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,14 +117,13 @@ public class PlaylistCommand extends ContextCommand {
|
||||||
boolean success = f.delete();
|
boolean success = f.delete();
|
||||||
if (success){
|
if (success){
|
||||||
log.log(BotLog.TYPE.INFO, MessageFormat.format(resourceBundle.getString("commands.command.playlist.delete.log"), context.getArgs()[1]));
|
log.log(BotLog.TYPE.INFO, MessageFormat.format(resourceBundle.getString("commands.command.playlist.delete.log"), context.getArgs()[1]));
|
||||||
sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.delete.message"), context.getArgs()[1]), context.getChannel());
|
context.getChannel().sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.delete.message"), context.getArgs()[1]));
|
||||||
window.updatePlaylistNames();//Refresh the list of names in the GUI.
|
|
||||||
} else {
|
} else {
|
||||||
log.log(BotLog.TYPE.ERROR, MessageFormat.format(resourceBundle.getString("commands.command.playlist.error.delete.log"), context.getArgs()[1]));
|
log.log(BotLog.TYPE.ERROR, MessageFormat.format(resourceBundle.getString("commands.command.playlist.error.delete.log"), context.getArgs()[1]));
|
||||||
sendMessage(resourceBundle.getString("commands.command.playlist.error.delete.message"), context.getChannel());
|
context.getChannel().sendMessage(resourceBundle.getString("commands.command.playlist.error.delete.message"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sendMessage(resourceBundle.getString("commands.command.playlist.error.deletePlaylistName"), context.getChannel());
|
context.getChannel().sendMessage(resourceBundle.getString("commands.command.playlist.error.deletePlaylistName"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,20 +137,14 @@ public class PlaylistCommand extends ContextCommand {
|
||||||
return;
|
return;
|
||||||
Playlist playlist = new Playlist(context.getArgs()[1]);
|
Playlist playlist = new Playlist(context.getArgs()[1]);
|
||||||
playlist.load();
|
playlist.load();
|
||||||
sendMessage(playlist.getEmbed(), context.getChannel());
|
context.getChannel().sendMessage(playlist.toString());
|
||||||
} else {
|
} else {
|
||||||
List<String> playlists = Playlist.getAvailablePlaylists();
|
List<String> playlists = Playlist.getAvailablePlaylists();
|
||||||
EmbedBuilder eb = new EmbedBuilder();
|
StringBuilder sb = new StringBuilder("**Playlists:**\n");
|
||||||
eb.withTitle("Playlists:");
|
|
||||||
eb.withColor(Color.red);
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (String playlist : playlists) {
|
for (String playlist : playlists) {
|
||||||
Playlist p = new Playlist(playlist);
|
sb.append(playlist).append('\n');
|
||||||
p.load();
|
|
||||||
sb.append(p.getName()).append(", ").append(p.getTrackCount()).append(" tracks.\n");
|
|
||||||
}
|
}
|
||||||
eb.withDescription(sb.toString());
|
context.getChannel().sendMessage(sb.toString());
|
||||||
sendMessage(eb.build(), context.getChannel());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,29 +158,18 @@ public class PlaylistCommand extends ContextCommand {
|
||||||
return;
|
return;
|
||||||
Playlist playlist = new Playlist(context.getArgs()[1]);
|
Playlist playlist = new Playlist(context.getArgs()[1]);
|
||||||
playlist.load();
|
playlist.load();
|
||||||
if (context.getArgs()[2].startsWith("http")){
|
for (int i = 2; i < context.getArgs().length; i++){
|
||||||
//These are songs, so add them immediately.
|
playlist.loadTrack(context.getArgs()[i]);
|
||||||
for (int i = 2; i < context.getArgs().length; i++){
|
RequestBuffer.request(() -> context.getChannel().sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.add.message"), playlist.getName()))).get();
|
||||||
playlist.loadTrack(context.getArgs()[i]);
|
|
||||||
sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.add.message"), playlist.getName()), context.getChannel());
|
|
||||||
}
|
|
||||||
playlist.save();
|
|
||||||
log.log(BotLog.TYPE.INFO, MessageFormat.format(resourceBundle.getString("commands.command.playlist.add.log"), playlist.getName()));
|
|
||||||
} else {
|
|
||||||
//This is a youtube search query.
|
|
||||||
List<Video> videos = YoutubeSearch.query(MessageUtils.getTextFromArgs(context.getArgs(), 2));
|
|
||||||
if (videos != null) {
|
|
||||||
List<String> urls = new ArrayList<>(videos.size());
|
|
||||||
videos.forEach((video) -> urls.add(WATCH_URL+video.getId()));
|
|
||||||
IMessage message = YoutubeSearch.displayChoicesDialog(videos, context.getChannel());
|
|
||||||
ReactionHandler.addListener(new YoutubePlaylistAddListener(message, context.getUser(), urls, playlist));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
playlist.save();
|
||||||
|
context.getChannel().sendMessage(playlist.toString());
|
||||||
|
log.log(BotLog.TYPE.INFO, MessageFormat.format(resourceBundle.getString("commands.command.playlist.add.log"), playlist.getName()));
|
||||||
} else {
|
} else {
|
||||||
if (context.getArgs().length == 1){
|
if (context.getArgs().length == 1){
|
||||||
sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.error.addNameNeeded"), getPlaylistShowString(context)), context.getChannel());
|
context.getChannel().sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.error.addNameNeeded"), getPlaylistShowString(context)));
|
||||||
} else {
|
} else {
|
||||||
sendMessage(resourceBundle.getString("commands.command.playlist.error.addUrlNeeded"), context.getChannel());
|
context.getChannel().sendMessage(resourceBundle.getString("commands.command.playlist.error.addUrlNeeded"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,11 +185,11 @@ public class PlaylistCommand extends ContextCommand {
|
||||||
Playlist playlist = new Playlist(context.getArgs()[1]);
|
Playlist playlist = new Playlist(context.getArgs()[1]);
|
||||||
playlist.load();
|
playlist.load();
|
||||||
log.log(BotLog.TYPE.INFO, MessageFormat.format(resourceBundle.getString("commands.command.playlist.play.log"), playlist.getName()));
|
log.log(BotLog.TYPE.INFO, MessageFormat.format(resourceBundle.getString("commands.command.playlist.play.log"), playlist.getName()));
|
||||||
sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.play.message"), playlist.getName()), context.getChannel());
|
context.getChannel().sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.play.message"), playlist.getName()));
|
||||||
HandieBot.musicPlayer.getMusicManager(context.getGuild()).scheduler.setPlaylist(playlist);
|
HandieBot.musicPlayer.getMusicManager(context.getGuild()).scheduler.setPlaylist(playlist);
|
||||||
HandieBot.musicPlayer.getMusicManager(context.getGuild()).scheduler.nextTrack();
|
HandieBot.musicPlayer.getMusicManager(context.getGuild()).scheduler.nextTrack();
|
||||||
} else {
|
} else {
|
||||||
sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.error.playPlaylistNeeded"), getPlaylistShowString(context)), context.getChannel());
|
context.getChannel().sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.error.playPlaylistNeeded"), getPlaylistShowString(context)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,15 +204,15 @@ public class PlaylistCommand extends ContextCommand {
|
||||||
File f = new File(System.getProperty("user.home")+"/.handiebot/playlist/"+context.getArgs()[1].replace(" ", "_")+".txt");
|
File f = new File(System.getProperty("user.home")+"/.handiebot/playlist/"+context.getArgs()[1].replace(" ", "_")+".txt");
|
||||||
boolean success = f.renameTo(new File(System.getProperty("user.home")+"/.handiebot/playlist/"+context.getArgs()[2].replace(" ", "_")+".txt"));
|
boolean success = f.renameTo(new File(System.getProperty("user.home")+"/.handiebot/playlist/"+context.getArgs()[2].replace(" ", "_")+".txt"));
|
||||||
if (success){
|
if (success){
|
||||||
sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.rename.message"), context.getArgs()[1], context.getArgs()[2]), context.getChannel());
|
context.getChannel().sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.rename.message"), context.getArgs()[1], context.getArgs()[2]));
|
||||||
log.log(BotLog.TYPE.INFO, MessageFormat.format(resourceBundle.getString("commands.command.playlist.rename.log"), context.getArgs()[1], context.getArgs()[2]));
|
log.log(BotLog.TYPE.INFO, MessageFormat.format(resourceBundle.getString("commands.command.playlist.rename.log"), context.getArgs()[1], context.getArgs()[2]));
|
||||||
} else {
|
} else {
|
||||||
String response = MessageFormat.format(resourceBundle.getString("commands.command.playlist.error.renameError"), context.getArgs()[1], context.getArgs()[2]);
|
String response = MessageFormat.format(resourceBundle.getString("commands.command.playlist.error.renameError"), context.getArgs()[1], context.getArgs()[2]);
|
||||||
sendMessage(response, context.getChannel());
|
context.getChannel().sendMessage(response);
|
||||||
log.log(BotLog.TYPE.ERROR, response);
|
log.log(BotLog.TYPE.ERROR, response);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sendMessage(resourceBundle.getString("commands.command.playlist.error.renameBadArgs"), context.getChannel());
|
context.getChannel().sendMessage(resourceBundle.getString("commands.command.playlist.error.renameBadArgs"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,17 +231,17 @@ public class PlaylistCommand extends ContextCommand {
|
||||||
UnloadedTrack track = playlist.getTracks().get(index);
|
UnloadedTrack track = playlist.getTracks().get(index);
|
||||||
playlist.removeTrack(track);
|
playlist.removeTrack(track);
|
||||||
playlist.save();
|
playlist.save();
|
||||||
sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.remove.message"), track.getTitle(), playlist.getName()), context.getChannel());
|
context.getChannel().sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.remove.message"), track.getTitle(), playlist.getName()));
|
||||||
log.log(BotLog.TYPE.MUSIC, MessageFormat.format(resourceBundle.getString("commands.command.playlist.remove.log"), track.getTitle(), playlist.getName()));
|
log.log(BotLog.TYPE.MUSIC, MessageFormat.format(resourceBundle.getString("commands.command.playlist.remove.log"), track.getTitle(), playlist.getName()));
|
||||||
} catch (IndexOutOfBoundsException | NumberFormatException e){
|
} catch (IndexOutOfBoundsException | NumberFormatException e){
|
||||||
String response = MessageFormat.format(resourceBundle.getString("commands.command.playlist.error.removeError"), playlist.getName());
|
String response = MessageFormat.format(resourceBundle.getString("commands.command.playlist.error.removeError"), playlist.getName());
|
||||||
sendMessage(response, context.getChannel());
|
context.getChannel().sendMessage(response);
|
||||||
log.log(BotLog.TYPE.ERROR, response);
|
log.log(BotLog.TYPE.ERROR, response);
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
sendMessage(resourceBundle.getString("commands.command.playlist.error.removeBadArgs"), context.getChannel());
|
context.getChannel().sendMessage(resourceBundle.getString("commands.command.playlist.error.removeBadArgs"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,7 +261,7 @@ public class PlaylistCommand extends ContextCommand {
|
||||||
oldIndex = Integer.parseInt(context.getArgs()[2])-1;
|
oldIndex = Integer.parseInt(context.getArgs()[2])-1;
|
||||||
newIndex = Integer.parseInt(context.getArgs()[3])-1;
|
newIndex = Integer.parseInt(context.getArgs()[3])-1;
|
||||||
} catch (NumberFormatException e){
|
} catch (NumberFormatException e){
|
||||||
sendMessage(resourceBundle.getString("commands.command.playlist.error.moveIndexError"), context.getChannel());
|
context.getChannel().sendMessage(resourceBundle.getString("commands.command.playlist.error.moveIndexError"));
|
||||||
}
|
}
|
||||||
UnloadedTrack track;
|
UnloadedTrack track;
|
||||||
if ((oldIndex > -1 && oldIndex < playlist.getTrackCount()) &&
|
if ((oldIndex > -1 && oldIndex < playlist.getTrackCount()) &&
|
||||||
|
@ -299,13 +269,13 @@ public class PlaylistCommand extends ContextCommand {
|
||||||
track = playlist.getTracks().remove(oldIndex);
|
track = playlist.getTracks().remove(oldIndex);
|
||||||
playlist.getTracks().add(newIndex, track);
|
playlist.getTracks().add(newIndex, track);
|
||||||
playlist.save();
|
playlist.save();
|
||||||
sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.move.message"), track.getTitle(), oldIndex + 1, newIndex + 1), context.getChannel());
|
context.getChannel().sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.move.message"), track.getTitle(), oldIndex + 1, newIndex + 1));
|
||||||
log.log(BotLog.TYPE.MUSIC, MessageFormat.format(resourceBundle.getString("commands.command.playlist.move.log"), track.getTitle(), oldIndex + 1, newIndex + 1));
|
log.log(BotLog.TYPE.MUSIC, MessageFormat.format(resourceBundle.getString("commands.command.playlist.move.log"), track.getTitle(), oldIndex + 1, newIndex + 1));
|
||||||
} else {
|
} else {
|
||||||
sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.error.moveInvalidIndex"), oldIndex, newIndex), context.getChannel());
|
context.getChannel().sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.error.moveInvalidIndex"), oldIndex, newIndex));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sendMessage(resourceBundle.getString("commands.command.playlist.error.moveBadArgs"), context.getChannel());
|
context.getChannel().sendMessage(resourceBundle.getString("commands.command.playlist.error.moveBadArgs"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,8 +289,7 @@ public class PlaylistCommand extends ContextCommand {
|
||||||
if (Playlist.playlistExists(context.getArgs()[1])){
|
if (Playlist.playlistExists(context.getArgs()[1])){
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
IMessage message = sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.error.playlistDoesNotExist"), getPlaylistShowString(context)), context.getChannel());
|
new DisappearingMessage(context.getChannel(), MessageFormat.format(resourceBundle.getString("commands.command.playlist.error.playlistDoesNotExist"), getPlaylistShowString(context)), 3000);
|
||||||
MessageUtils.deleteMessageAfter(3000, message);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,17 +5,12 @@ import handiebot.command.CommandContext;
|
||||||
import handiebot.command.Commands;
|
import handiebot.command.Commands;
|
||||||
import handiebot.command.types.ContextCommand;
|
import handiebot.command.types.ContextCommand;
|
||||||
import handiebot.lavaplayer.playlist.Playlist;
|
import handiebot.lavaplayer.playlist.Playlist;
|
||||||
import handiebot.lavaplayer.playlist.UnloadedTrack;
|
|
||||||
import handiebot.view.BotLog;
|
import handiebot.view.BotLog;
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static handiebot.HandieBot.log;
|
import static handiebot.HandieBot.log;
|
||||||
import static handiebot.HandieBot.resourceBundle;
|
import static handiebot.HandieBot.resourceBundle;
|
||||||
import static handiebot.utils.MessageUtils.sendMessage;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andrew Lalis
|
* @author Andrew Lalis
|
||||||
|
@ -25,19 +20,16 @@ public class QueueCommand extends ContextCommand {
|
||||||
|
|
||||||
public QueueCommand() {
|
public QueueCommand() {
|
||||||
super("queue",
|
super("queue",
|
||||||
"[all|clear|save|remove|move]",
|
"[all|clear|save]",
|
||||||
resourceBundle.getString("commands.command.queue.description.main")+"\n" +
|
resourceBundle.getString("commands.command.queue.description.main")+"\n" +
|
||||||
"\t`all` - "+resourceBundle.getString("commands.command.queue.description.all")+"\n" +
|
"\t`all` - "+resourceBundle.getString("commands.command.queue.description.all")+"\n" +
|
||||||
"\t`clear` - "+resourceBundle.getString("commands.command.queue.description.clear")+"\n" +
|
"\t`clear` - "+resourceBundle.getString("commands.command.queue.description.clear")+"\n" +
|
||||||
"\t`save <PLAYLIST>` - "+resourceBundle.getString("commands.command.queue.description.save")+"\n"+
|
"\t`save <PLAYLIST>` - "+resourceBundle.getString("commands.command.queue.description.save"),
|
||||||
"\t`remove <INDEX| INDEX2...>` - "+resourceBundle.getString("commands.command.queue.description.remove")+"\n"+
|
|
||||||
"\t`move <INDEX> <INDEX> - "+resourceBundle.getString("commands.command.queue.description.move"),
|
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(CommandContext context) {
|
public void execute(CommandContext context) {
|
||||||
//TODO: Ensure that queue embed never runs out of space.
|
|
||||||
if (context.getArgs().length > 0){
|
if (context.getArgs().length > 0){
|
||||||
switch (context.getArgs()[0]){
|
switch (context.getArgs()[0]){
|
||||||
case ("all"):
|
case ("all"):
|
||||||
|
@ -54,45 +46,8 @@ public class QueueCommand extends ContextCommand {
|
||||||
Playlist p = HandieBot.musicPlayer.getAllSongsInQueue(context.getGuild());
|
Playlist p = HandieBot.musicPlayer.getAllSongsInQueue(context.getGuild());
|
||||||
p.setName(context.getArgs()[1]);
|
p.setName(context.getArgs()[1]);
|
||||||
p.save();
|
p.save();
|
||||||
sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.queue.save.message"), p.getTrackCount(), p.getName()), context.getChannel());
|
context.getChannel().sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.queue.save.message"), p.getTrackCount(), p.getName()));
|
||||||
log.log(BotLog.TYPE.INFO, MessageFormat.format(resourceBundle.getString("commands.command.queue.save.log"), p.getName()));
|
log.log(BotLog.TYPE.INFO, MessageFormat.format(resourceBundle.getString("commands.command.queue.save.log"), p.getName()));
|
||||||
} else {
|
|
||||||
sendMessage(resourceBundle.getString("commands.command.queue.error.save"), context.getChannel());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ("remove"):
|
|
||||||
if (context.getArgs().length > 1 && Commands.hasPermission(context, 8)){
|
|
||||||
List<Integer> songsToRemove = new ArrayList<>();
|
|
||||||
for (int i = 1; i < context.getArgs().length; i++){
|
|
||||||
songsToRemove.add(Integer.parseInt(context.getArgs()[i]));
|
|
||||||
}
|
|
||||||
songsToRemove.sort(Collections.reverseOrder());
|
|
||||||
for (Integer i : songsToRemove){
|
|
||||||
HandieBot.musicPlayer.getMusicManager(context.getGuild()).scheduler.remove(i-1);
|
|
||||||
}
|
|
||||||
sendMessage(resourceBundle.getString("commands.command.queue.remove.message"), context.getChannel());
|
|
||||||
log.log(BotLog.TYPE.MUSIC, context.getGuild(), resourceBundle.getString("commands.command.queue.remove.message"));
|
|
||||||
} else {
|
|
||||||
sendMessage(resourceBundle.getString("commands.command.queue.remove.error"), context.getChannel());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ("move"):
|
|
||||||
if (context.getArgs().length == 3 && Commands.hasPermission(context, 8)){
|
|
||||||
int startIndex = Integer.parseInt(context.getArgs()[1]);
|
|
||||||
int newIndex = Integer.parseInt(context.getArgs()[2]);
|
|
||||||
Playlist playlist = HandieBot.musicPlayer.getMusicManager(context.getGuild()).scheduler.getActivePlaylist();
|
|
||||||
int trackCount = playlist.getTrackCount();
|
|
||||||
//Test if the indices are valid, and if not, show an error message.
|
|
||||||
if ((startIndex > 0) && (startIndex <= trackCount) && (newIndex > 0) && (newIndex <= trackCount)){
|
|
||||||
List<UnloadedTrack> tracks = playlist.getTracks();
|
|
||||||
UnloadedTrack track = tracks.remove(startIndex-1);
|
|
||||||
tracks.add(newIndex-1, track);
|
|
||||||
sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.queue.move.success"), track.getTitle(), startIndex, newIndex), context.getChannel());
|
|
||||||
} else {
|
|
||||||
sendMessage(resourceBundle.getString("commands.command.queue.move.indexError"), context.getChannel());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sendMessage(resourceBundle.getString("commands.command.queue.move.error"), context.getChannel());
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,10 @@ import handiebot.HandieBot;
|
||||||
import handiebot.command.CommandContext;
|
import handiebot.command.CommandContext;
|
||||||
import handiebot.command.Commands;
|
import handiebot.command.Commands;
|
||||||
import handiebot.command.types.ContextCommand;
|
import handiebot.command.types.ContextCommand;
|
||||||
import handiebot.utils.FileUtil;
|
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
|
|
||||||
import static handiebot.HandieBot.resourceBundle;
|
import static handiebot.HandieBot.resourceBundle;
|
||||||
import static handiebot.HandieBot.settings;
|
|
||||||
import static handiebot.utils.MessageUtils.sendMessage;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andrew Lalis
|
* @author Andrew Lalis
|
||||||
|
@ -30,10 +27,8 @@ public class RepeatCommand extends ContextCommand {
|
||||||
if (context.getArgs().length == 1 && Commands.hasPermission(context, 8)){
|
if (context.getArgs().length == 1 && Commands.hasPermission(context, 8)){
|
||||||
boolean shouldRepeat = (context.getArgs()[0].toLowerCase().equals("true"));
|
boolean shouldRepeat = (context.getArgs()[0].toLowerCase().equals("true"));
|
||||||
HandieBot.musicPlayer.setRepeat(context.getGuild(), shouldRepeat);
|
HandieBot.musicPlayer.setRepeat(context.getGuild(), shouldRepeat);
|
||||||
HandieBot.settings.setProperty(context.getGuild().getName()+"_repeat", Boolean.toString(shouldRepeat));
|
|
||||||
FileUtil.saveSettings(settings);
|
|
||||||
} else {
|
} else {
|
||||||
sendMessage(MessageFormat.format(resourceBundle.getString("player.getRepeat"), HandieBot.musicPlayer.isRepeating(context.getGuild())), context.getChannel());
|
context.getChannel().sendMessage(MessageFormat.format(resourceBundle.getString("player.getRepeat"), HandieBot.musicPlayer.isRepeating(context.getGuild())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,10 @@ import handiebot.HandieBot;
|
||||||
import handiebot.command.CommandContext;
|
import handiebot.command.CommandContext;
|
||||||
import handiebot.command.Commands;
|
import handiebot.command.Commands;
|
||||||
import handiebot.command.types.ContextCommand;
|
import handiebot.command.types.ContextCommand;
|
||||||
import handiebot.utils.FileUtil;
|
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
|
|
||||||
import static handiebot.HandieBot.resourceBundle;
|
import static handiebot.HandieBot.resourceBundle;
|
||||||
import static handiebot.HandieBot.settings;
|
|
||||||
import static handiebot.utils.MessageUtils.sendMessage;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andrew Lalis
|
* @author Andrew Lalis
|
||||||
|
@ -28,13 +25,10 @@ public class ShuffleCommand extends ContextCommand {
|
||||||
@Override
|
@Override
|
||||||
public void execute(CommandContext context) {
|
public void execute(CommandContext context) {
|
||||||
if (context.getArgs().length == 1 && Commands.hasPermission(context, 8)){
|
if (context.getArgs().length == 1 && Commands.hasPermission(context, 8)){
|
||||||
boolean shouldShuffle = (context.getArgs()[0].equalsIgnoreCase("true"));
|
boolean shouldShuffle = (context.getArgs()[0].toLowerCase().equals("true"));
|
||||||
HandieBot.musicPlayer.setShuffle(context.getGuild(), shouldShuffle);
|
HandieBot.musicPlayer.setShuffle(context.getGuild(), shouldShuffle);
|
||||||
//Save the settings for this guild to the settings file.
|
|
||||||
HandieBot.settings.setProperty(context.getGuild().getName()+"_shuffle", Boolean.toString(shouldShuffle));
|
|
||||||
FileUtil.saveSettings(settings);
|
|
||||||
} else {
|
} else {
|
||||||
sendMessage(MessageFormat.format(resourceBundle.getString("player.getShuffle"), HandieBot.musicPlayer.isShuffling(context.getGuild())), context.getChannel());
|
context.getChannel().sendMessage(MessageFormat.format(resourceBundle.getString("player.getShuffle"), HandieBot.musicPlayer.isShuffling(context.getGuild())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/**
|
/**
|
||||||
* @author Andrew Lalis & Zino Holwerda
|
* @author Andrew Lalis
|
||||||
* Contains all Commands which can be executed from a Discord server or the Console.
|
* Contains all Commands which can be executed from a Discord server or the Console.
|
||||||
*/
|
*/
|
||||||
package handiebot.command.commands;
|
package handiebot.command.commands;
|
|
@ -7,7 +7,6 @@ import handiebot.command.types.ContextCommand;
|
||||||
import sx.blah.discord.handle.obj.IPrivateChannel;
|
import sx.blah.discord.handle.obj.IPrivateChannel;
|
||||||
|
|
||||||
import static handiebot.HandieBot.resourceBundle;
|
import static handiebot.HandieBot.resourceBundle;
|
||||||
import static handiebot.utils.MessageUtils.sendMessage;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andrew Lalis
|
* @author Andrew Lalis
|
||||||
|
@ -25,6 +24,7 @@ public class HelpCommand extends ContextCommand {
|
||||||
@Override
|
@Override
|
||||||
public void execute(CommandContext context) {
|
public void execute(CommandContext context) {
|
||||||
IPrivateChannel pm = context.getUser().getOrCreatePMChannel();
|
IPrivateChannel pm = context.getUser().getOrCreatePMChannel();
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder("HandieBot Commands:\n");
|
StringBuilder sb = new StringBuilder("HandieBot Commands:\n");
|
||||||
for (Command cmd : Commands.commands){
|
for (Command cmd : Commands.commands){
|
||||||
StringBuilder commandText = new StringBuilder();
|
StringBuilder commandText = new StringBuilder();
|
||||||
|
@ -36,12 +36,13 @@ public class HelpCommand extends ContextCommand {
|
||||||
}
|
}
|
||||||
commandText.append("`\n").append(cmd.getDescription()).append("\n\n");
|
commandText.append("`\n").append(cmd.getDescription()).append("\n\n");
|
||||||
if (sb.length() + commandText.length() > 2000){
|
if (sb.length() + commandText.length() > 2000){
|
||||||
sendMessage(sb.toString(), pm);
|
pm.sendMessage(sb.toString());
|
||||||
sb = commandText;
|
sb = commandText;
|
||||||
} else {
|
} else {
|
||||||
sb.append(commandText);
|
sb.append(commandText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sendMessage(sb.toString(), pm);
|
|
||||||
|
pm.sendMessage(sb.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
package handiebot.command.commands.support;
|
|
||||||
|
|
||||||
import handiebot.command.CommandContext;
|
|
||||||
import handiebot.command.types.ContextCommand;
|
|
||||||
import handiebot.utils.MessageUtils;
|
|
||||||
import handiebot.view.BotLog;
|
|
||||||
import sx.blah.discord.api.internal.json.objects.EmbedObject;
|
|
||||||
import sx.blah.discord.handle.obj.IRole;
|
|
||||||
import sx.blah.discord.handle.obj.IUser;
|
|
||||||
import sx.blah.discord.handle.obj.Permissions;
|
|
||||||
import sx.blah.discord.util.EmbedBuilder;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static handiebot.HandieBot.log;
|
|
||||||
import static handiebot.HandieBot.resourceBundle;
|
|
||||||
import static handiebot.utils.MessageUtils.sendMessage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrew Lalis
|
|
||||||
* Command to allow anyone to report a user, and have all administrators be notified of this report, and then
|
|
||||||
* choose a proper punishment.
|
|
||||||
*/
|
|
||||||
public class ReportCommand extends ContextCommand {
|
|
||||||
|
|
||||||
|
|
||||||
public ReportCommand() {
|
|
||||||
super("report",
|
|
||||||
"<USER> [REASON]",
|
|
||||||
resourceBundle.getString("commands.command.report.description"),
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(CommandContext context) {
|
|
||||||
if (context.getArgs().length < 1){
|
|
||||||
sendMessage(resourceBundle.getString("commands.command.report.error"), context.getChannel());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<IRole> roles = context.getGuild().getRoles();
|
|
||||||
List<IRole> adminRoles = new ArrayList<>();
|
|
||||||
for (IRole role : roles){
|
|
||||||
if (role.getPermissions().contains(Permissions.VOICE_MUTE_MEMBERS) && role.getPermissions().contains(Permissions.VOICE_DEAFEN_MEMBERS)){
|
|
||||||
//The role has sufficient reason to be notified.
|
|
||||||
adminRoles.add(role);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EmbedBuilder builder = new EmbedBuilder();
|
|
||||||
builder.withTitle("Report");
|
|
||||||
builder.withColor(Color.red);
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append(context.getUser().mention()).append(" has reported ").append(context.getArgs()[0]).append(".");
|
|
||||||
if (context.getArgs().length > 1){
|
|
||||||
sb.append('\n').append("Reason: ").append(MessageUtils.getTextFromArgs(context.getArgs(), 1));
|
|
||||||
}
|
|
||||||
builder.withDescription(sb.toString());
|
|
||||||
EmbedObject eo = builder.build();
|
|
||||||
for (IUser user : context.getGuild().getUsers()){
|
|
||||||
if (!user.isBot()) {
|
|
||||||
for (IRole role : adminRoles) {
|
|
||||||
if (user.getRolesForGuild(context.getGuild()).contains(role)) {
|
|
||||||
//The user has sufficient reason to be notified.
|
|
||||||
user.getOrCreatePMChannel().sendMessage(eo);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.log(BotLog.TYPE.COMMAND, context.getGuild(), eo.description);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
package handiebot.command.reactionListeners;
|
|
||||||
|
|
||||||
import handiebot.HandieBot;
|
|
||||||
import handiebot.command.ReactionHandler;
|
|
||||||
import handiebot.command.types.ReactionListener;
|
|
||||||
import handiebot.view.BotLog;
|
|
||||||
import sx.blah.discord.handle.impl.events.guild.channel.message.reaction.ReactionEvent;
|
|
||||||
import sx.blah.discord.handle.obj.IMessage;
|
|
||||||
import sx.blah.discord.handle.obj.IReaction;
|
|
||||||
import sx.blah.discord.handle.obj.IUser;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static handiebot.HandieBot.log;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrew Lalis
|
|
||||||
* Listen for downvotes on the most recently played song title.
|
|
||||||
*/
|
|
||||||
public class DownvoteListener implements ReactionListener {
|
|
||||||
|
|
||||||
private static final String thumbsDown = "\uD83D\uDC4E";
|
|
||||||
|
|
||||||
private final IMessage message;
|
|
||||||
|
|
||||||
public DownvoteListener(IMessage message){
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReactionEvent(ReactionEvent event) {
|
|
||||||
if (event.getReaction().toString().equals(thumbsDown)) {
|
|
||||||
IMessage message = event.getMessage();
|
|
||||||
//Filter out reactions to previous messages.
|
|
||||||
if (message.getLongID() != this.message.getLongID()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<IUser> usersHere = HandieBot.musicPlayer.getVoiceChannel(event.getGuild()).getConnectedUsers();
|
|
||||||
//Remove the bot from the list of users in the voice channel.
|
|
||||||
usersHere.removeIf(user -> (user.getLongID() == HandieBot.client.getOurUser().getLongID()) ||
|
|
||||||
(user.getVoiceStateForGuild(event.getGuild()).isDeafened()) ||
|
|
||||||
(user.getVoiceStateForGuild(event.getGuild()).isSelfDeafened()));
|
|
||||||
|
|
||||||
int userCount = usersHere.size();
|
|
||||||
int userDownvotes = 0;
|
|
||||||
IReaction reaction = message.getReactionByUnicode(thumbsDown);
|
|
||||||
for (IUser user : reaction.getUsers()) {
|
|
||||||
if (usersHere.contains(user)) {
|
|
||||||
userDownvotes++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (userDownvotes > (userCount / 2)) {
|
|
||||||
log.log(BotLog.TYPE.MUSIC, event.getGuild(), "Users voted to skip the current song.");
|
|
||||||
HandieBot.musicPlayer.skipTrack(event.getGuild());
|
|
||||||
ReactionHandler.removeListener(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
package handiebot.command.reactionListeners;
|
|
||||||
|
|
||||||
import handiebot.command.ReactionHandler;
|
|
||||||
import handiebot.command.types.ReactionListener;
|
|
||||||
import handiebot.view.BotLog;
|
|
||||||
import sx.blah.discord.handle.impl.events.guild.channel.message.reaction.ReactionEvent;
|
|
||||||
import sx.blah.discord.handle.obj.IMessage;
|
|
||||||
import sx.blah.discord.handle.obj.IUser;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static handiebot.HandieBot.log;
|
|
||||||
import static java.lang.Thread.sleep;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrew Lalis
|
|
||||||
* Interface for youtube search results choices. A new instance of this listener is created every time a youtube
|
|
||||||
* query is shown, and is unique for each user.
|
|
||||||
*/
|
|
||||||
public abstract class YoutubeChoiceListener implements ReactionListener {
|
|
||||||
|
|
||||||
protected final IMessage message;//The message generated that this listener should attach to.
|
|
||||||
protected final IUser user;//The user who needs to make a decision.
|
|
||||||
protected final List<String> urls;//The list of URLs to display information about.
|
|
||||||
protected static final long timeout = 30000;//Time until the choice times out and deletes itself.
|
|
||||||
|
|
||||||
//These are just the raw characters for the numbers 1 - 5.
|
|
||||||
private static final String[] choices = {
|
|
||||||
"1⃣",
|
|
||||||
"2⃣",
|
|
||||||
"3⃣",
|
|
||||||
"4⃣",
|
|
||||||
"5⃣"
|
|
||||||
};
|
|
||||||
|
|
||||||
public YoutubeChoiceListener(IMessage message, IUser user, List<String> urls){
|
|
||||||
this.message = message;
|
|
||||||
this.user = user;
|
|
||||||
this.urls = urls;
|
|
||||||
new Thread(() -> {
|
|
||||||
try {
|
|
||||||
sleep(timeout);
|
|
||||||
} catch (InterruptedException e){
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
if (!message.isDeleted()){
|
|
||||||
log.log(BotLog.TYPE.MUSIC, message.getGuild(), "Youtube Choice timed out.");
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReactionEvent(ReactionEvent event) {
|
|
||||||
if ((event.getMessage().getLongID() == this.message.getLongID()) &&
|
|
||||||
(this.user.getLongID() == event.getUser().getLongID())){
|
|
||||||
for (int i = 0; i < choices.length; i++){
|
|
||||||
if (event.getReaction().getEmoji().getName().equals(choices[i])){
|
|
||||||
onChoice(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to delete the large, unwieldy message and remove the listener for this set of videos.
|
|
||||||
*/
|
|
||||||
private void cleanup(){
|
|
||||||
ReactionHandler.requestMessageDeletion();
|
|
||||||
ReactionHandler.removeListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* What to do when a choice is made.
|
|
||||||
* @param choice An integer value from 0 to 4, describing which choice the player has chosen.
|
|
||||||
*/
|
|
||||||
protected abstract void onChoice(int choice);
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
package handiebot.command.reactionListeners;
|
|
||||||
|
|
||||||
import handiebot.HandieBot;
|
|
||||||
import handiebot.lavaplayer.playlist.UnloadedTrack;
|
|
||||||
import handiebot.view.BotLog;
|
|
||||||
import sx.blah.discord.handle.obj.IMessage;
|
|
||||||
import sx.blah.discord.handle.obj.IUser;
|
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static handiebot.HandieBot.log;
|
|
||||||
import static handiebot.HandieBot.resourceBundle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrew Lalis
|
|
||||||
* Specific Listener for choices in the Play command, where songs chosen are added to the active queue.
|
|
||||||
*/
|
|
||||||
public class YoutubePlayListener extends YoutubeChoiceListener {
|
|
||||||
|
|
||||||
public YoutubePlayListener(IMessage message, IUser user, List<String> urls) {
|
|
||||||
super(message, user, urls);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onChoice(int choice) {
|
|
||||||
try {
|
|
||||||
HandieBot.musicPlayer.addToQueue(message.getGuild(), new UnloadedTrack(urls.get(choice)), this.user);
|
|
||||||
log.log(BotLog.TYPE.MUSIC, message.getGuild(), MessageFormat.format(resourceBundle.getString("commands.youtube.choiceMade.log"), this.user.getName(), choice+1));
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
package handiebot.command.reactionListeners;
|
|
||||||
|
|
||||||
import handiebot.lavaplayer.playlist.Playlist;
|
|
||||||
import sx.blah.discord.handle.obj.IMessage;
|
|
||||||
import sx.blah.discord.handle.obj.IUser;
|
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static handiebot.HandieBot.resourceBundle;
|
|
||||||
import static handiebot.utils.MessageUtils.sendMessage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrew Lalis
|
|
||||||
* Specific Listener for adding songs to a playlist that must be saved.
|
|
||||||
*/
|
|
||||||
public class YoutubePlaylistAddListener extends YoutubeChoiceListener {
|
|
||||||
|
|
||||||
private Playlist playlist;
|
|
||||||
|
|
||||||
public YoutubePlaylistAddListener(IMessage message, IUser user, List<String> urls, Playlist playlist) {
|
|
||||||
super(message, user, urls);
|
|
||||||
this.playlist = playlist;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onChoice(int choice) {
|
|
||||||
this.playlist.loadTrack(this.urls.get(choice));
|
|
||||||
this.playlist.save();
|
|
||||||
sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.add.message"), this.playlist.getName()), message.getChannel());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
/**
|
|
||||||
* @author Andrew Lalis
|
|
||||||
* Package for listeners of reactions, such as in-text menus.
|
|
||||||
*/
|
|
||||||
package handiebot.command.reactionListeners;
|
|
|
@ -1,8 +0,0 @@
|
||||||
package handiebot.command.types;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrew Lalis
|
|
||||||
* If a command implements this Interface, it is marked as safe to use in the command line.
|
|
||||||
*/
|
|
||||||
public interface CommandLineCommand {
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
package handiebot.command.types;
|
|
||||||
|
|
||||||
import sx.blah.discord.handle.impl.events.guild.channel.message.reaction.ReactionEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrew Lalis
|
|
||||||
* Interface for objects that require reaction events.
|
|
||||||
*/
|
|
||||||
public interface ReactionListener {
|
|
||||||
|
|
||||||
void onReactionEvent(ReactionEvent event);
|
|
||||||
|
|
||||||
}
|
|
|
@ -6,10 +6,13 @@ import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers;
|
||||||
import handiebot.command.Commands;
|
import handiebot.command.Commands;
|
||||||
import handiebot.lavaplayer.playlist.Playlist;
|
import handiebot.lavaplayer.playlist.Playlist;
|
||||||
import handiebot.lavaplayer.playlist.UnloadedTrack;
|
import handiebot.lavaplayer.playlist.UnloadedTrack;
|
||||||
import handiebot.utils.MessageUtils;
|
import handiebot.utils.DisappearingMessage;
|
||||||
import handiebot.utils.Pastebin;
|
import handiebot.utils.Pastebin;
|
||||||
import handiebot.view.BotLog;
|
import handiebot.view.BotLog;
|
||||||
import sx.blah.discord.handle.obj.*;
|
import sx.blah.discord.handle.obj.IChannel;
|
||||||
|
import sx.blah.discord.handle.obj.IGuild;
|
||||||
|
import sx.blah.discord.handle.obj.IUser;
|
||||||
|
import sx.blah.discord.handle.obj.IVoiceChannel;
|
||||||
import sx.blah.discord.util.EmbedBuilder;
|
import sx.blah.discord.util.EmbedBuilder;
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
|
@ -20,7 +23,6 @@ import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static handiebot.HandieBot.log;
|
import static handiebot.HandieBot.log;
|
||||||
import static handiebot.HandieBot.resourceBundle;
|
import static handiebot.HandieBot.resourceBundle;
|
||||||
import static handiebot.utils.MessageUtils.sendMessage;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andrew Lalis
|
* @author Andrew Lalis
|
||||||
|
@ -126,7 +128,7 @@ public class MusicPlayer {
|
||||||
getMusicManager(guild).scheduler.setRepeat(value);
|
getMusicManager(guild).scheduler.setRepeat(value);
|
||||||
String message = MessageFormat.format(resourceBundle.getString("player.setRepeat"), getMusicManager(guild).scheduler.isRepeating());
|
String message = MessageFormat.format(resourceBundle.getString("player.setRepeat"), getMusicManager(guild).scheduler.isRepeating());
|
||||||
log.log(BotLog.TYPE.MUSIC, guild, message);
|
log.log(BotLog.TYPE.MUSIC, guild, message);
|
||||||
sendMessage(":repeat: "+message, getChatChannel(guild));
|
getChatChannel(guild).sendMessage(":repeat: "+message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -155,7 +157,7 @@ public class MusicPlayer {
|
||||||
getMusicManager(guild).scheduler.setShuffle(value);
|
getMusicManager(guild).scheduler.setShuffle(value);
|
||||||
String message = MessageFormat.format(resourceBundle.getString("player.setShuffle"), getMusicManager(guild).scheduler.isShuffling());
|
String message = MessageFormat.format(resourceBundle.getString("player.setShuffle"), getMusicManager(guild).scheduler.isShuffling());
|
||||||
log.log(BotLog.TYPE.MUSIC, guild, message);
|
log.log(BotLog.TYPE.MUSIC, guild, message);
|
||||||
sendMessage(":twisted_rightwards_arrows: "+message, getChatChannel(guild));
|
getChatChannel(guild).sendMessage(":twisted_rightwards_arrows: "+message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -174,15 +176,14 @@ public class MusicPlayer {
|
||||||
List<UnloadedTrack> tracks = getMusicManager(guild).scheduler.queueList();
|
List<UnloadedTrack> tracks = getMusicManager(guild).scheduler.queueList();
|
||||||
if (tracks.size() == 0) {
|
if (tracks.size() == 0) {
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
sendMessage(MessageFormat.format(resourceBundle.getString("player.queueEmpty"), Commands.get("play").getUsage()), getChatChannel(guild));
|
getChatChannel(guild).sendMessage(MessageFormat.format(resourceBundle.getString("player.queueEmpty"), Commands.get("play").getUsage()));
|
||||||
} else {
|
} else {
|
||||||
if (tracks.size() > 10 && showAll) {
|
if (tracks.size() > 10 && showAll) {
|
||||||
String result = Pastebin.paste("Current queue for discord server: "+guild.getName()+".", getMusicManager(guild).scheduler.getActivePlaylist().toString());
|
String result = Pastebin.paste("Current queue for discord server: "+guild.getName()+".", getMusicManager(guild).scheduler.getActivePlaylist().toString());
|
||||||
if (result != null && result.startsWith("https://pastebin.com/")){
|
if (result != null && result.startsWith("https://pastebin.com/")){
|
||||||
log.log(BotLog.TYPE.INFO, guild, MessageFormat.format(resourceBundle.getString("player.queueUploaded"), result));
|
log.log(BotLog.TYPE.INFO, guild, MessageFormat.format(resourceBundle.getString("player.queueUploaded"), result));
|
||||||
//Only display the pastebin link for 10 minutes.
|
//Only display the pastebin link for 10 minutes.
|
||||||
IMessage message = sendMessage(MessageFormat.format(resourceBundle.getString("player.pastebinLink"), result), getChatChannel(guild));
|
new DisappearingMessage(getChatChannel(guild), MessageFormat.format(resourceBundle.getString("player.pastebinLink"), result), 600000);
|
||||||
MessageUtils.deleteMessageAfter(600000, message);
|
|
||||||
} else {
|
} else {
|
||||||
log.log(BotLog.TYPE.ERROR, guild, MessageFormat.format(resourceBundle.getString("player.pastebinError"), result));
|
log.log(BotLog.TYPE.ERROR, guild, MessageFormat.format(resourceBundle.getString("player.pastebinError"), result));
|
||||||
}
|
}
|
||||||
|
@ -219,13 +220,16 @@ public class MusicPlayer {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
if (timeUntilPlay > 0) {
|
if (timeUntilPlay > 0) {
|
||||||
sb.append(MessageFormat.format(resourceBundle.getString("player.addedToQueue"), user.getName(), track.getTitle()));
|
sb.append(MessageFormat.format(resourceBundle.getString("player.addedToQueue"), user.getName(), track.getTitle()));
|
||||||
sb.append(String.format("\nTime until play: %d min, %02d sec",
|
}
|
||||||
|
//If there's some tracks in the queue, get the time until this one plays.
|
||||||
|
if (timeUntilPlay > 0){
|
||||||
|
sb.append(String.format("\nTime until play: %d min, %d sec",
|
||||||
TimeUnit.MILLISECONDS.toMinutes(timeUntilPlay),
|
TimeUnit.MILLISECONDS.toMinutes(timeUntilPlay),
|
||||||
TimeUnit.MILLISECONDS.toSeconds(timeUntilPlay) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeUntilPlay))
|
TimeUnit.MILLISECONDS.toSeconds(timeUntilPlay) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeUntilPlay))
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if (sb.length() > 0) {
|
if (sb.length() > 0) {
|
||||||
sendMessage(sb.toString(), getChatChannel(guild));
|
getChatChannel(guild).sendMessage(sb.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,11 +237,10 @@ public class MusicPlayer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If possible, try to begin playing from the track scheduler's queue.
|
* If possible, try to begin playing from the track scheduler's queue.
|
||||||
* @param guild The guild to play music on.
|
|
||||||
*/
|
*/
|
||||||
public void playQueue(IGuild guild){
|
public void playQueue(IGuild guild){
|
||||||
if (getMusicManager(guild).scheduler.getActivePlaylist().getTrackCount() == 0){
|
if (getMusicManager(guild).scheduler.getActivePlaylist().getTrackCount() == 0){
|
||||||
sendMessage(resourceBundle.getString("player.playQueueEmpty"), getChatChannel(guild));
|
getChatChannel(guild).sendMessage(resourceBundle.getString("player.playQueueEmpty"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
IVoiceChannel vc = this.getVoiceChannel(guild);
|
IVoiceChannel vc = this.getVoiceChannel(guild);
|
||||||
|
@ -247,23 +250,18 @@ public class MusicPlayer {
|
||||||
getMusicManager(guild).scheduler.nextTrack();
|
getMusicManager(guild).scheduler.nextTrack();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the queue for a specified guild.
|
|
||||||
* @param guild The guild to clear the queue for.
|
|
||||||
*/
|
|
||||||
public void clearQueue(IGuild guild){
|
public void clearQueue(IGuild guild){
|
||||||
getMusicManager(guild).scheduler.clearQueue();
|
getMusicManager(guild).scheduler.clearQueue();
|
||||||
sendMessage(resourceBundle.getString("player.queueCleared"), getChatChannel(guild));
|
getChatChannel(guild).sendMessage(resourceBundle.getString("player.queueCleared"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Skips the current track.
|
* Skips the current track.
|
||||||
* @param guild The guild to skip the track for.
|
|
||||||
*/
|
*/
|
||||||
public void skipTrack(IGuild guild){
|
public void skipTrack(IGuild guild){
|
||||||
String message = resourceBundle.getString("player.skippingCurrent");
|
String message = resourceBundle.getString("player.skippingCurrent");
|
||||||
log.log(BotLog.TYPE.MUSIC, guild, message);
|
log.log(BotLog.TYPE.MUSIC, guild, message);
|
||||||
sendMessage(":track_next: "+message, getChatChannel(guild));
|
getChatChannel(guild).sendMessage(":track_next: "+message);
|
||||||
getMusicManager(guild).scheduler.nextTrack();
|
getMusicManager(guild).scheduler.nextTrack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,7 +272,7 @@ public class MusicPlayer {
|
||||||
public void stop(IGuild guild){
|
public void stop(IGuild guild){
|
||||||
getMusicManager(guild).scheduler.stop();
|
getMusicManager(guild).scheduler.stop();
|
||||||
String message = resourceBundle.getString("player.musicStopped");
|
String message = resourceBundle.getString("player.musicStopped");
|
||||||
sendMessage(":stop_button: "+message, getChatChannel(guild));
|
getChatChannel(guild).sendMessage(":stop_button: "+message);
|
||||||
log.log(BotLog.TYPE.MUSIC, guild, message);
|
log.log(BotLog.TYPE.MUSIC, guild, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,6 @@ import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
|
||||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
||||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason;
|
import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason;
|
||||||
import handiebot.HandieBot;
|
import handiebot.HandieBot;
|
||||||
import handiebot.command.ReactionHandler;
|
|
||||||
import handiebot.command.reactionListeners.DownvoteListener;
|
|
||||||
import handiebot.lavaplayer.playlist.Playlist;
|
import handiebot.lavaplayer.playlist.Playlist;
|
||||||
import handiebot.lavaplayer.playlist.UnloadedTrack;
|
import handiebot.lavaplayer.playlist.UnloadedTrack;
|
||||||
import handiebot.view.BotLog;
|
import handiebot.view.BotLog;
|
||||||
|
@ -15,14 +13,13 @@ import sx.blah.discord.handle.obj.IChannel;
|
||||||
import sx.blah.discord.handle.obj.IGuild;
|
import sx.blah.discord.handle.obj.IGuild;
|
||||||
import sx.blah.discord.handle.obj.IMessage;
|
import sx.blah.discord.handle.obj.IMessage;
|
||||||
import sx.blah.discord.handle.obj.IVoiceChannel;
|
import sx.blah.discord.handle.obj.IVoiceChannel;
|
||||||
|
import sx.blah.discord.util.RequestBuffer;
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static handiebot.HandieBot.log;
|
import static handiebot.HandieBot.log;
|
||||||
import static handiebot.HandieBot.resourceBundle;
|
import static handiebot.HandieBot.resourceBundle;
|
||||||
import static handiebot.utils.MessageUtils.addReaction;
|
|
||||||
import static handiebot.utils.MessageUtils.sendMessage;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andrew Lalis
|
* @author Andrew Lalis
|
||||||
|
@ -37,9 +34,10 @@ public class TrackScheduler extends AudioEventAdapter {
|
||||||
private final AudioPlayer player;
|
private final AudioPlayer player;
|
||||||
|
|
||||||
private Playlist activePlaylist;
|
private Playlist activePlaylist;
|
||||||
|
private long activePlayMessageId;
|
||||||
|
|
||||||
private boolean repeat;
|
private boolean repeat = true;
|
||||||
private boolean shuffle;
|
private boolean shuffle = false;
|
||||||
|
|
||||||
private IGuild guild;
|
private IGuild guild;
|
||||||
|
|
||||||
|
@ -52,8 +50,7 @@ public class TrackScheduler extends AudioEventAdapter {
|
||||||
this.player = player;
|
this.player = player;
|
||||||
this.guild = guild;
|
this.guild = guild;
|
||||||
this.activePlaylist = new Playlist("HandieBot Active Playlist");
|
this.activePlaylist = new Playlist("HandieBot Active Playlist");
|
||||||
this.repeat = Boolean.parseBoolean(HandieBot.settings.getProperty(guild.getName()+"_repeat"));
|
//this.activePlaylist = new Playlist("HandieBot Active Playlist");
|
||||||
this.shuffle = Boolean.parseBoolean(HandieBot.settings.getProperty(guild.getName()+"_shuffle"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,6 +65,10 @@ public class TrackScheduler extends AudioEventAdapter {
|
||||||
return this.activePlaylist;
|
return this.activePlaylist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getPlayMessageId(){
|
||||||
|
return this.activePlayMessageId;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the queue.
|
* Clears the queue.
|
||||||
*/
|
*/
|
||||||
|
@ -156,16 +157,6 @@ public class TrackScheduler extends AudioEventAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a song at a specified index from the queue.
|
|
||||||
* @param songIndex The index of the song to remove.
|
|
||||||
*/
|
|
||||||
public void remove(int songIndex){
|
|
||||||
if (songIndex >= 0 && songIndex < this.activePlaylist.getTrackCount()){
|
|
||||||
this.activePlaylist.getTracks().remove(songIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the next track, stopping the current one if it's playing.
|
* Starts the next track, stopping the current one if it's playing.
|
||||||
*/
|
*/
|
||||||
|
@ -204,10 +195,10 @@ public class TrackScheduler extends AudioEventAdapter {
|
||||||
log.log(BotLog.TYPE.MUSIC, this.guild, MessageFormat.format(resourceBundle.getString("trackSchedule.trackStarted"), track.getInfo().title));
|
log.log(BotLog.TYPE.MUSIC, this.guild, MessageFormat.format(resourceBundle.getString("trackSchedule.trackStarted"), track.getInfo().title));
|
||||||
List<IChannel> channels = this.guild.getChannelsByName(MusicPlayer.CHANNEL_NAME.toLowerCase());
|
List<IChannel> channels = this.guild.getChannelsByName(MusicPlayer.CHANNEL_NAME.toLowerCase());
|
||||||
if (channels.size() > 0){
|
if (channels.size() > 0){
|
||||||
IMessage message = sendMessage(MessageFormat.format(":arrow_forward: "+resourceBundle.getString("trackSchedule.nowPlaying"), track.getInfo().title, new UnloadedTrack(track).getFormattedDuration()), channels.get(0));
|
IMessage message = channels.get(0).sendMessage(MessageFormat.format(":arrow_forward: "+resourceBundle.getString("trackSchedule.nowPlaying"), track.getInfo().title, new UnloadedTrack(track).getFormattedDuration()));
|
||||||
addReaction(message, ":thumbsup:");
|
this.activePlayMessageId = message.getLongID();
|
||||||
addReaction(message, ":thumbsdown:");
|
RequestBuffer.request(() -> message.addReaction(":thumbsup:")).get();
|
||||||
ReactionHandler.addListener(new DownvoteListener(message));
|
RequestBuffer.request(() -> message.addReaction(":thumbsdown:")).get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,11 @@
|
||||||
package handiebot.lavaplayer.playlist;
|
package handiebot.lavaplayer.playlist;
|
||||||
|
|
||||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
||||||
import handiebot.utils.Pastebin;
|
|
||||||
import handiebot.view.BotLog;
|
import handiebot.view.BotLog;
|
||||||
import sx.blah.discord.api.internal.json.objects.EmbedObject;
|
|
||||||
import sx.blah.discord.util.EmbedBuilder;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -66,20 +61,6 @@ public class Playlist {
|
||||||
this.tracks.remove(track);
|
this.tracks.remove(track);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if the playlist already has a song with the same URL.
|
|
||||||
* @param track The track to check existence of.
|
|
||||||
* @return True if the track exists in the playlist, and false if not.
|
|
||||||
*/
|
|
||||||
public boolean hasTrack(UnloadedTrack track){
|
|
||||||
for (UnloadedTrack t : this.tracks){
|
|
||||||
if (t.getURL().equalsIgnoreCase(track.getURL())){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies all the tracks from another playlist onto this one.
|
* Copies all the tracks from another playlist onto this one.
|
||||||
* @param playlist A playlist.
|
* @param playlist A playlist.
|
||||||
|
@ -122,12 +103,10 @@ public class Playlist {
|
||||||
public void loadTrack(String url){
|
public void loadTrack(String url){
|
||||||
try {
|
try {
|
||||||
UnloadedTrack track = new UnloadedTrack(url);
|
UnloadedTrack track = new UnloadedTrack(url);
|
||||||
if (!this.hasTrack(track)) {
|
this.tracks.add(track);
|
||||||
this.tracks.add(track);
|
log.log(BotLog.TYPE.MUSIC, "Added "+track.getTitle()+" to playlist ["+this.name+"].");
|
||||||
}
|
|
||||||
log.log(BotLog.TYPE.MUSIC, MessageFormat.format(resourceBundle.getString("playlist.loadTrack.log"), track.getTitle(), this.name));
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.log(BotLog.TYPE.ERROR, MessageFormat.format(resourceBundle.getString("playlist.loadTrack.error"), url, this.name));
|
log.log(BotLog.TYPE.ERROR, "Unable to add "+url+" to the playlist ["+this.name+"].");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,13 +115,15 @@ public class Playlist {
|
||||||
* Gets a 'shuffled index' from a given list length. That means:
|
* Gets a 'shuffled index' from a given list length. That means:
|
||||||
* - A random number from 0 to (listLength-1) - threshold*(listLength), where threshold is some percentage of
|
* - A random number from 0 to (listLength-1) - threshold*(listLength), where threshold is some percentage of
|
||||||
* recent songs that should be ignored; for example, the most recent 20% of the playlist can be ignored.
|
* recent songs that should be ignored; for example, the most recent 20% of the playlist can be ignored.
|
||||||
|
* - A greater likelihood for numbers closer to 0 (those which have not been played in a while).
|
||||||
* @param listLength The number of items in a potential list to choose from.
|
* @param listLength The number of items in a potential list to choose from.
|
||||||
* @return A pseudo-random choice as to which item to pick from the list.
|
* @return A pseudo-random choice as to which item to pick from the list.
|
||||||
*/
|
*/
|
||||||
private static int getShuffledIndex(int listLength){
|
public static int getShuffledIndex(int listLength){
|
||||||
float threshold = 0.2f;
|
float threshold = 0.2f;
|
||||||
int trueLength = listLength - (int)(threshold*(float)listLength);
|
int trueLength = listLength - (int)(threshold*(float)listLength);
|
||||||
Random rand = new Random();
|
Random rand = new Random();
|
||||||
|
//TODO Add in a small gradient in chance for a song to be picked.
|
||||||
return rand.nextInt(trueLength);
|
return rand.nextInt(trueLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,11 +135,12 @@ public class Playlist {
|
||||||
File playlistDir = new File(homeDir+"/.handiebot/playlist");
|
File playlistDir = new File(homeDir+"/.handiebot/playlist");
|
||||||
if (!playlistDir.exists()){
|
if (!playlistDir.exists()){
|
||||||
if (!playlistDir.mkdirs()){
|
if (!playlistDir.mkdirs()){
|
||||||
log.log(BotLog.TYPE.ERROR, MessageFormat.format(resourceBundle.getString("playlist.save.error.directory"), playlistDir.getPath()));
|
log.log(BotLog.TYPE.ERROR, "Unable to make directory: "+playlistDir.getPath());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File playlistFile = new File(playlistDir.getPath()+"/"+this.name.replace(" ", "_")+".txt");
|
File playlistFile = new File(playlistDir.getPath()+"/"+this.name.replace(" ", "_")+".txt");
|
||||||
|
log.log(BotLog.TYPE.INFO, "Saving playlist to: "+playlistFile.getAbsolutePath());
|
||||||
try(Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(playlistFile)))){
|
try(Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(playlistFile)))){
|
||||||
writer.write(Integer.toString(this.tracks.size())+'\n');
|
writer.write(Integer.toString(this.tracks.size())+'\n');
|
||||||
for (UnloadedTrack track : this.tracks){
|
for (UnloadedTrack track : this.tracks){
|
||||||
|
@ -166,7 +148,7 @@ public class Playlist {
|
||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
}
|
}
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
log.log(BotLog.TYPE.ERROR, MessageFormat.format(resourceBundle.getString("playlist.save.error.fileNotFound"), this.name));
|
log.log(BotLog.TYPE.ERROR, "Unable to find file to write playlist: "+this.name);
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -178,22 +160,24 @@ public class Playlist {
|
||||||
*/
|
*/
|
||||||
public void load(){
|
public void load(){
|
||||||
String path = System.getProperty("user.home")+"/.handiebot/playlist/"+name.replace(" ", "_")+".txt";
|
String path = System.getProperty("user.home")+"/.handiebot/playlist/"+name.replace(" ", "_")+".txt";
|
||||||
|
log.log(BotLog.TYPE.MUSIC, "Loading playlist from: "+path);
|
||||||
File playlistFile = new File(path);
|
File playlistFile = new File(path);
|
||||||
if (playlistFile.exists()){
|
if (playlistFile.exists()){
|
||||||
try {
|
try {
|
||||||
List<String> lines = Files.readAllLines(Paths.get(playlistFile.toURI()));
|
List<String> lines = Files.readAllLines(Paths.get(playlistFile.toURI()));
|
||||||
int trackCount = Integer.parseInt(lines.remove(0));
|
int trackCount = Integer.parseInt(lines.remove(0));
|
||||||
|
this.name = name;
|
||||||
this.tracks = new ArrayList<>(trackCount);
|
this.tracks = new ArrayList<>(trackCount);
|
||||||
for (int i = 0; i < trackCount; i++){
|
for (int i = 0; i < trackCount; i++){
|
||||||
String[] words = lines.remove(0).split(" / ");
|
String[] words = lines.remove(0).split(" / ");
|
||||||
this.tracks.add(new UnloadedTrack(words[0], words[1], Long.parseLong(words[2])));
|
this.tracks.add(new UnloadedTrack(words[0], words[1], Long.parseLong(words[2])));
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.log(BotLog.TYPE.ERROR, MessageFormat.format(resourceBundle.getString("playlist.load.error.IOException"), this.name, e.getMessage()));
|
log.log(BotLog.TYPE.ERROR, "IOException while loading playlist ["+this.name+"]. "+e.getMessage());
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.log(BotLog.TYPE.ERROR, MessageFormat.format(resourceBundle.getString("playlist.load.error.exists"), this.name));
|
log.log(BotLog.TYPE.ERROR, "The playlist ["+this.name+"] does not exist.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,24 +225,4 @@ public class Playlist {
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public EmbedObject getEmbed(){
|
|
||||||
EmbedBuilder eb = new EmbedBuilder();
|
|
||||||
eb.withTitle(this.getName());
|
|
||||||
eb.withFooterText(this.getTrackCount()+" tracks.");
|
|
||||||
eb.withColor(Color.red);
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
boolean needsPastebin = this.getTrackCount() > 20;
|
|
||||||
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');
|
|
||||||
}
|
|
||||||
if (needsPastebin){
|
|
||||||
String result = Pastebin.paste(this.getName(), sb.toString());
|
|
||||||
eb.withUrl(result);
|
|
||||||
eb.withDescription(resourceBundle.getString("playlist.embedTooLarge"));
|
|
||||||
} else {
|
|
||||||
eb.withDescription(sb.toString());
|
|
||||||
}
|
|
||||||
return eb.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ import static handiebot.HandieBot.log;
|
||||||
* This is useful for quickly loading playlists and only loading a track when it is needed.
|
* This is useful for quickly loading playlists and only loading a track when it is needed.
|
||||||
*/
|
*/
|
||||||
public class UnloadedTrack implements Cloneable {
|
public class UnloadedTrack implements Cloneable {
|
||||||
//TODO: Externalize strings.
|
|
||||||
private String title;
|
private String title;
|
||||||
private String url;
|
private String url;
|
||||||
private long duration;
|
private long duration;
|
||||||
|
@ -92,10 +92,6 @@ public class UnloadedTrack implements Cloneable {
|
||||||
return this.title;
|
return this.title;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTitle(String newTitle){
|
|
||||||
this.title = newTitle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getURL(){
|
public String getURL(){
|
||||||
return this.url;
|
return this.url;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
package handiebot.utils;
|
||||||
|
|
||||||
|
import handiebot.HandieBot;
|
||||||
|
import handiebot.view.BotLog;
|
||||||
|
import sx.blah.discord.handle.obj.IChannel;
|
||||||
|
import sx.blah.discord.handle.obj.IMessage;
|
||||||
|
import sx.blah.discord.handle.obj.Permissions;
|
||||||
|
import sx.blah.discord.util.RequestBuffer;
|
||||||
|
|
||||||
|
import static handiebot.HandieBot.log;
|
||||||
|
import static handiebot.HandieBot.resourceBundle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrew Lalis
|
||||||
|
* Creates a message on a channel that will disappear after some time.
|
||||||
|
*/
|
||||||
|
public class DisappearingMessage extends Thread implements Runnable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new disappearing message that times out after some time.
|
||||||
|
* @param channel The channel to write the message in.
|
||||||
|
* @param message The message content.
|
||||||
|
* @param timeout How long until the message is deleted.
|
||||||
|
*/
|
||||||
|
public DisappearingMessage(IChannel channel, String message, long timeout){
|
||||||
|
IMessage sentMessage = channel.sendMessage(message);
|
||||||
|
try {
|
||||||
|
sleep(timeout);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (canDelete(sentMessage))
|
||||||
|
RequestBuffer.request(sentMessage::delete);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a message after a set amount of time.
|
||||||
|
* @param timeout The delay until deletion, in milliseconds.
|
||||||
|
* @param message The message to delete.
|
||||||
|
*/
|
||||||
|
public static void deleteMessageAfter(long timeout, IMessage message){
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
sleep(timeout);
|
||||||
|
} catch (InterruptedException e){
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (canDelete(message))
|
||||||
|
RequestBuffer.request(message::delete);
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if it is possible to delete a message before doing so.
|
||||||
|
* @param message The message that may be deleted.
|
||||||
|
* @return True if it is safe to delete, false otherwise.
|
||||||
|
*/
|
||||||
|
private static boolean canDelete(IMessage message){
|
||||||
|
if (HandieBot.hasPermission(Permissions.MANAGE_MESSAGES, message.getChannel())){
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
log.log(BotLog.TYPE.ERROR, message.getGuild(), resourceBundle.getString("log.deleteMessageError"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,14 +1,15 @@
|
||||||
package handiebot.utils;
|
package handiebot.utils;
|
||||||
|
|
||||||
import handiebot.HandieBot;
|
|
||||||
import handiebot.view.BotLog;
|
import handiebot.view.BotLog;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
import static handiebot.HandieBot.log;
|
import static handiebot.HandieBot.log;
|
||||||
import static handiebot.HandieBot.resourceBundle;
|
import static handiebot.HandieBot.resourceBundle;
|
||||||
|
@ -19,19 +20,10 @@ import static handiebot.HandieBot.resourceBundle;
|
||||||
*/
|
*/
|
||||||
public class FileUtil {
|
public class FileUtil {
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the directory where handiebot's data is stored.
|
|
||||||
* @return The directory leading to 'user.home'.
|
|
||||||
*/
|
|
||||||
public static String getDataDirectory(){
|
public static String getDataDirectory(){
|
||||||
return System.getProperty("user.home")+"/.handiebot/";
|
return System.getProperty("user.home")+"/.handiebot/";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a file, and returns a list of lines in the file.
|
|
||||||
* @param file The file to read.
|
|
||||||
* @return A list of lines from the file.
|
|
||||||
*/
|
|
||||||
public static List<String> getLinesFromFile(File file){
|
public static List<String> getLinesFromFile(File file){
|
||||||
try {
|
try {
|
||||||
return Files.readAllLines(file.toPath());
|
return Files.readAllLines(file.toPath());
|
||||||
|
@ -41,11 +33,6 @@ public class FileUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a list of strings to a file, separated by newlines.
|
|
||||||
* @param lines The list of lines.
|
|
||||||
* @param file The file to write to.
|
|
||||||
*/
|
|
||||||
public static void writeLinesToFile(List<String> lines, File file){
|
public static void writeLinesToFile(List<String> lines, File file){
|
||||||
if (lines.size() == 0){
|
if (lines.size() == 0){
|
||||||
return;
|
return;
|
||||||
|
@ -73,46 +60,4 @@ public class FileUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves the global set of settings.
|
|
||||||
* @param settings The settings to save.
|
|
||||||
*/
|
|
||||||
public static void saveSettings(Properties settings){
|
|
||||||
try {
|
|
||||||
settings.store(new FileWriter(FileUtil.getDataDirectory()+"settings"), "Settings for HandieBot");
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads a properties file.
|
|
||||||
* @return The settings saved locally for HandieBot.
|
|
||||||
*/
|
|
||||||
public static Properties loadSettings(){
|
|
||||||
Properties settings = new Properties();
|
|
||||||
try {
|
|
||||||
settings.load(HandieBot.class.getClassLoader().getResourceAsStream("default_settings"));
|
|
||||||
settings.load(new FileInputStream(FileUtil.getDataDirectory()+"settings"));
|
|
||||||
} catch (IOException e){
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads the private discord token necessary to start the bot. If this fails, the bot will shut down.
|
|
||||||
* @return The string token needed to log in.
|
|
||||||
*/
|
|
||||||
public static String readToken(){
|
|
||||||
String path = FileUtil.getDataDirectory()+"token.txt";
|
|
||||||
String result = "";
|
|
||||||
try(BufferedReader reader = new BufferedReader(new FileReader(path))){
|
|
||||||
result = reader.readLine();
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.err.println("Unable to find the token file. You are unable to start the bot without this.");
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,170 +0,0 @@
|
||||||
package handiebot.utils;
|
|
||||||
|
|
||||||
import handiebot.HandieBot;
|
|
||||||
import handiebot.view.BotLog;
|
|
||||||
import sx.blah.discord.api.internal.json.objects.EmbedObject;
|
|
||||||
import sx.blah.discord.handle.obj.IChannel;
|
|
||||||
import sx.blah.discord.handle.obj.IMessage;
|
|
||||||
import sx.blah.discord.handle.obj.Permissions;
|
|
||||||
import sx.blah.discord.util.RequestBuffer;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
|
|
||||||
import static handiebot.HandieBot.log;
|
|
||||||
import static handiebot.HandieBot.resourceBundle;
|
|
||||||
import static java.lang.Thread.sleep;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrew Lalis
|
|
||||||
* Creates a message on a channel that will disappear after some time.
|
|
||||||
*/
|
|
||||||
public class MessageUtils {
|
|
||||||
|
|
||||||
private MessageUtils(){}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a message to a channel safely, using a request buffer.
|
|
||||||
* @param content The string content of the message.
|
|
||||||
* @param channel The channel to send the message on.
|
|
||||||
* @return The message object that was sent.
|
|
||||||
*/
|
|
||||||
public static IMessage sendMessage(String content, IChannel channel){
|
|
||||||
return RequestBuffer.request(() -> (IMessage)channel.sendMessage(content)).get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends an embed object to a channel safely, using a request buffer.
|
|
||||||
* @param embed The content of the message.
|
|
||||||
* @param channel The channel to send the message on.
|
|
||||||
* @return The message object that was sent.
|
|
||||||
*/
|
|
||||||
public static IMessage sendMessage(EmbedObject embed, IChannel channel){
|
|
||||||
return RequestBuffer.request(() -> (IMessage)channel.sendMessage(embed)).get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a file object to a channel safely, using a request buffer.
|
|
||||||
* @param file The file to send.
|
|
||||||
* @param channel The channel to send the message on.
|
|
||||||
* @return The message that was sent, or null if the file could not be found.
|
|
||||||
*/
|
|
||||||
public static IMessage sendFile(File file, String content, IChannel channel){
|
|
||||||
return RequestBuffer.request(() -> {
|
|
||||||
IMessage msg = null;
|
|
||||||
try {
|
|
||||||
msg = channel.sendFile(content, file);
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return msg;
|
|
||||||
}).get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a reaction to a message safely, using the request buffer.
|
|
||||||
* @param message The message to add a reaction to.
|
|
||||||
* @param reaction The reaction to add, in string format.
|
|
||||||
*/
|
|
||||||
public static void addReaction(IMessage message, String reaction){
|
|
||||||
RequestBuffer.request(() -> message.addReaction(reaction)).get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes a message after a set amount of time.
|
|
||||||
* @param timeout The delay until deletion, in milliseconds.
|
|
||||||
* @param message The message to delete.
|
|
||||||
*/
|
|
||||||
public static void deleteMessageAfter(long timeout, IMessage message){
|
|
||||||
new Thread(() -> {
|
|
||||||
try {
|
|
||||||
sleep(timeout);
|
|
||||||
} catch (InterruptedException e){
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
if (canDelete(message))
|
|
||||||
RequestBuffer.request(message::delete);
|
|
||||||
}).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check to see if it is possible to delete a message before doing so.
|
|
||||||
* @param message The message that may be deleted.
|
|
||||||
* @return True if it is safe to delete, false otherwise.
|
|
||||||
*/
|
|
||||||
private static boolean canDelete(IMessage message){
|
|
||||||
if (HandieBot.hasPermission(Permissions.MANAGE_MESSAGES, message.getChannel())){
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
log.log(BotLog.TYPE.ERROR, message.getGuild(), resourceBundle.getString("log.deleteMessageError"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a number into one or more emojis.
|
|
||||||
* @param number The number to convert.
|
|
||||||
* @return A string of emojis.
|
|
||||||
*/
|
|
||||||
public static String getNumberEmoji(int number){
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
while (number > 0){
|
|
||||||
int digit = number % 10;
|
|
||||||
number /= 10;
|
|
||||||
sb.append(getDigitEmoji(digit));
|
|
||||||
if (number > 0){
|
|
||||||
sb.append(" ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the 'emoji' for a specific digit. If the digit given is not one digit, zero is used.
|
|
||||||
* @param digit The digit to convert.
|
|
||||||
* @return A String representation of the emoji.
|
|
||||||
*/
|
|
||||||
private static String getDigitEmoji(int digit){
|
|
||||||
switch (digit){
|
|
||||||
case 1:
|
|
||||||
return ":one:";
|
|
||||||
case 2:
|
|
||||||
return ":two:";
|
|
||||||
case 3:
|
|
||||||
return ":three:";
|
|
||||||
case 4:
|
|
||||||
return ":four:";
|
|
||||||
case 5:
|
|
||||||
return ":five:";
|
|
||||||
case 6:
|
|
||||||
return ":six:";
|
|
||||||
case 7:
|
|
||||||
return ":seven:";
|
|
||||||
case 8:
|
|
||||||
return ":eight:";
|
|
||||||
case 9:
|
|
||||||
return ":nine:";
|
|
||||||
default:
|
|
||||||
return ":zero:";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a space-separated list of words from a given index until the end of an arguments list.
|
|
||||||
* @param args The args list, as it is given from a command context.
|
|
||||||
* @param firstWordIndex The index of the first word to read as text.
|
|
||||||
* @return A string of all the words combined, with spaces between each one, just as they would appear in the
|
|
||||||
* user's actual input string.
|
|
||||||
*/
|
|
||||||
public static String getTextFromArgs(String[] args, int firstWordIndex){
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (int i = firstWordIndex; i < args.length; i++){
|
|
||||||
sb.append(args[i]);
|
|
||||||
if (i < args.length-1){
|
|
||||||
sb.append(' ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,429 +0,0 @@
|
||||||
package handiebot.utils;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.event.TableModelEvent;
|
|
||||||
import javax.swing.event.TableModelListener;
|
|
||||||
import javax.swing.table.TableCellRenderer;
|
|
||||||
import javax.swing.table.TableColumn;
|
|
||||||
import javax.swing.table.TableColumnModel;
|
|
||||||
import javax.swing.table.TableModel;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.beans.PropertyChangeEvent;
|
|
||||||
import java.beans.PropertyChangeListener;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class to manage the widths of colunmns in a table.
|
|
||||||
*
|
|
||||||
* Various properties control how the width of the column is calculated.
|
|
||||||
* Another property controls whether column width calculation should be dynamic.
|
|
||||||
* Finally, various Actions will be added to the table to allow the user
|
|
||||||
* to customize the functionality.
|
|
||||||
*
|
|
||||||
* This class was designed to be used with tables that use an auto resize mode
|
|
||||||
* of AUTO_RESIZE_OFF. With all other modes you are constrained as the width
|
|
||||||
* of the columns must fit inside the table. So if you increase one column, one
|
|
||||||
* or more of the other columns must decrease. Because of this the resize mode
|
|
||||||
* of RESIZE_ALL_COLUMNS will work the best.
|
|
||||||
*/
|
|
||||||
public class TableColumnAdjuster implements PropertyChangeListener, TableModelListener
|
|
||||||
{
|
|
||||||
private JTable table;
|
|
||||||
private int spacing;
|
|
||||||
private boolean isColumnHeaderIncluded;
|
|
||||||
private boolean isColumnDataIncluded;
|
|
||||||
private boolean isOnlyAdjustLarger;
|
|
||||||
private boolean isDynamicAdjustment;
|
|
||||||
private Map<TableColumn, Integer> columnSizes = new HashMap<TableColumn, Integer>();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Specify the table and use default spacing
|
|
||||||
*/
|
|
||||||
public TableColumnAdjuster(JTable table)
|
|
||||||
{
|
|
||||||
this(table, 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Specify the table and spacing
|
|
||||||
*/
|
|
||||||
public TableColumnAdjuster(JTable table, int spacing)
|
|
||||||
{
|
|
||||||
this.table = table;
|
|
||||||
this.spacing = spacing;
|
|
||||||
setColumnHeaderIncluded( true );
|
|
||||||
setColumnDataIncluded( true );
|
|
||||||
setOnlyAdjustLarger( false );
|
|
||||||
setDynamicAdjustment( false );
|
|
||||||
installActions();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Adjust the widths of all the columns in the table
|
|
||||||
*/
|
|
||||||
public void adjustColumns()
|
|
||||||
{
|
|
||||||
TableColumnModel tcm = table.getColumnModel();
|
|
||||||
|
|
||||||
for (int i = 0; i < tcm.getColumnCount(); i++)
|
|
||||||
{
|
|
||||||
adjustColumn(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Adjust the width of the specified column in the table
|
|
||||||
*/
|
|
||||||
public void adjustColumn(final int column)
|
|
||||||
{
|
|
||||||
TableColumn tableColumn = table.getColumnModel().getColumn(column);
|
|
||||||
|
|
||||||
if (! tableColumn.getResizable()) return;
|
|
||||||
|
|
||||||
int columnHeaderWidth = getColumnHeaderWidth( column );
|
|
||||||
int columnDataWidth = getColumnDataWidth( column );
|
|
||||||
int preferredWidth = Math.max(columnHeaderWidth, columnDataWidth);
|
|
||||||
|
|
||||||
updateTableColumn(column, preferredWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Calculated the width based on the column name
|
|
||||||
*/
|
|
||||||
private int getColumnHeaderWidth(int column)
|
|
||||||
{
|
|
||||||
if (! isColumnHeaderIncluded) return 0;
|
|
||||||
|
|
||||||
TableColumn tableColumn = table.getColumnModel().getColumn(column);
|
|
||||||
Object value = tableColumn.getHeaderValue();
|
|
||||||
TableCellRenderer renderer = tableColumn.getHeaderRenderer();
|
|
||||||
|
|
||||||
if (renderer == null)
|
|
||||||
{
|
|
||||||
renderer = table.getTableHeader().getDefaultRenderer();
|
|
||||||
}
|
|
||||||
|
|
||||||
Component c = renderer.getTableCellRendererComponent(table, value, false, false, -1, column);
|
|
||||||
return c.getPreferredSize().width;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Calculate the width based on the widest cell renderer for the
|
|
||||||
* given column.
|
|
||||||
*/
|
|
||||||
private int getColumnDataWidth(int column)
|
|
||||||
{
|
|
||||||
if (! isColumnDataIncluded) return 0;
|
|
||||||
|
|
||||||
int preferredWidth = 0;
|
|
||||||
int maxWidth = table.getColumnModel().getColumn(column).getMaxWidth();
|
|
||||||
|
|
||||||
for (int row = 0; row < table.getRowCount(); row++)
|
|
||||||
{
|
|
||||||
preferredWidth = Math.max(preferredWidth, getCellDataWidth(row, column));
|
|
||||||
|
|
||||||
// We've exceeded the maximum width, no need to check other rows
|
|
||||||
|
|
||||||
if (preferredWidth >= maxWidth)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return preferredWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the preferred width for the specified cell
|
|
||||||
*/
|
|
||||||
private int getCellDataWidth(int row, int column)
|
|
||||||
{
|
|
||||||
// Inovke the renderer for the cell to calculate the preferred width
|
|
||||||
|
|
||||||
TableCellRenderer cellRenderer = table.getCellRenderer(row, column);
|
|
||||||
Component c = table.prepareRenderer(cellRenderer, row, column);
|
|
||||||
int width = c.getPreferredSize().width + table.getIntercellSpacing().width;
|
|
||||||
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Update the TableColumn with the newly calculated width
|
|
||||||
*/
|
|
||||||
private void updateTableColumn(int column, int width)
|
|
||||||
{
|
|
||||||
final TableColumn tableColumn = table.getColumnModel().getColumn(column);
|
|
||||||
|
|
||||||
if (! tableColumn.getResizable()) return;
|
|
||||||
|
|
||||||
width += spacing;
|
|
||||||
|
|
||||||
// Don't shrink the column width
|
|
||||||
|
|
||||||
if (isOnlyAdjustLarger)
|
|
||||||
{
|
|
||||||
width = Math.max(width, tableColumn.getPreferredWidth());
|
|
||||||
}
|
|
||||||
|
|
||||||
columnSizes.put(tableColumn, new Integer(tableColumn.getWidth()));
|
|
||||||
|
|
||||||
table.getTableHeader().setResizingColumn(tableColumn);
|
|
||||||
tableColumn.setWidth(width);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Restore the widths of the columns in the table to its previous width
|
|
||||||
*/
|
|
||||||
public void restoreColumns()
|
|
||||||
{
|
|
||||||
TableColumnModel tcm = table.getColumnModel();
|
|
||||||
|
|
||||||
for (int i = 0; i < tcm.getColumnCount(); i++)
|
|
||||||
{
|
|
||||||
restoreColumn(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Restore the width of the specified column to its previous width
|
|
||||||
*/
|
|
||||||
private void restoreColumn(int column)
|
|
||||||
{
|
|
||||||
TableColumn tableColumn = table.getColumnModel().getColumn(column);
|
|
||||||
Integer width = columnSizes.get(tableColumn);
|
|
||||||
|
|
||||||
if (width != null)
|
|
||||||
{
|
|
||||||
table.getTableHeader().setResizingColumn(tableColumn);
|
|
||||||
tableColumn.setWidth( width.intValue() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Indicates whether to include the header in the width calculation
|
|
||||||
*/
|
|
||||||
public void setColumnHeaderIncluded(boolean isColumnHeaderIncluded)
|
|
||||||
{
|
|
||||||
this.isColumnHeaderIncluded = isColumnHeaderIncluded;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Indicates whether to include the model data in the width calculation
|
|
||||||
*/
|
|
||||||
public void setColumnDataIncluded(boolean isColumnDataIncluded)
|
|
||||||
{
|
|
||||||
this.isColumnDataIncluded = isColumnDataIncluded;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Indicates whether columns can only be increased in size
|
|
||||||
*/
|
|
||||||
public void setOnlyAdjustLarger(boolean isOnlyAdjustLarger)
|
|
||||||
{
|
|
||||||
this.isOnlyAdjustLarger = isOnlyAdjustLarger;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Indicate whether changes to the model should cause the width to be
|
|
||||||
* dynamically recalculated.
|
|
||||||
*/
|
|
||||||
public void setDynamicAdjustment(boolean isDynamicAdjustment)
|
|
||||||
{
|
|
||||||
// May need to add or remove the TableModelListener when changed
|
|
||||||
|
|
||||||
if (this.isDynamicAdjustment != isDynamicAdjustment)
|
|
||||||
{
|
|
||||||
if (isDynamicAdjustment)
|
|
||||||
{
|
|
||||||
table.addPropertyChangeListener( this );
|
|
||||||
table.getModel().addTableModelListener( this );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
table.removePropertyChangeListener( this );
|
|
||||||
table.getModel().removeTableModelListener( this );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isDynamicAdjustment = isDynamicAdjustment;
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// Implement the PropertyChangeListener
|
|
||||||
//
|
|
||||||
public void propertyChange(PropertyChangeEvent e)
|
|
||||||
{
|
|
||||||
// When the TableModel changes we need to update the listeners
|
|
||||||
// and column widths
|
|
||||||
|
|
||||||
if ("model".equals(e.getPropertyName()))
|
|
||||||
{
|
|
||||||
TableModel model = (TableModel)e.getOldValue();
|
|
||||||
model.removeTableModelListener( this );
|
|
||||||
|
|
||||||
model = (TableModel)e.getNewValue();
|
|
||||||
model.addTableModelListener( this );
|
|
||||||
adjustColumns();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// Implement the TableModelListener
|
|
||||||
//
|
|
||||||
public void tableChanged(TableModelEvent e)
|
|
||||||
{
|
|
||||||
if (! isColumnDataIncluded) return;
|
|
||||||
|
|
||||||
// Needed when table is sorted.
|
|
||||||
|
|
||||||
SwingUtilities.invokeLater(new Runnable()
|
|
||||||
{
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
// A cell has been updated
|
|
||||||
|
|
||||||
int column = table.convertColumnIndexToView(e.getColumn());
|
|
||||||
|
|
||||||
if (e.getType() == TableModelEvent.UPDATE && column != -1)
|
|
||||||
{
|
|
||||||
// Only need to worry about an increase in width for this cell
|
|
||||||
|
|
||||||
if (isOnlyAdjustLarger)
|
|
||||||
{
|
|
||||||
int row = e.getFirstRow();
|
|
||||||
TableColumn tableColumn = table.getColumnModel().getColumn(column);
|
|
||||||
|
|
||||||
if (tableColumn.getResizable())
|
|
||||||
{
|
|
||||||
int width = getCellDataWidth(row, column);
|
|
||||||
updateTableColumn(column, width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Could be an increase of decrease so check all rows
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
adjustColumn( column );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The update affected more than one column so adjust all columns
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
adjustColumns();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Install Actions to give user control of certain functionality.
|
|
||||||
*/
|
|
||||||
private void installActions()
|
|
||||||
{
|
|
||||||
installColumnAction(true, true, "adjustColumn", "control ADD");
|
|
||||||
installColumnAction(false, true, "adjustColumns", "control shift ADD");
|
|
||||||
installColumnAction(true, false, "restoreColumn", "control SUBTRACT");
|
|
||||||
installColumnAction(false, false, "restoreColumns", "control shift SUBTRACT");
|
|
||||||
|
|
||||||
installToggleAction(true, false, "toggleDynamic", "control MULTIPLY");
|
|
||||||
installToggleAction(false, true, "toggleLarger", "control DIVIDE");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Update the input and action maps with a new ColumnAction
|
|
||||||
*/
|
|
||||||
private void installColumnAction(
|
|
||||||
boolean isSelectedColumn, boolean isAdjust, String key, String keyStroke)
|
|
||||||
{
|
|
||||||
Action action = new ColumnAction(isSelectedColumn, isAdjust);
|
|
||||||
KeyStroke ks = KeyStroke.getKeyStroke( keyStroke );
|
|
||||||
table.getInputMap().put(ks, key);
|
|
||||||
table.getActionMap().put(key, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Update the input and action maps with new ToggleAction
|
|
||||||
*/
|
|
||||||
private void installToggleAction(
|
|
||||||
boolean isToggleDynamic, boolean isToggleLarger, String key, String keyStroke)
|
|
||||||
{
|
|
||||||
Action action = new ToggleAction(isToggleDynamic, isToggleLarger);
|
|
||||||
KeyStroke ks = KeyStroke.getKeyStroke( keyStroke );
|
|
||||||
table.getInputMap().put(ks, key);
|
|
||||||
table.getActionMap().put(key, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Action to adjust or restore the width of a single column or all columns
|
|
||||||
*/
|
|
||||||
class ColumnAction extends AbstractAction
|
|
||||||
{
|
|
||||||
private boolean isSelectedColumn;
|
|
||||||
private boolean isAdjust;
|
|
||||||
|
|
||||||
public ColumnAction(boolean isSelectedColumn, boolean isAdjust)
|
|
||||||
{
|
|
||||||
this.isSelectedColumn = isSelectedColumn;
|
|
||||||
this.isAdjust = isAdjust;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
// Handle selected column(s) width change actions
|
|
||||||
|
|
||||||
if (isSelectedColumn)
|
|
||||||
{
|
|
||||||
int[] columns = table.getSelectedColumns();
|
|
||||||
|
|
||||||
for (int i = 0; i < columns.length; i++)
|
|
||||||
{
|
|
||||||
if (isAdjust)
|
|
||||||
adjustColumn(columns[i]);
|
|
||||||
else
|
|
||||||
restoreColumn(columns[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (isAdjust)
|
|
||||||
adjustColumns();
|
|
||||||
else
|
|
||||||
restoreColumns();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Toggle properties of the TableColumnAdjuster so the user can
|
|
||||||
* customize the functionality to their preferences
|
|
||||||
*/
|
|
||||||
class ToggleAction extends AbstractAction
|
|
||||||
{
|
|
||||||
private boolean isToggleDynamic;
|
|
||||||
private boolean isToggleLarger;
|
|
||||||
|
|
||||||
public ToggleAction(boolean isToggleDynamic, boolean isToggleLarger)
|
|
||||||
{
|
|
||||||
this.isToggleDynamic = isToggleDynamic;
|
|
||||||
this.isToggleLarger = isToggleLarger;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
if (isToggleDynamic)
|
|
||||||
{
|
|
||||||
setDynamicAdjustment(! isDynamicAdjustment);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isToggleLarger)
|
|
||||||
{
|
|
||||||
setOnlyAdjustLarger(! isOnlyAdjustLarger);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,214 +0,0 @@
|
||||||
package handiebot.utils;
|
|
||||||
|
|
||||||
import com.google.api.client.auth.oauth2.Credential;
|
|
||||||
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
|
|
||||||
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
|
|
||||||
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
|
|
||||||
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
|
|
||||||
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
|
|
||||||
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
|
|
||||||
import com.google.api.client.http.HttpTransport;
|
|
||||||
import com.google.api.client.json.JsonFactory;
|
|
||||||
import com.google.api.client.json.jackson2.JacksonFactory;
|
|
||||||
import com.google.api.client.util.store.FileDataStoreFactory;
|
|
||||||
import com.google.api.services.youtube.YouTube;
|
|
||||||
import com.google.api.services.youtube.YouTubeScopes;
|
|
||||||
import com.google.api.services.youtube.model.SearchListResponse;
|
|
||||||
import com.google.api.services.youtube.model.SearchResult;
|
|
||||||
import com.google.api.services.youtube.model.Video;
|
|
||||||
import com.google.api.services.youtube.model.VideoListResponse;
|
|
||||||
import com.google.common.base.Joiner;
|
|
||||||
import sx.blah.discord.api.internal.json.objects.EmbedObject;
|
|
||||||
import sx.blah.discord.handle.obj.IChannel;
|
|
||||||
import sx.blah.discord.handle.obj.IMessage;
|
|
||||||
import sx.blah.discord.util.EmbedBuilder;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.text.NumberFormat;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import static handiebot.HandieBot.APPLICATION_NAME;
|
|
||||||
import static handiebot.HandieBot.resourceBundle;
|
|
||||||
import static handiebot.utils.MessageUtils.addReaction;
|
|
||||||
import static handiebot.utils.MessageUtils.sendMessage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrew Lalis
|
|
||||||
* Class to query Youtube Data API for results to searches, and return these in a nice list.
|
|
||||||
*/
|
|
||||||
public class YoutubeSearch {
|
|
||||||
|
|
||||||
private static final String KEY = "AIzaSyAjYuxCYBCuZCNvW4w573LQ-jw5UKL64G8";
|
|
||||||
private static final int NUMBER_OF_VIDEOS_RETURNED = 5;
|
|
||||||
|
|
||||||
public static final String WATCH_URL = "https://www.youtube.com/watch?v=";
|
|
||||||
|
|
||||||
private static final File DATA_STORE_DIR = new File(FileUtil.getDataDirectory()+"googleData/");
|
|
||||||
private static FileDataStoreFactory DATA_STORE_FACTORY;
|
|
||||||
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
|
|
||||||
private static HttpTransport HTTP_TRANSPORT;
|
|
||||||
|
|
||||||
private static final List<String> SCOPES = Arrays.asList(YouTubeScopes.YOUTUBE_READONLY);
|
|
||||||
|
|
||||||
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
|
|
||||||
DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR);
|
|
||||||
} catch (GeneralSecurityException | IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
HTTP_TRANSPORT = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an authorized Credential object.
|
|
||||||
* @return an authorized Credential object.
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static Credential authorize() throws IOException {
|
|
||||||
|
|
||||||
// Load client secrets.
|
|
||||||
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY,
|
|
||||||
new InputStreamReader(new FileInputStream(FileUtil.getDataDirectory()+"googleData/client_secret.json")));
|
|
||||||
|
|
||||||
// Build flow and trigger user authorization request.
|
|
||||||
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
|
|
||||||
.setDataStoreFactory(DATA_STORE_FACTORY)
|
|
||||||
.setAccessType("offline")
|
|
||||||
.build();
|
|
||||||
return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build and return an authorized API client service, such as a YouTube
|
|
||||||
* Data API client service.
|
|
||||||
* @return an authorized API client service
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static YouTube getYouTubeService() throws IOException {
|
|
||||||
Credential credential = authorize();
|
|
||||||
return new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
|
|
||||||
.setApplicationName(APPLICATION_NAME)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Query Youtube Data API for a list of videos matching a given string.
|
|
||||||
* @param searchString The string to use for the search.
|
|
||||||
* @return A List of SearchResult objects which contain data about each video.
|
|
||||||
*/
|
|
||||||
public static List<Video> query(String searchString){
|
|
||||||
try {
|
|
||||||
YouTube youtube = getYouTubeService();
|
|
||||||
YouTube.Search.List search = youtube.search().list("id,snippet");
|
|
||||||
search.setKey(KEY);
|
|
||||||
search.setQ(searchString);
|
|
||||||
search.setType("video");
|
|
||||||
search.setFields("items(id/videoId)");
|
|
||||||
search.setMaxResults((long)NUMBER_OF_VIDEOS_RETURNED);
|
|
||||||
|
|
||||||
SearchListResponse searchResponse = search.execute();
|
|
||||||
List<SearchResult> results = searchResponse.getItems();
|
|
||||||
List<String> videoIds = new ArrayList<>();
|
|
||||||
|
|
||||||
if (results != null){
|
|
||||||
for (SearchResult searchResult : results){
|
|
||||||
videoIds.add(searchResult.getId().getVideoId());
|
|
||||||
}
|
|
||||||
Joiner stringJoiner = Joiner.on(',');
|
|
||||||
String videosId = stringJoiner.join(videoIds);
|
|
||||||
YouTube.Videos.List listVideosRequest = youtube.videos().list("snippet,statistics,contentDetails").setId(videosId);
|
|
||||||
VideoListResponse listResponse = listVideosRequest.execute();
|
|
||||||
|
|
||||||
return listResponse.getItems();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (GoogleJsonResponseException e) {
|
|
||||||
System.err.println("There was a service error: " + e.getDetails().getCode() + " : "
|
|
||||||
+ e.getDetails().getMessage());
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an embed object to display.
|
|
||||||
* @param results The list of videos to use to generate an embed object.
|
|
||||||
* @return A fully assembled embedded object.
|
|
||||||
*/
|
|
||||||
public static EmbedObject createEmbed(List<Video> results){
|
|
||||||
EmbedBuilder builder = new EmbedBuilder();
|
|
||||||
if (results != null) {
|
|
||||||
builder.withTitle(MessageFormat.format(resourceBundle.getString("commands.youtube.title"), NUMBER_OF_VIDEOS_RETURNED));
|
|
||||||
builder.withColor(Color.red);
|
|
||||||
for (int i = 0; i < results.size(); i++) {
|
|
||||||
Video video = results.get(i);
|
|
||||||
String views = NumberFormat.getNumberInstance(Locale.US).format(video.getStatistics().getViewCount());
|
|
||||||
String duration = video.getContentDetails().getDuration()
|
|
||||||
.replace("PT", "")
|
|
||||||
.replace("H", ":")
|
|
||||||
.replace("M", ":")
|
|
||||||
.replace("S", "");
|
|
||||||
String[] components = duration.split(":");
|
|
||||||
int hours, minutes, seconds;
|
|
||||||
String formattedTime = "Unknown";
|
|
||||||
if (components.length == 2){
|
|
||||||
minutes = Integer.parseInt(components[0]);
|
|
||||||
seconds = Integer.parseInt(components[1]);
|
|
||||||
formattedTime = String.format("%d:%02d", minutes, seconds);
|
|
||||||
} else if (components.length == 3){
|
|
||||||
hours = Integer.parseInt(components[0]);
|
|
||||||
minutes = Integer.parseInt(components[1]);
|
|
||||||
seconds = Integer.parseInt(components[2]);
|
|
||||||
formattedTime = String.format("%d:%02d:%02d", hours, minutes, seconds);
|
|
||||||
}
|
|
||||||
String channelName = video.getSnippet().getChannelTitle();
|
|
||||||
double likeDislikeRatio = (double)video.getStatistics().getLikeCount().longValue() / (double)video.getStatistics().getDislikeCount().longValue();
|
|
||||||
builder.appendField(MessageUtils.getNumberEmoji(i+1) + video.getSnippet().getTitle(),
|
|
||||||
":signal_strength: " + views +
|
|
||||||
"\t:watch: " + formattedTime +
|
|
||||||
"\t:copyright: "+ channelName +
|
|
||||||
"\t:arrow_up_down: "+ String.format("%.2f", likeDislikeRatio) +
|
|
||||||
"\n"+ WATCH_URL + video.getId(),
|
|
||||||
false);
|
|
||||||
}
|
|
||||||
builder.withFooterText(resourceBundle.getString("commands.youtube.footerInstruction"));
|
|
||||||
}
|
|
||||||
return builder.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays the first five results from a youtube search, and adds reactions so that a user may choose an option.
|
|
||||||
* @param videos The list of videos, returned from calling {@code query}.
|
|
||||||
* @param channel The channel to display the dialog in.
|
|
||||||
*/
|
|
||||||
public static IMessage displayChoicesDialog(List<Video> videos, IChannel channel){
|
|
||||||
EmbedObject e = YoutubeSearch.createEmbed(videos);
|
|
||||||
IMessage message = sendMessage(e, channel);
|
|
||||||
List<String> urls = new ArrayList<>(videos.size());
|
|
||||||
videos.forEach((video) -> urls.add(WATCH_URL + video.getId()));
|
|
||||||
addReaction(message, ":one:");
|
|
||||||
addReaction(message, ":two:");
|
|
||||||
addReaction(message, ":three:");
|
|
||||||
addReaction(message, ":four:");
|
|
||||||
addReaction(message, ":five:");
|
|
||||||
addReaction(message, ":x:");
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,11 +1,6 @@
|
||||||
package handiebot.view;
|
package handiebot.view;
|
||||||
|
|
||||||
import handiebot.HandieBot;
|
import handiebot.HandieBot;
|
||||||
import handiebot.view.listeners.CommandLineListener;
|
|
||||||
import handiebot.view.listeners.PlaylistSelectionListener;
|
|
||||||
import handiebot.view.listeners.SongRenameListener;
|
|
||||||
import handiebot.view.tableModels.PlaylistTableModel;
|
|
||||||
import handiebot.view.tableModels.SongsTableModel;
|
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
@ -17,71 +12,24 @@ import java.io.IOException;
|
||||||
import static handiebot.HandieBot.resourceBundle;
|
import static handiebot.HandieBot.resourceBundle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andrew Lalis & Zino Holwerda
|
* @author Andrew Lalis
|
||||||
* This class inherits JFrame and simplifies the creation of a window.
|
* This class inherits JFrame and simplifies the creation of a window.
|
||||||
*/
|
*/
|
||||||
public class BotWindow extends JFrame {
|
public class BotWindow extends JFrame {
|
||||||
|
|
||||||
//Console output panel.
|
|
||||||
private JTextPane outputArea;
|
private JTextPane outputArea;
|
||||||
|
|
||||||
//Playlist display variables.
|
|
||||||
private PlaylistTableModel playlistTableModel;
|
|
||||||
private SongsTableModel songsTableModel;
|
|
||||||
private JPanel playlistDisplayPanel;
|
|
||||||
|
|
||||||
public BotWindow(){
|
public BotWindow(){
|
||||||
super(HandieBot.APPLICATION_NAME);
|
super(HandieBot.APPLICATION_NAME);
|
||||||
//Setup GUI
|
//Setup GUI
|
||||||
|
|
||||||
//Output area.
|
//Output area.
|
||||||
outputArea = new JTextPane();
|
outputArea = new JTextPane();
|
||||||
outputArea.setBackground(Color.white);
|
outputArea.setBackground(Color.white);
|
||||||
outputArea.setEditable(false);
|
|
||||||
JScrollPane scrollPane = new JScrollPane();
|
JScrollPane scrollPane = new JScrollPane();
|
||||||
scrollPane.setViewportView(outputArea);
|
scrollPane.setViewportView(outputArea);
|
||||||
scrollPane.setAutoscrolls(true);
|
scrollPane.setAutoscrolls(true);
|
||||||
getContentPane().add(scrollPane, BorderLayout.CENTER);
|
getContentPane().add(scrollPane, BorderLayout.CENTER);
|
||||||
|
|
||||||
//updatePlaylistNames();
|
|
||||||
playlistDisplayPanel = new JPanel();
|
|
||||||
playlistDisplayPanel.setPreferredSize(new Dimension(250, 0));
|
|
||||||
playlistDisplayPanel.setLayout(new BorderLayout());
|
|
||||||
|
|
||||||
this.songsTableModel = new SongsTableModel();
|
|
||||||
this.playlistTableModel = new PlaylistTableModel();
|
|
||||||
|
|
||||||
JTable songsTable = new JTable(this.songsTableModel);
|
|
||||||
JTable playlistTable = new JTable(playlistTableModel);
|
|
||||||
|
|
||||||
//Playlist name scroll pane.
|
|
||||||
playlistTable.setRowSelectionAllowed(true);
|
|
||||||
playlistTable.setDragEnabled(false);
|
|
||||||
playlistTable.getTableHeader().setResizingAllowed(false);
|
|
||||||
playlistTable.getTableHeader().setReorderingAllowed(false);
|
|
||||||
playlistTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
|
||||||
playlistTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
|
|
||||||
playlistTable.getSelectionModel().addListSelectionListener(new PlaylistSelectionListener(this.songsTableModel, playlistTable, songsTable));
|
|
||||||
JScrollPane playlistNamesScrollPane = new JScrollPane(playlistTable);
|
|
||||||
playlistNamesScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
|
|
||||||
playlistNamesScrollPane.setPreferredSize(new Dimension(250, 200));
|
|
||||||
playlistTable.getColumnModel().getColumn(0).setPreferredWidth(190);
|
|
||||||
playlistTable.getColumnModel().getColumn(1).setPreferredWidth(42);
|
|
||||||
playlistDisplayPanel.add(playlistNamesScrollPane, BorderLayout.PAGE_START);
|
|
||||||
|
|
||||||
//Song names scroll pane.
|
|
||||||
songsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
|
||||||
songsTable.setDragEnabled(false);
|
|
||||||
songsTable.getTableHeader().setResizingAllowed(false);
|
|
||||||
songsTable.getTableHeader().setReorderingAllowed(false);
|
|
||||||
songsTable.setRowSelectionAllowed(true);
|
|
||||||
songsTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
|
|
||||||
songsTable.addMouseListener(new SongRenameListener());
|
|
||||||
JScrollPane songNamesScrollPane = new JScrollPane(songsTable);
|
|
||||||
songNamesScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
|
|
||||||
playlistDisplayPanel.add(songNamesScrollPane, BorderLayout.CENTER);
|
|
||||||
|
|
||||||
getContentPane().add(playlistDisplayPanel, BorderLayout.EAST);
|
|
||||||
|
|
||||||
//Command field.
|
//Command field.
|
||||||
JTextField commandField = new JTextField();
|
JTextField commandField = new JTextField();
|
||||||
commandField.setFont(new Font("Courier New", Font.PLAIN, 16));
|
commandField.setFont(new Font("Courier New", Font.PLAIN, 16));
|
||||||
|
@ -90,7 +38,6 @@ public class BotWindow extends JFrame {
|
||||||
|
|
||||||
//Standard JFrame setup code.
|
//Standard JFrame setup code.
|
||||||
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
|
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
|
||||||
|
|
||||||
//Add a listener to override the user attempting to close the program.
|
//Add a listener to override the user attempting to close the program.
|
||||||
addWindowListener(new WindowAdapter() {
|
addWindowListener(new WindowAdapter() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -103,34 +50,17 @@ public class BotWindow extends JFrame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//Attempt to set the icon of the window.
|
|
||||||
try {
|
try {
|
||||||
setIconImage(ImageIO.read(getClass().getClassLoader().getResourceAsStream("avatarIcon.png")));
|
setIconImage(ImageIO.read(getClass().getClassLoader().getResourceAsStream("avatarIcon.png")));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
setJMenuBar(new MenuBar(this));
|
setJMenuBar(new MenuBar());
|
||||||
setPreferredSize(new Dimension(800, 600));
|
setPreferredSize(new Dimension(800, 600));
|
||||||
pack();
|
pack();
|
||||||
setLocationRelativeTo(null);
|
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the list of playlist names.
|
|
||||||
*/
|
|
||||||
public void updatePlaylistNames(){
|
|
||||||
this.playlistTableModel.loadPlaylistData();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the playlists panel as visible or invisible.
|
|
||||||
*/
|
|
||||||
public void togglePlaylistsVisibility(){
|
|
||||||
this.playlistDisplayPanel.setVisible(!this.playlistDisplayPanel.isVisible());
|
|
||||||
}
|
|
||||||
|
|
||||||
public JTextPane getOutputArea(){
|
public JTextPane getOutputArea(){
|
||||||
return this.outputArea;
|
return this.outputArea;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package handiebot.view;
|
||||||
|
|
||||||
|
import handiebot.command.Commands;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.event.KeyEvent;
|
||||||
|
import java.awt.event.KeyListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrew Lalis
|
||||||
|
* Class to listen for commands from the console command line.
|
||||||
|
*/
|
||||||
|
public class CommandLineListener implements KeyListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyTyped(KeyEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyPressed(KeyEvent e) {
|
||||||
|
if (e.getKeyCode() == KeyEvent.VK_ENTER){
|
||||||
|
//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];
|
||||||
|
System.arraycopy(words, 1, args, 0, words.length - 1);
|
||||||
|
executeCommand(command, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyReleased(KeyEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes a given command on the command line.
|
||||||
|
* @param command The first word typed, or the command itself.
|
||||||
|
* @param args The list of arguments for the command.
|
||||||
|
*/
|
||||||
|
private void executeCommand(String command, String[] args){
|
||||||
|
if (command.equals("quit")){
|
||||||
|
Commands.executeCommand("quit", null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,41 +5,19 @@ import handiebot.view.actions.ActionItem;
|
||||||
import handiebot.view.actions.CommandAction;
|
import handiebot.view.actions.CommandAction;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.ResourceBundle;
|
|
||||||
|
|
||||||
import static handiebot.HandieBot.resourceBundle;
|
import static handiebot.HandieBot.resourceBundle;
|
||||||
import static handiebot.HandieBot.settings;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andrew Lalis & Zino Holwerda
|
* @author Andrew Lalis
|
||||||
* Custom menu bar to be added to the console control panel.
|
* Custom menu bar to be added to the console control panel.
|
||||||
*/
|
*/
|
||||||
public class MenuBar extends JMenuBar {
|
public class MenuBar extends JMenuBar {
|
||||||
//TODO: Implement a way to restart the program in nederlands.
|
|
||||||
private BotWindow window;
|
|
||||||
private int language;
|
|
||||||
|
|
||||||
public MenuBar(BotWindow window){
|
public MenuBar(){
|
||||||
this.window = window;
|
JMenu fileMenu = new JMenu(resourceBundle.getString("menu.filemenu.title"));
|
||||||
JMenu fileMenu = new JMenu(resourceBundle.getString("menu.fileMenu.title"));
|
fileMenu.add(new ActionItem(resourceBundle.getString("menu.filemenu.quit"), new CommandAction(Commands.get("quit"))));
|
||||||
fileMenu.add(new ActionItem(resourceBundle.getString("menu.fileMenu.quit"), new CommandAction(Commands.get("quit"))));
|
|
||||||
this.add(fileMenu);
|
this.add(fileMenu);
|
||||||
JMenu viewMenu = new JMenu(resourceBundle.getString("menu.viewMenu.view"));
|
|
||||||
JMenu language = new JMenu(resourceBundle.getString("menu.viewMenu.language"));
|
|
||||||
language.add(new ActionItem(resourceBundle.getString("menu.viewMenu.language.english"), e -> {
|
|
||||||
resourceBundle = ResourceBundle.getBundle("Strings", Locale.US);
|
|
||||||
settings.setProperty("language", "en");
|
|
||||||
}));
|
|
||||||
language.add(new ActionItem(resourceBundle.getString("menu.viewMenu.language.dutch"), e -> {
|
|
||||||
resourceBundle = ResourceBundle.getBundle("Strings", Locale.forLanguageTag("nl"));
|
|
||||||
settings.setProperty("language", "nl");
|
|
||||||
}));
|
|
||||||
viewMenu.add(language);
|
|
||||||
viewMenu.add(new ActionItem(resourceBundle.getString("menu.viewMenu.playlistsVisible"), e -> window.togglePlaylistsVisibility()));
|
|
||||||
//TODO: Add method to toggle visibility of the servers panel.
|
|
||||||
viewMenu.add(new ActionItem(resourceBundle.getString("menu.viewMenu.serversVisible"), e -> {}));
|
|
||||||
this.add(viewMenu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
package handiebot.view.listeners;
|
|
||||||
|
|
||||||
import handiebot.HandieBot;
|
|
||||||
import handiebot.command.CommandContext;
|
|
||||||
import handiebot.command.types.Command;
|
|
||||||
import handiebot.command.types.CommandLineCommand;
|
|
||||||
import handiebot.command.types.ContextCommand;
|
|
||||||
import handiebot.command.types.StaticCommand;
|
|
||||||
import handiebot.view.BotLog;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import java.awt.event.KeyEvent;
|
|
||||||
import java.awt.event.KeyListener;
|
|
||||||
|
|
||||||
import static handiebot.HandieBot.log;
|
|
||||||
import static handiebot.command.Commands.commands;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrew Lalis
|
|
||||||
* Class to listen for commands from the console command line.
|
|
||||||
*/
|
|
||||||
public class CommandLineListener implements KeyListener {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void keyTyped(KeyEvent e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void keyPressed(KeyEvent e) {
|
|
||||||
if (e.getKeyCode() == KeyEvent.VK_ENTER){
|
|
||||||
//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];
|
|
||||||
System.arraycopy(words, 1, args, 0, words.length - 1);
|
|
||||||
executeCommand(command, new CommandContext(HandieBot.client.getOurUser(), null, null, args));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void keyReleased(KeyEvent e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes a given command on the command line. This must be written separate from the {@code executeCommand}
|
|
||||||
* method in {@code Commands}, because here, no permissions may be checked.
|
|
||||||
* @param command The first word typed, or the command itself.
|
|
||||||
* @param context The list of arguments for the command.
|
|
||||||
*/
|
|
||||||
private void executeCommand(String command, CommandContext context) {
|
|
||||||
for (Command cmd : commands){
|
|
||||||
if (cmd.getName().equals(command) && (cmd instanceof CommandLineCommand)){
|
|
||||||
log.log(BotLog.TYPE.COMMAND, "Command issued: "+command);
|
|
||||||
if (cmd instanceof StaticCommand){
|
|
||||||
((StaticCommand) cmd).execute();
|
|
||||||
} else if (cmd instanceof ContextCommand){
|
|
||||||
((ContextCommand) cmd).execute(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
package handiebot.view.listeners;
|
|
||||||
|
|
||||||
import handiebot.lavaplayer.playlist.Playlist;
|
|
||||||
import handiebot.utils.TableColumnAdjuster;
|
|
||||||
import handiebot.view.tableModels.SongsTableModel;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.event.ListSelectionEvent;
|
|
||||||
import javax.swing.event.ListSelectionListener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrew Lalis
|
|
||||||
* Listens for if the user selects a playlist from the list.
|
|
||||||
*/
|
|
||||||
public class PlaylistSelectionListener implements ListSelectionListener {
|
|
||||||
|
|
||||||
//The table model for the songs list.
|
|
||||||
private SongsTableModel songsModel;
|
|
||||||
|
|
||||||
//The table that shows the playlist names.
|
|
||||||
private JTable table;
|
|
||||||
private JTable songsTable;
|
|
||||||
|
|
||||||
public PlaylistSelectionListener(SongsTableModel songsModel, JTable table, JTable songsTable){
|
|
||||||
this.songsModel = songsModel;
|
|
||||||
this.table = table;
|
|
||||||
this.songsTable = songsTable;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void valueChanged(ListSelectionEvent e) {
|
|
||||||
if (e.getValueIsAdjusting()){
|
|
||||||
updatePlaylistData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the list of songs for a selected playlist.
|
|
||||||
* Does not update the list of playlists.
|
|
||||||
*/
|
|
||||||
private void updatePlaylistData() {
|
|
||||||
String selectedValue = (String) this.table.getModel().getValueAt(this.table.getSelectedRow(), 0);
|
|
||||||
if (selectedValue != null && Playlist.playlistExists(selectedValue)){
|
|
||||||
Playlist playlist = new Playlist(selectedValue);
|
|
||||||
playlist.load();
|
|
||||||
this.songsModel.setPlaylist(playlist);
|
|
||||||
this.songsTable.setName(playlist.getName());
|
|
||||||
new TableColumnAdjuster(this.songsTable).adjustColumns();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
package handiebot.view.listeners;
|
|
||||||
|
|
||||||
import handiebot.lavaplayer.playlist.Playlist;
|
|
||||||
import handiebot.utils.TableColumnAdjuster;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.awt.event.MouseListener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrew Lalis
|
|
||||||
* Listener to check if the user has double-clicked on a song's name, and give them an option to rename that song.
|
|
||||||
*/
|
|
||||||
public class SongRenameListener implements MouseListener {
|
|
||||||
//TODO: Externalize strings.
|
|
||||||
@Override
|
|
||||||
public void mouseClicked(MouseEvent e) {
|
|
||||||
if (e.getClickCount() == 2){
|
|
||||||
JTable table = (JTable) e.getSource();
|
|
||||||
int row = table.rowAtPoint(e.getPoint());
|
|
||||||
int col = table.columnAtPoint(e.getPoint());
|
|
||||||
if (col == 1){
|
|
||||||
String oldValue = (String) table.getModel().getValueAt(row, col);
|
|
||||||
String result = JOptionPane.showInputDialog(table, "Enter a modified name for the song.", oldValue);
|
|
||||||
if (result != null){
|
|
||||||
table.getModel().setValueAt(result, row, col);
|
|
||||||
new TableColumnAdjuster(table).adjustColumns();
|
|
||||||
Playlist playlist = new Playlist(table.getName());
|
|
||||||
playlist.load();
|
|
||||||
playlist.getTracks().get(row).setTitle(result);
|
|
||||||
playlist.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mousePressed(MouseEvent e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseReleased(MouseEvent e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseEntered(MouseEvent e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseExited(MouseEvent e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
package handiebot.view.tableModels;
|
|
||||||
|
|
||||||
import handiebot.lavaplayer.playlist.Playlist;
|
|
||||||
|
|
||||||
import javax.swing.table.AbstractTableModel;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrew Lalis
|
|
||||||
* Class for a model of data to be supplied to a table.
|
|
||||||
*/
|
|
||||||
public class PlaylistTableModel extends AbstractTableModel {
|
|
||||||
|
|
||||||
private static final String[] columnNames = {
|
|
||||||
"Playlist",
|
|
||||||
"Tracks"
|
|
||||||
};
|
|
||||||
|
|
||||||
private String[][] data;
|
|
||||||
|
|
||||||
public PlaylistTableModel(){
|
|
||||||
loadPlaylistData();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getRowCount() {
|
|
||||||
return data.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getColumnCount() {
|
|
||||||
return columnNames.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getColumnName(int col) {
|
|
||||||
return columnNames[col];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
|
|
||||||
data[rowIndex][columnIndex] = (String)aValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
|
||||||
return data[rowIndex][columnIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads from the file system a list of playlists and sets the data to the updated list.
|
|
||||||
*/
|
|
||||||
public void loadPlaylistData(){
|
|
||||||
List<String> playlistNames = Playlist.getAvailablePlaylists();
|
|
||||||
data = new String[playlistNames.size()][columnNames.length];
|
|
||||||
for (int i = 0; i < playlistNames.size(); i++){
|
|
||||||
data[i][0] = playlistNames.get(i);
|
|
||||||
Playlist p = new Playlist(playlistNames.get(i));
|
|
||||||
p.load();
|
|
||||||
data[i][1] = Integer.toString(p.getTrackCount());
|
|
||||||
}
|
|
||||||
this.fireTableDataChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
package handiebot.view.tableModels;
|
|
||||||
|
|
||||||
import handiebot.lavaplayer.playlist.Playlist;
|
|
||||||
|
|
||||||
import javax.swing.table.AbstractTableModel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrew Lalis
|
|
||||||
*/
|
|
||||||
public class SongsTableModel extends AbstractTableModel {
|
|
||||||
|
|
||||||
private static final String[] columnNames = {
|
|
||||||
"#",
|
|
||||||
"Song",
|
|
||||||
"Time"
|
|
||||||
};
|
|
||||||
|
|
||||||
private String[][] data;
|
|
||||||
|
|
||||||
public SongsTableModel(Playlist playlist){
|
|
||||||
setPlaylist(playlist);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SongsTableModel(){
|
|
||||||
this.data = new String[0][0];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getRowCount() {
|
|
||||||
return data.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getColumnCount() {
|
|
||||||
return columnNames.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getColumnName(int column) {
|
|
||||||
return columnNames[column];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
|
||||||
return data[rowIndex][columnIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setValueAt(Object obj, int rowIndex, int columnIndex){
|
|
||||||
this.data[rowIndex][columnIndex] = (String) obj;
|
|
||||||
this.fireTableDataChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPlaylist(Playlist playlist){
|
|
||||||
this.data = new String[playlist.getTrackCount()][columnNames.length];
|
|
||||||
for (int i = 0; i < playlist.getTrackCount(); i++){
|
|
||||||
this.data[i][0] = Integer.toString(i+1);
|
|
||||||
this.data[i][1] = playlist.getTracks().get(i).getTitle();
|
|
||||||
this.data[i][2] = playlist.getTracks().get(i).getFormattedDuration().replace("[","").replace("]","");
|
|
||||||
}
|
|
||||||
this.fireTableDataChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,8 +1,5 @@
|
||||||
#author: Andrew Lalis & Zino Holwerda
|
#Strings for HandieBot:
|
||||||
#INFO Strings for HandieBot:
|
# The following strings are organized in a way that it should be intuitive how it will be used.
|
||||||
#INFO The following strings are organized in a way that it should be intuitive how it will be used.
|
|
||||||
#INFO Language: English
|
|
||||||
|
|
||||||
#Log
|
#Log
|
||||||
log.loggingIn=Logging client in...
|
log.loggingIn=Logging client in...
|
||||||
log.init=HandieBot initialized.
|
log.init=HandieBot initialized.
|
||||||
|
@ -14,19 +11,8 @@ log.newVoiceChannel=No voice channel found, creating a new one.
|
||||||
window.close.question=Are you sure you want to exit and shutdown the bot?
|
window.close.question=Are you sure you want to exit and shutdown the bot?
|
||||||
window.close.title=Confirm shutdown
|
window.close.title=Confirm shutdown
|
||||||
#MenuBar
|
#MenuBar
|
||||||
menu.fileMenu.title=File
|
menu.filemenu.title=File
|
||||||
menu.fileMenu.quit=Quit
|
menu.filemenu.quit=Quit
|
||||||
menu.viewMenu.view=View
|
|
||||||
menu.viewMenu.language=Language
|
|
||||||
menu.viewMenu.language.english=English
|
|
||||||
menu.viewMenu.language.dutch=Dutch
|
|
||||||
menu.viewMenu.playlistsVisible=Playlists
|
|
||||||
menu.viewMenu.serversVisible=Servers
|
|
||||||
#Actions
|
|
||||||
action.menu.playlist=Edit playlists
|
|
||||||
action.menu.playlist.add=Add
|
|
||||||
action.menu.playlist.delete=Delete
|
|
||||||
action.menu.playlist.edit=Edit
|
|
||||||
#Generic Command Messages
|
#Generic Command Messages
|
||||||
commands.noPermission.message=You do not have permission to use the command `{0}`.
|
commands.noPermission.message=You do not have permission to use the command `{0}`.
|
||||||
commands.noPermission.log=User {0} does not have permission to execute {1}
|
commands.noPermission.log=User {0} does not have permission to execute {1}
|
||||||
|
@ -38,18 +24,16 @@ commands.command.setPrefix.loadedPrefixes=Loaded prefixes.
|
||||||
commands.command.setPrefix.savedPrefixes=Saved prefixes.
|
commands.command.setPrefix.savedPrefixes=Saved prefixes.
|
||||||
commands.command.help.description=Displays a list of commands and what they do.
|
commands.command.help.description=Displays a list of commands and what they do.
|
||||||
commands.command.info.description=Displays some common commands and information about the bot.
|
commands.command.info.description=Displays some common commands and information about the bot.
|
||||||
commands.command.info.embed.description=HandieBot is a Discord bot created by Andrew Lalis & Zino Holwerda. It can play music, manage playlists, and provide other assistance to users. Some useful commands are shown below.
|
commands.command.info.embed.description=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.
|
||||||
commands.command.info.embed.helpCommand=Receive a message with a detailed list of all commands and how to use them.
|
commands.command.info.embed.helpCommand=Receive a message with a detailed list of all commands and how to use them.
|
||||||
commands.command.info.embed.playCommand=Play a song, or add it to the queue if one is already playing. A URL can be a YouTube or SoundCloud link.
|
commands.command.info.embed.playCommand=Play a song, or add it to the queue if one is already playing. A URL can be a YouTube or SoundCloud link.
|
||||||
commands.command.info.embed.queueCommand=Show a list of songs that will soon be played.
|
commands.command.info.embed.queueCommand=Show a list of songs that will soon be played.
|
||||||
commands.command.quit.description=Shuts down the bot on all servers.
|
commands.command.quit.description=Shuts down the bot on all servers.
|
||||||
commands.command.broadcast.description=Broadcasts a message to every server the bot is connected to.
|
|
||||||
commands.command.setPrefix.description=Sets the prefix for commands.
|
commands.command.setPrefix.description=Sets the prefix for commands.
|
||||||
commands.command.setPrefix.changed=Changed command prefix to "{0}"
|
commands.command.setPrefix.changed=Changed command prefix to "{0}"
|
||||||
commands.command.setPrefix.noPrefixError=You must provide a new prefix.
|
commands.command.setPrefix.noPrefixError=You must provide a new prefix.
|
||||||
commands.command.play.description=Plays a song, or adds it to the queue.
|
commands.command.play.description=Plays a song, or adds it to the queue.
|
||||||
commands.command.play.songAddError=Unable to add song to queue: {0}.
|
commands.command.play.songAddError=Unable to add song to queue: {0}.
|
||||||
commands.command.playnow.description=Plays a song immediately, and skips any currently playing song.
|
|
||||||
#Playlist strings.
|
#Playlist strings.
|
||||||
commands.command.playlist.description.main=Do actions to a playlist.
|
commands.command.playlist.description.main=Do actions to a playlist.
|
||||||
commands.command.playlist.description.create=Creates a playlist.
|
commands.command.playlist.description.create=Creates a playlist.
|
||||||
|
@ -96,17 +80,9 @@ commands.command.queue.description.main=Shows the first 10 songs in the queue.
|
||||||
commands.command.queue.description.all=Shows all songs.
|
commands.command.queue.description.all=Shows all songs.
|
||||||
commands.command.queue.description.clear=Clears the queue and stops playing.
|
commands.command.queue.description.clear=Clears the queue and stops playing.
|
||||||
commands.command.queue.description.save=Saves the queue to a playlist.
|
commands.command.queue.description.save=Saves the queue to a playlist.
|
||||||
commands.command.queue.description.remove=Removes a song from the queue.
|
|
||||||
commands.command.queue.description.move=Moves a song from one index to another.
|
|
||||||
commands.command.queue.clear=Cleared queue.
|
commands.command.queue.clear=Cleared queue.
|
||||||
commands.command.queue.save.message=Saved {0} tracks to playlist **{1}**.
|
commands.command.queue.save.message=Saved {0} tracks to playlist **{1}**.
|
||||||
commands.command.queue.save.log=Saved queue to playlist [{0}].
|
commands.command.queue.save.log=Saved queue to playlist [{0}].
|
||||||
commands.command.queue.error.save=Unable to save the queue to a playlist.
|
|
||||||
commands.command.queue.remove.message=Removed song(s) from the active queue.
|
|
||||||
commands.command.queue.remove.error=You must give the index of a song to remove from the queue.
|
|
||||||
commands.command.queue.move.error=You must give the original index of a song in the queue, and a new index.
|
|
||||||
commands.command.queue.move.indexError=The indices you entered are invalid.
|
|
||||||
commands.command.queue.move.success=Moved song *{0}* from position {1} to position {2}.
|
|
||||||
#Repeat
|
#Repeat
|
||||||
commands.command.repeat.description=Sets repeating.
|
commands.command.repeat.description=Sets repeating.
|
||||||
#Shuffle
|
#Shuffle
|
||||||
|
@ -117,13 +93,6 @@ commands.command.skip.description=Skips the current song.
|
||||||
commands.command.stop.description=Stops playing music.
|
commands.command.stop.description=Stops playing music.
|
||||||
#Tengwar translator
|
#Tengwar translator
|
||||||
commands.command.tengwar.description=Translates text to tengwar, or decodes tengwar text back into human readable form.
|
commands.command.tengwar.description=Translates text to tengwar, or decodes tengwar text back into human readable form.
|
||||||
#Youtube Interface
|
|
||||||
commands.youtube.choiceMade.log={0} chose item {1} from the Youtube query.
|
|
||||||
commands.youtube.title=Showing the first {0} results from YouTube.com.
|
|
||||||
commands.youtube.footerInstruction=Please add a reaction to select a song, or cancel. Choice times out in 30 seconds.
|
|
||||||
#Report
|
|
||||||
commands.command.report.description=Reports a user to administrators.
|
|
||||||
commands.command.report.error=You must name a user in your report.
|
|
||||||
#Music Player
|
#Music Player
|
||||||
player.setRepeat=Set **Repeat** to *{0}*.
|
player.setRepeat=Set **Repeat** to *{0}*.
|
||||||
player.setShuffle=Set **Shuffle** to *{0}*.
|
player.setShuffle=Set **Shuffle** to *{0}*.
|
||||||
|
@ -147,15 +116,5 @@ fileutil.fileCreateError=Unable to create file. {0}
|
||||||
fileutil.writeError=Unable to write to file. {0}
|
fileutil.writeError=Unable to write to file. {0}
|
||||||
#Playlist strings
|
#Playlist strings
|
||||||
playlist.empty=There are no songs in this playlist.
|
playlist.empty=There are no songs in this playlist.
|
||||||
playlist.embedTooLarge=The playlist is too large for a discord message. Please follow the link in the title to the full list on Pastebin.com.
|
|
||||||
playlist.loadTrack.log=Added {0} to playlist [{1}].
|
|
||||||
playlist.loadTrack.error=Unable to add {0} to the playlist [{1}].
|
|
||||||
playlist.save.error.directory=Unable to make directory: {0}
|
|
||||||
playlist.save.error.fileNotFound=Unable to find file to write playlist: {0}
|
|
||||||
playlist.load.error.IOException=IOException while loading playlist [{0}]. {1}
|
|
||||||
playlist.load.error.exists=The playlist [{0}] does not exist.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,22 @@
|
||||||
#author: Zino Holwerda
|
#Strings for HandieBot:
|
||||||
#INFO Strings for HandieBot:
|
# The following strings are organized in a way that it should be intuitive how it will be used.
|
||||||
#INFO The following strings are organized in a way that it should be intuitive how it will be used.
|
|
||||||
#INFO Language: Dutch
|
|
||||||
|
|
||||||
#Log
|
#Log
|
||||||
log.loggingIn=Bezig met inloggen van de client...
|
log.loggingIn=Logging client in...
|
||||||
log.init=HandieBot ge<EFBFBD>nitialiseerd.
|
log.init=HandieBot initialized.
|
||||||
log.shuttingDown=Bezig met het afsluiten van de bot.
|
log.shuttingDown=Shutting down the bot.
|
||||||
log.deleteMessageError=Niet mogelijk het bericht te vewijderen. Zorg er alstublieft voor dat de bot MANAGE_MESSAGES aan heeft, met name in dit kanaal.
|
log.deleteMessageError=Unable to delete message. Please ensure that the bot has MANAGE_MESSAGES enabled, especially for this channel.
|
||||||
log.creatingChatChannel=Geen chat gevonden. Bezig met het maken er van.
|
log.creatingChatChannel=No chat channel found, creating a new one.
|
||||||
log.newVoiceChannel=Geen voice kanaal gevonden, Bezig met het maken er van.
|
log.newVoiceChannel=No voice channel found, creating a new one.
|
||||||
#Window
|
#Window
|
||||||
window.close.question=Weet je zeker dat je de bot wil afsluiten?
|
window.close.question=Are you sure you want to exit and shutdown the bot?
|
||||||
window.close.title=Stopzetten Bevestigen.
|
window.close.title=Confirm shutdown
|
||||||
#MenuBar
|
#MenuBar
|
||||||
menu.fileMenu.title=Bestand
|
menu.filemenu.title=File
|
||||||
menu.fileMenu.quit=Verlaten
|
menu.filemenu.quit=Quit
|
||||||
menu.fileMenu.edit=Bewerken
|
|
||||||
menu.fileMenu.view=Beeld
|
|
||||||
#Generic Command Messages
|
#Generic Command Messages
|
||||||
commands.noPermission.message=U hebt niet de toestemming om dit commando uit te voeren.`{0}`.
|
commands.noPermission.message=You do not have permission to use the command `{0}`.
|
||||||
commands.noPermission.log=Gebruiker {0} heeft niet de toestemming voor het uitvoeren van {1}
|
commands.noPermission.log=User {0} does not have permission to execute {1}
|
||||||
commands.noPermission.subcommand=U hebt niet de toestemming om dat te doen.
|
commands.noPermission.subcommand=You don't have permission to do that.
|
||||||
commands.invalidCommand.noContext=Invalid command issued: {0}
|
commands.invalidCommand.noContext=Invalid command issued: {0}
|
||||||
commands.invalidCommand.context=Invalid command: {0} issued by: {1}
|
commands.invalidCommand.context=Invalid command: {0} issued by: {1}
|
||||||
#Messages for specific commands.
|
#Messages for specific commands.
|
||||||
|
@ -121,19 +116,5 @@ fileutil.fileCreateError=Unable to create file. {0}
|
||||||
fileutil.writeError=Unable to write to file. {0}
|
fileutil.writeError=Unable to write to file. {0}
|
||||||
#Playlist strings
|
#Playlist strings
|
||||||
playlist.empty=There are no songs in this playlist.
|
playlist.empty=There are no songs in this playlist.
|
||||||
playlist.embedTooLarge=The playlist is too large for a discord message. Please follow the link in the title to the full list on Pastebin.com.
|
|
||||||
playlist.loadTrack.log=Added {0} to playlist [{1}].
|
|
||||||
playlist.loadTrack.error=Unable to add {0} to the playlist [{1}].
|
|
||||||
playlist.save.error=Unable to make directory: {0}
|
|
||||||
playlist.save.error.fileNotFound=Unable to find file to write playlist: {0}
|
|
||||||
playlist.load.IOException=IOException while loading playlist [{0}]. {1}
|
|
||||||
playlist.load.error.exists=The playlist [{0}] does not exist.
|
|
||||||
commands.youtube.footerInstruction=Please add a reaction to select a song, or cancel. Choice times out in 30 seconds.
|
|
||||||
commands.command.report.description=Reports a user to administrators.
|
|
||||||
commands.command.report.error=You must name a user in your report.
|
|
||||||
commands.command.queue.remove=Removed song(s) from the active queue.
|
|
||||||
commands.command.queue.remove.error=You must give the index of a song to remove from the queue.
|
|
||||||
commands.command.queue.move.success=Moved song *{0}* from position {1} to position {2}.
|
|
||||||
commands.command.playnow.description=Plays a song immediately, and skips any currently playing song.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 9.4 KiB |
|
@ -1 +0,0 @@
|
||||||
{"installed":{"client_id":"901338445852-9e4l5o697fgj83q27gjaftonffdg2o9u.apps.googleusercontent.com","project_id":"pacific-nuance-172611","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://accounts.google.com/o/oauth2/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"XQMJwz1gELEZAeu6hmEuFN1P","redirect_uris":["urn:ietf:wg:oauth:2.0:oob","http://localhost"]}}
|
|
|
@ -1,2 +0,0 @@
|
||||||
#HandieBot default settings
|
|
||||||
language:en
|
|
Loading…
Reference in New Issue