diff --git a/src/main/java/netneutrality/NetNeutrality.java b/src/main/java/netneutrality/NetNeutrality.java index 5d13e51..80e804d 100644 --- a/src/main/java/netneutrality/NetNeutrality.java +++ b/src/main/java/netneutrality/NetNeutrality.java @@ -58,6 +58,7 @@ public class NetNeutrality { } public static void initJDA() { + // When upgrading JDA -> GatewayIntent.MESSAGE_CONTENT try { jda = JDABuilder .createDefault(Settings.getInstance().get("BOT_TOKEN")) diff --git a/src/main/java/netneutrality/command/AbstractMusicCommand.java b/src/main/java/netneutrality/command/AbstractMusicCommand.java index 2c1a991..44bbf20 100644 --- a/src/main/java/netneutrality/command/AbstractMusicCommand.java +++ b/src/main/java/netneutrality/command/AbstractMusicCommand.java @@ -11,6 +11,7 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Role; import net.dv8tion.jda.api.entities.TextChannel; import netneutrality.core.GuildManager; +import netneutrality.db.GSettings; import netneutrality.utils.UserFunction; public abstract class AbstractMusicCommand extends AbstractCommand { @@ -27,7 +28,7 @@ public abstract class AbstractMusicCommand extends AbstractCommand { @Override public boolean canBeExecutedBy(Guild guild, Member member) { - String roleDb = GuildManager.getManager(guild).getSetting(GuildManager.GSettings.MUSIC_ROLE); + String roleDb = GuildManager.getManager(guild).getSetting(GSettings.MUSIC_ROLE); if (roleDb != null && !roleDb.isEmpty()) { if (UserFunction.isAdmin(member)) { @@ -37,7 +38,7 @@ public abstract class AbstractMusicCommand extends AbstractCommand { Role neededRole = guild.getRoleById(roleDb); if (neededRole == null) { // Role doesn't exist on guild anymore, remove from db - GuildManager.getManager(guild).setSettingValue(GuildManager.GSettings.MUSIC_ROLE, null); + GuildManager.getManager(guild).setSettingValue(GSettings.MUSIC_ROLE, null); return true; } @@ -49,7 +50,7 @@ public abstract class AbstractMusicCommand extends AbstractCommand { @Override public boolean canBeExecutedFrom(Guild guild, TextChannel channel) { - String channelDb = GuildManager.getManager(guild).getSetting(GuildManager.GSettings.MUSIC_CHANNEL); + String channelDb = GuildManager.getManager(guild).getSetting(GSettings.MUSIC_CHANNEL); if (channelDb != null && !channelDb.isEmpty()) { return channelDb.equals(channel.getId()); diff --git a/src/main/java/netneutrality/command/bot/ConfigureCommand.java b/src/main/java/netneutrality/command/bot/ConfigureCommand.java index 85dcd45..a038154 100644 --- a/src/main/java/netneutrality/command/bot/ConfigureCommand.java +++ b/src/main/java/netneutrality/command/bot/ConfigureCommand.java @@ -13,6 +13,7 @@ import netneutrality.command.CommandType; import netneutrality.command.CommandUsage; import netneutrality.core.GuildManager; import netneutrality.core.context.CommandContext; +import netneutrality.db.GSettings; import netneutrality.music.MusicManager; import java.util.Arrays; @@ -66,7 +67,7 @@ public class ConfigureCommand extends AbstractCommand { // Role for music commands if (context.getArgument(0).equals("music-role")) { if (args.length == 1) { - String roleDb = guildManager.getSetting(GuildManager.GSettings.MUSIC_ROLE); + String roleDb = guildManager.getSetting(GSettings.MUSIC_ROLE); Role role = null; if (!roleDb.isEmpty()) { role = context.getGuild().getRoleById(roleDb); @@ -78,8 +79,8 @@ public class ConfigureCommand extends AbstractCommand { if (args.length == 2) { if (context.getArgument(1).equals("reset")) { - if (!guildManager.getSetting(GuildManager.GSettings.MUSIC_ROLE).isEmpty()) { - guildManager.setSettingValue(GuildManager.GSettings.MUSIC_ROLE, null); + if (!guildManager.getSetting(GSettings.MUSIC_ROLE).isEmpty()) { + guildManager.setSettingValue(GSettings.MUSIC_ROLE, null); } context.reply("Successful reset of the role"); @@ -89,7 +90,7 @@ public class ConfigureCommand extends AbstractCommand { if (roles.size() == 1) { Role role = roles.get(0); if (role.getGuild().getId().equals(context.getGuild().getId())) { - guildManager.setSettingValue(GuildManager.GSettings.MUSIC_ROLE, role.getId()); + guildManager.setSettingValue(GSettings.MUSIC_ROLE, role.getId()); context.reply("Successfully set %s as the role needed for music command", role.getAsMention()); } } @@ -99,7 +100,7 @@ public class ConfigureCommand extends AbstractCommand { // Role for music commands if (context.getArgument(0).equals("music-channel")) { if (args.length == 1) { - String channelDb = guildManager.getSetting(GuildManager.GSettings.MUSIC_CHANNEL); + String channelDb = guildManager.getSetting(GSettings.MUSIC_CHANNEL); TextChannel channel = null; if (!channelDb.isEmpty()) { channel = context.getGuild().getTextChannelById(channelDb); @@ -111,8 +112,8 @@ public class ConfigureCommand extends AbstractCommand { if (args.length == 2) { if (context.getArgument(1).equals("reset")) { - if (!guildManager.getSetting(GuildManager.GSettings.MUSIC_CHANNEL).isEmpty()) { - guildManager.setSettingValue(GuildManager.GSettings.MUSIC_CHANNEL, null); + if (!guildManager.getSetting(GSettings.MUSIC_CHANNEL).isEmpty()) { + guildManager.setSettingValue(GSettings.MUSIC_CHANNEL, null); } context.reply("Successful reset of the channel"); @@ -122,7 +123,7 @@ public class ConfigureCommand extends AbstractCommand { if (channels.size() == 1) { TextChannel channel = channels.get(0); if (channel.getGuild().getId().equals(context.getGuild().getId())) { - guildManager.setSettingValue(GuildManager.GSettings.MUSIC_CHANNEL, channel.getId()); + guildManager.setSettingValue(GSettings.MUSIC_CHANNEL, channel.getId()); context.reply("Successfully set %s as the channel required to execute music command", channel.getAsMention()); } } @@ -132,7 +133,7 @@ public class ConfigureCommand extends AbstractCommand { // Default volume for music player if (context.getArgument(0).equals("music-volume")) { if (args.length == 1) { - int volume = Integer.parseInt(guildManager.getSetting(GuildManager.GSettings.MUSIC_VOLUME)); + int volume = Integer.parseInt(guildManager.getSetting(GSettings.MUSIC_VOLUME)); context.reply("Default volume for music player: %d", volume); context.reply("Set using 'conf music-volume '"); @@ -143,7 +144,7 @@ public class ConfigureCommand extends AbstractCommand { int volume = Integer.parseInt(args[1]); if (volume > 0 && volume <= 100) { - guildManager.setSettingValue(GuildManager.GSettings.MUSIC_VOLUME, String.valueOf(volume)); + guildManager.setSettingValue(GSettings.MUSIC_VOLUME, String.valueOf(volume)); MusicManager.get(context.getGuild()).setVolume(volume); context.reply("Default volume for music player is now %d", volume); @@ -159,7 +160,7 @@ public class ConfigureCommand extends AbstractCommand { // Music topic change if (context.getArgument(0).equals("music-topic")) { if (args.length == 1) { - boolean enabled = "1".equals(guildManager.getSetting(GuildManager.GSettings.MUSIC_TOPIC)); + boolean enabled = "1".equals(guildManager.getSetting(GSettings.MUSIC_TOPIC)); context.reply("Set currently playing track in text channel topic: %s", (enabled ? "enabled" : "disabled")); context.reply("Use 'conf music-topic 0/1' to toggle between states (0 = disabled, 1 = enabled)."); @@ -167,9 +168,9 @@ public class ConfigureCommand extends AbstractCommand { if (args.length == 2) { String str = args[1]; - boolean enabled = "1".equals(guildManager.getSetting(GuildManager.GSettings.MUSIC_TOPIC)); + boolean enabled = "1".equals(guildManager.getSetting(GSettings.MUSIC_TOPIC)); if (str.equals("0") || str.equals("1")) { - guildManager.setSettingValue(GuildManager.GSettings.MUSIC_TOPIC, str); + guildManager.setSettingValue(GSettings.MUSIC_TOPIC, str); enabled = "1".equals(str); } @@ -209,7 +210,7 @@ public class ConfigureCommand extends AbstractCommand { String allowedPrefixes = "!$%?&*"; if (args.length == 1) { - String prefix = guildManager.getSetting(GuildManager.GSettings.PREFIX); + String prefix = guildManager.getSetting(GSettings.PREFIX); context.reply("Current prefix for commands: '%s'", prefix); context.reply("Allowed prefixes: %s", Arrays.toString(allowedPrefixes.toCharArray())); @@ -220,7 +221,7 @@ public class ConfigureCommand extends AbstractCommand { String prefix = args[1].trim(); if (prefix.length() == 1 && allowedPrefixes.contains(prefix)) { - guildManager.setSettingValue(GuildManager.GSettings.PREFIX, prefix); + guildManager.setSettingValue(GSettings.PREFIX, prefix); context.reply("Prefix for commands is now '%s'", prefix); } else { diff --git a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java index f9a907e..f94fafb 100644 --- a/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/BitcoinPriceCommand.java @@ -15,7 +15,6 @@ import netneutrality.http.WebModule; import org.json.JSONException; import org.json.JSONObject; -import java.io.IOException; import java.text.NumberFormat; import java.util.Locale; diff --git a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java index 1706b26..be13696 100644 --- a/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/CryptoPriceCommand.java @@ -15,7 +15,6 @@ import netneutrality.http.WebModule; import org.json.JSONException; import org.json.JSONObject; -import java.io.IOException; import java.text.NumberFormat; import java.util.Locale; diff --git a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java index 214813f..6e7c768 100644 --- a/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/EthereumPriceCommand.java @@ -15,7 +15,6 @@ import netneutrality.http.WebModule; import org.json.JSONException; import org.json.JSONObject; -import java.io.IOException; import java.text.NumberFormat; import java.util.Locale; diff --git a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java index 662d120..bf33780 100644 --- a/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java +++ b/src/main/java/netneutrality/command/crypto/LitecoinPriceCommand.java @@ -15,7 +15,6 @@ import netneutrality.http.WebModule; import org.json.JSONException; import org.json.JSONObject; -import java.io.IOException; import java.text.NumberFormat; import java.util.Locale; diff --git a/src/main/java/netneutrality/core/BotState.java b/src/main/java/netneutrality/core/BotState.java new file mode 100644 index 0000000..dd06023 --- /dev/null +++ b/src/main/java/netneutrality/core/BotState.java @@ -0,0 +1,79 @@ +package netneutrality.core;/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + + +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import net.dv8tion.jda.api.entities.TextChannel; +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.util.Map; + +public class BotState { + public static boolean SAFE = false; + + //TODO: is it needed? + private static void saveGuildsState() { + Map managers = GuildManager.getManagers(); + + JSONObject main = new JSONObject(); + JSONArray guildsArray = new JSONArray(); + + for (GuildManager manager : managers.values()) { + MusicManager musicManager = MusicManager.get(manager.getGuild()); + TrackScheduler trackScheduler = musicManager.getScheduler(); + + JSONObject guild = new JSONObject(); + JSONObject music = new JSONObject(); + guild.put("id", manager.getGuild().getId()); + + TextChannel currentChannel = trackScheduler.getTextChannel(); + if (currentChannel == null) { + music.put("current_channel", "null"); + } else { + music.put("current_channel", currentChannel.getId()); + } + + guild.put("music", music); + + guildsArray.put(guild); + } + + main.put("guilds", guildsArray); + + File state = new File("state.json"); + try { + if (!state.exists()) { + state.createNewFile(); + } + + try (FileWriter writer = new FileWriter(state)) { + writer.write(main.toString()); + } + + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void dump() { + if (!SAFE) { + saveGuildsState(); + } + } +} diff --git a/src/main/java/netneutrality/core/GuildManager.java b/src/main/java/netneutrality/core/GuildManager.java index 877debf..63e951d 100644 --- a/src/main/java/netneutrality/core/GuildManager.java +++ b/src/main/java/netneutrality/core/GuildManager.java @@ -12,6 +12,7 @@ import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.TextChannel; import netneutrality.NetNeutrality; import netneutrality.db.DBController; +import netneutrality.db.GSettings; import netneutrality.db.controllers.DBMessage; import netneutrality.db.entities.OBlacklist; import netneutrality.db.entities.OGuild; @@ -21,7 +22,6 @@ import netneutrality.handler.ratelimiter.MessageRateLimiterImpl; import netneutrality.thread.ThreadManager; import netneutrality.utils.JpaUtils; import netneutrality.utils.MessageFunction; -import netneutrality.utils.Settings; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.slf4j.Logger; @@ -35,31 +35,6 @@ import java.util.concurrent.ConcurrentHashMap; public class GuildManager { - public enum GSettings { - PREFIX("PREFIX", Settings.getInstance().get("BOT_PREFIX", "$")), - MUSIC_ROLE("MUSIC_ROLE", ""), - MUSIC_CHANNEL("MUSIC_CHANNEL", ""), - MUSIC_VOLUME("MUSIC_VOLUME", "30"), - MUSIC_TOPIC("MUSIC_TOPIC", "0"), - BLACKLIST_CHANNELS("BLACKLIST_EXCLUDE_CHANNELS", ""); - - private final String name; - private final String defaultValue; - - GSettings(String name, String defaultValue) { - this.name = name; - this.defaultValue = defaultValue; - } - - public String getName() { - return name; - } - - public String getDefaultValue() { - return defaultValue; - } - } - private static final Logger logger = LoggerFactory.getLogger(GuildManager.class); private static final Map managers = new ConcurrentHashMap<>(); private static final SessionFactory sessionFactory = SessionManager.getSessionFactory(); diff --git a/src/main/java/netneutrality/core/LogHandler.java b/src/main/java/netneutrality/core/LogHandler.java index 1319974..2165707 100644 --- a/src/main/java/netneutrality/core/LogHandler.java +++ b/src/main/java/netneutrality/core/LogHandler.java @@ -7,9 +7,11 @@ package netneutrality.core; */ import io.sentry.Sentry; +import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.TextChannel; import netneutrality.core.context.CommandContext; import netneutrality.exceptions.CommandErrorException; +import netneutrality.exceptions.CommandException; import netneutrality.exceptions.CommandExecutionException; import netneutrality.utils.MessageFunction; import org.slf4j.Logger; @@ -27,15 +29,19 @@ public class LogHandler { public static void log(Exception e) { if (e instanceof CommandErrorException) { sendMessageToChannel((CommandErrorException) e); - } else if (e instanceof CommandExecutionException) { + logInternally((CommandErrorException) e); + return; + } + + if (e instanceof CommandExecutionException) { Sentry.captureException(e); logInternally((CommandExecutionException) e); tryLogToDebugChannel((CommandExecutionException) e); - } else { - Sentry.captureException(e); - logger.error(e.getMessage(), e); + return; } + Sentry.captureException(e); + logger.error(e.getMessage(), e); } public static void log(String s, Exception e) { @@ -47,12 +53,22 @@ public class LogHandler { log((Exception) e); } - private static void logInternally(CommandExecutionException error) { + public static void sendMessageToDebugChannel(Guild guild, String message) { + if (GuildManager.getManager(guild).isDebugEnabled()) { + guild.getTextChannels() + .stream() + .filter(textChannel -> textChannel.getName().equals("debug") || textChannel.getName().equals("log")) + .filter(TextChannel::canTalk) + .forEach(textChannel -> textChannel.sendMessage(message).queue()); + } + } + + private static void logInternally(CommandException error) { CommandContext context = error.getCommandContext(); logger.error("Exception thrown from command [{}] in guild [{}]: {}", context.getCommand().getCommandName(), context.getGuild().getId(), error.getMessage(), error); } - private static void tryLogToDebugChannel(CommandExecutionException error) { + private static void tryLogToDebugChannel(CommandException error) { CommandContext context = error.getCommandContext(); if (context.getGuild() != null) { @@ -65,12 +81,10 @@ public class LogHandler { .forEach(textChannel -> textChannel.sendMessageEmbeds(MessageFunction.buildDebugMessage(context, error)).queue()); } } - } private static void sendMessageToChannel(CommandErrorException error) { CommandContext context = error.getCommandContext(); - logger.error("Exception thrown from command [{}] in guild [{}]: {}", context.getCommand().getCommandName(), context.getGuild().getId(), error.getMessage()); context.reply(error.getMessage()); } } diff --git a/src/main/java/netneutrality/core/SessionManager.java b/src/main/java/netneutrality/core/SessionManager.java index 69e990d..249f459 100644 --- a/src/main/java/netneutrality/core/SessionManager.java +++ b/src/main/java/netneutrality/core/SessionManager.java @@ -47,7 +47,10 @@ public class SessionManager { sessionFactory = metadata.getSessionFactoryBuilder().build(); } catch (Exception e) { - Sentry.captureException(e); + String env = Settings.getInstance().get("BOT_ENV", "dev"); + if (!"dev".equals(env)) { + Sentry.captureException(e); + } shutdown(); logger.error("Error connecting to database. Shutting down..", e); diff --git a/src/main/java/netneutrality/core/UnsafeShutdown.java b/src/main/java/netneutrality/core/UnsafeShutdown.java deleted file mode 100644 index 9b5e016..0000000 --- a/src/main/java/netneutrality/core/UnsafeShutdown.java +++ /dev/null @@ -1,67 +0,0 @@ -package netneutrality.core;/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - - -/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -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.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(); - } -} diff --git a/src/main/java/netneutrality/core/context/CommandContext.java b/src/main/java/netneutrality/core/context/CommandContext.java index 4173d53..40d3395 100644 --- a/src/main/java/netneutrality/core/context/CommandContext.java +++ b/src/main/java/netneutrality/core/context/CommandContext.java @@ -156,6 +156,10 @@ public class CommandContext { } } + public void replyToMessage(String format, Object... arguments) { + replyToMessage(String.format(format, arguments)); + } + public void replyToMessage(Message msg) { if (channel != null && channel.canTalk() && message != null) { message.reply(msg).queue(); diff --git a/src/main/java/netneutrality/db/GSettings.java b/src/main/java/netneutrality/db/GSettings.java new file mode 100644 index 0000000..8ec59c0 --- /dev/null +++ b/src/main/java/netneutrality/db/GSettings.java @@ -0,0 +1,36 @@ +package netneutrality.db; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + + +import netneutrality.utils.Settings; + +public enum GSettings { + //TODO: description + PREFIX("PREFIX", Settings.getInstance().get("BOT_PREFIX", "$")), + MUSIC_ROLE("MUSIC_ROLE", ""), + MUSIC_CHANNEL("MUSIC_CHANNEL", ""), + MUSIC_VOLUME("MUSIC_VOLUME", "30"), + MUSIC_TOPIC("MUSIC_TOPIC", "0"), + BLACKLIST_CHANNELS("BLACKLIST_EXCLUDE_CHANNELS", ""); + + private final String name; + private final String defaultValue; + + GSettings(String name, String defaultValue) { + this.name = name; + this.defaultValue = defaultValue; + } + + public String getName() { + return name; + } + + public String getDefaultValue() { + return defaultValue; + } +} diff --git a/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java b/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java index 4816ff6..62bb276 100644 --- a/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java +++ b/src/main/java/netneutrality/handler/hooks/message/MessageReceivedHandler.java @@ -15,6 +15,7 @@ import netneutrality.command.AbstractCommand; import netneutrality.core.CommandManager; import netneutrality.core.GuildManager; import netneutrality.core.context.CommandContext; +import netneutrality.db.GSettings; import netneutrality.utils.Settings; import org.jetbrains.annotations.NotNull; @@ -39,7 +40,7 @@ public class MessageReceivedHandler extends ListenerAdapter { String rawMessage = message.getContentDisplay().trim(); //String prefix = Settings.getInstance().get("BOT_PREFIX", "$"); - String prefix = GuildManager.getManager(guild).getSetting(GuildManager.GSettings.PREFIX); + String prefix = GuildManager.getManager(guild).getSetting(GSettings.PREFIX); if (rawMessage.startsWith(prefix)) { rawMessage = rawMessage.replaceFirst(String.format("^[%s\\s]{1,}", prefix), "").trim(); diff --git a/src/main/java/netneutrality/handler/hooks/voice/VoiceEventHandler.java b/src/main/java/netneutrality/handler/hooks/voice/VoiceEventHandler.java index 338977e..7a42370 100644 --- a/src/main/java/netneutrality/handler/hooks/voice/VoiceEventHandler.java +++ b/src/main/java/netneutrality/handler/hooks/voice/VoiceEventHandler.java @@ -1,10 +1,4 @@ -package netneutrality.handler.hooks.voice;/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - +package netneutrality.handler.hooks.voice; /* * Copyright (c) anthorob * diff --git a/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java b/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java index fd51090..bd0d641 100644 --- a/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java +++ b/src/main/java/netneutrality/handler/ratelimiter/MessageRateLimiterImpl.java @@ -1,10 +1,4 @@ -package netneutrality.handler.ratelimiter;/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - +package netneutrality.handler.ratelimiter; /* * Copyright (c) anthorob * @@ -18,6 +12,7 @@ import net.dv8tion.jda.api.entities.TextChannel; import java.time.OffsetDateTime; +//TODO: to remove? or atleast make it useful public class MessageRateLimiterImpl implements IMessageRateLimiter { private final int messagePerSecond = 5; private static Member lastSender; diff --git a/src/main/java/netneutrality/music/AudioPlayerSendHandler.java b/src/main/java/netneutrality/music/AudioPlayerSendHandler.java index 688fb46..b36e4d5 100644 --- a/src/main/java/netneutrality/music/AudioPlayerSendHandler.java +++ b/src/main/java/netneutrality/music/AudioPlayerSendHandler.java @@ -1,5 +1,4 @@ package netneutrality.music; - /* * Copyright (c) anthorob * diff --git a/src/main/java/netneutrality/music/MusicManager.java b/src/main/java/netneutrality/music/MusicManager.java index ba63d4e..de0ea5e 100644 --- a/src/main/java/netneutrality/music/MusicManager.java +++ b/src/main/java/netneutrality/music/MusicManager.java @@ -7,33 +7,30 @@ package netneutrality.music; * https://discord.gg/CdFcyQ */ -import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler; import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager; -import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers; +import com.sedmelluq.discord.lavaplayer.source.AudioSourceManager; import com.sedmelluq.discord.lavaplayer.source.soundcloud.SoundCloudAudioSourceManager; import com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAudioSourceManager; -import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; -import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.entities.VoiceChannel; import netneutrality.core.GuildManager; +import netneutrality.core.LogHandler; import netneutrality.core.context.CommandContext; +import netneutrality.db.GSettings; +import netneutrality.exceptions.CommandExecutionException; import netneutrality.music.loadable.LoadableSong; import netneutrality.thread.MusicPlayerAutoDisconnectThread; import netneutrality.thread.ThreadManager; -import netneutrality.utils.MessageFunction; import netneutrality.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.List; -import java.util.Map; -import java.util.Queue; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; @@ -46,10 +43,11 @@ public class MusicManager { private final static ScheduledExecutorService executor = (ScheduledExecutorService) ThreadManager.getExecutor("music", ThreadManager.ExecutorType.SCHEDULED); private final static AudioPlayerManager playerManager = new DefaultAudioPlayerManager(); + private final static Map sources = new HashMap<>(); private final Guild guild; private final AudioPlayer player; private final TrackScheduler scheduler; - private TrackLoadingHandler lastLoadingHandler; + private TrackLoader lastTrackLoader; private ScheduledFuture autoDisconnectThread; private final int baseVolume; @@ -57,7 +55,7 @@ public class MusicManager { this.guild = guild; this.player = playerManager.createPlayer(); this.scheduler = new TrackScheduler(this); - this.baseVolume = Integer.parseInt(GuildManager.getManager(guild).getSetting(GuildManager.GSettings.MUSIC_VOLUME)); + this.baseVolume = Integer.parseInt(GuildManager.getManager(guild).getSetting(GSettings.MUSIC_VOLUME)); guild.getAudioManager().setSendingHandler(new AudioPlayerSendHandler(player)); player.addListener(scheduler); @@ -74,21 +72,23 @@ public class MusicManager { } public static void initPlayerManager() { - AudioSourceManagers.registerRemoteSources(playerManager); - - playerManager.registerSourceManager(new YoutubeAudioSourceManager( - true, + YoutubeAudioSourceManager youtubeSource = new YoutubeAudioSourceManager(true, Settings.getInstance().get("GG_EMAIL", ""), - Settings.getInstance().get("GG_PASS", ""))); - playerManager.registerSourceManager(SoundCloudAudioSourceManager.createDefault()); + Settings.getInstance().get("GG_PASS", "")); + SoundCloudAudioSourceManager soundcloudSource = SoundCloudAudioSourceManager.createDefault(); + + sources.put("youtube", youtubeSource); + sources.put("soundcloud", soundcloudSource); + playerManager.registerSourceManager(youtubeSource); + playerManager.registerSourceManager(soundcloudSource); } - public boolean isConnectedTo(VoiceChannel vChannel) { - return vChannel != null && vChannel.equals(guild.getAudioManager().getConnectedChannel()); + public boolean isNotConnectedTo(VoiceChannel vChannel) { + return vChannel == null || !vChannel.equals(guild.getAudioManager().getConnectedChannel()); } public synchronized void connect(VoiceChannel vChannel) { - if (vChannel != null && !isConnectedTo(vChannel)) { + if (vChannel != null && isNotConnectedTo(vChannel)) { logger.debug("Guild {}: connecting to voice channel {}", vChannel.getGuild().getId(), vChannel.getId()); guild.getAudioManager().openAudioConnection(vChannel); guild.getAudioManager().setSelfDeafened(true); @@ -131,24 +131,22 @@ public class MusicManager { return guild; } - public TrackLoadingHandler getLastLoadingHandler() { - return lastLoadingHandler; + public void stopLoading() { + lastTrackLoader.stopLoading(); } public synchronized void leave() { - if (isConnected()) { + if (guild != null && guild.getAudioManager().getConnectedChannel() != null) { logger.debug("Guild {}: leaving voice channel {}", guild.getId(), guild.getAudioManager().getConnectedChannel().getId()); player.stopTrack(); guild.getAudioManager().closeAudioConnection(); } - scheduler.getTopicManager().detachTextChannel(); + scheduler.detachTextChannel(); if (autoDisconnectThread != null) { - boolean cancel = autoDisconnectThread.cancel(true); - - if (cancel) - autoDisconnectThread = null; + autoDisconnectThread.cancel(true); + autoDisconnectThread = null; } } @@ -167,41 +165,12 @@ public class MusicManager { } public synchronized void play(String url, CommandContext context, boolean needToBeConnected, boolean silent) { - Member member = context.getGuildUser(); - TextChannel channel = context.getChannel(); - logger.debug("Guild {}: request to play by user {}, string=[{}]", guild.getId(), context.getGuildUser().getId(), url); + logger.debug("Guild {}: request to play {} by user {}", guild.getId(), url, context.getGuildUser().getId()); - if (member.getVoiceState() == null) { - context.deleteMessage(); - return; - } + List toLoad = new ArrayList<>(); + toLoad.add(new LoadableSong(null, url, null)); - if (!member.getVoiceState().inVoiceChannel()) { - context.reply("You are not in a voice channel"); - context.deleteMessage(); - return; - } - - VoiceChannel vChannel = member.getVoiceState().getChannel(); - if (needToBeConnected && !isConnectedTo(vChannel)) { - context.reply("The player is not in your voice channel"); - context.deleteMessage(); - return; - } - - if (!isConnectedTo(vChannel)) { - connect(vChannel); - } - - String identifier = SourceFinder.getIdentifier(url); - scheduler.getTopicManager().attachTextChannel(channel); - - if (identifier != null) { - lastLoadingHandler = new TrackLoadingHandler(identifier, silent, this, context); - playerManager.loadItemOrdered(this, identifier, lastLoadingHandler); - } else { - context.replyToMessage("No source found to play the given url"); - } + play(toLoad, context, needToBeConnected, silent); } public void play(List songs, CommandContext context, boolean needToBeConnected, boolean silent) { @@ -209,103 +178,33 @@ public class MusicManager { TextChannel channel = context.getChannel(); if (member.getVoiceState() == null) { + logger.error("Guild {}: Voice state is null", guild.getId()); + context.replyToMessage("Voice state is null, something has gone wrong."); + LogHandler.log(new CommandExecutionException("Voice state is null", context, null)); + return; } if (!member.getVoiceState().inVoiceChannel()) { - context.reply("You are not in a voice channel"); + context.replyToMessage("You are not in a voice channel"); return; } VoiceChannel vChannel = member.getVoiceState().getChannel(); - if (needToBeConnected && !isConnectedTo(vChannel)) { - context.reply("The player is not in your voice channel"); + if (needToBeConnected && isNotConnectedTo(vChannel)) { + context.replyToMessage("The player is not in your voice channel"); return; } - if (!isConnectedTo(vChannel)) { + if (isNotConnectedTo(vChannel)) { connect(vChannel); + scheduler.attachTextChannel(channel); } - scheduler.getTopicManager().attachTextChannel(channel); - boolean fromOnlineSource = songs.size() > 1; - - for (LoadableSong song : songs) { - String identifier = SourceFinder.getIdentifier(song.name()); - - if (identifier != null) { - playerManager.loadItemOrdered(this, identifier, new AudioLoadResultHandler() { - @Override - public void trackLoaded(AudioTrack track) { - if (!fromOnlineSource) { - logger.debug("Guild {}: track loaded: {}", guild.getId(), identifier); - context.deleteMessage(); - - scheduler.getQueueManager().queue(track, member); - - if (!silent) { - //context.replyToMessage("Added track to queue"); - context.reply(MessageFunction.buildAddingTrackMessage(track, member, identifier)); - } - } - } - - @Override - public void playlistLoaded(AudioPlaylist playlist) { - logger.debug("Guild {}: playlist loaded: {}", guild.getId(), identifier); - - if (!playlist.getTracks().isEmpty()) { - context.deleteMessage(); - - if (playlist.isSearchResult()) { - AudioTrack track = playlist.getTracks().get(0); - scheduler.getQueueManager().queue(track, member); - - if (!silent && !fromOnlineSource) { - //context.replyToMessage(new MessageBuilder("Added track to queue: ").append(String.format("https://youtu.be/%s", track.getIdentifier())).build()); - context.reply(MessageFunction.buildAddingTrackMessage(track, member, String.format("https://youtu.be/%s", track.getIdentifier()))); - } - - } else { - if (!silent && !fromOnlineSource) { - //context.replyToMessage("Added playlist to queue"); - context.reply(MessageFunction.buildAddingPlaylistMessage(playlist, member, identifier)); - } - - for (AudioTrack track : playlist.getTracks()) { - synchronized (scheduler.getQueueManager().getQueue()) { - scheduler.getQueueManager().queue(track, member); - } - } - } - } else { - context.replyToMessage("Playlist is empty"); - } - - } - - @Override - public void noMatches() { - logger.debug("Guild {}: no matches for identifier {}", guild.getId(), identifier); - - if (fromOnlineSource) { - //TODO: - } - context.replyToMessage("No matches found"); - } - - @Override - public void loadFailed(FriendlyException e) { - logger.debug("Guild {}: load failed for identifier {}", guild.getId(), identifier, e); - context.replyToMessage("Failed to load track: " + e.getMessage()); - } - }); - } else { - context.replyToMessage("No source found to play the given url"); - } - - } + TrackLoader loader = new TrackLoader(this, context, playerManager, silent); + lastTrackLoader = loader; + loader.loadAllSongs(songs); } public synchronized boolean removeFromQueue(int index) { @@ -345,22 +244,23 @@ public class MusicManager { // Minus the bot itself int connected = voiceChannel.getMembers().size() - 1; - if (connected > 2) { - double needed = connected / 2.1; - - info.addSkip(context.getGuildUser()); - logger.debug("VoteSkip: guild={}, connected={}, needed={}, skips={}, user={}", context.getGuild().getId(), connected, needed, info.getSkips().size(), context.getGuildUser().getId()); - - if (info.getSkips().size() > needed) { - context.reply("Skipping current track: %s", info.getTrack().getInfo().title); - skip(1); - } else { - context.reply("Adding your vote to skip the current track. Current votes: %d/%d", info.getSkips().size(), (int) Math.ceil(needed)); - } - - } else { + if (connected < 3) { context.reply("Skipping current track since not enough people are connected to the voice channel."); skip(1); + + return; + } + + double needed = connected / 2.1; + + info.addSkip(context.getGuildUser()); + logger.debug("VoteSkip: guild={}, connected={}, needed={}, skips={}, user={}", context.getGuild().getId(), connected, needed, info.getSkips().size(), context.getGuildUser().getId()); + + if (info.getSkips().size() > needed) { + context.reply("Skipping current track: %s", info.getTrack().getInfo().title); + skip(1); + } else { + context.reply("Adding your vote to skip the current track. Current votes: %d/%d", info.getSkips().size(), (int) Math.ceil(needed)); } } @@ -368,7 +268,7 @@ public class MusicManager { player.setVolume(volume); } - public int getQueueSize () { + public int getQueueSize() { synchronized (scheduler.getQueueManager().getQueue()) { return scheduler.getQueueManager().getQueue().size(); } diff --git a/src/main/java/netneutrality/music/QueueManager.java b/src/main/java/netneutrality/music/QueueManager.java index 5b18728..550449f 100644 --- a/src/main/java/netneutrality/music/QueueManager.java +++ b/src/main/java/netneutrality/music/QueueManager.java @@ -117,7 +117,7 @@ public class QueueManager { public void clearQueue() { scheduler.getMusicManager().leave(); - scheduler.getMusicManager().getLastLoadingHandler().stopLoading(); + scheduler.getMusicManager().stopLoading(); synchronized (queue) { queue.clear(); diff --git a/src/main/java/netneutrality/music/SourceFinder.java b/src/main/java/netneutrality/music/SourceFinder.java index eca65df..e18eb07 100644 --- a/src/main/java/netneutrality/music/SourceFinder.java +++ b/src/main/java/netneutrality/music/SourceFinder.java @@ -12,7 +12,7 @@ import java.util.regex.Pattern; public class SourceFinder { - public enum AvailableSource { + public enum AudioSourceType { Youtube, Soundcloud, Bandcamp, @@ -24,23 +24,22 @@ public class SourceFinder { private static final Pattern youtubePattern = Pattern.compile("^(?:https?://)?(?:(?:www\\.)?)?(?:youtube\\.com|youtu\\.be)/.*?(?:embed|e|v|watch.*?v=)?/?([-_a-z0-9]{10,})?(?:&?index=\\d+)?(?>(?:playlist\\?|&)?list=([^#\\\\&?]{12,}))?", Pattern.CASE_INSENSITIVE); private static final Pattern soundcloudPattern = Pattern.compile("^(?:https?://)?(?:www\\.)?(?:m\\.)?soundcloud\\.com/([a-zA-Z0-9-_]+)/([a-zA-Z0-9-_]+)(?:\\\\?.*|)$", Pattern.CASE_INSENSITIVE); - private static Matcher BandcampMatcher; - private static Matcher vimeoMatcher; + private static Matcher twitchMatcher; - public static AvailableSource getSource(String url) { + public static AudioSourceType getSource(String url) { Matcher youtubeMatcher = youtubePattern.matcher(url); Matcher soundcloudMatcher = soundcloudPattern.matcher(url); if (youtubeMatcher.find()) - return AvailableSource.Youtube; + return AudioSourceType.Youtube; if (soundcloudMatcher.find()) - return AvailableSource.Soundcloud; + return AudioSourceType.Soundcloud; if (!(url.startsWith("http://") || url.startsWith("https://"))) - return AvailableSource.YTSearch; + return AudioSourceType.YTSearch; - return AvailableSource.Nothing; + return AudioSourceType.Nothing; } public static String getIdentifier(String url) { diff --git a/src/main/java/netneutrality/music/TopicManager.java b/src/main/java/netneutrality/music/TopicManager.java deleted file mode 100644 index d080d9a..0000000 --- a/src/main/java/netneutrality/music/TopicManager.java +++ /dev/null @@ -1,84 +0,0 @@ -package netneutrality.music;/* - * Copyright (c) anthorob - * - * https://xtremcommunity.com/ - * https://discord.gg/CdFcyQ - */ - -import com.sedmelluq.discord.lavaplayer.track.AudioTrack; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.TextChannel; -import netneutrality.core.GuildManager; -import org.apache.logging.log4j.LogManager; - -import java.util.concurrent.TimeUnit; - -public class TopicManager { - - private final TrackScheduler scheduler; - private final Guild guild; - private TextChannel channel; - private String originalTopic; - - public TopicManager(TrackScheduler scheduler) { - this.scheduler = scheduler; - this.guild = scheduler.getGuild(); - } - - public TrackScheduler getScheduler() { - return scheduler; - } - - public Guild getGuild() { - return guild; - } - - public TextChannel getTextChannel() { - return channel; - } - - public String getOriginalTopic() { - return originalTopic; - } - - public synchronized void attachTextChannel(TextChannel channel) { - this.channel = channel; - - if (originalTopic == null) { - String current = channel.getTopic(); - originalTopic = (current == null ? "" : current); - } - } - - public synchronized void detachTextChannel() { - updateTopic(null); - - this.channel = null; - this.originalTopic = null; - } - - public synchronized void updateTopic(AudioTrack track) { - if (isEnabled() && channel != null) { - - if (track == null) { - LogManager.getLogger(TopicManager.class).debug("Guild {}: Resetting topic for channel {}", guild.getId(), channel.getId()); - channel.getManager().setTopic(originalTopic).queueAfter(5, TimeUnit.SECONDS); - } else { - LogManager.getLogger(TopicManager.class).debug("Guild {}: Setting topic for channel {} to [{}]", guild.getId(), channel.getId(), track.getInfo().title); - channel.getManager().setTopic(":speaker: Now playing: " + track.getInfo().title).queueAfter(5, TimeUnit.SECONDS); - } - - } - } - - public void sendMessageToChannel(String msg) { - if (channel != null) { - channel.sendMessage(msg).queue(); - } - } - - private boolean isEnabled() { - // rate limiting too much - return false; - } -} diff --git a/src/main/java/netneutrality/music/TrackLoader.java b/src/main/java/netneutrality/music/TrackLoader.java new file mode 100644 index 0000000..462f0f2 --- /dev/null +++ b/src/main/java/netneutrality/music/TrackLoader.java @@ -0,0 +1,116 @@ +package netneutrality.music; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; +import netneutrality.core.LogHandler; +import netneutrality.core.context.CommandContext; +import netneutrality.music.loadable.CachedSource; +import netneutrality.music.loadable.LoadableMusicSource; +import netneutrality.music.loadable.LoadableSong; +import netneutrality.thread.ThreadManager; + +import java.util.List; + +public class TrackLoader implements Runnable { + + private final CommandContext context; + private final MusicManager musicManager; + private final AudioPlayerManager audioPlayerManager; + private TrackLoadingHandler lastLoadingHandler; + private List songs; + private LoadableMusicSource source; + private int numberOfTracksLoaded; + private int totalNumberOfTracks; + private boolean loadingDisabled = false; + private boolean silent; + private final Object sync = new Object(); + + public TrackLoader(MusicManager musicManager, CommandContext context, AudioPlayerManager playerManager, boolean silent) { + this.musicManager = musicManager; + this.context = context; + this.audioPlayerManager = playerManager; + this.silent = silent; + } + + public void loadAllSongs(List songs) { + this.songs = songs; + if (songs.size() > 1) { + silent = true; + } + + ThreadManager.getExecutor("Track loader").submit(this); + } + + public void loadAllSongs(CachedSource cachedSource) { + this.source = cachedSource.getSource(); + + loadAllSongs(cachedSource.getSongs()); + } + + public void stopLoading() { + loadingDisabled = true; + + if (lastLoadingHandler != null) { + lastLoadingHandler.stopLoading(); + } + } + + @Override + public void run() { + for (LoadableSong song : songs) { + if (loadingDisabled) { + break; + } + + SourceFinder.AudioSourceType type = SourceFinder.getSource(song.name()); + String identifier = SourceFinder.getIdentifier(song.name()); + + if (identifier != null) { + TrackLoadingHandler loadingHandler = new TrackLoadingHandler(context, musicManager, identifier, type, silent); + loadingHandler.useCallbackOnLoad(success -> { + + synchronized (sync) { + if (success) { + numberOfTracksLoaded++; + } + + totalNumberOfTracks++; + + System.out.println("notify, loaded: " + numberOfTracksLoaded + ", total: " + totalNumberOfTracks); + sync.notify(); + } + + }); + lastLoadingHandler = loadingHandler; + + audioPlayerManager.loadItemOrdered(this, identifier, loadingHandler); + } else { + if (songs.size() == 1) { + context.replyToMessage("No source found to play the given url"); + } + } + } + + try { + synchronized (sync) { + while (!(songs.size() == totalNumberOfTracks)) { + System.out.println("wait"); + sync.wait(); + } + + //TODO: logic + if (songs.size() > 1 && source != null && !loadingDisabled) { + context.replyToMessage("Loaded %d of %d tracks from online source", numberOfTracksLoaded, totalNumberOfTracks); + } + } + } catch (InterruptedException exception) { + LogHandler.log(exception); + } + + } +} diff --git a/src/main/java/netneutrality/music/TrackLoadingHandler.java b/src/main/java/netneutrality/music/TrackLoadingHandler.java index 97a84e5..6d7f853 100644 --- a/src/main/java/netneutrality/music/TrackLoadingHandler.java +++ b/src/main/java/netneutrality/music/TrackLoadingHandler.java @@ -12,23 +12,29 @@ import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import net.dv8tion.jda.api.entities.Guild; +import netneutrality.core.LogHandler; import netneutrality.core.context.CommandContext; import netneutrality.utils.MessageFunction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.function.Consumer; + public class TrackLoadingHandler implements AudioLoadResultHandler { private final Logger logger = LoggerFactory.getLogger(TrackLoadingHandler.class); private final String identifier; + private final SourceFinder.AudioSourceType type; private final boolean silent; + private Consumer loadConsumer; private boolean loadingDisabled = false; private final Guild guild; private final TrackScheduler scheduler; private final CommandContext context; - public TrackLoadingHandler(String identifier, boolean silent, MusicManager manager, CommandContext context) { + public TrackLoadingHandler(CommandContext context, MusicManager manager, String identifier, SourceFinder.AudioSourceType type, boolean silent) { this.identifier = identifier; + this.type = type; this.silent = silent; this.guild = manager.getGuild(); this.scheduler = manager.getScheduler(); @@ -40,45 +46,59 @@ public class TrackLoadingHandler implements AudioLoadResultHandler { loadingDisabled = true; } + public void useCallbackOnLoad(Consumer consumer) { + this.loadConsumer = consumer; + } + @Override public void trackLoaded(AudioTrack audioTrack) { + if (loadConsumer != null) { + loadConsumer.accept(true); + } + if (loadingDisabled) { return; } - logger.debug("Guild {}: track loaded: {}", guild.getId(), identifier); context.deleteMessage(); + logger.debug("Guild {}: track loaded: {}", guild.getId(), audioTrack.getIdentifier()); scheduler.getQueueManager().queue(audioTrack, context.getGuildUser()); if (!silent) { - //context.replyToMessage("Added track to queue"); - context.reply(MessageFunction.buildAddingTrackMessage(audioTrack, context.getGuildUser(), identifier)); + scheduler.sendMessageToChannel(MessageFunction.buildAddingTrackMessage(audioTrack, context.getGuildUser(), type)); + // context.reply(MessageFunction.buildAddingTrackMessage(audioTrack, context.getGuildUser(), type)); } } @Override public void playlistLoaded(AudioPlaylist audioPlaylist) { + if (loadConsumer != null) { + loadConsumer.accept(true); + } + if (loadingDisabled) { return; } - logger.debug("Guild {}: playlist loaded: {}", guild.getId(), identifier); - context.deleteMessage(); - if (audioPlaylist.isSearchResult()) { - AudioTrack track = audioPlaylist.getTracks().get(0); - scheduler.getQueueManager().queue(track, context.getGuildUser()); + if (!audioPlaylist.getTracks().isEmpty()) { + if (audioPlaylist.isSearchResult()) { + AudioTrack track = audioPlaylist.getTracks().get(0); + scheduler.getQueueManager().queue(track, context.getGuildUser()); - if (!silent) { - //context.replyToMessage(new MessageBuilder("Added track to queue: ").append(String.format("https://youtu.be/%s", track.getIdentifier())).build()); - context.reply(MessageFunction.buildAddingTrackMessage(track, context.getGuildUser(), String.format("https://youtu.be/%s", track.getIdentifier()))); + if (!silent) { + scheduler.sendMessageToChannel(MessageFunction.buildAddingTrackMessage(track, context.getGuildUser(), type)); + // context.reply(MessageFunction.buildAddingTrackMessage(track, context.getGuildUser(), type)); + } + + return; } - } else { + context.deleteMessage(); if (!silent) { - //context.replyToMessage("Added playlist to queue"); - context.reply(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, context.getGuildUser(), identifier)); + scheduler.sendMessageToChannel(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, context.getGuildUser(), identifier, type)); + // context.reply(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, context.getGuildUser(), identifier, type)); } for (AudioTrack track : audioPlaylist.getTracks()) { @@ -91,19 +111,28 @@ public class TrackLoadingHandler implements AudioLoadResultHandler { } } } - - } @Override public void noMatches() { logger.debug("Guild {}: no matches for identifier {}", guild.getId(), identifier); - context.replyToMessage("No matches found"); + + if (!silent) + context.replyToMessage("No matches found"); + + if (loadConsumer != null) + loadConsumer.accept(false); } @Override public void loadFailed(FriendlyException e) { logger.debug("Guild {}: load failed for identifier {}", guild.getId(), identifier, e); - context.replyToMessage("Failed to load track: " + e.getMessage()); + LogHandler.log(e); + + if (!silent) + context.replyToMessage("Failed to load track: " + e.getMessage()); + + if (loadConsumer != null) + loadConsumer.accept(false); } } diff --git a/src/main/java/netneutrality/music/TrackScheduler.java b/src/main/java/netneutrality/music/TrackScheduler.java index 658d5d1..da3031b 100644 --- a/src/main/java/netneutrality/music/TrackScheduler.java +++ b/src/main/java/netneutrality/music/TrackScheduler.java @@ -1,5 +1,4 @@ package netneutrality.music; - /* * Copyright (c) anthorob * @@ -13,6 +12,9 @@ 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.Guild; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.entities.TextChannel; +import netneutrality.core.LogHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,9 +22,9 @@ public class TrackScheduler extends AudioEventAdapter { private final static Logger logger = LoggerFactory.getLogger(TrackScheduler.class); private final QueueManager queueManager; - private final TopicManager topicManager; private final MusicManager manager; private final AudioPlayer player; + private TextChannel currentChannel; private final Guild guild; public TrackScheduler(MusicManager manager) { @@ -30,17 +32,12 @@ public class TrackScheduler extends AudioEventAdapter { this.player = manager.getPlayer(); this.guild = manager.getGuild(); this.queueManager = new QueueManager(this); - this.topicManager = new TopicManager(this); } public QueueManager getQueueManager() { return queueManager; } - public TopicManager getTopicManager() { - return topicManager; - } - public MusicManager getMusicManager() { return manager; } @@ -53,6 +50,30 @@ public class TrackScheduler extends AudioEventAdapter { return guild; } + public TextChannel getTextChannel() { + return currentChannel; + } + + public synchronized void attachTextChannel(TextChannel channel) { + this.currentChannel = channel; + } + + public synchronized void detachTextChannel() { + this.currentChannel = null; + } + + public void sendMessageToChannel(String msg) { + if (currentChannel != null && currentChannel.canTalk()) { + currentChannel.sendMessage(msg).queue(); + } + } + + public void sendMessageToChannel(MessageEmbed embed, MessageEmbed... embeds) { + if (currentChannel != null && currentChannel.canTalk()) { + currentChannel.sendMessageEmbeds(embed, embeds).queue(); + } + } + @Override public void onPlayerPause(AudioPlayer player) { // Player was paused @@ -66,7 +87,6 @@ public class TrackScheduler extends AudioEventAdapter { @Override public void onTrackStart(AudioPlayer player, AudioTrack track) { logger.debug("Guild {}: starting track: {}", guild.getId(), track.getIdentifier()); - topicManager.updateTopic(track); } @Override @@ -84,7 +104,6 @@ public class TrackScheduler extends AudioEventAdapter { if (endReason == AudioTrackEndReason.STOPPED) { synchronized (queueManager.getQueue()) { - topicManager.updateTopic(null); queueManager.getQueue().poll(); } } @@ -100,15 +119,14 @@ public class TrackScheduler extends AudioEventAdapter { @Override public void onTrackException(AudioPlayer player, AudioTrack track, FriendlyException exception) { logger.debug("Guild {}: exception while playing track [{}]: {}", guild.getId(), track.getIdentifier(), exception.getMessage()); - topicManager.updateTopic(null); - topicManager.sendMessageToChannel("Error while playing track [" + track.getInfo().title + "]: " + exception.getMessage()); + LogHandler.log(exception); + sendMessageToChannel("Error while playing track [" + track.getInfo().title + "]: " + exception.getMessage()); } @Override public void onTrackStuck(AudioPlayer player, AudioTrack track, long thresholdMs) { logger.debug("Guild {}: currently playing track is stuck: {}", guild.getId(), track.getIdentifier()); - topicManager.updateTopic(null); - topicManager.sendMessageToChannel("Current track is stuck, skipping to next"); + sendMessageToChannel("Current track is stuck, skipping to next"); queueManager.nextTrack(player); } } diff --git a/src/main/java/netneutrality/music/loadable/CachedSource.java b/src/main/java/netneutrality/music/loadable/CachedSource.java index 2dc83c3..3be39ed 100644 --- a/src/main/java/netneutrality/music/loadable/CachedSource.java +++ b/src/main/java/netneutrality/music/loadable/CachedSource.java @@ -15,7 +15,7 @@ public class CachedSource { private OffsetDateTime lastAccess; private final List songs; - public CachedSource(LoadableMusicSource source, List songs) { + protected CachedSource(LoadableMusicSource source, List songs) { this.source = source; this.lastAccess = OffsetDateTime.now(); this.songs = songs; diff --git a/src/main/java/netneutrality/music/loadable/LoadableSourceManager.java b/src/main/java/netneutrality/music/loadable/LoadableSourceManager.java index 4265a3d..ff2c46e 100644 --- a/src/main/java/netneutrality/music/loadable/LoadableSourceManager.java +++ b/src/main/java/netneutrality/music/loadable/LoadableSourceManager.java @@ -34,14 +34,13 @@ public class LoadableSourceManager { } return cachedSource; - } else { - List songs = loadFromUrl(source); - CachedSource newCachedSource = new CachedSource(source, songs); - - cache.put(source.getIdentifier(), newCachedSource); - return newCachedSource; } + List songs = loadFromUrl(source); + CachedSource newCachedSource = new CachedSource(source, songs); + + cache.put(source.getIdentifier(), newCachedSource); + return newCachedSource; } private List loadFromUrl(LoadableMusicSource source) { diff --git a/src/main/java/netneutrality/utils/MessageFunction.java b/src/main/java/netneutrality/utils/MessageFunction.java index 4c214b0..a6069ca 100644 --- a/src/main/java/netneutrality/utils/MessageFunction.java +++ b/src/main/java/netneutrality/utils/MessageFunction.java @@ -15,8 +15,11 @@ import net.dv8tion.jda.api.entities.*; import netneutrality.command.AbstractCommand; import netneutrality.command.CommandType; import netneutrality.core.context.CommandContext; +import netneutrality.exceptions.CommandException; import netneutrality.exceptions.CommandExecutionException; import netneutrality.music.MusicManager; +import netneutrality.music.SourceFinder; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DurationFormatUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -69,40 +72,62 @@ public class MessageFunction { return message.build(); } - public static MessageEmbed buildAddingTrackMessage(AudioTrack track, Member user, String identifier) { + public static MessageEmbed buildAddingTrackMessage(AudioTrack track, Member member, SourceFinder.AudioSourceType type) { EmbedBuilder message = new EmbedBuilder(); - message.setAuthor("Link to track", identifier); - message.setThumbnail(String.format("https://img.youtube.com/vi/%s/default.jpg", track.getIdentifier())); + String avatarUrl = StringUtils.isEmpty(member.getAvatarUrl()) ? member.getUser().getAvatarUrl() : member.getAvatarUrl(); + String url = track.getIdentifier(); + String thumbnail = null; + + if (type == SourceFinder.AudioSourceType.Youtube || type == SourceFinder.AudioSourceType.YTSearch) { + url = String.format("https://youtu.be/%s", track.getIdentifier()); + thumbnail = String.format("https://img.youtube.com/vi/%s/default.jpg", track.getIdentifier()); + } + + if (thumbnail != null) { + message.setThumbnail(thumbnail); + } message.setTitle("Adding track to queue.."); message.setColor(Color.BLUE); - message.addField("Track title: ", track.getInfo().title, false); + message.addField("Track title: ", String.format("[**`%s`**](%s)", track.getInfo().title, url), false); message.addField("Duration: ", DurationFormatUtils.formatDuration(track.getDuration(), "**HH:mm:ss**", true), false); - message.setFooter("Requested by " + user.getEffectiveName(), user.getAvatarUrl()); + message.setFooter("Requested by " + member.getEffectiveName(), avatarUrl); message.setTimestamp(OffsetDateTime.now()); return message.build(); } - public static MessageEmbed buildAddingPlaylistMessage(AudioPlaylist playlist, Member user, String identifier) { + public static MessageEmbed buildAddingPlaylistMessage(AudioPlaylist playlist, Member member, String identifier, SourceFinder.AudioSourceType type) { EmbedBuilder message = new EmbedBuilder(); - message.setAuthor("Link to playlist", identifier); - message.setThumbnail(String.format("https://img.youtube.com/vi/%s/default.jpg", playlist.getSelectedTrack().getIdentifier())); + String avatarUrl = StringUtils.isEmpty(member.getAvatarUrl()) ? member.getUser().getAvatarUrl() : member.getAvatarUrl(); + String url = identifier; + String thumbnail = null; + + if (type == SourceFinder.AudioSourceType.Youtube || type == SourceFinder.AudioSourceType.YTSearch) { + url = String.format("https://youtu.be/%s", playlist.getSelectedTrack().getIdentifier()); + thumbnail = String.format("https://img.youtube.com/vi/%s/default.jpg", playlist.getSelectedTrack().getIdentifier()); + } + + if (thumbnail != null) { + message.setThumbnail(thumbnail); + } message.setTitle("Adding playlist to queue.."); message.setColor(Color.BLUE); - message.addField("Playlist: ", playlist.getName(), false); + message.addField("Playlist: ", String.format("[**`%s`**](%s)", playlist.getName(), url), false); message.addField("Number of tracks: ", String.valueOf(playlist.getTracks().size()), false); - message.setFooter("Requested by " + user.getEffectiveName(), user.getAvatarUrl()); + message.setFooter("Requested by " + member.getEffectiveName(), avatarUrl); message.setTimestamp(OffsetDateTime.now()); return message.build(); } - public static MessageEmbed buildViewQueueMessage(MusicManager manager, Member user, boolean currentlyPlaying) { + public static MessageEmbed buildViewQueueMessage(MusicManager manager, Member member, boolean currentlyPlaying) { + String avatarUrl = StringUtils.isEmpty(member.getAvatarUrl()) ? member.getUser().getAvatarUrl() : member.getAvatarUrl(); ArrayList tracks = manager.getScheduler().getQueueManager().getAllQueuedTrack(); AudioTrack current = manager.getCurrentlyPlaying(); + int numberofTracksShown = Math.min(tracks.size(), 10); EmbedBuilder message = new EmbedBuilder(); - message.setTitle("Current queue (showing 10 out of " + tracks.size() + " items):"); + message.setTitle(String.format("Current queue (showing %d out of %d items):", numberofTracksShown, tracks.size())); message.setColor(Color.BLUE); int index = 0; @@ -118,7 +143,7 @@ public class MessageFunction { if (index == 10) break; } - message.setFooter("Requested by " + user.getEffectiveName(), user.getAvatarUrl()); + message.setFooter("Requested by " + member.getEffectiveName(), avatarUrl); message.setTimestamp(OffsetDateTime.now()); return message.build(); @@ -191,7 +216,7 @@ public class MessageFunction { return messages; } - public static MessageEmbed buildDebugMessage(CommandContext context, CommandExecutionException error) { + public static MessageEmbed buildDebugMessage(CommandContext context, CommandException error) { EmbedBuilder message = new EmbedBuilder(); message.setColor(Color.RED); message.setTitle(":warning: Exception in command execution"); diff --git a/src/main/java/netneutrality/utils/MiscUtils.java b/src/main/java/netneutrality/utils/MiscUtils.java new file mode 100644 index 0000000..1ff5648 --- /dev/null +++ b/src/main/java/netneutrality/utils/MiscUtils.java @@ -0,0 +1,26 @@ +package netneutrality.utils; +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + + +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; + +public class MiscUtils { + + public static boolean isValidUrl(String url) { + try { + URL object = new URL(url); + object.toURI(); + + return true; + } catch (MalformedURLException | URISyntaxException e) { + return false; + } + } +}