Refactor command packages
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2022-11-20 18:56:57 +01:00
parent 3474593dc9
commit 913e8e023a
10 changed files with 44 additions and 31 deletions

View File

@@ -0,0 +1,33 @@
package wtf.beatrice.hidekobot.commands.completer;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.interactions.commands.Command;
import org.jetbrains.annotations.NotNull;
import wtf.beatrice.hidekobot.commands.slash.AvatarCommand;
import java.util.ArrayList;
import java.util.List;
public class AvatarCompleter
{
public AvatarCompleter(@NotNull CommandAutoCompleteInteractionEvent event)
{
if(event.getFocusedOption().getName().equals("size"))
{
List<Command.Choice> options = new ArrayList<>();
for(int res : AvatarCommand.acceptedSizes)
{
String resString = String.valueOf(res);
String userInput = event.getFocusedOption().getValue();
if(resString.startsWith(userInput))
options.add(new Command.Choice(resString, res));
}
event.replyChoices(options).queue();
}
}
}

View File

@@ -0,0 +1,87 @@
package wtf.beatrice.hidekobot.commands.slash;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
public class AvatarCommand
{
// discord api returns a broken image if you don't use specific sizes (powers of 2), so we limit it to these
public static final int[] acceptedSizes = { 16, 32, 64, 128, 256, 512, 1024 };
public AvatarCommand(@NotNull SlashCommandInteractionEvent event)
{
event.deferReply().queue();
User user;
int resolution;
OptionMapping userArg = event.getOption("user");
if(userArg != null)
{
user = userArg.getAsUser();
} else {
user = event.getUser();
}
OptionMapping sizeArg = event.getOption("size");
if(sizeArg != null)
{
resolution = sizeArg.getAsInt();
// method to find closest value to accepted values
int distance = Math.abs(acceptedSizes[0] - resolution);
int idx = 0;
for(int c = 1; c < acceptedSizes.length; c++){
int cdistance = Math.abs(acceptedSizes[c] - resolution);
if(cdistance < distance){
idx = c;
distance = cdistance;
}
}
resolution = acceptedSizes[idx];
} else {
resolution = 512;
}
EmbedBuilder embedBuilder = new EmbedBuilder();
// embed processing
{
embedBuilder.setColor(Color.PINK);
embedBuilder.setTitle("Profile picture");
embedBuilder.addField("User", "<@" + user.getId() + ">", false);
embedBuilder.addField("Current resolution", resolution + " × " + resolution, false);
// string builder to create a string that links to all available resolutions
StringBuilder links = new StringBuilder();
for(int pos = 0; pos < acceptedSizes.length; pos++)
{
int currSize = acceptedSizes[pos];
String currLink = user.getEffectiveAvatar().getUrl(currSize);
links.append("[").append(currSize).append("px](").append(currLink).append(")");
if(pos + 1 != acceptedSizes.length) // don't add a separator on the last iteration
{
links.append(" | ");
}
}
embedBuilder.addField("Available resolutions", links.toString(), false);
embedBuilder.setImage(user.getEffectiveAvatar().getUrl(resolution));
}
event.getHook().editOriginalEmbeds(embedBuilder.build()).queue();
}
}

View File

@@ -0,0 +1,150 @@
package wtf.beatrice.hidekobot.commands.slash;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageHistory;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionHook;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public class ClearChatCommand
{
public ClearChatCommand(@NotNull SlashCommandInteractionEvent event)
{
MessageChannel channel = event.getChannel();
if(!(channel instanceof TextChannel))
{
event.reply("Sorry! I can't delete messages here.").queue();
return;
}
/* get the amount from the command args.
NULL should not be possible because we specified them as mandatory,
but apparently the mobile app doesn't care and still sends the command if you omit the args. */
OptionMapping amountMapping = event.getOption("amount");
int toDeleteAmount = amountMapping == null ? 1 : amountMapping.getAsInt();
if(toDeleteAmount <= 0)
{
event.reply("Sorry, I can't delete that amount of messages!").queue();
}
else {
// answer by saying that the operation has begun.
InteractionHook replyInteraction = event.reply("\uD83D\uDEA7 Clearing...").complete();
// int to keep track of how many messages we deleted.
int deleted = 0;
int limit = 95; //discord limits this method to range 2-100. we set it to 95 to be safe..
// increase the count by 1, because we technically aren't clearing the first ID ever
// which is actually the slash command's ID and not a message.
toDeleteAmount++;
// count how many times we have to iterate this to delete the full <toDeleteAmount> messages.
int iterations = toDeleteAmount / limit;
//if there are some messages left, but less than <limit>, we need one more iterations.
int remainder = toDeleteAmount % limit;
if(remainder != 0) iterations++;
// set the starting point.
long messageId = event.getInteraction().getIdLong();
// boolean to see if we're trying to delete more messages than possible.
boolean outOfBounds = false;
// do iterate.
for(int iteration = 0; iteration < iterations; iteration++)
{
if(outOfBounds) break;
// set how many messages to delete for this iteration (usually <limit> unless there's a remainder)
int iterationSize = limit;
// if we are at the last iteration...
if(iteration+1 == iterations)
{
// check if we have <limit> or fewer messages to delete
if(remainder != 0) iterationSize = remainder;
}
if(iterationSize == 1)
{
// grab the message
Message toDelete = ((TextChannel)channel).retrieveMessageById(messageId).complete();
//only delete one message
if(toDelete != null) toDelete.delete().queue();
else outOfBounds = true;
// increase deleted counter by 1
deleted++;
} else {
// get the last <iterationSize - 1> messages.
MessageHistory.MessageRetrieveAction action = channel.getHistoryBefore(messageId, iterationSize - 1);
// note: first one is the most recent, last one is the oldest message.
List<Message> messages = new ArrayList<>();
// (we are skipping first iteration since it would return an error, given that the id is the slash command and not a message)
if(iteration!=0) messages.add(((TextChannel)channel).retrieveMessageById(messageId).complete());
messages.addAll(action.complete().getRetrievedHistory());
// check if we only have one or zero messages left (trying to delete more than possible)
if(messages.size() <= 1)
{
outOfBounds = true;
} else {
// before deleting, we need to grab the <previous to the oldest> message's id for next iteration.
action = channel.getHistoryBefore(messages.get(messages.size() - 1).getIdLong(), 1);
List<Message> previousMessage = action.complete().getRetrievedHistory();
// if that message exists (we are not out of bounds)... store it
if(!previousMessage.isEmpty()) messageId = previousMessage.get(0).getIdLong();
else outOfBounds = true;
}
// queue messages for deletion
if(messages.size() == 1)
{
messages.get(0).delete().queue();
}
else if(!messages.isEmpty())
{
try {
((TextChannel) channel).deleteMessages(messages).complete();
/* alternatively, we could use purgeMessages, which is smarter...
however, it also tries to delete messages older than 2 weeks
which are restricted by discord, and thus has to use
a less efficient way that triggers rate-limiting very quickly. */
} catch (Exception e)
{
replyInteraction.editOriginal("\uD83D\uDE22 Sorry, it seems like there was an issue! " + e.getMessage()).queue();
return; // warning: this quits everything.
}
}
// increase deleted counter by <list size>
deleted += messages.size();
}
}
// log having deleted the messages.
if(deleted < 1)
{
replyInteraction.editOriginal("\uD83D\uDE22 Couldn't clear any message!").queue();
} else if(deleted == 1)
{
replyInteraction.editOriginal("✂ Cleared 1 message!").queue();
} else {
replyInteraction.editOriginal("✂ Cleared " + deleted + " messages!").queue();
}
}
}
}

View File

@@ -0,0 +1,24 @@
package wtf.beatrice.hidekobot.commands.slash;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.jetbrains.annotations.NotNull;
import wtf.beatrice.hidekobot.utils.RandomUtil;
public class CoinFlipCommand
{
public CoinFlipCommand(@NotNull SlashCommandInteractionEvent event)
{
int rand = RandomUtil.getRandomNumber(0, 1);
String msg;
if(rand == 1)
{
msg = ":coin: It's **Heads**!";
} else {
msg = "It's **Tails**! :coin:";
}
event.reply(msg).queue();
}
}

View File

@@ -0,0 +1,24 @@
package wtf.beatrice.hidekobot.commands.slash;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.jetbrains.annotations.NotNull;
import wtf.beatrice.hidekobot.Configuration;
import wtf.beatrice.hidekobot.HidekoBot;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class DieCommand
{
public DieCommand(@NotNull SlashCommandInteractionEvent event)
{
if(Configuration.getBotOwnerId() != event.getMember().getIdLong())
{
event.reply("Sorry, only the bot owner can run this command!").setEphemeral(true).queue();
} else {
event.reply("Going to sleep! Cya ✨").queue();
Executors.newSingleThreadScheduledExecutor().schedule(HidekoBot::shutdown, 3, TimeUnit.SECONDS);
}
}
}

View File

@@ -0,0 +1,23 @@
package wtf.beatrice.hidekobot.commands.slash;
import net.dv8tion.jda.api.entities.channel.ChannelType;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction;
import org.jetbrains.annotations.NotNull;
import wtf.beatrice.hidekobot.Configuration;
public class InviteCommand
{
public InviteCommand(@NotNull SlashCommandInteractionEvent event)
{
ReplyCallbackAction reply = event.reply("Here's your link ✨ " + Configuration.getInviteUrl());
// only make message permanent in DMs
if(!(event.getChannelType() == ChannelType.PRIVATE))
{
reply = reply.setEphemeral(true);
}
reply.queue();
}
}

View File

@@ -0,0 +1,12 @@
package wtf.beatrice.hidekobot.commands.slash;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.jetbrains.annotations.NotNull;
public class PingCommand
{
public PingCommand(@NotNull SlashCommandInteractionEvent event)
{
event.reply("Pong!").queue();
}
}