Improve cleanup for music player, fix resume logic, check if player is connected before checking url, refactor context
This commit is contained in:
1 parent
bcf78920e9
commit
6f2ba795d4
27 files changed
+321
-282
No files matched your search
@@ -11,7 +11,6 @@ import me.bobert.netneutrality.core.LogHandler;
|
||||
import me.bobert.netneutrality.core.command.CommandManager;
|
||||
import me.bobert.netneutrality.core.db.SessionManager;
|
||||
import me.bobert.netneutrality.core.tasks.TaskManager;
|
||||
import me.bobert.netneutrality.core.thread.BaseThreadFactory;
|
||||
import me.bobert.netneutrality.core.thread.ThreadManager;
|
||||
import me.bobert.netneutrality.hooks.guilds.ServerJoinHook;
|
||||
import me.bobert.netneutrality.hooks.interaction.ButtonInteractionHook;
|
||||
@@ -35,10 +34,10 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.core.config.Configurator;
|
||||
|
||||
public class NetNeutrality {
|
||||
|
||||
private static JDA jda;
|
||||
private final static Logger logger = LogManager.getLogger(NetNeutrality.class);
|
||||
private static final Logger logger = LogManager.getLogger(NetNeutrality.class);
|
||||
public static final String VERSION = Settings.getInstance().getMavenVersion();
|
||||
private static NetNeutrality instance;
|
||||
private static JDA jda;
|
||||
|
||||
public static void main(String[] args) {
|
||||
String env = Settings.getInstance().get("NETNEUTRALITY_BOT_ENV", "dev");
|
||||
@@ -60,6 +59,14 @@ public class NetNeutrality {
|
||||
Configurator.setLevel("net.dv8tion.jda", Level.DEBUG);
|
||||
}
|
||||
|
||||
instance = new NetNeutrality();
|
||||
}
|
||||
|
||||
public NetNeutrality() {
|
||||
startup();
|
||||
}
|
||||
|
||||
private void startup() {
|
||||
// DatabaseMigration.migrate();
|
||||
SessionManager.getSessionFactory();
|
||||
initJDA();
|
||||
@@ -72,11 +79,14 @@ public class NetNeutrality {
|
||||
new WebApi(Integer.parseInt(Settings.getInstance().get("NETNEUTRALITY_API_PORT", "9000")));
|
||||
jda.getPresence().setActivity(Activity.watching("you"));
|
||||
|
||||
Runtime.getRuntime().addShutdownHook(new BaseThreadFactory("shutdown").newThread(new ShutdownThread()));
|
||||
|
||||
Runtime.getRuntime().addShutdownHook(new ShutdownThread(this));
|
||||
}
|
||||
|
||||
public static void initJDA() {
|
||||
public static NetNeutrality getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void initJDA() {
|
||||
String token = Settings.getInstance().get("NETNEUTRALITY_BOT_TOKEN");
|
||||
if (token == null) {
|
||||
SessionManager.shutdown();
|
||||
@@ -96,7 +106,7 @@ public class NetNeutrality {
|
||||
}
|
||||
}
|
||||
|
||||
public static void shutdown() {
|
||||
public void shutdown() {
|
||||
System.out.println("[Net Neutrality] Shutting down...");
|
||||
MusicManager.disconnectPlayers();
|
||||
ThreadManager.shutdownExecutor();
|
||||
@@ -105,16 +115,16 @@ public class NetNeutrality {
|
||||
System.out.println("[Net Neutrality] Shutdown complete");
|
||||
}
|
||||
|
||||
public static JDA getJDA() {
|
||||
public JDA getJDA() {
|
||||
return jda;
|
||||
}
|
||||
|
||||
public static User getSelf() {
|
||||
public User getSelf() {
|
||||
return jda.getSelfUser();
|
||||
|
||||
}
|
||||
|
||||
private static void disconnect() {
|
||||
private void disconnect() {
|
||||
if (jda != null) {
|
||||
jda.shutdown();
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import me.bobert.netneutrality.command.AbstractMusicCommand;
|
||||
import me.bobert.netneutrality.context.SlashCommandContext;
|
||||
import me.bobert.netneutrality.core.command.CommandExecutionResult;
|
||||
import me.bobert.netneutrality.music.MusicManager;
|
||||
import me.bobert.netneutrality.music.QueueManager;
|
||||
import me.bobert.netneutrality.utils.MessageFunction;
|
||||
import me.bobert.netneutrality.utils.MusicUtils;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
@@ -62,32 +61,25 @@ public class QueueCommand extends AbstractMusicCommand {
|
||||
@Override
|
||||
public CommandExecutionResult execute(SlashCommandContext context) {
|
||||
MusicManager manager = MusicManager.get(context.getGuild());
|
||||
QueueManager queueManager = manager.getQueueManager();
|
||||
context.ack();
|
||||
String sub = context.getSubCommand();
|
||||
context.ack();
|
||||
|
||||
if (MusicUtils.checkIfConnected(context)) {
|
||||
|
||||
switch (sub) {
|
||||
case "clear-all" -> {
|
||||
return queueManager.clearQueue();
|
||||
return manager.getQueueManager().clearQueue();
|
||||
}
|
||||
|
||||
case "delete-track" -> {
|
||||
int position = context.getEvent().getOption("position", 0, OptionMapping::getAsInt);
|
||||
return queueManager.removeFromQueue(position);
|
||||
return manager.getQueueManager().removeFromQueue(position);
|
||||
}
|
||||
|
||||
case "show-queue" -> {
|
||||
if (queueManager.getQueueSize() == 0) {
|
||||
return CommandExecutionResult.info("Queue is empty!");
|
||||
}
|
||||
|
||||
context.reply(MessageFunction.buildViewQueueMessage(manager));
|
||||
}
|
||||
case "show-queue" -> context.reply(MessageFunction.buildViewQueueMessage(manager));
|
||||
|
||||
case "shuffle" -> {
|
||||
return queueManager.shuffle();
|
||||
return manager.getQueueManager().shuffle();
|
||||
}
|
||||
|
||||
case "from-user" -> {
|
||||
@@ -105,13 +97,7 @@ public class QueueCommand extends AbstractMusicCommand {
|
||||
return CommandExecutionResult.warn("The user isn't from this guild");
|
||||
}
|
||||
|
||||
int size = queueManager.getQueueWithFilter(trackInfo -> member.equals(trackInfo.getRequester())).size();
|
||||
if (size == 0) {
|
||||
return CommandExecutionResult.info(String.format("No tracks added by user %s", member.getEffectiveName()));
|
||||
}
|
||||
|
||||
queueManager.removeTracksFromUser(member);
|
||||
context.reply("Removed all tracks from user %s", member.getEffectiveName());
|
||||
return manager.getQueueManager().removeTracksFromUser(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ public class ResumeCommand extends AbstractMusicCommand {
|
||||
MusicManager manager = MusicManager.get(context.getGuild());
|
||||
|
||||
if (MusicUtils.checkIfConnected(context)) {
|
||||
return manager.getQueueManager().skip();
|
||||
return manager.resume();
|
||||
}
|
||||
|
||||
return CommandExecutionResult.none();
|
||||
|
||||
+9
-8
@@ -1,4 +1,4 @@
|
||||
package me.bobert.netneutrality.core;
|
||||
package me.bobert.netneutrality.context;
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
@@ -14,19 +14,20 @@ import net.dv8tion.jda.api.interactions.modals.Modal;
|
||||
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
|
||||
import net.dv8tion.jda.api.utils.messages.MessageEditData;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class AsyncMessage extends AbstractContext {
|
||||
public class AsyncContext extends AbstractContext {
|
||||
private final InteractionHook hook;
|
||||
private final Message message;
|
||||
|
||||
public AsyncMessage(InteractionHook hook) {
|
||||
public AsyncContext(InteractionHook hook) {
|
||||
super(hook.getJDA(), hook.getInteraction().getGuild(), hook.getInteraction().getMessageChannel(), hook.getInteraction().getMember(), hook.getInteraction().getUser());
|
||||
this.hook = hook;
|
||||
this.message = null;
|
||||
}
|
||||
|
||||
public AsyncMessage(Message message) {
|
||||
public AsyncContext(Message message) {
|
||||
super(message.getJDA(), message.getGuild(), message.getChannel(), message.getMember(), message.getAuthor());
|
||||
this.hook = null;
|
||||
this.message = message;
|
||||
@@ -49,7 +50,7 @@ public class AsyncMessage extends AbstractContext {
|
||||
|
||||
@Override
|
||||
public boolean isFromGuild() {
|
||||
return false;
|
||||
return message != null ? message.isFromGuild() : hook.getInteraction().isFromGuild();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,7 +70,7 @@ public class AsyncMessage extends AbstractContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reply(MessageCreateData messageCreateData, boolean ephemeral, Consumer<AsyncMessage> consumer, LayoutComponent... components) {
|
||||
public void reply(MessageCreateData messageCreateData, boolean ephemeral, List<LayoutComponent> components, Consumer<AsyncContext> consumer) {
|
||||
if (hook != null) {
|
||||
hook.sendMessage(messageCreateData).queue();
|
||||
}
|
||||
@@ -80,7 +81,7 @@ public class AsyncMessage extends AbstractContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defer(Consumer<AsyncMessage> consumer) {
|
||||
public void defer(boolean ephemeral, Consumer<AsyncContext> consumer) {
|
||||
|
||||
}
|
||||
|
||||
@@ -90,7 +91,7 @@ public class AsyncMessage extends AbstractContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void edit(MessageEditData messageEditData, boolean ephemeral, Consumer<AsyncMessage> consumer, LayoutComponent... components) {
|
||||
public void edit(MessageEditData messageEditData, boolean ephemeral, List<LayoutComponent> components, Consumer<AsyncContext> consumer) {
|
||||
if (hook != null) {
|
||||
hook.editOriginal(messageEditData).queue();
|
||||
}
|
||||
@@ -5,7 +5,6 @@ package me.bobert.netneutrality.context;
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.core.AsyncMessage;
|
||||
import me.bobert.netneutrality.core.context.CommandContext;
|
||||
import me.bobert.netneutrality.utils.Settings;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
@@ -15,6 +14,7 @@ import net.dv8tion.jda.api.interactions.components.LayoutComponent;
|
||||
import net.dv8tion.jda.api.interactions.modals.Modal;
|
||||
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -77,14 +77,14 @@ public class MessageCommandContext extends CommandContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defer(Consumer<AsyncMessage> consumer) {
|
||||
public void defer(boolean ephemeral, Consumer<AsyncContext> consumer) {
|
||||
reply("Bot is thinking...", consumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reply(MessageCreateData messageCreateData, boolean ephemeral, Consumer<AsyncMessage> consumer, LayoutComponent... components) {
|
||||
public void reply(MessageCreateData messageCreateData, boolean ephemeral, List<LayoutComponent> components, Consumer<AsyncContext> consumer) {
|
||||
if (getChannel() != null && getChannel().canTalk()) {
|
||||
message.reply(messageCreateData).setComponents(components).queue(message1 -> consumer.accept(new AsyncMessage(message1)));
|
||||
message.reply(messageCreateData).setComponents(components).queue(message -> consumer.accept(new AsyncContext(message)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,8 +94,8 @@ public class MessageCommandContext extends CommandContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replyEphemeral(MessageCreateData message) {
|
||||
sendMessageInPrivate(message);
|
||||
public void replyEphemeral(MessageCreateData messageCreateData) {
|
||||
sendMessageInPrivate(messageCreateData);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,7 +5,6 @@ package me.bobert.netneutrality.context;
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.core.AsyncMessage;
|
||||
import me.bobert.netneutrality.core.context.AbstractContext;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
|
||||
@@ -15,6 +14,7 @@ import net.dv8tion.jda.api.interactions.components.LayoutComponent;
|
||||
import net.dv8tion.jda.api.interactions.modals.Modal;
|
||||
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class MusicChannelContext extends AbstractContext {
|
||||
@@ -54,14 +54,14 @@ public class MusicChannelContext extends AbstractContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reply(MessageCreateData message, boolean ephemeral, Consumer<AsyncMessage> consumer, LayoutComponent... components) {
|
||||
public void reply(MessageCreateData messageCreateData, boolean ephemeral, List<LayoutComponent> components, Consumer<AsyncContext> consumer) {
|
||||
if (getChannel().canTalk()) {
|
||||
getChannel().sendMessage(message).setComponents(components).queue(message1 -> consumer.accept(new AsyncMessage(message1)));
|
||||
getChannel().sendMessage(messageCreateData).setComponents(components).queue(message -> consumer.accept(new AsyncContext(message)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defer(Consumer<AsyncMessage> consumer) {
|
||||
public void defer(boolean ephemeral, Consumer<AsyncContext> consumer) {
|
||||
reply("Bot is thinking", consumer);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,17 +5,13 @@ package me.bobert.netneutrality.context;
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.core.AsyncMessage;
|
||||
import me.bobert.netneutrality.core.context.CommandContext;
|
||||
import me.bobert.netneutrality.core.context.InteractionContext;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import net.dv8tion.jda.api.interactions.InteractionHook;
|
||||
import net.dv8tion.jda.api.interactions.components.LayoutComponent;
|
||||
import net.dv8tion.jda.api.interactions.modals.Modal;
|
||||
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class SlashCommandContext extends CommandContext {
|
||||
public class SlashCommandContext extends CommandContext implements InteractionContext {
|
||||
private final SlashCommandInteractionEvent event;
|
||||
|
||||
public SlashCommandContext(SlashCommandInteractionEvent event) {
|
||||
@@ -28,16 +24,6 @@ public class SlashCommandContext extends CommandContext {
|
||||
return event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAcknowledged() {
|
||||
return event.isAcknowledged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFromGuild() {
|
||||
return event.isFromGuild();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionHook getInteractionHook() {
|
||||
if (!event.isAcknowledged())
|
||||
@@ -51,36 +37,11 @@ public class SlashCommandContext extends CommandContext {
|
||||
// not implemented
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defer(Consumer<AsyncMessage> consumer) {
|
||||
event.deferReply().queue(hook -> consumer.accept(new AsyncMessage(hook)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reply(MessageCreateData message, boolean ephemeral, Consumer<AsyncMessage> consumer, LayoutComponent... components) {
|
||||
if (isAcknowledged()) {
|
||||
getInteractionHook().sendMessage(message).setEphemeral(ephemeral).setComponents(components)
|
||||
.queue(message1 -> consumer.accept(new AsyncMessage(message1)));
|
||||
return;
|
||||
}
|
||||
|
||||
event.reply(message).setEphemeral(ephemeral).setComponents(components)
|
||||
.queue(message1 -> consumer.accept(new AsyncMessage(message1)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reply(Modal modal) {
|
||||
event.replyModal(modal).queue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ack(boolean ephemeral) {
|
||||
if (event.isAcknowledged())
|
||||
throw new RuntimeException("Interaction is already acknowledged, please use getInteractionHook() instead.");
|
||||
|
||||
event.deferReply(ephemeral).queue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parseCommandName() {
|
||||
return event.getName();
|
||||
|
||||
@@ -5,16 +5,12 @@ package me.bobert.netneutrality.context.tasks;
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.core.AsyncMessage;
|
||||
import me.bobert.netneutrality.core.context.InteractionContext;
|
||||
import me.bobert.netneutrality.core.context.TaskContext;
|
||||
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
|
||||
import net.dv8tion.jda.api.interactions.InteractionHook;
|
||||
import net.dv8tion.jda.api.interactions.components.LayoutComponent;
|
||||
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class ButtonTaskContext extends TaskContext {
|
||||
public class ButtonTaskContext extends TaskContext implements InteractionContext {
|
||||
private final ButtonInteractionEvent event;
|
||||
|
||||
public ButtonTaskContext(ButtonInteractionEvent event) {
|
||||
@@ -36,40 +32,4 @@ public class ButtonTaskContext extends TaskContext {
|
||||
public InteractionHook getInteractionHook() {
|
||||
return event.getHook();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defer(Consumer<AsyncMessage> consumer) {
|
||||
event.deferReply().queue(hook -> consumer.accept(new AsyncMessage(hook)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAcknowledged() {
|
||||
return event.isAcknowledged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFromGuild() {
|
||||
return event.isFromGuild();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reply(MessageCreateData message, boolean ephemeral, Consumer<AsyncMessage> consumer, LayoutComponent... components) {
|
||||
if (isAcknowledged()) {
|
||||
getInteractionHook().sendMessage(message)
|
||||
.setEphemeral(ephemeral)
|
||||
.setComponents(components)
|
||||
.queue(message1 -> consumer.accept(new AsyncMessage(message1)));
|
||||
return;
|
||||
}
|
||||
|
||||
event.reply(message)
|
||||
.setEphemeral(ephemeral)
|
||||
.setComponents(components)
|
||||
.queue(message1 -> consumer.accept(new AsyncMessage(message1)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ack(boolean ephemeral) {
|
||||
event.deferReply(ephemeral).queue();
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ package me.bobert.netneutrality.context.tasks;
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.core.AsyncMessage;
|
||||
import me.bobert.netneutrality.context.AsyncContext;
|
||||
import me.bobert.netneutrality.core.context.TaskContext;
|
||||
import net.dv8tion.jda.api.entities.MessageReaction;
|
||||
import net.dv8tion.jda.api.entities.emoji.EmojiUnion;
|
||||
@@ -14,6 +14,7 @@ import net.dv8tion.jda.api.interactions.InteractionHook;
|
||||
import net.dv8tion.jda.api.interactions.components.LayoutComponent;
|
||||
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class EmojiTaskContext extends TaskContext {
|
||||
@@ -50,7 +51,7 @@ public class EmojiTaskContext extends TaskContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defer(Consumer<AsyncMessage> consumer) {
|
||||
public void defer(boolean ephemeral, Consumer<AsyncContext> consumer) {
|
||||
reply("Bot is thinking...", consumer);
|
||||
}
|
||||
|
||||
@@ -65,15 +66,15 @@ public class EmojiTaskContext extends TaskContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reply(MessageCreateData message, boolean ephemeral, Consumer<AsyncMessage> consumer, LayoutComponent... components) {
|
||||
public void reply(MessageCreateData messageCreateData, boolean ephemeral, List<LayoutComponent> components, Consumer<AsyncContext> consumer) {
|
||||
if (getChannel() != null && getChannel().canTalk()) {
|
||||
getChannel().sendMessage(message).setComponents(components).queue(message1 -> consumer.accept(new AsyncMessage(message1)));
|
||||
getChannel().sendMessage(messageCreateData).setComponents(components).queue(message -> consumer.accept(new AsyncContext(message)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replyEphemeral(MessageCreateData message) {
|
||||
sendMessageInPrivate(message);
|
||||
public void replyEphemeral(MessageCreateData messageCreateData) {
|
||||
sendMessageInPrivate(messageCreateData);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,16 +5,12 @@ package me.bobert.netneutrality.context.tasks;
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.core.AsyncMessage;
|
||||
import me.bobert.netneutrality.core.context.InteractionContext;
|
||||
import me.bobert.netneutrality.core.context.TaskContext;
|
||||
import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
|
||||
import net.dv8tion.jda.api.interactions.InteractionHook;
|
||||
import net.dv8tion.jda.api.interactions.components.LayoutComponent;
|
||||
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class ModalTaskContext extends TaskContext {
|
||||
public class ModalTaskContext extends TaskContext implements InteractionContext {
|
||||
private final ModalInteractionEvent event;
|
||||
|
||||
public ModalTaskContext(ModalInteractionEvent event) {
|
||||
@@ -36,36 +32,4 @@ public class ModalTaskContext extends TaskContext {
|
||||
public InteractionHook getInteractionHook() {
|
||||
return event.getHook();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defer(Consumer<AsyncMessage> consumer) {
|
||||
event.deferReply().queue(hook -> consumer.accept(new AsyncMessage(hook)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAcknowledged() {
|
||||
return event.isAcknowledged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFromGuild() {
|
||||
return event.isFromGuild();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reply(MessageCreateData message, boolean ephemeral, Consumer<AsyncMessage> consumer, LayoutComponent... components) {
|
||||
if (isAcknowledged()) {
|
||||
getInteractionHook().sendMessage(message).setEphemeral(ephemeral).setComponents(components)
|
||||
.queue(message1 -> consumer.accept(new AsyncMessage(message1)));
|
||||
return;
|
||||
}
|
||||
|
||||
event.reply(message).setEphemeral(ephemeral).setComponents(components)
|
||||
.queue(message1 -> consumer.accept(new AsyncMessage(message1)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ack(boolean ephemeral) {
|
||||
event.deferReply(ephemeral).queue();
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,7 @@ public class GuildManager {
|
||||
return managers.get(guildId);
|
||||
}
|
||||
|
||||
Guild temp = NetNeutrality.getJDA().getGuildById(guildId);
|
||||
Guild temp = NetNeutrality.getInstance().getJDA().getGuildById(guildId);
|
||||
if (temp == null) {
|
||||
throw new IllegalArgumentException("Guild does not exist in current cache");
|
||||
}
|
||||
|
||||
@@ -60,7 +60,12 @@ public class LogHandler {
|
||||
|
||||
private static void logInternally(ContextException exception) {
|
||||
Context context = exception.getContext();
|
||||
logger.error("Exception thrown from context in guild {}: {}", context.getGuild() == null ? "PrivateMessage": context.getGuild().getId(), exception.getMessage());
|
||||
String guildId = context.getGuild() == null ? "PrivateMessage" : context.getGuild().getId();
|
||||
|
||||
logger.error("Exception thrown from context (guild: {}, user: {}): {}", guildId,
|
||||
context.getDiscordUser().getId(),
|
||||
exception.getMessage()
|
||||
);
|
||||
|
||||
if (context instanceof CommandContext commandContext) {
|
||||
logger.error("Caused by command: {}", commandContext.getCommand().getCommandName(), exception);
|
||||
|
||||
@@ -5,7 +5,7 @@ package me.bobert.netneutrality.core.context;
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.core.AsyncMessage;
|
||||
import me.bobert.netneutrality.context.AsyncContext;
|
||||
import me.bobert.netneutrality.core.GuildManager;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
@@ -47,9 +47,9 @@ public interface Context {
|
||||
|
||||
void reply(Modal modal);
|
||||
|
||||
void reply(MessageCreateData message, boolean ephemeral, Consumer<AsyncMessage> consumer, LayoutComponent... components);
|
||||
void reply(MessageCreateData messageCreateData, boolean ephemeral, List<LayoutComponent> components, Consumer<AsyncContext> consumer);
|
||||
|
||||
void defer(Consumer<AsyncMessage> consumer);
|
||||
void defer(boolean ephemeral, Consumer<AsyncContext> consumer);
|
||||
|
||||
void ack(boolean ephemeral);
|
||||
|
||||
@@ -65,8 +65,8 @@ public interface Context {
|
||||
ack(true);
|
||||
}
|
||||
|
||||
default void reply(MessageCreateData message) {
|
||||
reply(message, false, asyncMessage -> {});
|
||||
default void reply(MessageCreateData messageCreateData) {
|
||||
reply(messageCreateData, false, List.of(), asyncMessage -> {});
|
||||
}
|
||||
|
||||
default void reply(String message) {
|
||||
@@ -81,21 +81,21 @@ public interface Context {
|
||||
reply(String.format(format, arguments));
|
||||
}
|
||||
|
||||
default void edit(MessageEditData message, boolean ephemeral, Consumer<AsyncMessage> consumer, LayoutComponent... components) {
|
||||
default void edit(MessageEditData messageEditData, boolean ephemeral, List<LayoutComponent> components, Consumer<AsyncContext> consumer) {
|
||||
if (isAcknowledged() && getInteractionHook() != null) {
|
||||
getInteractionHook().editOriginal(message).setComponents(components).queue(message1 -> consumer.accept(new AsyncMessage(message1)));
|
||||
getInteractionHook().editOriginal(messageEditData).setComponents(components).queue(message1 -> consumer.accept(new AsyncContext(message1)));
|
||||
return;
|
||||
}
|
||||
|
||||
reply(MessageCreateData.fromEditData(message), ephemeral, consumer, components);
|
||||
reply(MessageCreateData.fromEditData(messageEditData), ephemeral, components, consumer);
|
||||
}
|
||||
|
||||
default void edit(MessageEditData message, LayoutComponent... components) {
|
||||
edit(message, false, asyncMessage -> {}, components);
|
||||
default void edit(MessageEditData messageEditData, List<LayoutComponent> components) {
|
||||
edit(messageEditData, false, components, asyncMessage -> {});
|
||||
}
|
||||
|
||||
default void edit(MessageEditData message) {
|
||||
edit(message, false, asyncMessage -> {});
|
||||
default void edit(MessageEditData messageEditData) {
|
||||
edit(messageEditData, false, List.of(), asyncMessage -> {});
|
||||
}
|
||||
|
||||
default void edit(String message) {
|
||||
@@ -106,7 +106,7 @@ public interface Context {
|
||||
edit(MessageEditData.fromEmbeds(embed));
|
||||
}
|
||||
|
||||
default void edit(MessageEmbed embeds, LayoutComponent... components) {
|
||||
default void edit(MessageEmbed embeds, List<LayoutComponent> components) {
|
||||
edit(MessageEditData.fromEmbeds(embeds), components);
|
||||
}
|
||||
|
||||
@@ -114,20 +114,20 @@ public interface Context {
|
||||
edit(String.format(format, arguments));
|
||||
}
|
||||
|
||||
default void async(MessageCreateData message, Consumer<AsyncMessage> consumer) {
|
||||
reply(message, false, consumer);
|
||||
default void async(MessageCreateData messageCreateData, Consumer<AsyncContext> consumer) {
|
||||
reply(messageCreateData, false, List.of(), consumer);
|
||||
}
|
||||
|
||||
default void async(String message, Consumer<AsyncMessage> consumer) {
|
||||
default void async(String message, Consumer<AsyncContext> consumer) {
|
||||
async(MessageCreateData.fromContent(message), consumer);
|
||||
}
|
||||
|
||||
default void async(Consumer<AsyncMessage> consumer) {
|
||||
defer(consumer);
|
||||
default void async(Consumer<AsyncContext> consumer) {
|
||||
defer(false, consumer);
|
||||
}
|
||||
|
||||
default void replyEphemeral(MessageCreateData message) {
|
||||
reply(message, true, asyncMessage -> {});
|
||||
default void replyEphemeral(MessageCreateData messageCreateData) {
|
||||
reply(messageCreateData, true, List.of(), asyncMessage -> {});
|
||||
}
|
||||
|
||||
default void replyEphemeral(String message) {
|
||||
@@ -142,10 +142,10 @@ public interface Context {
|
||||
replyEphemeral(MessageCreateData.fromEmbeds(embeds));
|
||||
}
|
||||
|
||||
default void sendMessageInPrivate(MessageCreateData msg) {
|
||||
default void sendMessageInPrivate(MessageCreateData messageCreateData) {
|
||||
User user = getDiscordUser();
|
||||
if (user != null) {
|
||||
user.openPrivateChannel().flatMap(channel -> channel.sendMessage(msg)).queue();
|
||||
user.openPrivateChannel().flatMap(channel -> channel.sendMessage(messageCreateData)).queue();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package me.bobert.netneutrality.core.context;
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.context.AsyncContext;
|
||||
import net.dv8tion.jda.api.events.Event;
|
||||
import net.dv8tion.jda.api.interactions.Interaction;
|
||||
import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback;
|
||||
import net.dv8tion.jda.api.interactions.components.LayoutComponent;
|
||||
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public interface InteractionContext extends Context {
|
||||
|
||||
@Override
|
||||
default void ack(boolean ephemeral) {
|
||||
defer(ephemeral, asyncMessage -> {});
|
||||
}
|
||||
|
||||
@Override
|
||||
default void defer(boolean ephemeral, Consumer<AsyncContext> consumer) {
|
||||
if (isAcknowledged()) {
|
||||
throw new RuntimeException("Interaction is already acknowledged, please use getInteractionHook() instead.");
|
||||
}
|
||||
|
||||
getReplyCallback(getEvent()).deferReply(ephemeral).queue(hook -> consumer.accept(new AsyncContext(hook)));
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean isFromGuild() {
|
||||
Event event = getEvent();
|
||||
try {
|
||||
Interaction interaction = (Interaction) event;
|
||||
return interaction.isFromGuild();
|
||||
} catch (ClassCastException e) {
|
||||
throw new IllegalArgumentException(event.getClass().getSimpleName() + " does not implement class 'Interaction'", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean isAcknowledged() {
|
||||
Event event = getEvent();
|
||||
try {
|
||||
Interaction interaction = (Interaction) event;
|
||||
return interaction.isAcknowledged();
|
||||
} catch (ClassCastException e) {
|
||||
throw new IllegalArgumentException(event.getClass().getSimpleName() + " does not implement class 'Interaction'", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
default void reply(MessageCreateData messageCreateData, boolean ephemeral, List<LayoutComponent> components, Consumer<AsyncContext> consumer) {
|
||||
if (isAcknowledged()) {
|
||||
getInteractionHook().sendMessage(messageCreateData).setEphemeral(ephemeral).setComponents(components).queue(message -> consumer.accept(new AsyncContext(message)));
|
||||
return;
|
||||
}
|
||||
|
||||
getReplyCallback(getEvent()).reply(messageCreateData).setEphemeral(ephemeral).setComponents(components).queue(message -> consumer.accept(new AsyncContext(message)));
|
||||
}
|
||||
|
||||
static IReplyCallback getReplyCallback(Event event) {
|
||||
try {
|
||||
return (IReplyCallback) event;
|
||||
} catch (ClassCastException e) {
|
||||
throw new IllegalArgumentException(event.getClass().getSimpleName() + " does not implement class 'IReplyCallback'", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,9 +16,9 @@ public interface Task {
|
||||
/**
|
||||
* <p>This method should generate a unique ID to differentiate it from other tasks.</p>
|
||||
* <p>
|
||||
* For button and modal interaction, this is the ID of the component sent to discord.
|
||||
* For other types of interaction, for example emoji reaction,
|
||||
* each reaction should get a unique ID generated by the context.
|
||||
* This determines what triggers a task to be executed.
|
||||
* For example, a modal or button would use the component id.
|
||||
* For an emoji reaction, the guild and message id would be combined.
|
||||
* </p>
|
||||
* @return a unique ID for this task
|
||||
*/
|
||||
|
||||
@@ -26,7 +26,7 @@ public class ActionHandler extends AbstractHandler {
|
||||
|
||||
if (path.equals("/actions/shutdown")) {
|
||||
LogManager.getLogger(NetNeutrality.class).info("Request to shutdown received");
|
||||
NetNeutrality.shutdown();
|
||||
NetNeutrality.getInstance().shutdown();
|
||||
sendStringResponse(exchange, "Shutting down..");
|
||||
|
||||
System.exit(0);
|
||||
@@ -35,8 +35,8 @@ public class ActionHandler extends AbstractHandler {
|
||||
|
||||
if (path.equals("/actions/status")) {
|
||||
TreeMap<String, String> json = new TreeMap<>();
|
||||
json.put("health", String.valueOf(NetNeutrality.getJDA().getStatus()));
|
||||
json.put("ping", String.valueOf(NetNeutrality.getJDA().getGatewayPing()));
|
||||
json.put("health", String.valueOf(NetNeutrality.getInstance().getJDA().getStatus()));
|
||||
json.put("ping", String.valueOf(NetNeutrality.getInstance().getJDA().getGatewayPing()));
|
||||
|
||||
sendJsonResponse(exchange, WebModule.createJson(json));
|
||||
return;
|
||||
@@ -47,7 +47,7 @@ public class ActionHandler extends AbstractHandler {
|
||||
String[] args = exchange.getRequestURI().toString().split("/");
|
||||
String guildId = args[args.length - 1];
|
||||
|
||||
Guild guild = NetNeutrality.getJDA().getGuildById(guildId);
|
||||
Guild guild = NetNeutrality.getInstance().getJDA().getGuildById(guildId);
|
||||
if (guild != null) {
|
||||
GuildManager manager = GuildManager.getManager(guild);
|
||||
Map<String, String> settings = manager.getGuildConfigManager().getSettings();
|
||||
@@ -68,7 +68,7 @@ public class ActionHandler extends AbstractHandler {
|
||||
String[] args = exchange.getRequestURI().toString().split("/");
|
||||
String guildId = args[args.length - 1];
|
||||
|
||||
Guild guild = NetNeutrality.getJDA().getGuildById(guildId);
|
||||
Guild guild = NetNeutrality.getInstance().getJDA().getGuildById(guildId);
|
||||
boolean ok = true; //TODO: add bool
|
||||
if (guild == null)
|
||||
GuildManager.getManager(guildId).getGuildConfigManager().reloadSettingsCache();
|
||||
|
||||
@@ -25,7 +25,7 @@ public class GuildHandler extends AbstractHandler {
|
||||
|
||||
JSONArray array = new JSONArray();
|
||||
|
||||
JDA jda = NetNeutrality.getJDA();
|
||||
JDA jda = NetNeutrality.getInstance().getJDA();
|
||||
|
||||
jda.getGuilds().forEach(guild -> {
|
||||
JSONObject obj = new JSONObject();
|
||||
@@ -45,7 +45,7 @@ public class GuildHandler extends AbstractHandler {
|
||||
String guild = args[args.length - 1];
|
||||
JSONArray array = new JSONArray();
|
||||
|
||||
JDA jda = NetNeutrality.getJDA();
|
||||
JDA jda = NetNeutrality.getInstance().getJDA();
|
||||
|
||||
if (jda.getGuildById(guild) == null) {
|
||||
sendStringResponse(exchange, path);
|
||||
@@ -69,7 +69,7 @@ public class GuildHandler extends AbstractHandler {
|
||||
String[] args = exchange.getRequestURI().toString().split("/");
|
||||
String guild = args[args.length - 1];
|
||||
JSONArray array = new JSONArray();
|
||||
JDA jda = NetNeutrality.getJDA();
|
||||
JDA jda = NetNeutrality.getInstance().getJDA();
|
||||
|
||||
if (jda.getGuildById(guild) == null) {
|
||||
sendStringResponse(exchange, path);
|
||||
|
||||
@@ -19,6 +19,7 @@ import me.bobert.netneutrality.core.context.CommandContext;
|
||||
import me.bobert.netneutrality.core.thread.ThreadManager;
|
||||
import me.bobert.netneutrality.db.GSettings;
|
||||
import me.bobert.netneutrality.music.source.UdioAudioSourceManager;
|
||||
import me.bobert.netneutrality.thread.MusicManagerCleanupThread;
|
||||
import me.bobert.netneutrality.thread.MusicPlayerAutoDisconnectThread;
|
||||
import me.bobert.netneutrality.utils.MusicUtils;
|
||||
import me.bobert.netneutrality.utils.Settings;
|
||||
@@ -27,24 +28,20 @@ import net.dv8tion.jda.api.entities.channel.middleman.AudioChannel;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class MusicManager {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger(MusicManager.class);
|
||||
private static final Map<String, MusicManager> managers = new ConcurrentHashMap<>();
|
||||
private static final ScheduledExecutorService executor = ThreadManager.getScheduledExecutor();
|
||||
|
||||
private static final AudioPlayerManager playerManager = new DefaultAudioPlayerManager();
|
||||
private final Guild guild;
|
||||
private final AudioPlayer player;
|
||||
private final TrackScheduler scheduler;
|
||||
private final int baseVolume;
|
||||
private ScheduledFuture<?> autoDisconnectThread;
|
||||
|
||||
private MusicManager(Guild guild) {
|
||||
this.guild = guild;
|
||||
@@ -75,6 +72,9 @@ public class MusicManager {
|
||||
String po = Settings.getInstance().get("NETNEUTRALITY_PO_TOKEN");
|
||||
String visitor = Settings.getInstance().get("NETNEUTRALITY_VISITOR_DATA");
|
||||
dev.lavalink.youtube.clients.Web.setPoTokenAndVisitorData(po, visitor);
|
||||
|
||||
ThreadManager.getScheduledExecutor().scheduleWithFixedDelay(new MusicPlayerAutoDisconnectThread(), 15, 15, TimeUnit.MINUTES);
|
||||
ThreadManager.getScheduledExecutor().scheduleWithFixedDelay(new MusicManagerCleanupThread(), 1, 1, TimeUnit.HOURS);
|
||||
}
|
||||
|
||||
public static void disconnectPlayers() {
|
||||
@@ -84,6 +84,10 @@ public class MusicManager {
|
||||
}
|
||||
}
|
||||
|
||||
public static Collection<MusicManager> getManagers() {
|
||||
return managers.values();
|
||||
}
|
||||
|
||||
public TrackScheduler getScheduler() {
|
||||
return scheduler;
|
||||
}
|
||||
@@ -105,14 +109,11 @@ public class MusicManager {
|
||||
}
|
||||
|
||||
public synchronized void connect(AudioChannel audioChannel) {
|
||||
if (audioChannel != null && isNotConnectedTo(audioChannel)) {
|
||||
if (audioChannel != null) {
|
||||
logger.debug("Guild {}: connecting to voice channel {}", audioChannel.getGuild().getId(), audioChannel.getId());
|
||||
guild.getAudioManager().openAudioConnection(audioChannel);
|
||||
guild.getAudioManager().setSelfDeafened(true);
|
||||
player.setVolume(baseVolume);
|
||||
|
||||
if (autoDisconnectThread == null)
|
||||
autoDisconnectThread = executor.scheduleWithFixedDelay(new MusicPlayerAutoDisconnectThread(this), 240, 240, TimeUnit.SECONDS);
|
||||
} else {
|
||||
throw new RuntimeException("Error connecting to voice channel");
|
||||
}
|
||||
@@ -126,11 +127,6 @@ public class MusicManager {
|
||||
}
|
||||
|
||||
scheduler.detachContext();
|
||||
|
||||
if (autoDisconnectThread != null) {
|
||||
autoDisconnectThread.cancel(true);
|
||||
autoDisconnectThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
@@ -152,6 +148,7 @@ public class MusicManager {
|
||||
public synchronized void play(String query, CommandContext context, boolean silent) {
|
||||
logger.debug("Guild {}: request to play '{}' by user {}", guild.getId(), query, context.getGuildUser().getId());
|
||||
|
||||
if (MusicUtils.canConnect(context)) {
|
||||
SourceFinder.AudioSourceType type = SourceFinder.getSource(query);
|
||||
String identifier = SourceFinder.getIdentifier(query);
|
||||
if (identifier == null) {
|
||||
@@ -159,7 +156,6 @@ public class MusicManager {
|
||||
return;
|
||||
}
|
||||
|
||||
if (MusicUtils.canConnect(context)) {
|
||||
TrackLoadingHandler loadingHandler = new TrackLoadingHandler(context, this, identifier, type, silent);
|
||||
playerManager.loadItemOrdered(this, identifier, loadingHandler);
|
||||
}
|
||||
@@ -169,6 +165,10 @@ public class MusicManager {
|
||||
player.stopTrack();
|
||||
}
|
||||
|
||||
public synchronized CommandExecutionResult resume() {
|
||||
return getQueueManager().resume();
|
||||
}
|
||||
|
||||
public synchronized CommandExecutionResult voteSkip(CommandContext context) {
|
||||
AudioChannel audioChannel = guild.getAudioManager().getConnectedChannel();
|
||||
if (audioChannel == null) {
|
||||
|
||||
@@ -90,14 +90,19 @@ public class QueueManager {
|
||||
}
|
||||
}
|
||||
|
||||
public void removeTracksFromUser(Member member) {
|
||||
public CommandExecutionResult removeTracksFromUser(Member member) {
|
||||
if (queue.stream().filter(trackInfo -> member.equals(trackInfo.getRequester())).toList().isEmpty()) {
|
||||
return CommandExecutionResult.info(String.format("No tracks added by user %s", member.getEffectiveName()));
|
||||
}
|
||||
|
||||
synchronized (queue) {
|
||||
int size = queue.stream().filter(trackInfo -> member.equals(trackInfo.getRequester())).toList().size();
|
||||
if (size == 0) {
|
||||
return CommandExecutionResult.info(String.format("No tracks added by user %s", member.getEffectiveName()));
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
if (size == queue.size()) {
|
||||
clearQueue();
|
||||
return;
|
||||
return clearQueue();
|
||||
}
|
||||
|
||||
TrackInfo first = queue.peek();
|
||||
@@ -106,7 +111,8 @@ public class QueueManager {
|
||||
if (first != null && member.equals(first.getRequester())) {
|
||||
skip(1);
|
||||
}
|
||||
}
|
||||
|
||||
return CommandExecutionResult.success(String.format("Removed all tracks from user %s", member.getEffectiveName()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,6 +125,10 @@ public class QueueManager {
|
||||
}
|
||||
}
|
||||
|
||||
public void queue(List<AudioTrack> tracks, Member member) {
|
||||
tracks.forEach(track -> queue(track, member));
|
||||
}
|
||||
|
||||
public void queue(AudioTrack track, Member member) {
|
||||
TrackInfo info = new TrackInfo(track, member);
|
||||
if (queue.contains(info)) {
|
||||
@@ -145,6 +155,20 @@ public class QueueManager {
|
||||
}
|
||||
}
|
||||
|
||||
public CommandExecutionResult resume() {
|
||||
synchronized (queue) {
|
||||
TrackInfo next = queue.peek();
|
||||
|
||||
if (next != null) {
|
||||
player.startTrack(next.getTrack().makeClone(), false);
|
||||
return CommandExecutionResult.success("Starting playback of track " + next.getTrack().getInfo().title);
|
||||
}
|
||||
|
||||
player.stopTrack();
|
||||
return CommandExecutionResult.info("Queue is empty, leaving voice channel");
|
||||
}
|
||||
}
|
||||
|
||||
public void startNextTrack() {
|
||||
synchronized (queue) {
|
||||
TrackInfo last = queue.poll();
|
||||
|
||||
@@ -67,6 +67,10 @@ public class TrackScheduler extends AudioEventAdapter {
|
||||
this.context = null;
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerPause(AudioPlayer player) {
|
||||
// Player was paused
|
||||
@@ -96,6 +100,7 @@ public class TrackScheduler extends AudioEventAdapter {
|
||||
}
|
||||
|
||||
if (endReason == AudioTrackEndReason.STOPPED) {
|
||||
// maybe skip removing head to make resuming easier?
|
||||
queueManager.removeHeadOfQueue();
|
||||
}
|
||||
|
||||
@@ -109,7 +114,7 @@ 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());
|
||||
logger.error("Guild {}: exception while playing track: {}", guild.getId(), track.getIdentifier());
|
||||
LogHandler.log(exception);
|
||||
|
||||
context.reply(
|
||||
|
||||
@@ -44,9 +44,7 @@ public class AddAllTracksTask extends ButtonTask implements WithParent<LoadPlayl
|
||||
Member member = context.getGuildUser();
|
||||
|
||||
if (MusicUtils.connect(context)) {
|
||||
for (AudioTrack track : tracks) {
|
||||
manager.getQueueManager().queue(track, member);
|
||||
}
|
||||
manager.getQueueManager().queue(tracks, member);
|
||||
|
||||
context.reply(MessageFunction.buildAddingPlaylistMessage(tracks, parentTask.getPlaylist().getName(), member, SourceFinder.AudioSourceType.Youtube));
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ public class LoadPlaylistTask extends ButtonTask implements WithChildren, Deleta
|
||||
ActionRow firstRow = ActionRow.of(buttonList);
|
||||
ActionRow secondRow = commonButtons(searchResults, "Add all tracks", "Not for me honey");
|
||||
|
||||
context.edit(MessageFunction.buildSearchResultsMessage(searchResults, context.getGuildUser()), firstRow, secondRow);
|
||||
context.edit(MessageFunction.buildSearchResultsMessage(searchResults, context.getGuildUser()), List.of(firstRow, secondRow));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -89,16 +89,14 @@ public class LoadPlaylistTask extends ButtonTask implements WithChildren, Deleta
|
||||
if (tracks.size() > maxPlaylistSizeBeforeAsking) {
|
||||
ActionRow firstRow = commonButtons(playlist.getTracks(), "I'm ready", "Please don't");
|
||||
|
||||
context.edit(MessageFunction.buildPlaylistLoadMessage(playlist, context.getGuildUser()), firstRow);
|
||||
context.edit(MessageFunction.buildPlaylistLoadMessage(playlist, context.getGuildUser()), List.of(firstRow));
|
||||
return;
|
||||
}
|
||||
|
||||
// Load playlist normally
|
||||
MusicManager manager = MusicManager.get(context.getGuild());
|
||||
if (MusicUtils.connect(context)) {
|
||||
for (AudioTrack track : tracks) {
|
||||
manager.getQueueManager().queue(track, context.getGuildUser());
|
||||
}
|
||||
manager.getQueueManager().queue(tracks, context.getGuildUser());
|
||||
|
||||
context.edit(MessageFunction.buildAddingPlaylistMessage(tracks, playlist.getName(), context.getGuildUser(), Youtube));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package me.bobert.netneutrality.thread;
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.music.MusicManager;
|
||||
import me.bobert.netneutrality.music.TrackScheduler;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class MusicManagerCleanupThread implements Runnable {
|
||||
private static final Logger logger = LogManager.getLogger(MusicManagerCleanupThread.class);
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
|
||||
for (MusicManager manager : MusicManager.getManagers()) {
|
||||
processManager(manager);
|
||||
}
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("Interrupted while running MusicManagerCleanupThread", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void processManager(MusicManager manager) throws InterruptedException {
|
||||
TrackScheduler scheduler = manager.getScheduler();
|
||||
|
||||
// Context is still attached after bot is disconnected, the bot might have been kicked from the channel
|
||||
if (scheduler.getContext() != null && !manager.isConnected()) {
|
||||
manager.disconnect();
|
||||
manager.getQueueManager().clearQueue();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,7 @@ package me.bobert.netneutrality.thread;
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.NetNeutrality;
|
||||
import me.bobert.netneutrality.music.MusicManager;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.AudioChannel;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@@ -16,40 +14,47 @@ import org.apache.logging.log4j.Logger;
|
||||
import java.util.List;
|
||||
|
||||
public class MusicPlayerAutoDisconnectThread implements Runnable {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger(MusicPlayerAutoDisconnectThread.class);
|
||||
private final MusicManager manager;
|
||||
|
||||
//TODO: move to scheduler
|
||||
public MusicPlayerAutoDisconnectThread(MusicManager musicManager) {
|
||||
manager = musicManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Guild guild = manager.getGuild();
|
||||
AudioChannel channel = guild.getAudioManager().getConnectedChannel();
|
||||
|
||||
try {
|
||||
|
||||
for (MusicManager manager : MusicManager.getManagers()) {
|
||||
processManager(manager);
|
||||
}
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("Interrupted while running MusicPlayerAutoDisconnectThread", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void processManager(MusicManager manager) throws InterruptedException {
|
||||
logger.debug("Processing MusicPlayerAutoDisconnectThread for guild {}", manager.getGuild().getId());
|
||||
AudioChannel channel = manager.getGuild().getAudioManager().getConnectedChannel();
|
||||
|
||||
if (channel != null) {
|
||||
if (conditionsMetToDisconnect(channel)) {
|
||||
if (conditionsMetToDisconnect(manager)) {
|
||||
logger.debug("Guild {}: Sleeping 30 seconds and checking again", manager.getGuild().getId());
|
||||
// Sleep 30 seconds then check again (prevents disconnecting right after a track ends)
|
||||
Thread.sleep(30000);
|
||||
|
||||
if (conditionsMetToDisconnect(channel)) {
|
||||
logger.debug("Guild {}: auto-disconnect player from voice channel: {}", guild.getId(), channel.getId());
|
||||
if (conditionsMetToDisconnect(manager)) {
|
||||
logger.debug("Guild {}: auto-disconnect player from voice channel: {}", manager.getGuild().getId(), channel.getId());
|
||||
manager.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean conditionsMetToDisconnect(AudioChannel channel) {
|
||||
List<Member> members = channel.getMembers().stream().filter(member -> !member.getId().equals(NetNeutrality.getSelf().getId())).toList();
|
||||
private boolean conditionsMetToDisconnect(MusicManager manager) {
|
||||
AudioChannel channel = manager.getGuild().getAudioManager().getConnectedChannel();
|
||||
if (channel != null) {
|
||||
List<Member> members = channel.getMembers().stream().filter(member -> !member.getId().equals(channel.getJDA().getSelfUser().getId())).toList();
|
||||
|
||||
return members.isEmpty() || manager.getQueueManager().isEmpty();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,12 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.core.LoggerContext;
|
||||
import org.apache.logging.log4j.core.config.Configurator;
|
||||
|
||||
public class ShutdownThread implements Runnable {
|
||||
public class ShutdownThread extends Thread {
|
||||
private final NetNeutrality main;
|
||||
|
||||
public ShutdownThread(NetNeutrality main) {
|
||||
this.main = main;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -20,8 +25,8 @@ public class ShutdownThread implements Runnable {
|
||||
Configurator.shutdown((LoggerContext) LogManager.getContext());
|
||||
}
|
||||
|
||||
if (NetNeutrality.getJDA() != null) {
|
||||
NetNeutrality.shutdown();
|
||||
if (main.getJDA() != null) {
|
||||
main.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,10 +31,8 @@ import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.awt.*;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
public class MessageFunction {
|
||||
|
||||
@@ -44,12 +42,12 @@ public class MessageFunction {
|
||||
AudioTrack current = manager.getCurrentlyPlaying();
|
||||
|
||||
EmbedBuilder message = new EmbedBuilder();
|
||||
message.setAuthor("Link to track", String.format("https://youtu.be/%s", current.getIdentifier()));
|
||||
message.setAuthor("Link to track (click me)", String.format("https://youtu.be/%s", current.getIdentifier()));
|
||||
message.setThumbnail(String.format("https://img.youtube.com/vi/%s/default.jpg", current.getIdentifier()));
|
||||
message.setTitle("Currently playing:");
|
||||
//message.setTitle("Currently playing:");
|
||||
message.setColor(Color.BLUE);
|
||||
message.addField("Track title: ", current.getInfo().title, false);
|
||||
message.addField("Duration: ", DurationFormatUtils.formatDuration(current.getPosition(), "**HH:mm:ss**", true) + " / " + DurationFormatUtils.formatDuration(current.getDuration(), "**HH:mm:ss**", true), false);
|
||||
message.addField("Currently playing: ", current.getInfo().title, true);
|
||||
message.addField("Duration: ", DurationFormatUtils.formatDuration(current.getPosition(), "HH:mm:ss", true) + " / " + DurationFormatUtils.formatDuration(current.getDuration(), "HH:mm:ss", true), true);
|
||||
message.setTimestamp(OffsetDateTime.now());
|
||||
|
||||
return message.build();
|
||||
@@ -110,8 +108,12 @@ public class MessageFunction {
|
||||
}
|
||||
|
||||
public static String buildViewQueueMessage(MusicManager manager) {
|
||||
int limit = 15;
|
||||
List<AudioTrack> tracks = manager.getQueueManager().getAllQueuedTracks();
|
||||
if (tracks.isEmpty()) {
|
||||
return "Queue is empty!";
|
||||
}
|
||||
|
||||
int limit = 10;
|
||||
AudioTrack current = manager.getCurrentlyPlaying();
|
||||
int numberofTracksShown = Math.min(tracks.size(), limit);
|
||||
|
||||
@@ -125,13 +127,14 @@ public class MessageFunction {
|
||||
|
||||
int index = 0;
|
||||
for (AudioTrack track : tracks) {
|
||||
index++;
|
||||
AudioTrackInfo info = track.getInfo();
|
||||
|
||||
message.append("\n");
|
||||
if (current != null && current.getInfo().title.equals(info.title)) {
|
||||
message.append("**").append(++index).append(". ").append(info.title).append("**");
|
||||
message.append("- ").append("**").append(info.title).append("**");
|
||||
} else {
|
||||
message.append(++index).append(". ").append(info.title);
|
||||
message.append("- ").append(info.title);
|
||||
}
|
||||
|
||||
if (index == limit) break;
|
||||
@@ -197,8 +200,8 @@ public class MessageFunction {
|
||||
return embed.build();
|
||||
}
|
||||
|
||||
public static ArrayList<MessageEmbed> buildHelpMessage() {
|
||||
HashMap<CommandType, EmbedBuilder> help = new HashMap<>();
|
||||
public static List<MessageEmbed> buildHelpMessage() {
|
||||
Map<CommandType, EmbedBuilder> help = new HashMap<>();
|
||||
|
||||
for (Command command : CommandManager.commands.values()) {
|
||||
if (command.getType() == null)
|
||||
@@ -226,7 +229,7 @@ public class MessageFunction {
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList<MessageEmbed> messages = new ArrayList<>();
|
||||
List<MessageEmbed> messages = new ArrayList<>();
|
||||
help.values().forEach(embedBuilder -> messages.add(embedBuilder.build()));
|
||||
|
||||
return messages;
|
||||
@@ -262,10 +265,11 @@ public class MessageFunction {
|
||||
if (exception.getCause() != null) {
|
||||
String cause;
|
||||
if (exception.getCause().getMessage() != null && !exception.getCause().getMessage().isEmpty()) {
|
||||
cause = exception.getCause().getMessage();
|
||||
cause = exception.getCause().getMessage().substring(0, 64);
|
||||
} else {
|
||||
cause = exception.getCause().getClass().getName();
|
||||
}
|
||||
|
||||
message.addField("Caused by:", cause, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,10 +17,10 @@ import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
|
||||
public class MusicUtils {
|
||||
|
||||
public static boolean connect(Context context) {
|
||||
return connect(context, false, false);
|
||||
return connect(context, false);
|
||||
}
|
||||
|
||||
public static boolean connect(Context context, boolean skipChecks, boolean checkOnly) {
|
||||
public static boolean connect(Context context, boolean checkOnly) {
|
||||
MusicManager manager = MusicManager.get(context.getGuild());
|
||||
Member member = context.getGuildUser();
|
||||
if (member == null) {
|
||||
@@ -34,7 +34,7 @@ public class MusicUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!skipChecks && !isUserDj(member) && (manager.isConnected() && manager.isNotConnectedTo(audioChannel))) {
|
||||
if (!isUserDj(member) && (manager.isConnected() && manager.isNotConnectedTo(audioChannel))) {
|
||||
context.reply("The bot isn't connected to your voice channel");
|
||||
return false;
|
||||
}
|
||||
@@ -48,7 +48,7 @@ public class MusicUtils {
|
||||
}
|
||||
|
||||
public static boolean canConnect(Context context) {
|
||||
return connect(context, false, true);
|
||||
return connect(context, true);
|
||||
}
|
||||
|
||||
public static boolean checkIfConnected(Context context) {
|
||||
|
||||
Reference in new issue
Block a user