Bunch of improvements to tasks and DB logic
Use locks when executing tasks Decouple GuildManager into services Add more logging when failing to load a persistable task Add ping method to WebModule Improve Task interface and implementations Start work on step tasks
This commit is contained in:
1 parent
e58854a85c
commit
d0c06cd6bf
15 files changed
+204
-224
No files matched your search
@@ -49,7 +49,7 @@ public class NetNeutrality {
|
|||||||
options.setEnvironment(env);
|
options.setEnvironment(env);
|
||||||
options.setTracesSampleRate(1.0);
|
options.setTracesSampleRate(1.0);
|
||||||
options.setDebug(false);
|
options.setDebug(false);
|
||||||
options.setRelease(VERSION);
|
options.setRelease(Settings.getVersion());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,14 @@ public abstract class AbstractMessageMenuCommand extends AbstractCommand {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isGuildOnly() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSlashCommandOnly() {
|
public boolean isSlashCommandOnly() {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -27,6 +32,11 @@ public abstract class AbstractMessageMenuCommand extends AbstractCommand {
|
|||||||
// no options for context commands
|
// no options for context commands
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandCategory getCategory() {
|
||||||
|
return CommandCategory.UNLISTED;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type getType() {
|
public Type getType() {
|
||||||
return Type.MESSAGE;
|
return Type.MESSAGE;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package me.bobert.netneutrality.core.context;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import io.sentry.Sentry;
|
import io.sentry.Sentry;
|
||||||
|
import me.bobert.netneutrality.context.command.SlashCommandContext;
|
||||||
import net.dv8tion.jda.api.JDA;
|
import net.dv8tion.jda.api.JDA;
|
||||||
import net.dv8tion.jda.api.entities.Guild;
|
import net.dv8tion.jda.api.entities.Guild;
|
||||||
import net.dv8tion.jda.api.entities.Member;
|
import net.dv8tion.jda.api.entities.Member;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package me.bobert.netneutrality.core.tasks;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import me.bobert.netneutrality.core.context.CommandContext;
|
import me.bobert.netneutrality.core.context.CommandContext;
|
||||||
|
import me.bobert.netneutrality.core.context.TaskContext;
|
||||||
|
|
||||||
public abstract class AbstractBuiltInTask extends AbstractTask implements BuiltInTask {
|
public abstract class AbstractBuiltInTask extends AbstractTask implements BuiltInTask {
|
||||||
|
|
||||||
@@ -19,11 +20,6 @@ public abstract class AbstractBuiltInTask extends AbstractTask implements BuiltI
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean oneshot() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isExpired() {
|
public boolean isExpired() {
|
||||||
return false;
|
return false;
|
||||||
@@ -33,4 +29,12 @@ public abstract class AbstractBuiltInTask extends AbstractTask implements BuiltI
|
|||||||
public void replyToInteraction(CommandContext context) {
|
public void replyToInteraction(CommandContext context) {
|
||||||
// Task is loaded at runtime, this will never be called
|
// Task is loaded at runtime, this will never be called
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Lifecycle execute(TaskContext context) {
|
||||||
|
executeTask(context);
|
||||||
|
return Lifecycle.BUILTIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void executeTask(TaskContext context);
|
||||||
}
|
}
|
||||||
@@ -15,11 +15,6 @@ public abstract class AbstractPersistableTask extends AbstractTask implements Pe
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean oneshot() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isExpired() {
|
public boolean isExpired() {
|
||||||
return false;
|
return false;
|
||||||
@@ -30,6 +25,30 @@ public abstract class AbstractPersistableTask extends AbstractTask implements Pe
|
|||||||
// Task loaded from database, this will never be called
|
// Task loaded from database, this will never be called
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insert(CommandContext context) {
|
||||||
|
if (TaskManager.getInstance().hasTask(getId())) {
|
||||||
|
throw new RuntimeException("Cannot insert a task that already exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskManager.getInstance().insert(context, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save() {
|
||||||
|
if (!TaskManager.getInstance().hasTask(getId())) {
|
||||||
|
throw new RuntimeException("Cannot save a task that doesn't exist yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskManager.getInstance().getTaskService().persistTask(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete() {
|
||||||
|
TaskManager.getInstance().getTaskService().unpersistTask(this);
|
||||||
|
TaskManager.getInstance().removeTask(this);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toPayload() {
|
public String toPayload() {
|
||||||
JSONObject payload = new JSONObject(this);
|
JSONObject payload = new JSONObject(this);
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ package me.bobert.netneutrality.core.tasks;
|
|||||||
* https://discord.gg/qUa6zNFZsd
|
* https://discord.gg/qUa6zNFZsd
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import me.bobert.netneutrality.core.context.CommandContext;
|
||||||
|
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@@ -26,8 +28,8 @@ public abstract class AbstractTask implements Task {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TaskButtonCreator createButton() {
|
public void insert(CommandContext context) {
|
||||||
return new TaskButtonCreator(getId());
|
TaskManager.getInstance().insert(context, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -46,6 +48,6 @@ public abstract class AbstractTask implements Task {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("Task{id=%s, class=%s, name=%s, oneshot=%b, creationTime=%s}", getId(), getClass().getSimpleName(), getName(), oneshot(), getCreationTime());
|
return String.format("Task{id=%s, lockId=%s, class=%s, name=%s, creationTime=%s}", getId(), getLockId(), getClass().getSimpleName(), getName(), getCreationTime());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package me.bobert.netneutrality.core.tasks;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) anthorob
|
||||||
|
*
|
||||||
|
* https://discord.gg/qUa6zNFZsd
|
||||||
|
*/
|
||||||
|
|
||||||
|
import net.dv8tion.jda.api.interactions.components.buttons.Button;
|
||||||
|
|
||||||
|
public abstract class GenericCustomIdTask extends AbstractTask {
|
||||||
|
private final String customId;
|
||||||
|
|
||||||
|
public GenericCustomIdTask(String id) {
|
||||||
|
this.customId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return customId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Button createButton() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package me.bobert.netneutrality.core.tasks;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) anthorob
|
||||||
|
*
|
||||||
|
* https://discord.gg/qUa6zNFZsd
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public abstract class GenericRandomIdTask extends GenericCustomIdTask {
|
||||||
|
public GenericRandomIdTask() {
|
||||||
|
super(UUID.randomUUID().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
package me.bobert.netneutrality.core.tasks.impl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) anthorob
|
||||||
|
*
|
||||||
|
* https://discord.gg/qUa6zNFZsd
|
||||||
|
*/
|
||||||
|
|
||||||
|
import me.bobert.netneutrality.core.context.CommandContext;
|
||||||
|
import me.bobert.netneutrality.core.context.MessageContext;
|
||||||
|
import me.bobert.netneutrality.core.context.TaskContext;
|
||||||
|
import me.bobert.netneutrality.core.tasks.AbstractTask;
|
||||||
|
import me.bobert.netneutrality.core.tasks.TaskManager;
|
||||||
|
import net.dv8tion.jda.api.entities.Guild;
|
||||||
|
import net.dv8tion.jda.api.entities.Message;
|
||||||
|
import net.dv8tion.jda.api.interactions.components.buttons.Button;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public abstract class StepTask extends AbstractTask {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(StepTask.class);
|
||||||
|
|
||||||
|
public enum StepType {
|
||||||
|
STRING, ROLE, EMOJI
|
||||||
|
}
|
||||||
|
|
||||||
|
private Guild guild;
|
||||||
|
private String id = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void replyToInteraction(CommandContext context) {
|
||||||
|
if (context.isFromGuild()) {
|
||||||
|
guild = context.getGuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (guild == null && getStepType() == StepType.ROLE) {
|
||||||
|
throw new IllegalArgumentException("Step task if of type role but it was inserted in a non-guild context");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inDM()) {
|
||||||
|
context.replyEphemeral("Please follow the instructions sent in DM.");
|
||||||
|
context.sendMessageInPrivate(getStepDescription() + "\n" + getStepQuestion(), asyncContext -> assignId(asyncContext.getMessageId()));
|
||||||
|
} else {
|
||||||
|
context.reply(getStepQuestion(), asyncContext -> id = asyncContext.getMessageId());
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("step id : " + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Lifecycle execute(TaskContext context) {
|
||||||
|
if (context instanceof MessageContext messageContext) {
|
||||||
|
Message message = messageContext.getMessage();
|
||||||
|
String answer = message.getContentRaw();
|
||||||
|
|
||||||
|
if (validateAnswer(answer)) {
|
||||||
|
StepTask nextStep = executeStep(answer);
|
||||||
|
|
||||||
|
//TODO: to finish
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Lifecycle.REMOVE_SELF;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isExpired() {
|
||||||
|
return getCreationTime().plusMinutes(30).isBefore(OffsetDateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Button createButton() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean validateAnswer(String answer) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assignId(String newId) {
|
||||||
|
if (newId == null || newId.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("Task ID cannot be null or empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (this) {
|
||||||
|
this.id = newId;
|
||||||
|
TaskManager.getInstance().activateTask(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.id = newId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract boolean inDM();
|
||||||
|
|
||||||
|
public abstract StepType getStepType();
|
||||||
|
|
||||||
|
public abstract String getStepDescription();
|
||||||
|
|
||||||
|
public abstract String getStepQuestion();
|
||||||
|
|
||||||
|
public abstract StepTask executeStep(String answer);
|
||||||
|
}
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
package me.bobert.netneutrality.tasks;
|
|
||||||
/*
|
|
||||||
* Copyright (c) anthorob
|
|
||||||
*
|
|
||||||
* https://discord.gg/qUa6zNFZsd
|
|
||||||
*/
|
|
||||||
|
|
||||||
import me.bobert.netneutrality.core.tasks.AbstractTask;
|
|
||||||
|
|
||||||
import java.time.OffsetDateTime;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public abstract class ButtonTask extends AbstractTask {
|
|
||||||
private final UUID id = UUID.randomUUID();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return id.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean oneshot() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isExpired() {
|
|
||||||
return getCreationTime().plusMinutes(15).isBefore(OffsetDateTime.now());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package me.bobert.netneutrality.tasks;
|
|
||||||
/*
|
|
||||||
* Copyright (c) anthorob
|
|
||||||
*
|
|
||||||
* https://discord.gg/qUa6zNFZsd
|
|
||||||
*/
|
|
||||||
|
|
||||||
import me.bobert.netneutrality.core.tasks.AbstractPersistableTask;
|
|
||||||
|
|
||||||
public abstract class EmojiTask extends AbstractPersistableTask {
|
|
||||||
private final String guildId;
|
|
||||||
private final String messageId;
|
|
||||||
|
|
||||||
public EmojiTask(String guildId, String messageId) {
|
|
||||||
this.guildId = guildId;
|
|
||||||
this.messageId = messageId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getGuildId() {
|
|
||||||
return guildId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMessageId() {
|
|
||||||
return messageId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return String.format("%s:%s", getGuildId(), getMessageId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
package me.bobert.netneutrality.tasks;
|
|
||||||
/*
|
|
||||||
* Copyright (c) anthorob
|
|
||||||
*
|
|
||||||
* https://discord.gg/qUa6zNFZsd
|
|
||||||
*/
|
|
||||||
|
|
||||||
import me.bobert.netneutrality.core.context.TaskContext;
|
|
||||||
import me.bobert.netneutrality.core.tasks.AbstractTask;
|
|
||||||
import net.dv8tion.jda.api.interactions.modals.ModalMapping;
|
|
||||||
|
|
||||||
import java.time.OffsetDateTime;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public abstract class ModalTask extends AbstractTask {
|
|
||||||
private final UUID id = UUID.randomUUID();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return id.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean oneshot() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isExpired() {
|
|
||||||
return getCreationTime().plusMinutes(5).isBefore(OffsetDateTime.now());
|
|
||||||
}
|
|
||||||
|
|
||||||
public ModalMapping getValue(String key, TaskContext context) {
|
|
||||||
List<?> mappings = (List<?>) context.getContextData("values");
|
|
||||||
return mappings.stream()
|
|
||||||
.filter(o -> o instanceof ModalMapping)
|
|
||||||
.map(o -> (ModalMapping) o)
|
|
||||||
.filter(mapping -> mapping.getId().equals(key))
|
|
||||||
.findFirst().orElse(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
package me.bobert.netneutrality.tasks.music;
|
|
||||||
/*
|
|
||||||
* Copyright (c) anthorob
|
|
||||||
*
|
|
||||||
* https://discord.gg/qUa6zNFZsd
|
|
||||||
*/
|
|
||||||
|
|
||||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
|
||||||
import me.bobert.netneutrality.core.context.CommandContext;
|
|
||||||
import me.bobert.netneutrality.core.context.TaskContext;
|
|
||||||
import me.bobert.netneutrality.core.tasks.trait.WithParent;
|
|
||||||
import me.bobert.netneutrality.music.MusicManager;
|
|
||||||
import me.bobert.netneutrality.music.SourceFinder;
|
|
||||||
import me.bobert.netneutrality.tasks.ButtonTask;
|
|
||||||
import me.bobert.netneutrality.utils.MessageFunction;
|
|
||||||
import me.bobert.netneutrality.utils.MusicUtils;
|
|
||||||
import net.dv8tion.jda.api.entities.Member;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class AddAllTracksTask extends ButtonTask implements WithParent<LoadPlaylistTask> {
|
|
||||||
private final LoadPlaylistTask parentTask;
|
|
||||||
List<AudioTrack> tracks;
|
|
||||||
|
|
||||||
public AddAllTracksTask(LoadPlaylistTask parentTask, List<AudioTrack> tracks) {
|
|
||||||
this.parentTask = parentTask;
|
|
||||||
this.tracks = tracks;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return "add-all-tracks";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void replyToInteraction(CommandContext context) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(TaskContext context) {
|
|
||||||
MusicManager manager = MusicManager.get(context.getGuild());
|
|
||||||
Member member = context.getGuildUser();
|
|
||||||
|
|
||||||
if (MusicUtils.connect(context)) {
|
|
||||||
manager.getQueueManager().queue(tracks, member);
|
|
||||||
|
|
||||||
context.reply(MessageFunction.buildAddingPlaylistMessage(tracks, parentTask.getPlaylist().getName(), member, SourceFinder.AudioSourceType.Youtube));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LoadPlaylistTask getParentTask() {
|
|
||||||
return parentTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldKeepChilds() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
package me.bobert.netneutrality.tasks.music;
|
|
||||||
/*
|
|
||||||
* Copyright (c) anthorob
|
|
||||||
*
|
|
||||||
* https://discord.gg/qUa6zNFZsd
|
|
||||||
*/
|
|
||||||
|
|
||||||
import me.bobert.netneutrality.core.context.CommandContext;
|
|
||||||
import me.bobert.netneutrality.core.context.TaskContext;
|
|
||||||
import me.bobert.netneutrality.core.tasks.trait.NotAcknowledgeable;
|
|
||||||
import me.bobert.netneutrality.core.tasks.trait.WithParent;
|
|
||||||
import me.bobert.netneutrality.tasks.ButtonTask;
|
|
||||||
|
|
||||||
public class CancelLoadTask extends ButtonTask implements WithParent<LoadPlaylistTask>, NotAcknowledgeable {
|
|
||||||
private final LoadPlaylistTask parentTask;
|
|
||||||
|
|
||||||
public CancelLoadTask(LoadPlaylistTask parentTask) {
|
|
||||||
this.parentTask = parentTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return "cancel-playlist-loading";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void replyToInteraction(CommandContext context) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LoadPlaylistTask getParentTask() {
|
|
||||||
return parentTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldKeepChilds() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(TaskContext context) {
|
|
||||||
// Interaction will get removed after execution
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -13,6 +13,7 @@ import me.bobert.netneutrality.utils.MessageFunction;
|
|||||||
import me.bobert.netneutrality.utils.MusicUtils;
|
import me.bobert.netneutrality.utils.MusicUtils;
|
||||||
import net.dv8tion.jda.api.components.buttons.ButtonStyle;
|
import net.dv8tion.jda.api.components.buttons.ButtonStyle;
|
||||||
import net.dv8tion.jda.api.entities.Member;
|
import net.dv8tion.jda.api.entities.Member;
|
||||||
|
import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
|
||||||
|
|
||||||
public class LoadTrackFromPlaylistTask extends AcceptButton<LoadPlaylistTask> {
|
public class LoadTrackFromPlaylistTask extends AcceptButton<LoadPlaylistTask> {
|
||||||
private final AudioTrack track;
|
private final AudioTrack track;
|
||||||
|
|||||||
Reference in new issue
Block a user