Refactored music manager
This commit is contained in:
1 parent
02c1eab6e3
commit
64dd0da604
29 files changed
+483
-423
No files matched your search
@@ -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"))
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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 <value between 0 and 100>'");
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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<String, GuildManager> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<String, GuildManager> managers = new ConcurrentHashMap<>();
|
||||
private static final SessionFactory sessionFactory = SessionManager.getSessionFactory();
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,10 @@ public class SessionManager {
|
||||
sessionFactory = metadata.getSessionFactoryBuilder().build();
|
||||
|
||||
} catch (Exception 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);
|
||||
|
||||
@@ -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<String, GuildManager> 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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
package netneutrality.music;
|
||||
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
|
||||
@@ -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<String, AudioSourceManager> 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,23 +131,21 @@ 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.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<LoadableSong> 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<LoadableSong> 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,7 +244,13 @@ public class MusicManager {
|
||||
// Minus the bot itself
|
||||
int connected = voiceChannel.getMembers().size() - 1;
|
||||
|
||||
if (connected > 2) {
|
||||
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());
|
||||
@@ -357,11 +262,6 @@ public class MusicManager {
|
||||
} else {
|
||||
context.reply("Adding your vote to skip the current track. Current votes: %d/%d", info.getSkips().size(), (int) Math.ceil(needed));
|
||||
}
|
||||
|
||||
} else {
|
||||
context.reply("Skipping current track since not enough people are connected to the voice channel.");
|
||||
skip(1);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void setVolume(int volume) {
|
||||
|
||||
@@ -117,7 +117,7 @@ public class QueueManager {
|
||||
|
||||
public void clearQueue() {
|
||||
scheduler.getMusicManager().leave();
|
||||
scheduler.getMusicManager().getLastLoadingHandler().stopLoading();
|
||||
scheduler.getMusicManager().stopLoading();
|
||||
|
||||
synchronized (queue) {
|
||||
queue.clear();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<LoadableSong> 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<LoadableSong> 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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<Boolean> 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<Boolean> 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.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())));
|
||||
scheduler.sendMessageToChannel(MessageFunction.buildAddingTrackMessage(track, context.getGuildUser(), type));
|
||||
// context.reply(MessageFunction.buildAddingTrackMessage(track, context.getGuildUser(), type));
|
||||
}
|
||||
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
LogHandler.log(e);
|
||||
|
||||
if (!silent)
|
||||
context.replyToMessage("Failed to load track: " + e.getMessage());
|
||||
|
||||
if (loadConsumer != null)
|
||||
loadConsumer.accept(false);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ public class CachedSource {
|
||||
private OffsetDateTime lastAccess;
|
||||
private final List<LoadableSong> songs;
|
||||
|
||||
public CachedSource(LoadableMusicSource source, List<LoadableSong> songs) {
|
||||
protected CachedSource(LoadableMusicSource source, List<LoadableSong> songs) {
|
||||
this.source = source;
|
||||
this.lastAccess = OffsetDateTime.now();
|
||||
this.songs = songs;
|
||||
|
||||
@@ -34,7 +34,8 @@ public class LoadableSourceManager {
|
||||
}
|
||||
|
||||
return cachedSource;
|
||||
} else {
|
||||
}
|
||||
|
||||
List<LoadableSong> songs = loadFromUrl(source);
|
||||
CachedSource newCachedSource = new CachedSource(source, songs);
|
||||
|
||||
@@ -42,8 +43,6 @@ public class LoadableSourceManager {
|
||||
return newCachedSource;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private List<LoadableSong> loadFromUrl(LoadableMusicSource source) {
|
||||
WebModule web = new WebModule(source.url());
|
||||
JSONObject obj = web.request().getAsObject();
|
||||
|
||||
@@ -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<AudioTrack> 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");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user