From 048b645e61ff7c6ae8799381b43ecac80f74e736 Mon Sep 17 00:00:00 2001 From: anthorob Date: Tue, 8 Feb 2022 18:34:06 -0500 Subject: [PATCH] Add voteskip command and update music player --- pom.xml | 266 +++++++++--------- src/main/java/netneutrality/GuildManager.java | 57 +++- src/main/java/netneutrality/MusicBot.java | 25 +- .../java/netneutrality/ThreadManager.java | 28 +- .../command/AbstractMusicCommand.java | 12 +- .../netneutrality/command/CommandContext.java | 45 ++- .../netneutrality/command/CommandUsage.java | 49 ++++ .../command/basic/HelpCommand.java | 4 +- .../command/basic/PingCommand.java | 2 +- .../command/crypto/BitcoinPriceCommand.java | 2 +- .../command/crypto/CryptoPriceCommand.java | 2 +- .../command/crypto/EthereumPriceCommand.java | 2 +- .../command/crypto/LitecoinPriceCommand.java | 2 +- .../command/music/DeleteQueueCommand.java | 2 +- .../command/music/JoinCommand.java | 2 +- .../command/music/LeaveCommand.java | 2 +- .../command/music/PlayCommand.java | 6 +- .../command/music/SkipCommand.java | 12 +- .../command/music/StopCommand.java | 16 +- .../command/music/ViewQueueCommand.java | 8 +- .../command/music/VolumeCommand.java | 7 +- .../command/music/VoteSkipCommand.java | 11 +- .../java/netneutrality/db/DBController.java | 2 +- .../db/controllers/DBBlacklist.java | 17 +- .../db/entities/AbstractEntity.java | 4 +- .../netneutrality/db/models/MRowModel.java | 20 ++ .../netneutrality/db/models/MTableModel.java | 6 + .../netneutrality/handler/LogHandler.java | 2 +- .../handler/{ => message}/EditHandler.java | 17 +- .../{ => message}/MessageReceivedHandler.java | 4 +- .../http/server/ActionHandler.java | 37 ++- .../http/server/GuildHandler.java | 60 +++- .../netneutrality/http/server/WebApi.java | 4 +- .../music/LoadResultHandler.java | 18 +- .../netneutrality/music/MusicManager.java | 85 ++++-- .../netneutrality/music/TrackScheduler.java | 121 ++++++-- ...BaseThread.java => BaseThreadFactory.java} | 4 +- .../netneutrality/thread/ShutdownThread.java | 28 ++ .../netneutrality/utils/ChannelFunction.java | 2 +- .../netneutrality/utils/MessageFunction.java | 32 ++- .../netneutrality/utils/UnsafeShutdown.java | 62 ++++ 41 files changed, 779 insertions(+), 308 deletions(-) create mode 100644 src/main/java/netneutrality/command/CommandUsage.java rename src/main/java/netneutrality/handler/{ => message}/EditHandler.java (71%) rename src/main/java/netneutrality/handler/{ => message}/MessageReceivedHandler.java (94%) rename src/main/java/netneutrality/thread/{BaseThread.java => BaseThreadFactory.java} (87%) create mode 100644 src/main/java/netneutrality/thread/ShutdownThread.java create mode 100644 src/main/java/netneutrality/utils/UnsafeShutdown.java diff --git a/pom.xml b/pom.xml index 50dbbea..06f5297 100644 --- a/pom.xml +++ b/pom.xml @@ -1,151 +1,155 @@ + + - 4.0.0 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 - com.xtremcommunity.discord - netneutrality - 1.0.0 - netneutrality-discord-bot - Discord bot - jar + com.xtremcommunity.discord + netneutrality + 1.0.0 + netneutrality-discord-bot + Discord bot + jar - - 17 - UTF-8 - + + 17 + UTF-8 + 17 + 17 + - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.0 - - 17 - UTF-8 + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 17 + UTF-8 17 17 - - - - org.apache.maven.plugins - maven-jar-plugin - 3.2.0 - - - - true - lib/ - netneutrality.MusicBot - - - - + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.0 + + + + true + lib/ + netneutrality.MusicBot + + + + - - maven-assembly-plugin - 3.3.0 - - - - netneutrality.MusicBot - true - true - - - true - - - - jar-with-dependencies - - netneutrality - - - - make-assembly - package - - single - - - - - - + + maven-assembly-plugin + 3.3.0 + + + + netneutrality.MusicBot + true + true + + + true + + + + jar-with-dependencies + + netneutrality + + + + make-assembly + package + + single + + + + + + - - - central - https://repo.maven.apache.org/maven2 - + + + central + https://repo.maven.apache.org/maven2 + - - dv8tion - m2-dv8tion - https://m2.dv8tion.net/releases - + + dv8tion + m2-dv8tion + https://m2.dv8tion.net/releases + - + - - - net.dv8tion - JDA - 4.4.0_350 - + + + net.dv8tion + JDA + 4.4.0_350 + - - com.squareup.okhttp3 - okhttp - 4.9.3 - + + com.squareup.okhttp3 + okhttp + 4.9.3 + - - - org.json - json - 20210307 - + + + org.json + json + 20210307 + - - org.reflections - reflections - 0.10.2 - + + org.reflections + reflections + 0.10.2 + - - mysql - mysql-connector-java - 8.0.27 - - - org.apache.logging.log4j - log4j-api - 2.17.0 - - - org.apache.logging.log4j - log4j-core - 2.17.0 - - - org.apache.logging.log4j - log4j-slf4j-impl - 2.17.0 - + + mysql + mysql-connector-java + 8.0.27 + + + org.apache.logging.log4j + log4j-api + 2.17.0 + + + org.apache.logging.log4j + log4j-core + 2.17.0 + + + org.apache.logging.log4j + log4j-slf4j-impl + 2.17.0 + - - org.apache.commons - commons-lang3 - 3.12.0 - - - com.sedmelluq - lavaplayer - 1.3.78 - + + org.apache.commons + commons-lang3 + 3.12.0 + + + com.sedmelluq + lavaplayer + 1.3.78 + junit junit diff --git a/src/main/java/netneutrality/GuildManager.java b/src/main/java/netneutrality/GuildManager.java index 53a29bd..e657422 100644 --- a/src/main/java/netneutrality/GuildManager.java +++ b/src/main/java/netneutrality/GuildManager.java @@ -10,8 +10,6 @@ import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.TextChannel; -import netneutrality.db.DBController; -import netneutrality.db.controllers.DBMessage; import netneutrality.db.entities.OGuild; import netneutrality.handler.ratelimiter.IMessageRateLimiter; import netneutrality.handler.ratelimiter.MessageRateLimiterImpl; @@ -24,17 +22,30 @@ import java.util.concurrent.ConcurrentHashMap; public class GuildManager { - public enum GuildSettings { - MUSIC_ROLE("muisc.role"), MUSIC_CHANNEL("music.channel"), BLACKLIST_CHANNELS("blacklist.exclude.channels"); + public enum GuildSetting { + MUSIC_ROLE("music.role", null), MUSIC_CHANNEL("music.channel", null), BLACKLIST_CHANNELS("blacklist.exclude.channels", null); private final String setting; + private final String defaultValue; - GuildSettings(String setting) { + GuildSetting(String setting, String defaultValue) { this.setting = setting; + this.defaultValue = defaultValue; + } + + public String getSetting() { + return setting; + } + + public String getDefaultValue() { + return defaultValue; } @Override public String toString() { + if (setting == null) + return defaultValue; + return setting; } } @@ -61,6 +72,36 @@ public class GuildManager { } } + public static GuildManager getManager(String guildId) { + return managers.getOrDefault(guildId, null); + } + + public static Map getManagers() { + return managers; + } + + public static boolean reloadSettingsForGuild(String guildId) { + if (managers.containsKey(guildId)) { + GuildManager manager = managers.get(guildId); + manager.reloadSettings(); + + return true; + } + + return false; + } + + public static boolean reloadSettingsForGuild(Guild guild) { + if (managers.containsKey(guild.getId())) { + GuildManager manager = GuildManager.getManager(guild.getId()); + manager.reloadSettings(); + + return true; + } + + return false; + } + public void checkAndLogMessage(Message message, Member member, TextChannel channel) { //((DBMessage) DBController.get("message")).log(guild, channel, member, message); } @@ -74,10 +115,14 @@ public class GuildManager { return guildEntity.getSettings().getSettingByKey(key); } - public String getSetting(GuildSettings key) { + public String getSetting(GuildSetting key) { return guildEntity.getSettings().getSettingByKey(key.toString()); } + public Map getSettings() { + return guildEntity.getSettings().getSettings(); + } + public void reloadSettings() { guildEntity.reloadSettings(); } diff --git a/src/main/java/netneutrality/MusicBot.java b/src/main/java/netneutrality/MusicBot.java index 3f4a025..6ee210f 100644 --- a/src/main/java/netneutrality/MusicBot.java +++ b/src/main/java/netneutrality/MusicBot.java @@ -7,16 +7,15 @@ import net.dv8tion.jda.api.requests.GatewayIntent; import netneutrality.command.CommandManager; import netneutrality.db.DBController; -import netneutrality.handler.EditHandler; -import netneutrality.handler.MessageReceivedHandler; +import netneutrality.handler.message.EditHandler; +import netneutrality.handler.message.MessageReceivedHandler; import netneutrality.handler.ServerJoinHandler; import netneutrality.http.server.WebApi; import netneutrality.music.MusicManager; +import netneutrality.thread.BaseThreadFactory; +import netneutrality.thread.ShutdownThread; import netneutrality.utils.Settings; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.config.Configurator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,28 +32,20 @@ public class MusicBot { initJDA(); CommandManager.init(); + MusicManager.registerSources(); jda.getPresence().setActivity(Activity.watching("me load...")); jda.addEventListener(new MessageReceivedHandler(), new EditHandler(), new ServerJoinHandler()); new WebApi(); jda.getPresence().setActivity(Activity.watching("you")); - Runtime.getRuntime().addShutdownHook(new Thread(() -> { - if( LogManager.getContext() instanceof LoggerContext) { - logger.debug("Shutting down log4j2"); - Configurator.shutdown((LoggerContext)LogManager.getContext()); - } - - MusicBot.shutdown(); - })); + Runtime.getRuntime().addShutdownHook(new BaseThreadFactory("shutdown").newThread(new ShutdownThread())); } public static void initJDA() { try { - jda = JDABuilder.createDefault(Settings.getInstance().get("BOT_TOKEN")) - .enableIntents(GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_MESSAGE_REACTIONS, GatewayIntent.GUILD_VOICE_STATES) - .build(); + jda = JDABuilder.createDefault(Settings.getInstance().get("BOT_TOKEN")).enableIntents(GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_MESSAGE_REACTIONS, GatewayIntent.GUILD_VOICE_STATES).build(); jda.awaitReady(); } catch (LoginException | IllegalArgumentException | InterruptedException e) { logger.error(e.getMessage()); @@ -77,7 +68,7 @@ public class MusicBot { private static void disconnect() { if (jda != null) { - jda.shutdownNow(); + jda.shutdown(); } } diff --git a/src/main/java/netneutrality/ThreadManager.java b/src/main/java/netneutrality/ThreadManager.java index d16b4a4..03fbb15 100644 --- a/src/main/java/netneutrality/ThreadManager.java +++ b/src/main/java/netneutrality/ThreadManager.java @@ -1,6 +1,6 @@ package netneutrality; -import netneutrality.thread.BaseThread; +import netneutrality.thread.BaseThreadFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,7 +17,7 @@ public class ThreadManager { private final static Logger logger = LoggerFactory.getLogger(ThreadManager.class); public static ExecutorService getExecutor(String name) { - return executors.computeIfAbsent(name, s -> Executors.newSingleThreadExecutor(new BaseThread(name))); + return executors.computeIfAbsent(name, s -> Executors.newSingleThreadExecutor(new BaseThreadFactory(name))); } @@ -26,36 +26,18 @@ public class ThreadManager { switch (type) { case FIXED: - executor = executors.computeIfAbsent(name, s -> Executors.newFixedThreadPool(5, new BaseThread(name))); + executor = executors.computeIfAbsent(name, s -> Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new BaseThreadFactory(name))); break; case SCHEDULED: - executor = executors.computeIfAbsent(name, s -> Executors.newScheduledThreadPool(5, new BaseThread(name))); + executor = executors.computeIfAbsent(name, s -> Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(), new BaseThreadFactory(name))); break; default: - executor = executors.computeIfAbsent(name, s -> Executors.newSingleThreadExecutor(new BaseThread(name))); + executor = executors.computeIfAbsent(name, s -> Executors.newSingleThreadExecutor(new BaseThreadFactory(name))); } return executor; } - public static ExecutorService getExecutor(String name, ExecutorType type, Integer poolSize) { - ExecutorService executor; - - switch (type) { - case FIXED: - executor = executors.computeIfAbsent(name, s -> Executors.newFixedThreadPool(poolSize, new BaseThread(name))); - break; - case SCHEDULED: - executor = executors.computeIfAbsent(name, s -> Executors.newScheduledThreadPool(poolSize, new BaseThread(name))); - break; - default: - executor = executors.computeIfAbsent(name, s -> Executors.newSingleThreadExecutor(new BaseThread(name))); - } - - return executor; - } - - public static Future dispatch(ExecutorService executor, Runnable task) { return executor.submit(task); } diff --git a/src/main/java/netneutrality/command/AbstractMusicCommand.java b/src/main/java/netneutrality/command/AbstractMusicCommand.java index 91a2136..8ea1990 100644 --- a/src/main/java/netneutrality/command/AbstractMusicCommand.java +++ b/src/main/java/netneutrality/command/AbstractMusicCommand.java @@ -1,4 +1,5 @@ -package netneutrality.command;/* +package netneutrality.command; +/* * Copyright (c) anthorob * * https://xtremcommunity.com/ @@ -10,6 +11,8 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Role; import netneutrality.GuildManager; +import java.util.List; + public abstract class AbstractMusicCommand extends AbstractCommand { @Override @@ -24,14 +27,15 @@ public abstract class AbstractMusicCommand extends AbstractCommand { @Override public boolean canBeExecutedBy(Guild guild, Member member) { - String roleDb = GuildManager.getManager(guild).getSetting(GuildManager.GuildSettings.MUSIC_ROLE); + String roleDb = GuildManager.getManager(guild).getSetting(GuildManager.GuildSetting.MUSIC_ROLE); + boolean can = true; //System.out.println(roleDb); if (roleDb != null && !roleDb.isEmpty()) { Role neededRole = guild.getRoleById(roleDb); - return member.getRoles().contains(neededRole); + can = member.getRoles().contains(neededRole); } - return true; + return can; } } diff --git a/src/main/java/netneutrality/command/CommandContext.java b/src/main/java/netneutrality/command/CommandContext.java index ba03f25..0655d4e 100644 --- a/src/main/java/netneutrality/command/CommandContext.java +++ b/src/main/java/netneutrality/command/CommandContext.java @@ -15,11 +15,12 @@ import netneutrality.utils.Settings; import netneutrality.utils.UserFunction; import java.util.Arrays; +import java.util.Collection; import java.util.concurrent.ExecutorService; public class CommandContext { - private static final ExecutorService commandExecutor = ThreadManager.getExecutor("command-execution", ThreadManager.ExecutorType.FIXED, 10); + private static final ExecutorService commandExecutor = ThreadManager.getExecutor("command-execution", ThreadManager.ExecutorType.FIXED); private AbstractCommand command; private final Message message; @@ -49,11 +50,15 @@ public class CommandContext { return new CommandContext(message, member, user, guild, channel, jda); } + public String getArg(int index) { + return getArgumentsAsArray()[index]; + } + public String[] getArgumentsAsArray() { String msg = message.getContentDisplay().trim(); msg = msg.substring(Settings.getInstance().get("BOT_PREFIX", "$").length()).trim(); String cmd = msg.split(" ", 2)[0]; - String[] args = msg.replaceFirst("(" + cmd + ")(\s)?", "").split("\s"); + String[] args = msg.replaceFirst("(" + cmd + ")(\\s+)?", "").split("\s"); if (args.length == 1 && args[0].isEmpty()) args = new String[0]; @@ -97,6 +102,42 @@ public class CommandContext { return command; } + public void reply(String msg) { + if (channel != null) { + channel.sendMessage(msg).queue(); + } + } + + public void reply(Message msg) { + if (channel != null) { + channel.sendMessage(msg).queue(); + } + } + + public void reply(MessageEmbed embed, MessageEmbed... embeds) { + if (channel != null) { + channel.sendMessageEmbeds(embed, embeds).queue(); + } + } + + public void reply(Collection embeds) { + if (channel != null) { + channel.sendMessageEmbeds(embeds).queue(); + } + } + + public void replyPrivate(String msg) { + user.openPrivateChannel().flatMap(channel -> channel.sendMessage(msg)).queue(); + } + + public void replyPrivate(Message msg) { + user.openPrivateChannel().flatMap(channel -> channel.sendMessage(msg)).queue(); + } + + public void replyPrivate(Collection embeds) { + user.openPrivateChannel().flatMap(channel -> channel.sendMessageEmbeds(embeds)).queue(); + } + public void dispatch(AbstractCommand command) { this.command = command; //TODO: Add usage check diff --git a/src/main/java/netneutrality/command/CommandUsage.java b/src/main/java/netneutrality/command/CommandUsage.java new file mode 100644 index 0000000..956b946 --- /dev/null +++ b/src/main/java/netneutrality/command/CommandUsage.java @@ -0,0 +1,49 @@ +package netneutrality.command;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class CommandUsage { + + public static class Argument { + public enum Type { + OPTIONAL, REQUIRED + } + + private final Type type; + private final String description; + + public Argument(Type t, String desc) { + this.type = t; + this.description = desc; + } + + public String getDescription() { + return description; + } + + public Type getType() { + return type; + } + } + + private final Set args = new HashSet<>(); + + public CommandUsage(Argument... arguments) { + Collections.addAll(args, arguments); + } + + public static CommandUsage create(Argument... arguments) { + return new CommandUsage(arguments); + } + + public Set getArguments() { + return args; + } +} diff --git a/src/main/java/netneutrality/command/basic/HelpCommand.java b/src/main/java/netneutrality/command/basic/HelpCommand.java index cf53ca5..d5e0395 100644 --- a/src/main/java/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/netneutrality/command/basic/HelpCommand.java @@ -58,7 +58,7 @@ public class HelpCommand extends AbstractCommand { public void execute(CommandContext context) { List help = MessageFunction.buildHelpMessage(CommandManager.commands, CommandManager.commandsAlias, UserFunction.isAdmin(context.getGuildUser())); - context.getChannel().sendMessage(new MessageBuilder().append(context.getDiscordUser()).append(" help has been sent your way!").build()).queue(); - context.getDiscordUser().openPrivateChannel().queue(t -> t.sendMessageEmbeds(help).queue()); + context.reply(new MessageBuilder().append(context.getDiscordUser()).append(" help has been sent your way!").build()); + context.replyPrivate(help); } } diff --git a/src/main/java/netneutrality/command/basic/PingCommand.java b/src/main/java/netneutrality/command/basic/PingCommand.java index c6c6633..de9a442 100644 --- a/src/main/java/netneutrality/command/basic/PingCommand.java +++ b/src/main/java/netneutrality/command/basic/PingCommand.java @@ -51,7 +51,7 @@ public class PingCommand extends AbstractCommand { @Override public void execute(CommandContext context) { if (context.getArgumentsAsArray().length == 0) - context.getChannel().sendMessage("Pong! [" + MusicBot.getJDA().getGatewayPing() + " ms]").queue(); + context.reply(String.format("Pong! [%d ms]", context.getJDA().getGatewayPing())); } } diff --git a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java index 375167d..68a9414 100644 --- a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java @@ -88,7 +88,7 @@ public class BitcoinPriceCommand extends AbstractCommand { throw new CommandExecutionException("Error during web request", context, e); } - t.editMessage(String.format("The current price of %s in %s is %s$", crypto, finalCurrency, price)).queue(); + t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); }); } diff --git a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java index d63703b..3855472 100644 --- a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java @@ -44,7 +44,7 @@ public class CryptoPriceCommand extends AbstractCommand { @Override public String getUsage() { - return " "; + return " "; } @Override diff --git a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java index 29b8d64..2a17447 100644 --- a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java @@ -88,7 +88,7 @@ public class EthereumPriceCommand extends AbstractCommand { throw new CommandExecutionException("Error during web request", context, e); } - t.editMessage(String.format("The current price of %s in %s is %s$", crypto, finalCurrency, price)).queue(); + t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); }); } diff --git a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java index cc4439c..eb8e3b7 100644 --- a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java @@ -88,7 +88,7 @@ public class LitecoinPriceCommand extends AbstractCommand { throw new CommandExecutionException("Error during web request", context, e); } - t.editMessage(String.format("The current price of %s in %s is %s$", crypto, finalCurrency, price)).queue(); + t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); }); } diff --git a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java index 14bdd20..44fc51f 100644 --- a/src/main/java/netneutrality/command/music/DeleteQueueCommand.java +++ b/src/main/java/netneutrality/command/music/DeleteQueueCommand.java @@ -40,7 +40,7 @@ public class DeleteQueueCommand extends AbstractMusicCommand { @Override public String getDescription() { - return null; + return "Deletes the music queue"; } @Override diff --git a/src/main/java/netneutrality/command/music/JoinCommand.java b/src/main/java/netneutrality/command/music/JoinCommand.java index 3a2290a..1242f7e 100644 --- a/src/main/java/netneutrality/command/music/JoinCommand.java +++ b/src/main/java/netneutrality/command/music/JoinCommand.java @@ -37,7 +37,7 @@ public class JoinCommand extends AbstractMusicCommand { @Override public String getDescription() { - return null; + return "Make the bot join the current voice channel (if no music is playing, bot will disconnect automatically)"; } @Override diff --git a/src/main/java/netneutrality/command/music/LeaveCommand.java b/src/main/java/netneutrality/command/music/LeaveCommand.java index 0c18e89..71b578b 100644 --- a/src/main/java/netneutrality/command/music/LeaveCommand.java +++ b/src/main/java/netneutrality/command/music/LeaveCommand.java @@ -40,7 +40,7 @@ public class LeaveCommand extends AbstractMusicCommand { @Override public String getDescription() { - return null; + return "Make the bot leave the voice channel"; } @Override diff --git a/src/main/java/netneutrality/command/music/PlayCommand.java b/src/main/java/netneutrality/command/music/PlayCommand.java index 3df9ac4..52c4b81 100644 --- a/src/main/java/netneutrality/command/music/PlayCommand.java +++ b/src/main/java/netneutrality/command/music/PlayCommand.java @@ -35,19 +35,19 @@ public class PlayCommand extends AbstractMusicCommand { @Override public String getDescription() { - return "Get the party going"; + return "Get the party going!"; } @Override public void execute(CommandContext context) { MusicManager player = MusicManager.get(context.getGuild()); + context.getMessage().delete().queue(); if (context.getArgumentsAsArray().length > 0) { - context.getMessage().delete().queue(); player.play(context.getMessageText(), context, false, false); } else { - context.getChannel().sendMessage("No url provided").queue(); + context.reply("No url provided"); } } diff --git a/src/main/java/netneutrality/command/music/SkipCommand.java b/src/main/java/netneutrality/command/music/SkipCommand.java index 42818dc..257d58b 100644 --- a/src/main/java/netneutrality/command/music/SkipCommand.java +++ b/src/main/java/netneutrality/command/music/SkipCommand.java @@ -35,12 +35,12 @@ public class SkipCommand extends AbstractMusicCommand { @Override public String getUsage() { - return null; + return ""; } @Override public String getDescription() { - return null; + return "Used to skip to the next track in the queue (requires admin privileges)"; } @Override @@ -48,6 +48,12 @@ public class SkipCommand extends AbstractMusicCommand { MusicManager player = MusicManager.get(context.getGuild()); MusicUtils.checkIfConnected(player, context); - player.skip(); + if (context.getArgumentsAsArray().length > 0) { + int skips = Integer.parseInt(context.getArg(0)); + player.skip(skips); + } else { + player.skip(1); + } + } } diff --git a/src/main/java/netneutrality/command/music/StopCommand.java b/src/main/java/netneutrality/command/music/StopCommand.java index e4cad4b..b8cc556 100644 --- a/src/main/java/netneutrality/command/music/StopCommand.java +++ b/src/main/java/netneutrality/command/music/StopCommand.java @@ -11,12 +11,9 @@ import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandContext; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; +import netneutrality.utils.UserFunction; public class StopCommand extends AbstractMusicCommand { - @Override - public boolean needAdmin() { - return true; - } @Override public boolean isEnabled() { @@ -40,7 +37,7 @@ public class StopCommand extends AbstractMusicCommand { @Override public String getDescription() { - return null; + return "Stop the music player, deleting the queue in the process"; } @Override @@ -48,6 +45,13 @@ public class StopCommand extends AbstractMusicCommand { MusicManager player = MusicManager.get(context.getGuild()); MusicUtils.checkIfConnected(player, context); - player.leave(); + if (UserFunction.isAdmin(context.getGuildUser())) { + player.leave(); + return; + } + + if (context.getGuildUser().getId().equals(player.getRequesterOfCurrentTrack().getId())) { + player.leave(); + } } } diff --git a/src/main/java/netneutrality/command/music/ViewQueueCommand.java b/src/main/java/netneutrality/command/music/ViewQueueCommand.java index 580112e..0eaa4fb 100644 --- a/src/main/java/netneutrality/command/music/ViewQueueCommand.java +++ b/src/main/java/netneutrality/command/music/ViewQueueCommand.java @@ -32,7 +32,7 @@ public class ViewQueueCommand extends AbstractMusicCommand { @Override public String[] getAlias() { - return new String[]{"viewq"}; + return new String[]{"viewq", "queue"}; } @Override @@ -42,7 +42,7 @@ public class ViewQueueCommand extends AbstractMusicCommand { @Override public String getDescription() { - return null; + return "Get the current queue for the music player"; } @Override @@ -53,9 +53,9 @@ public class ViewQueueCommand extends AbstractMusicCommand { int queueSize = player.getScheduler().getQueue().size(); if (queueSize > 0) { - context.getChannel().sendMessageEmbeds(MessageFunction.buildViewQueueMessage(player, member)).queue(); + context.reply(MessageFunction.buildViewQueueMessage(player, member)); } else { - context.getChannel().sendMessage("Queue is empty!").queue(); + context.reply("Queue is empty!"); } } } diff --git a/src/main/java/netneutrality/command/music/VolumeCommand.java b/src/main/java/netneutrality/command/music/VolumeCommand.java index 576cac6..35a7fe2 100644 --- a/src/main/java/netneutrality/command/music/VolumeCommand.java +++ b/src/main/java/netneutrality/command/music/VolumeCommand.java @@ -9,6 +9,7 @@ package netneutrality.command.music; import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandContext; +import netneutrality.command.CommandUsage; import netneutrality.exceptions.CommandErrorException; import netneutrality.music.MusicManager; import netneutrality.utils.MusicUtils; @@ -31,17 +32,17 @@ public class VolumeCommand extends AbstractMusicCommand { @Override public String[] getAlias() { - return new String[0]; + return new String[] { "vol" }; } @Override public String getUsage() { - return null; + return ""; } @Override public String getDescription() { - return null; + return "Sets the volume for the music player"; } @Override diff --git a/src/main/java/netneutrality/command/music/VoteSkipCommand.java b/src/main/java/netneutrality/command/music/VoteSkipCommand.java index 54df3dc..d8ace4e 100644 --- a/src/main/java/netneutrality/command/music/VoteSkipCommand.java +++ b/src/main/java/netneutrality/command/music/VoteSkipCommand.java @@ -8,17 +8,19 @@ package netneutrality.command.music; import netneutrality.command.AbstractMusicCommand; import netneutrality.command.CommandContext; +import netneutrality.music.MusicManager; +import netneutrality.utils.MusicUtils; public class VoteSkipCommand extends AbstractMusicCommand { @Override public boolean isEnabled() { - return false; + return true; } @Override public String getCommand() { - return null; + return "voteskip"; } @Override @@ -33,11 +35,14 @@ public class VoteSkipCommand extends AbstractMusicCommand { @Override public String getDescription() { - return null; + return "Cast a vote to skip the currently playing track"; } @Override public void execute(CommandContext context) { + MusicManager manager = MusicManager.get(context.getGuild()); + MusicUtils.checkIfConnected(manager, context); + manager.voteSkip(context); } } diff --git a/src/main/java/netneutrality/db/DBController.java b/src/main/java/netneutrality/db/DBController.java index 19d0041..5168658 100644 --- a/src/main/java/netneutrality/db/DBController.java +++ b/src/main/java/netneutrality/db/DBController.java @@ -71,7 +71,7 @@ public class DBController { if (controllers.isEmpty()) loadControllers(); - ((ScheduledExecutorService) ThreadManager.getExecutor("db-keepalive", ThreadManager.ExecutorType.SCHEDULED, 5)).scheduleWithFixedDelay(() -> { + ((ScheduledExecutorService) ThreadManager.getExecutor("db-keepalive", ThreadManager.ExecutorType.SCHEDULED)).scheduleWithFixedDelay(() -> { DBController.get().query("SELECT 1;"); }, 0, 120, TimeUnit.SECONDS); } diff --git a/src/main/java/netneutrality/db/controllers/DBBlacklist.java b/src/main/java/netneutrality/db/controllers/DBBlacklist.java index c78d662..04a2d0e 100644 --- a/src/main/java/netneutrality/db/controllers/DBBlacklist.java +++ b/src/main/java/netneutrality/db/controllers/DBBlacklist.java @@ -26,6 +26,8 @@ public class DBBlacklist extends AbstractController { } + + public void delete(String word, String serverId, Consumer success) { isAlreadyBlacklisted(word, serverId, blacklisted -> { if (blacklisted >= 1) { @@ -119,18 +121,13 @@ public class DBBlacklist extends AbstractController { return output; } - @Deprecated private boolean isAlreadyBlacklisted(String word, String serverId) { - AtomicBoolean result = new AtomicBoolean(); + MTableModel table = database.prepareAndExecuteAsync("SELECT COUNT(*) FROM blacklist WHERE word = ? AND guild_id = ?", word, serverId).blocking(); + if (!table.isEmpty()) { + return ((int) table.getRowModel(0).getItem(0)) != 0; + } - database.prepareAndExecuteAsync("SELECT COUNT(*) FROM blacklist WHERE word = ? AND guild_id = ?", word, serverId).async(table -> { - if (!table.isEmpty()) { - result.set((int) table.getRowModel(0).getItem(0) != 0); - } - }); - - - return result.get(); + return false; } private void isAlreadyBlacklisted(String word, String serverId, Consumer result) { diff --git a/src/main/java/netneutrality/db/entities/AbstractEntity.java b/src/main/java/netneutrality/db/entities/AbstractEntity.java index 3a4d96a..0831784 100644 --- a/src/main/java/netneutrality/db/entities/AbstractEntity.java +++ b/src/main/java/netneutrality/db/entities/AbstractEntity.java @@ -30,13 +30,13 @@ public abstract class AbstractEntity implements EntityInterface { for (String pk : getPrimaryKeys()) { whereClause.append(pk + " = ?"); + //TODO: Fix last and if (getPrimaryKeys().length > 1) whereClause.append(" AND "); } - String sql = "SELECT * FROM " + getTableName() + " WHERE " + whereClause; - MusicBot.logger.debug(sql + " - pk: " + primaryKey); + // MusicBot.logger.debug(sql + " - pk: " + primaryKey); if (this.primaryKeys.length > 0) this.table = DBController.get().prepareAndExecuteAsync(sql, this.primaryKey, this.primaryKeys).blocking(); diff --git a/src/main/java/netneutrality/db/models/MRowModel.java b/src/main/java/netneutrality/db/models/MRowModel.java index a277bee..025d055 100644 --- a/src/main/java/netneutrality/db/models/MRowModel.java +++ b/src/main/java/netneutrality/db/models/MRowModel.java @@ -32,14 +32,34 @@ public class MRowModel { return rowIndex; } + /** + * Add an item to the row. No checks are made to match the table itself + * @param obj Object to add to the row + */ public void addColumnToRow(Object obj) { row.add(obj); } + /** + * Get a list of all objects in the row. + * @return List of objects + */ public List getRow() { return row; } + /** + *
+     * Get an item at the specified index.
+     *
+     * Example:
+     * SQL:   SELECT first,    second,    third
+     * Index:        0         1          2
+     * 
+ * + * @param index Index + * @return The object + */ public Object getItem(int index) { try { return row.get(index); diff --git a/src/main/java/netneutrality/db/models/MTableModel.java b/src/main/java/netneutrality/db/models/MTableModel.java index e69d5a4..4766908 100644 --- a/src/main/java/netneutrality/db/models/MTableModel.java +++ b/src/main/java/netneutrality/db/models/MTableModel.java @@ -67,6 +67,12 @@ public class MTableModel { return null; } + /** + * Represent a row in a table + * + * @param rowIndex The index of the row + * @return A row model + */ public MRowModel getRowModel(int rowIndex) { if (getNbRows() != 0) return rows.getRowModel(rowIndex); diff --git a/src/main/java/netneutrality/handler/LogHandler.java b/src/main/java/netneutrality/handler/LogHandler.java index 99bc553..15585e9 100644 --- a/src/main/java/netneutrality/handler/LogHandler.java +++ b/src/main/java/netneutrality/handler/LogHandler.java @@ -45,6 +45,6 @@ public class LogHandler { private static void sendMessageToChannel(CommandErrorException error) { CommandContext context = error.getCommandContext(); - context.getChannel().sendMessage(error.getMessage()).queue(); + context.reply(error.getMessage()); } } diff --git a/src/main/java/netneutrality/handler/EditHandler.java b/src/main/java/netneutrality/handler/message/EditHandler.java similarity index 71% rename from src/main/java/netneutrality/handler/EditHandler.java rename to src/main/java/netneutrality/handler/message/EditHandler.java index ad59f9a..ff3f80d 100644 --- a/src/main/java/netneutrality/handler/EditHandler.java +++ b/src/main/java/netneutrality/handler/message/EditHandler.java @@ -1,4 +1,4 @@ -package netneutrality.handler; +package netneutrality.handler.message; /* * Copyright (c) anthorob @@ -25,10 +25,12 @@ public class EditHandler extends ListenerAdapter { if (event.getAuthor().isBot()) return; - MTableModel table = DBController.get().prepareAndExecuteAsync("SELECT channel_id FROM logging WHERE guild_id = ? AND enabled = 1", event.getGuild().getId()).blocking(); + MTableModel table = DBController.get().prepareAndExecuteAsync("SELECT channel_id, guild_id FROM logging WHERE guild_id = ? AND enabled = 1", event.getGuild().getId()).blocking(); Object logChannel = table.getRowModel(0).getItem(0); - if (logChannel != null) { + Object guild = table.getRowModel(0).getItem(1); + + if (logChannel != null && guild != null) { String originalMessage = ((DBMessage) DBController.get("message")).getMessageString(event.getMessage().getId()); ((DBMessage) DBController.get("message")).logEdit(event.getMessage().getId(), event.getMessage().getContentDisplay()); @@ -38,18 +40,19 @@ public class EditHandler extends ListenerAdapter { try { editEmbed.addField("Original message", (originalMessage == null ? "Not available" : originalMessage), false); } catch (IllegalArgumentException ex) { - editEmbed.addField("Original message :", "Message too long. Check db for full message", false); + editEmbed.addField("Original message:", "Message too long.", false); } try { - editEmbed.addField("Edited to :", event.getMessage().getContentDisplay(), false); + editEmbed.addField("Edited to:", event.getMessage().getContentDisplay(), false); } catch (IllegalArgumentException ex) { - editEmbed.addField("Edited to :", "Message too long. Check db for full message", false); + editEmbed.addField("Edited to:", "Message too long.", false); } editEmbed.setFooter("ID : " + event.getMessageId(), null); editEmbed.setTimestamp(event.getMessage().getTimeCreated()); - event.getJDA().getTextChannelById(logChannel.toString()).sendMessageEmbeds(editEmbed.build()).queue(); + + event.getJDA().getGuildById((String) guild).getTextChannelById((String) logChannel).sendMessageEmbeds(editEmbed.build()).queue(); } diff --git a/src/main/java/netneutrality/handler/MessageReceivedHandler.java b/src/main/java/netneutrality/handler/message/MessageReceivedHandler.java similarity index 94% rename from src/main/java/netneutrality/handler/MessageReceivedHandler.java rename to src/main/java/netneutrality/handler/message/MessageReceivedHandler.java index 5ac58d1..f4a99a1 100644 --- a/src/main/java/netneutrality/handler/MessageReceivedHandler.java +++ b/src/main/java/netneutrality/handler/message/MessageReceivedHandler.java @@ -1,4 +1,4 @@ -package netneutrality.handler; +package netneutrality.handler.message; /* * Copyright (c) anthorob * @@ -7,6 +7,7 @@ package netneutrality.handler; */ import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.events.guild.voice.GuildVoiceLeaveEvent; import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import netneutrality.GuildManager; @@ -51,5 +52,4 @@ public class MessageReceivedHandler extends ListenerAdapter { GuildManager.getManager(guild).checkBlacklist(message, member, channel); } } - } diff --git a/src/main/java/netneutrality/http/server/ActionHandler.java b/src/main/java/netneutrality/http/server/ActionHandler.java index fc77d85..8a2a5b5 100644 --- a/src/main/java/netneutrality/http/server/ActionHandler.java +++ b/src/main/java/netneutrality/http/server/ActionHandler.java @@ -6,13 +6,13 @@ package netneutrality.http.server;/* */ import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; +import netneutrality.GuildManager; import netneutrality.MusicBot; import netneutrality.http.WebModule; import org.apache.logging.log4j.LogManager; +import org.json.JSONObject; import java.io.IOException; -import java.io.OutputStream; import java.util.Map; import java.util.TreeMap; @@ -25,6 +25,8 @@ public class ActionHandler extends AbstractHandler { if (path.equals("/actions/shutdown")) { LogManager.getLogger(MusicBot.class).info("Request to shutdown received"); sendStringResponse(exchange, "Shutting down.."); + MusicBot.shutdown(); + System.exit(0); return; } @@ -38,6 +40,37 @@ public class ActionHandler extends AbstractHandler { return; } + if (path.startsWith("/actions/settings/current/")) { + JSONObject json = new JSONObject(); + String[] args = exchange.getRequestURI().toString().split("/"); + String guild = args[args.length - 1]; + + GuildManager manager = GuildManager.getManager(MusicBot.getJDA().getGuildById(guild)); + if (manager != null) { + Map settings = manager.getSettings(); + JSONObject setting = new JSONObject(settings); + + json.put("status", "ok"); + json.put("settings", setting); + } else { + json.put("status", "error"); + } + + sendJsonResponse(exchange, json.toString()); + return; + } + + if (path.startsWith("/actions/settings/reload/")) { + TreeMap json = new TreeMap<>(); + String[] args = exchange.getRequestURI().toString().split("/"); + String guild = args[args.length - 1]; + + json.put("status", String.valueOf(GuildManager.reloadSettingsForGuild(MusicBot.getJDA().getGuildById(guild)))); + sendJsonResponse(exchange, WebModule.createJson(json)); + + return; + } + sendStringResponse(exchange, path); } diff --git a/src/main/java/netneutrality/http/server/GuildHandler.java b/src/main/java/netneutrality/http/server/GuildHandler.java index 525684b..616d4f4 100644 --- a/src/main/java/netneutrality/http/server/GuildHandler.java +++ b/src/main/java/netneutrality/http/server/GuildHandler.java @@ -14,6 +14,8 @@ import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import netneutrality.MusicBot; import netneutrality.http.WebModule; +import org.json.JSONArray; +import org.json.JSONObject; import java.io.IOException; import java.io.OutputStream; @@ -28,15 +30,67 @@ public class GuildHandler extends AbstractHandler { if (path.equals("/guilds/owner")) { - TreeMap owners = new TreeMap<>(); + JSONArray array = new JSONArray(); JDA jda = MusicBot.getJDA(); jda.getGuilds().forEach(guild -> { - owners.put(guild.getId(), guild.getOwnerId()); + JSONObject obj = new JSONObject(); + obj.put("guild_id", guild.getId()); + obj.put("owner_id", guild.getOwnerId()); + array.put(obj); }); - sendJsonResponse(exchange, WebModule.createJsonArray(owners)); + sendJsonResponse(exchange, array.toString()); + return; + + } + + if (path.startsWith("/guilds/channels/")) { + + String[] args = exchange.getRequestURI().toString().split("/"); + String guild = args[args.length - 1]; + JSONArray array = new JSONArray(); + + JDA jda = MusicBot.getJDA(); + + if (jda.getGuildById(guild) == null) { + sendStringResponse(exchange, path); + return; + } + + jda.getGuildById(guild).getTextChannels().forEach(channel -> { + JSONObject obj = new JSONObject(); + obj.put("channel_id", channel.getId()); + obj.put("channel_name", channel.getName()); + array.put(obj); + }); + + sendJsonResponse(exchange, array.toString()); + return; + + } + + if (path.startsWith("/guilds/roles/")) { + + String[] args = exchange.getRequestURI().toString().split("/"); + String guild = args[args.length - 1]; + JSONArray array = new JSONArray(); + JDA jda = MusicBot.getJDA(); + + if (jda.getGuildById(guild) == null) { + sendStringResponse(exchange, path); + return; + } + + jda.getGuildById(guild).getRoles().forEach(role -> { + JSONObject obj = new JSONObject(); + obj.put("channel_id", role.getId()); + obj.put("channel_name", role.getName()); + array.put(obj); + }); + + sendJsonResponse(exchange, array.toString()); return; } diff --git a/src/main/java/netneutrality/http/server/WebApi.java b/src/main/java/netneutrality/http/server/WebApi.java index 13da7b1..9d4c268 100644 --- a/src/main/java/netneutrality/http/server/WebApi.java +++ b/src/main/java/netneutrality/http/server/WebApi.java @@ -8,7 +8,7 @@ package netneutrality.http.server; */ import com.sun.net.httpserver.HttpServer; -import netneutrality.thread.BaseThread; +import netneutrality.thread.BaseThreadFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,7 +21,7 @@ import java.util.concurrent.Executors; public class WebApi { private final static Logger logger = LoggerFactory.getLogger(WebApi.class); - private final ExecutorService executor = Executors.newFixedThreadPool(10, new BaseThread("web-api")); + private final ExecutorService executor = Executors.newFixedThreadPool(10, new BaseThreadFactory("web-api")); private final int port = 9000; private HttpServer server; diff --git a/src/main/java/netneutrality/music/LoadResultHandler.java b/src/main/java/netneutrality/music/LoadResultHandler.java index 22c3a6a..de6456d 100644 --- a/src/main/java/netneutrality/music/LoadResultHandler.java +++ b/src/main/java/netneutrality/music/LoadResultHandler.java @@ -24,11 +24,16 @@ public class LoadResultHandler implements AudioLoadResultHandler { private final boolean silent; public LoadResultHandler(String identifier, TextChannel channel, Member user, TrackScheduler scheduler, boolean silent) { + if (user == null) + silent = true; + this.identifier = identifier; this.channel = channel; this.user = user; this.scheduler = scheduler; this.silent = silent; + + } @Override @@ -37,7 +42,7 @@ public class LoadResultHandler implements AudioLoadResultHandler { channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(audioTrack, user, identifier)).queue(); } - scheduler.queue(audioTrack); + scheduler.queue(audioTrack, user); } @Override @@ -46,12 +51,15 @@ public class LoadResultHandler implements AudioLoadResultHandler { if (identifier.startsWith("ytsearch:")) { AudioTrack track = audioPlaylist.getTracks().get(0); - channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(track, user, String.format("https://youtu.be/%s", track.getIdentifier()))).queue(); - scheduler.queue(track); + if (!silent) + channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(track, user, String.format("https://youtu.be/%s", track.getIdentifier()))).queue(); + + scheduler.queue(track, user); } else { - channel.sendMessageEmbeds(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, user, identifier)).queue(); + if (!silent) + channel.sendMessageEmbeds(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, user, identifier)).queue(); for (AudioTrack track : audioPlaylist.getTracks()) { - scheduler.queue(track); + scheduler.queue(track, user); } } } diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index f33eaec..77424b8 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -23,8 +23,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.List; import java.util.Map; -import java.util.concurrent.BlockingQueue; +import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -32,8 +33,9 @@ import java.util.concurrent.TimeUnit; public class MusicManager { private final static Logger logger = LoggerFactory.getLogger(MusicManager.class); - private final Guild guild; private final static AudioPlayerManager playerManager = new DefaultAudioPlayerManager(); + + private final Guild guild; private final AudioPlayer player; private final TrackScheduler scheduler; private final static Map managers = new ConcurrentHashMap<>(); @@ -47,9 +49,6 @@ public class MusicManager { player.addListener(scheduler); player.setVolume(15); - AudioSourceManagers.registerRemoteSources(playerManager); - AudioSourceManagers.registerLocalSource(playerManager); - managers.put(guild.getId(), this); } @@ -61,6 +60,10 @@ public class MusicManager { } } + public static void registerSources() { + AudioSourceManagers.registerRemoteSources(playerManager); + } + public boolean isConnectedTo(VoiceChannel vChannel) { return vChannel != null && vChannel.equals(guild.getAudioManager().getConnectedChannel()); } @@ -69,7 +72,7 @@ public class MusicManager { if (vChannel != null && !isConnectedTo(vChannel)) { guild.getAudioManager().openAudioConnection(vChannel); - ((ScheduledExecutorService) ThreadManager.getExecutor("music", ThreadManager.ExecutorType.SCHEDULED, 5)).scheduleWithFixedDelay(() -> { + ((ScheduledExecutorService) ThreadManager.getExecutor("music", ThreadManager.ExecutorType.SCHEDULED)).scheduleWithFixedDelay(() -> { if ((getCurrentlyPlaying() == null && scheduler.getQueue().isEmpty()) || vChannel.getMembers().size() == 0) { leave(); } @@ -84,18 +87,23 @@ public class MusicManager { return guild != null && guild.getAudioManager().getConnectedChannel() != null; } - public synchronized AudioTrack getCurrentlyPlaying() { + public AudioTrack getCurrentlyPlaying() { return player.getPlayingTrack(); } - public synchronized void leave() { + public Member getRequesterOfCurrentTrack() { + TrackScheduler.TrackInfo info = scheduler.getQueue().peek(); + return info.getRequester(); + } + + public void leave() { if (isConnected()) { player.stopTrack(); guild.getAudioManager().closeAudioConnection(); } scheduler.resetTopic(); - + System.out.println(scheduler.getQueue().size()); } public static void disconnectPlayers() { @@ -106,6 +114,12 @@ public class MusicManager { } } + public boolean restoreQueue(List track) { + + + return false; + } + public void play(String url, CommandContext context, boolean needToBeConnected, boolean silent) { Member member = context.getGuildUser(); TextChannel channel = context.getChannel(); @@ -139,15 +153,49 @@ public class MusicManager { } } - public synchronized void skip() { + public void skip(int nbTrack) { if (!scheduler.getQueue().isEmpty()) { - scheduler.nextTrack(); + if (nbTrack >= scheduler.getQueue().size()) { + nbTrack = 1; + } + + scheduler.skipAndPlay(nbTrack); } else { leave(); } } - public synchronized void setVolume(int volume) { + public void voteSkip(CommandContext context) { + Queue queue = scheduler.getQueue(); + VoiceChannel voiceChannel = guild.getAudioManager().getConnectedChannel(); + + if (getCurrentlyPlaying() == null) { + return; + } + + // Minus the bot itself + int connected = voiceChannel.getMembers().size() - 1; + if (connected > 2) { + TrackScheduler.TrackInfo info = queue.peek(); + + double needed = connected / 2.1; + + if (info != null) { + info.toggleSkip(context.getGuildUser()); + + if (info.getSkips().size() > needed) { + skip(1); + } else { + context.reply(String.format("Current skips: %d/%f", info.getSkips().size(), Math.ceil(needed))); + } + } + + } else { + skip(1); + } + } + + public void setVolume(int volume) { player.setVolume(volume); } @@ -155,14 +203,11 @@ public class MusicManager { return scheduler; } - public ArrayList getAllQueuedTrack() { - ArrayList queuedTracks = new ArrayList<>(); - BlockingQueue queue = scheduler.getQueue(); + public ArrayList getAllQueuedTrack() { + ArrayList tracks = new ArrayList<>(); + Queue queue = scheduler.getQueue(); - queue.forEach((a) -> { - queuedTracks.add(a.getInfo().title); - }); - - return queuedTracks; + queue.forEach(trackInfo -> tracks.add(trackInfo.getTrack())); + return tracks; } } diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index c60b2e1..ce17c4b 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -12,68 +12,131 @@ import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter; import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason; +import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.TextChannel; -import java.util.concurrent.BlockingQueue; +import java.util.*; import java.util.concurrent.LinkedBlockingQueue; public class TrackScheduler extends AudioEventAdapter { + class TrackInfo { + + private final AudioTrack track; + private final Member member; + private final Set skips; + + public TrackInfo(AudioTrack track, Member member) { + this.track = track; + this.member = member; + this.skips = new HashSet<>(); + } + + public AudioTrack getTrack() { + return track; + } + + public Set getSkips() { + return skips; + } + + public void toggleSkip(Member member) { + if (!hasSkip(member)) + skips.add(member.getId()); + else + skips.remove(member.getId()); + } + + public boolean hasSkip(Member member) { + return skips.contains(member.getId()); + } + + public Member getRequester() { + return member; + } + } + + private final Object topicLock = new Object(); private final AudioPlayer player; + private final Queue queue; private TextChannel channel; - private final BlockingQueue queue; - public String topic; + private String originalTopic; public TrackScheduler(AudioPlayer player) { this.player = player; this.queue = new LinkedBlockingQueue<>(); } - public void queue(AudioTrack track) { + public void queue(AudioTrack track, Member member) { // Calling startTrack with the noInterrupt set to true will start the track only if nothing is currently playing. If // something is playing, it returns false and does nothing. In that case the player was already playing so this // track goes to the queue instead. - boolean start = player.startTrack(track, true); + queue.offer(new TrackInfo(track, member)); - if (!start) { - queue.offer(track); + if (player.getPlayingTrack() == null) { + player.startTrack(track, true); } } - public void setTextChannel(TextChannel channel) { - this.channel = channel; - - if (topic == null) { - topic = channel.getTopic(); + public String getOriginalTopic() { + synchronized (topicLock) { + return originalTopic; } - } public TextChannel getTextChannel() { return channel; } - public BlockingQueue getQueue() { + public void setTextChannel(TextChannel channel) { + this.channel = channel; + + synchronized (topicLock) { + if (originalTopic == null) { + originalTopic = channel.getTopic(); + } + } + + } + + public void resetTextChannel() { + this.channel = null; + } + + public Queue getQueue() { return queue; } public void resetTopic() { - if (channel != null && (topic != null && !topic.equals(""))) { - //channel.getManager().setTopic(topic).queue(); + synchronized (topicLock) { + if (channel != null && (originalTopic != null && !originalTopic.equals(""))) { + //channel.getManager().setTopic(topic).queue(); + } + + originalTopic = null; } - topic = ""; } - /** - * Start the next track, stopping the current one if it is playing. - */ - public void nextTrack() { - // Start the next track, regardless of if something is already playing or not. In case queue was empty, we are - // giving null to startTrack, which is a valid argument and will simply stop the player. - AudioTrack track = queue.poll(); - if (track != null) { - player.startTrack(track, false); + public void nextTrack(AudioPlayer player) { + TrackInfo last = queue.poll(); + + if (queue.peek() != null) { + player.startTrack(queue.peek().getTrack(), false); + } + } + + public void skipAndPlay(int nb) { + if (nb == 0) + return; + + for (int i = 0; i < nb; i++) { + TrackInfo last = queue.poll(); + } + + TrackInfo current = queue.peek(); + if (current != null) { + player.startTrack(current.getTrack(), false); } } @@ -99,7 +162,9 @@ public class TrackScheduler extends AudioEventAdapter { resetTopic(); if (endReason.mayStartNext) { - nextTrack(); + nextTrack(player); + } else { + queue.poll(); } // endReason == FINISHED: A track finished or died by an exception (mayStartNext = true). @@ -119,6 +184,6 @@ public class TrackScheduler extends AudioEventAdapter { @Override public void onTrackStuck(AudioPlayer player, AudioTrack track, long thresholdMs) { resetTopic(); - nextTrack(); + nextTrack(player); } } diff --git a/src/main/java/netneutrality/thread/BaseThread.java b/src/main/java/netneutrality/thread/BaseThreadFactory.java similarity index 87% rename from src/main/java/netneutrality/thread/BaseThread.java rename to src/main/java/netneutrality/thread/BaseThreadFactory.java index 0c00b7f..75a6f5a 100644 --- a/src/main/java/netneutrality/thread/BaseThread.java +++ b/src/main/java/netneutrality/thread/BaseThreadFactory.java @@ -11,12 +11,12 @@ import org.jetbrains.annotations.NotNull; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicLong; -public class BaseThread implements ThreadFactory { +public class BaseThreadFactory implements ThreadFactory { private final AtomicLong threadId = new AtomicLong(1); private final String name; - public BaseThread(String name) { + public BaseThreadFactory(String name) { this.name = name; } diff --git a/src/main/java/netneutrality/thread/ShutdownThread.java b/src/main/java/netneutrality/thread/ShutdownThread.java new file mode 100644 index 0000000..34b92ba --- /dev/null +++ b/src/main/java/netneutrality/thread/ShutdownThread.java @@ -0,0 +1,28 @@ +package netneutrality.thread;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import netneutrality.MusicBot; +import netneutrality.utils.UnsafeShutdown; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.Configurator; + +public class ShutdownThread implements Runnable { + + @Override + public void run() { + if (LogManager.getContext() instanceof LoggerContext) { + System.out.println("Shutting down log4j2"); + Configurator.shutdown((LoggerContext) LogManager.getContext()); + } + + MusicBot.shutdown(); + if (!UnsafeShutdown.SAFE) { + //UnsafeShutdown.saveState(); + } + } +} diff --git a/src/main/java/netneutrality/utils/ChannelFunction.java b/src/main/java/netneutrality/utils/ChannelFunction.java index a859f9e..4cb37b1 100644 --- a/src/main/java/netneutrality/utils/ChannelFunction.java +++ b/src/main/java/netneutrality/utils/ChannelFunction.java @@ -17,7 +17,7 @@ public class ChannelFunction { if (toDelete >= 2500) return; - ThreadManager.getExecutor("bulk-delete", ThreadManager.ExecutorType.FIXED, 5).submit(() -> { + ThreadManager.getExecutor("bulk-delete", ThreadManager.ExecutorType.FIXED).submit(() -> { int toDeleteFinal = toDelete + 1; int iteration = toDeleteFinal / 100; diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index aa2684b..d198d13 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -69,6 +69,7 @@ public class MessageFunction { message.setTitle("Currently playing:"); message.setColor(Color.BLUE); message.addField("Track title: ", current.getInfo().title, false); + message.addField("Uploaded by: ", current.getInfo().author, false); message.addField("Duration: ", DurationFormatUtils.formatDuration(current.getPosition(), "**HH:mm:ss**", true) + " / " + DurationFormatUtils.formatDuration(current.getDuration(), "**HH:mm:ss**", true), false); message.setFooter("Requested by " + user.getUser().getName(), user.getUser().getAvatarUrl()); message.setTimestamp(OffsetDateTime.now()); @@ -83,6 +84,7 @@ public class MessageFunction { message.setTitle("Adding track to queue.."); message.setColor(Color.BLUE); message.addField("Track title: ", track.getInfo().title, false); + message.addField("Uploaded by: ", track.getInfo().author, false); message.addField("Duration: ", DurationFormatUtils.formatDuration(track.getDuration(), "**HH:mm:ss**", true), false); message.setFooter("Requested by " + user.getUser().getName(), user.getUser().getAvatarUrl()); message.setTimestamp(OffsetDateTime.now()); @@ -105,17 +107,20 @@ public class MessageFunction { } public static MessageEmbed buildViewQueueMessage(MusicManager manager, Member user) { - ArrayList tracks = manager.getAllQueuedTrack(); + ArrayList tracks = manager.getAllQueuedTrack(); AudioTrack current = manager.getCurrentlyPlaying(); EmbedBuilder message = new EmbedBuilder(); message.setTitle("Current queue (showing max 10 items):"); message.setColor(Color.BLUE); - message.addField("Track #1 (Currently playing)", current.getInfo().title, false); - int index = 1; - for (String track: tracks) { - message.addField("Track #" + ++index, track, false); + int index = 0; + for (AudioTrack track: tracks) { + if (track.getInfo().title.equals(current.getInfo().title)) { + message.addField("Track #" + ++index + " (Currently playing)", track.getInfo().title, false); + } else { + message.addField("Track #" + ++index, track.getInfo().title, false); + } if (index == 10) break; } @@ -136,8 +141,9 @@ public class MessageFunction { if (command.getType() == null) continue; - String usage = "None"; + String usage = "(no arguments required)"; String description = "No description yet"; + StringBuilder availAlias = new StringBuilder(); if (command.isEnabled() && command.getType() != CommandType.UNLISTED) { if (command.getType() == CommandType.ADMINISTRATION && !admin) @@ -149,6 +155,18 @@ public class MessageFunction { if (command.getDescription() != null) description = command.getDescription(); + if (command.getAlias() != null && command.getAlias().length > 0) { + availAlias.append("("); + for (String str : command.getAlias()) { + availAlias.append(str).append(","); + } + + if (!availAlias.isEmpty()) { + availAlias.deleteCharAt(availAlias.lastIndexOf(",")); + availAlias.append(")"); + } + } + EmbedBuilder message; if (help.containsKey(command.getType())) { message = help.get(command.getType()); @@ -161,7 +179,7 @@ public class MessageFunction { message.setColor(Color.GREEN); } - message.addField(Settings.getInstance().get("BOT_PREFIX") + command.getCommand() + " - Arguments: " + usage, description, false); + message.addField(String.format("%s%s %s %s", Settings.getInstance().get("BOT_PREFIX"), command.getCommand(), availAlias, usage), description, false); } } diff --git a/src/main/java/netneutrality/utils/UnsafeShutdown.java b/src/main/java/netneutrality/utils/UnsafeShutdown.java new file mode 100644 index 0000000..1b2d719 --- /dev/null +++ b/src/main/java/netneutrality/utils/UnsafeShutdown.java @@ -0,0 +1,62 @@ +package netneutrality.utils;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + + +import netneutrality.GuildManager; +import netneutrality.music.MusicManager; +import netneutrality.music.TrackScheduler; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Map; + +public class UnsafeShutdown { + public static boolean SAFE = false; + + //TODO: finish + private static void saveGuildsState() { + Map managers = GuildManager.getManagers(); + + for (GuildManager manager : managers.values()) { + File state = new File("state.json"); + + try { + if (!state.exists()) { + state.createNewFile(); + } + + FileWriter writer = new FileWriter(state); + JSONArray array = new JSONArray(); + + + + MusicManager musicManager = MusicManager.get(manager.getGuild()); + TrackScheduler trackScheduler = musicManager.getScheduler(); + + JSONObject music = new JSONObject(); + + music.put("current_channel", ""); + music.put("current_topic", ""); + music.put("current_topic", ""); + } catch (IOException e) { + e.printStackTrace(); + } + + + + + } + } + + public static void saveState() { + saveGuildsState(); + } +}