forked from Fascinated/Bat
Compare commits
41 Commits
eb8408eb8f
...
87bf0b9f67
Author | SHA1 | Date | |
---|---|---|---|
87bf0b9f67 | |||
419bdf1fea | |||
f2b2dbc794 | |||
8361f3c784 | |||
52349a17c3 | |||
c1f9bfec6a | |||
be7f8a9057 | |||
c93e112ebf | |||
7485bd2ec8 | |||
ed83175a39 | |||
a001f2dd4c | |||
b1785ce373 | |||
b1f5db9b2d | |||
d372c41c98 | |||
f566c3bcb5 | |||
6403c57db5 | |||
22d4558d84 | |||
ea546f02ca | |||
5b1ddb145f | |||
5ce5ef6898 | |||
729e0b482b | |||
5aa56c2955 | |||
ee6456e4d8 | |||
93350f1506 | |||
702aead53a | |||
b7f2b6a3d7 | |||
b66114503c | |||
50391e5344 | |||
91ecc9882c | |||
06a2584e63 | |||
29affe2f12 | |||
86c7afac42 | |||
b0949d17e6 | |||
df44ae90b9 | |||
4821e2a4fa | |||
4cb34fbb9a | |||
d824f957fe | |||
d2d898a5b8 | |||
320eab34a3 | |||
433dfb4693 | |||
71158fd477 |
23
pom.xml
23
pom.xml
@ -85,6 +85,29 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.sentry</groupId>
|
||||
<artifactId>sentry-spring-boot-starter-jakarta</artifactId>
|
||||
<version>7.10.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.mongock</groupId>
|
||||
<artifactId>mongock-bom</artifactId>
|
||||
<version>5.2.4</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.mongock</groupId>
|
||||
<artifactId>mongock-springboot-v3</artifactId>
|
||||
<version>5.2.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.mongock</groupId>
|
||||
<artifactId>mongodb-springdata-v4-driver</artifactId>
|
||||
<version>5.2.4</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Libraries -->
|
||||
<dependency>
|
||||
|
6
renovate.json
Normal file
6
renovate.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"local>Fascinated/renovate-config"
|
||||
]
|
||||
}
|
@ -1,7 +1,12 @@
|
||||
package cc.fascinated.bat;
|
||||
|
||||
import cc.fascinated.bat.config.Config;
|
||||
import cc.fascinated.bat.event.EventListener;
|
||||
import cc.fascinated.bat.service.EventService;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import io.mongock.runner.springboot.EnableMongock;
|
||||
import jakarta.annotation.PreDestroy;
|
||||
import lombok.NonNull;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
@ -15,7 +20,8 @@ import java.nio.file.StandardCopyOption;
|
||||
import java.util.Objects;
|
||||
|
||||
@EnableScheduling
|
||||
@SpringBootApplication
|
||||
@SpringBootApplication(scanBasePackages = "cc.fascinated.bat")
|
||||
@EnableMongock
|
||||
@Log4j2(topic = "Bat")
|
||||
public class BatApplication {
|
||||
public static Gson GSON = new GsonBuilder().create();
|
||||
@ -35,5 +41,15 @@ public class BatApplication {
|
||||
|
||||
// Start the app
|
||||
SpringApplication.run(BatApplication.class, args);
|
||||
|
||||
log.info("APP IS RUNNING IN %s MODE!!!!!!!!!".formatted(Config.isProduction() ? "PRODUCTION" : "DEVELOPMENT"));
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void onShutdown() {
|
||||
log.info("Shutting down...");
|
||||
for (EventListener listener : EventService.LISTENERS) {
|
||||
listener.onSpringShutdown();
|
||||
}
|
||||
}
|
||||
}
|
@ -8,4 +8,10 @@ public class Consts {
|
||||
public static final String SUPPORT_INVITE_URL = "https://discord.gg/invite/yjj2U3ctEG";
|
||||
public static String BOT_OWNER = "474221560031608833";
|
||||
public static String ADMIN_GUILD = "1203163422498361404";
|
||||
|
||||
static {
|
||||
if (System.getenv("ADMIN_GUILD") != null) {
|
||||
ADMIN_GUILD = System.getenv("ADMIN_GUILD");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
45
src/main/java/cc/fascinated/bat/Emojis.java
Normal file
45
src/main/java/cc/fascinated/bat/Emojis.java
Normal file
@ -0,0 +1,45 @@
|
||||
package cc.fascinated.bat;
|
||||
|
||||
import cc.fascinated.bat.service.DiscordService;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.entities.emoji.Emoji;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Log4j2
|
||||
public class Emojis {
|
||||
public static final Emoji SPOTIFY_EMOJI;
|
||||
public static final Emoji CHECK_MARK_EMOJI;
|
||||
public static final Emoji CROSS_MARK_EMOJI;
|
||||
public static final Emoji SAD_FACE_EMOJI;
|
||||
public static final Emoji PAUSE_EMOJI;
|
||||
public static final Emoji PLAY_EMOJI;
|
||||
public static final Emoji SKIP_EMOJI;
|
||||
|
||||
/**
|
||||
* Presence Status Emojis
|
||||
*/
|
||||
public static final Emoji ONLINE_EMOJI;
|
||||
public static final Emoji IDLE_EMOJI;
|
||||
public static final Emoji DND_EMOJI;
|
||||
public static final Emoji OFFLINE_EMOJI;
|
||||
|
||||
static {
|
||||
log.info("Loading emojis...");
|
||||
JDA jda = DiscordService.JDA;
|
||||
SPOTIFY_EMOJI = jda.getEmojiById("1256629771975266479");
|
||||
CHECK_MARK_EMOJI = jda.getEmojiById("1256633734065557676");
|
||||
CROSS_MARK_EMOJI = jda.getEmojiById("1256634487429922897");
|
||||
SAD_FACE_EMOJI = jda.getEmojiById("1256636078258131055");
|
||||
ONLINE_EMOJI = jda.getEmojiById("1256662465668710430");
|
||||
IDLE_EMOJI = jda.getEmojiById("1256662632203685991");
|
||||
DND_EMOJI = jda.getEmojiById("1256662572933845032");
|
||||
OFFLINE_EMOJI = jda.getEmojiById("1256662679402053662");
|
||||
PAUSE_EMOJI = Emoji.fromUnicode("⏸");
|
||||
PLAY_EMOJI = Emoji.fromUnicode("▶");
|
||||
SKIP_EMOJI = Emoji.fromUnicode("⏭");
|
||||
log.info("Loaded emojis!");
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package cc.fascinated.bat.command;
|
||||
|
||||
import cc.fascinated.bat.features.Feature;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.Setter;
|
||||
@ -38,6 +39,11 @@ public abstract class BatCommand implements BatCommandExecutor {
|
||||
*/
|
||||
private Category category;
|
||||
|
||||
/**
|
||||
* The feature that the command belongs to
|
||||
*/
|
||||
private Feature feature;
|
||||
|
||||
/**
|
||||
* Whether the command can only be used by the bot owner
|
||||
*/
|
||||
|
@ -12,20 +12,20 @@ import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
*/
|
||||
public interface BatCommandExecutor {
|
||||
/**
|
||||
* Executes the command using a slash command interaction.
|
||||
* Executes the command using a slash command event.
|
||||
*
|
||||
* @param guild the bat guild the command was executed in (null if the command was executed in a DM)
|
||||
* @param user the bat user that executed the command
|
||||
* @param channel the channel the command was executed in
|
||||
* @param member the member that executed the command
|
||||
* @param interaction the slash command interaction
|
||||
* @param event the slash command event
|
||||
*/
|
||||
default void execute(
|
||||
BatGuild guild,
|
||||
@NonNull BatUser user,
|
||||
@NonNull MessageChannel channel,
|
||||
Member member,
|
||||
@NonNull SlashCommandInteraction interaction
|
||||
@NonNull SlashCommandInteraction event
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +0,0 @@
|
||||
package cc.fascinated.bat.command.impl.server;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.EmbedBuilder;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Nick (okNick)
|
||||
*/
|
||||
@Component
|
||||
@CommandInfo(name = "membercount", description = "View the member count of the server!")
|
||||
public class MemberCountCommand extends BatCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
EmbedBuilder embed = EmbedUtils.genericEmbed().setAuthor("Member Count");
|
||||
Guild discordGuild = guild.getDiscordGuild();
|
||||
embed.setDescription("**%s** has a total of %s members.".formatted(discordGuild.getName(), discordGuild.getMembers().size()));
|
||||
interaction.replyEmbeds(embed.build()).queue();
|
||||
}
|
||||
}
|
83
src/main/java/cc/fascinated/bat/common/NumberFormatter.java
Normal file
83
src/main/java/cc/fascinated/bat/common/NumberFormatter.java
Normal file
@ -0,0 +1,83 @@
|
||||
package cc.fascinated.bat.common;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
public class NumberFormatter {
|
||||
/**
|
||||
* The suffixes for the numbers
|
||||
*/
|
||||
private static final String[] SUFFIXES = new String[] { "K", "M", "B", "T", "Q", "QT", "S", "SP", "O", "N", "D", "UD", "DD", "TD" };
|
||||
private static final DecimalFormat FORMAT = new DecimalFormat("###.##");
|
||||
|
||||
/**
|
||||
* Format the provided double
|
||||
*
|
||||
* @param input the value to format
|
||||
* @return the formatted double, in the format of xx.xx[suffix]
|
||||
*/
|
||||
public static String format(double input) {
|
||||
if (Double.isNaN(input)) {
|
||||
return "ERROR";
|
||||
}
|
||||
if (Double.isInfinite(input) || input == Double.MAX_VALUE) {
|
||||
return "∞";
|
||||
}
|
||||
if (1000 > input) {
|
||||
return FORMAT.format(input);
|
||||
}
|
||||
double power = (int) Math.log10(input);
|
||||
int index = (int) Math.floor(power / 3) - 1;
|
||||
double factor = input / Math.pow(10, 3 + index * 3);
|
||||
if (index >= SUFFIXES.length) {
|
||||
return "ERROR";
|
||||
}
|
||||
return FORMAT.format(factor) + SUFFIXES[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the provided double with commas
|
||||
*
|
||||
* @param input the value to format
|
||||
* @return the formatted double, in the format of xx,xxx,xxx
|
||||
*/
|
||||
public static String formatCommas(double input) {
|
||||
return String.format("%,.0f", input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns a provided string into a double, for example 1M -> 1000000.00
|
||||
* Accepts decimal and negative values and is not case-sensitive
|
||||
*
|
||||
* @param input the string to convert
|
||||
* @return the value the string represents
|
||||
*/
|
||||
public static double fromString(String input) {
|
||||
if ((input = input.trim()).isEmpty()) {
|
||||
return -1D;
|
||||
}
|
||||
try {
|
||||
double value = Double.parseDouble(input); // parse pure numbers
|
||||
if (Double.isNaN(value) || Double.isInfinite(value)) {
|
||||
return -1;
|
||||
}
|
||||
return value;
|
||||
} catch (NumberFormatException ignored) {
|
||||
input = input.toUpperCase(Locale.UK);
|
||||
for (int i = SUFFIXES.length - 1; i > 0; i--) {
|
||||
String suffix = SUFFIXES[i];
|
||||
if (!input.endsWith(suffix)) {
|
||||
continue;
|
||||
}
|
||||
String amount = input.substring(0, input.length() - suffix.length());
|
||||
if (!amount.isEmpty()) {
|
||||
return Double.parseDouble(amount) * Math.pow(10, 3 + i * 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package cc.fascinated.bat.common;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@UtilityClass
|
||||
public class NumberUtils {
|
||||
/**
|
||||
* Formats a number with commas.
|
||||
* <p>
|
||||
* Example: 1000 -> 1,000 | Example: 1000.5 -> 1,000.5
|
||||
* </p>
|
||||
*
|
||||
* @param number the number to format
|
||||
* @return the formatted number
|
||||
*/
|
||||
public static String formatNumberCommas(double number) {
|
||||
NumberFormat format = NumberFormat.getNumberInstance();
|
||||
format.setGroupingUsed(true);
|
||||
format.setMaximumFractionDigits(2);
|
||||
return format.format(number);
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package cc.fascinated.bat.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public abstract class Profile {
|
||||
/**
|
||||
* The key of the profile.
|
||||
*/
|
||||
private String profileKey;
|
||||
|
||||
public Profile() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the profile
|
||||
*/
|
||||
public abstract void reset();
|
||||
}
|
@ -1,6 +1,9 @@
|
||||
package cc.fascinated.bat.common;
|
||||
|
||||
import cc.fascinated.bat.BatApplication;
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -9,11 +12,11 @@ import java.util.Map;
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Getter
|
||||
public class ProfileHolder {
|
||||
public abstract class ProfileHolder {
|
||||
/**
|
||||
* The profiles for the holder
|
||||
*/
|
||||
private Map<String, Profile> profiles;
|
||||
private final Map<String, Serializable> profiles = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Gets a profile for the holder
|
||||
@ -22,19 +25,25 @@ public class ProfileHolder {
|
||||
* @param <T> The type of the profile
|
||||
* @return The profile
|
||||
*/
|
||||
public <T extends Profile> T getProfile(Class<T> clazz) {
|
||||
if (profiles == null) {
|
||||
profiles = new HashMap<>();
|
||||
}
|
||||
public abstract <T extends Serializable> T getProfile(Class<T> clazz);
|
||||
|
||||
Profile profile = profiles.values().stream().filter(p -> p.getClass().equals(clazz)).findFirst().orElse(null);
|
||||
/**
|
||||
* Gets the profiles for the holder
|
||||
* using the provided document
|
||||
*
|
||||
* @return the profiles
|
||||
*/
|
||||
@SneakyThrows
|
||||
protected <T extends Serializable> T getProfileFromDocument(Class<T> clazz, Document document) {
|
||||
Serializable profile = getProfiles().get(clazz.getSimpleName());
|
||||
if (profile == null) {
|
||||
try {
|
||||
profile = clazz.newInstance();
|
||||
profiles.put(profile.getProfileKey(), profile);
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
T newProfile = clazz.cast(clazz.getDeclaredConstructors()[0].newInstance());
|
||||
org.bson.Document profiles = document.get("profiles", new org.bson.Document());
|
||||
org.bson.Document profileDocument = profiles.isEmpty() ? new org.bson.Document() : profiles.get(clazz.getSimpleName(), new org.bson.Document());
|
||||
|
||||
newProfile.load(profileDocument, BatApplication.GSON);
|
||||
getProfiles().put(clazz.getSimpleName(), newProfile);
|
||||
return newProfile;
|
||||
}
|
||||
return clazz.cast(profile);
|
||||
}
|
||||
|
36
src/main/java/cc/fascinated/bat/common/Serializable.java
Normal file
36
src/main/java/cc/fascinated/bat/common/Serializable.java
Normal file
@ -0,0 +1,36 @@
|
||||
package cc.fascinated.bat.common;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.bson.Document;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public abstract class Serializable {
|
||||
/**
|
||||
* Load data from the provided document into this profile
|
||||
*
|
||||
* @param document the document to load data from
|
||||
* @param gson the GSON instance to use
|
||||
*/
|
||||
public abstract void load(Document document, Gson gson);
|
||||
|
||||
/**
|
||||
* Serialize this profile into a Bson document
|
||||
*
|
||||
* @param gson the GSON instance to use
|
||||
* @return the serialized document
|
||||
*/
|
||||
public abstract Document serialize(Gson gson);
|
||||
|
||||
/**
|
||||
* Resets the profile to its default state
|
||||
*/
|
||||
public abstract void reset();
|
||||
}
|
69
src/main/java/cc/fascinated/bat/common/SpotifyUtils.java
Normal file
69
src/main/java/cc/fascinated/bat/common/SpotifyUtils.java
Normal file
@ -0,0 +1,69 @@
|
||||
package cc.fascinated.bat.common;
|
||||
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.SpotifyService;
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import se.michaelthelin.spotify.model_objects.miscellaneous.CurrentlyPlaying;
|
||||
import se.michaelthelin.spotify.model_objects.specification.Track;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Log4j2
|
||||
public class SpotifyUtils {
|
||||
/**
|
||||
* Gets the URL of the track that is currently playing.
|
||||
*
|
||||
* @param currentlyPlaying The currently playing object.
|
||||
* @return The URL of the track that is currently playing.
|
||||
*/
|
||||
public static String getTrackUrl(CurrentlyPlaying currentlyPlaying) {
|
||||
return "https://open.spotify.com/track/" + currentlyPlaying.getItem().getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the formatted time of the currently playing track
|
||||
*
|
||||
* @param currentlyPlaying the currently playing track
|
||||
* @return the formatted time
|
||||
*/
|
||||
public static String getFormattedTime(@NonNull CurrentlyPlaying currentlyPlaying) {
|
||||
Track track = (Track) currentlyPlaying.getItem();
|
||||
int currentMinutes = currentlyPlaying.getProgress_ms() / 1000 / 60;
|
||||
int currentSeconds = currentlyPlaying.getProgress_ms() / 1000 % 60;
|
||||
int totalMinutes = track.getDurationMs() / 1000 / 60;
|
||||
int totalSeconds = track.getDurationMs() / 1000 % 60;
|
||||
|
||||
return "`%02d:%02d`/`%02d:%02d`".formatted(currentMinutes, currentSeconds, totalMinutes, totalSeconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next track that is playing
|
||||
*
|
||||
* @param user The user to get the track for
|
||||
* @param oldName The name of the old track
|
||||
* @return The new track
|
||||
*/
|
||||
public static CurrentlyPlaying getNewTrack(@NonNull SpotifyService spotifyService, @NonNull BatUser user, @NonNull String oldName) {
|
||||
int checks = 0;
|
||||
|
||||
try {
|
||||
Thread.sleep(150);
|
||||
while (checks < 10) {
|
||||
CurrentlyPlaying currentlyPlaying = spotifyService.getCurrentlyPlayingTrack(user);
|
||||
Track track = (Track) currentlyPlaying.getItem();
|
||||
if (track.getName().equals(oldName)) {
|
||||
Thread.sleep(250);
|
||||
checks++;
|
||||
} else {
|
||||
log.info("Found new track \"{}\" in {} check{}", track.getName(), checks, checks == 1 ? "" : "s");
|
||||
return currentlyPlaying;
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
20
src/main/java/cc/fascinated/bat/config/Config.java
Normal file
20
src/main/java/cc/fascinated/bat/config/Config.java
Normal file
@ -0,0 +1,20 @@
|
||||
package cc.fascinated.bat.config;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
public class Config {
|
||||
/**
|
||||
* Is the app running in a production environment?
|
||||
*/
|
||||
@Getter
|
||||
private static final boolean production;
|
||||
|
||||
static {
|
||||
// Are we running on production?
|
||||
String appEnv = System.getenv("APP_ENV");
|
||||
production = appEnv != null && (appEnv.equals("production"));
|
||||
}
|
||||
}
|
@ -27,7 +27,7 @@ public class SpotifyController {
|
||||
* @return the response entity
|
||||
*/
|
||||
@GetMapping(value = "/callback")
|
||||
public ResponseEntity<String> authorizationCallback(@RequestParam String code) {
|
||||
public ResponseEntity<String> authorizationCallback(@RequestParam(required = false) String code) {
|
||||
return ResponseEntity.ok(spotifyService.authorize(code));
|
||||
}
|
||||
}
|
||||
|
@ -8,10 +8,12 @@ import cc.fascinated.bat.model.token.beatsaber.scoresaber.ScoreSaberScoreToken;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent;
|
||||
import net.dv8tion.jda.api.events.guild.member.GuildMemberRemoveEvent;
|
||||
import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateNicknameEvent;
|
||||
import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
|
||||
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
|
||||
import net.dv8tion.jda.api.events.interaction.component.StringSelectInteractionEvent;
|
||||
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
|
||||
import net.dv8tion.jda.api.events.user.update.UserUpdateGlobalNameEvent;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
@ -81,4 +83,31 @@ public interface EventListener {
|
||||
*/
|
||||
default void onModalInteraction(BatGuild guild, @NonNull BatUser user, @NonNull ModalInteractionEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a user updates their global name
|
||||
*
|
||||
* @param user the user that updated their global name
|
||||
* @param oldName the old global name
|
||||
* @param newName the new global name
|
||||
*/
|
||||
default void onUserUpdateGlobalName(@NonNull BatUser user, String oldName, String newName, @NonNull UserUpdateGlobalNameEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a user updates their nickname in a guild
|
||||
*
|
||||
* @param guild the guild that the user updated their nickname in
|
||||
* @param user the user that updated their nickname
|
||||
* @param oldName the old nickname
|
||||
* @param newName the new nickname
|
||||
*/
|
||||
default void onGuildMemberUpdateNickname(@NonNull BatGuild guild, @NonNull BatUser user, String oldName, String newName, @NonNull GuildMemberUpdateNicknameEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when Spring is shutting down
|
||||
*/
|
||||
default void onSpringShutdown() {
|
||||
}
|
||||
}
|
||||
|
10
src/main/java/cc/fascinated/bat/exception/BatException.java
Normal file
10
src/main/java/cc/fascinated/bat/exception/BatException.java
Normal file
@ -0,0 +1,10 @@
|
||||
package cc.fascinated.bat.exception;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
public class BatException extends Exception {
|
||||
public BatException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@ import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(HttpStatus.TOO_MANY_REQUESTS)
|
||||
public class RateLimitException extends RuntimeException {
|
||||
|
||||
public RateLimitException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
package cc.fascinated.bat.exception.spotify;
|
||||
|
||||
import lombok.experimental.StandardException;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@StandardException
|
||||
public class SpotifyTokenRefreshException extends RuntimeException {
|
||||
public SpotifyTokenRefreshException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -20,6 +20,11 @@ public abstract class Feature {
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* The description of the feature
|
||||
*/
|
||||
public final boolean canBeDisabled;
|
||||
|
||||
/**
|
||||
* The category of the feature
|
||||
*/
|
||||
@ -32,7 +37,11 @@ public abstract class Feature {
|
||||
* @param command The command to register
|
||||
*/
|
||||
public void registerCommand(@NonNull CommandService commandService, @NonNull BatCommand command) {
|
||||
command.setCategory(category);
|
||||
// If the command using the default category then set the category to the feature's category
|
||||
if (command.getCategory() == Category.GENERAL) {
|
||||
command.setCategory(this.category);
|
||||
}
|
||||
command.setFeature(this);
|
||||
commandService.registerCommand(command);
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class AfkFeature extends Feature {
|
||||
public AfkFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService) {
|
||||
super("AFK", Category.GENERAL);
|
||||
super("AFK", true, Category.GENERAL);
|
||||
|
||||
registerCommand(commandService, context.getBean(AfkCommand.class));
|
||||
}
|
||||
|
@ -4,10 +4,8 @@ import cc.fascinated.bat.event.EventListener;
|
||||
import cc.fascinated.bat.features.afk.profile.AfkProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@ -15,13 +13,6 @@ import org.springframework.stereotype.Component;
|
||||
*/
|
||||
@Component
|
||||
public class AfkReturnListener implements EventListener {
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public AfkReturnListener(@NonNull GuildService guildService) {
|
||||
this.guildService = guildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuildMessageReceive(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull MessageReceivedEvent event) {
|
||||
AfkProfile profile = guild.getProfile(AfkProfile.class);
|
||||
@ -29,7 +20,6 @@ public class AfkReturnListener implements EventListener {
|
||||
return;
|
||||
}
|
||||
profile.removeAfkUser(guild, user.getId());
|
||||
guildService.saveGuild(guild);
|
||||
event.getMessage().reply("Welcome back, %s! You are no longer AFK.".formatted(user.getDiscordUser().getAsMention())).queue();
|
||||
}
|
||||
}
|
||||
|
@ -6,14 +6,12 @@ import cc.fascinated.bat.common.MemberUtils;
|
||||
import cc.fascinated.bat.features.afk.profile.AfkProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@ -22,26 +20,21 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
@CommandInfo(name = "afk", description = "Sets your AFK status")
|
||||
public class AfkCommand extends BatCommand {
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public AfkCommand(@NonNull GuildService guildService) {
|
||||
this.guildService = guildService;
|
||||
public AfkCommand() {
|
||||
super.addOption(OptionType.STRING, "reason", "The reason for being AFK", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
AfkProfile profile = guild.getProfile(AfkProfile.class);
|
||||
String reason = null;
|
||||
OptionMapping reasonOption = interaction.getOption("reason");
|
||||
OptionMapping reasonOption = event.getOption("reason");
|
||||
if (reasonOption != null) {
|
||||
reason = reasonOption.getAsString();
|
||||
}
|
||||
|
||||
profile.addAfkUser(guild, member.getId(), reason);
|
||||
guildService.saveGuild(guild);
|
||||
interaction.reply("You are now AFK: %s%s".formatted(
|
||||
event.reply("You are now AFK: %s%s".formatted(
|
||||
profile.getAfkReason(member.getId()),
|
||||
MemberUtils.hasPermissionToEdit(guild, user) ? "" :
|
||||
"\n\n*I do not have enough permissions to edit your user, and therefore cannot update your nickname*"
|
||||
|
@ -1,9 +1,12 @@
|
||||
package cc.fascinated.bat.features.afk.profile;
|
||||
|
||||
import cc.fascinated.bat.common.Profile;
|
||||
import cc.fascinated.bat.common.Serializable;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import org.bson.Document;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
@ -13,7 +16,8 @@ import java.util.Map;
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
public class AfkProfile extends Profile {
|
||||
@NoArgsConstructor
|
||||
public class AfkProfile extends Serializable {
|
||||
private static final String DEFAULT_REASON = "Away";
|
||||
|
||||
/**
|
||||
@ -98,4 +102,21 @@ public class AfkProfile extends Profile {
|
||||
public void reset() {
|
||||
afkUsers = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Document document, Gson gson) {
|
||||
afkUsers = new HashMap<>();
|
||||
for (String key : document.keySet()) {
|
||||
afkUsers.put(key, document.getString(key));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document serialize(Gson gson) {
|
||||
Document document = new Document();
|
||||
for (String key : afkUsers.keySet()) {
|
||||
document.put(key, afkUsers.get(key));
|
||||
}
|
||||
return document;
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import org.springframework.stereotype.Component;
|
||||
public class AutoRoleFeature extends Feature {
|
||||
@Autowired
|
||||
public AutoRoleFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService) {
|
||||
super("AutoRole", Category.SERVER);
|
||||
super("Auto Role",true, Category.SERVER);
|
||||
|
||||
registerCommand(commandService, context.getBean(AutoRoleCommand.class));
|
||||
}
|
||||
|
@ -4,10 +4,12 @@ import cc.fascinated.bat.event.EventListener;
|
||||
import cc.fascinated.bat.features.autorole.profile.AutoRoleProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.FeatureService;
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -19,8 +21,20 @@ import java.util.List;
|
||||
@Component
|
||||
@Log4j2
|
||||
public class AutoRoleListener implements EventListener {
|
||||
private final FeatureService featureService;
|
||||
|
||||
@Autowired
|
||||
public AutoRoleListener(@NonNull FeatureService featureService) {
|
||||
this.featureService = featureService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuildMemberJoin(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GuildMemberJoinEvent event) {
|
||||
AutoRoleFeature autoRoleFeature = featureService.getFeature(AutoRoleFeature.class);
|
||||
if (!guild.getFeatureProfile().isFeatureEnabled(autoRoleFeature)) { // Check if the feature is enabled
|
||||
return;
|
||||
}
|
||||
|
||||
AutoRoleProfile profile = guild.getProfile(AutoRoleProfile.class);
|
||||
if (profile.getRoles().isEmpty()) {
|
||||
return;
|
||||
|
@ -7,7 +7,6 @@ import cc.fascinated.bat.common.RoleUtils;
|
||||
import cc.fascinated.bat.features.autorole.profile.AutoRoleProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
@ -24,30 +23,27 @@ import org.springframework.stereotype.Component;
|
||||
@Component("autoroles:add.sub")
|
||||
@CommandInfo(name = "add", description = "Adds a role to the auto roles list")
|
||||
public class AddSubCommand extends BatSubCommand {
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public AddSubCommand(@NonNull GuildService guildService) {
|
||||
public AddSubCommand() {
|
||||
super.addOption(OptionType.ROLE, "role", "The role to add", true);
|
||||
this.guildService = guildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
AutoRoleProfile profile = guild.getProfile(AutoRoleProfile.class);
|
||||
// Check if the guild has reached the maximum auto roles count
|
||||
int maxRoleSlots = AutoRoleProfile.getMaxRoleSlots(guild);
|
||||
if (profile.getRoleSlotsInUse() >= maxRoleSlots) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("The guild can only have a maximum of %d auto roles"
|
||||
.formatted(maxRoleSlots))
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
OptionMapping option = interaction.getOption("role");
|
||||
OptionMapping option = event.getOption("role");
|
||||
if (option == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Please provide a role to add")
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -56,7 +52,7 @@ public class AddSubCommand extends BatSubCommand {
|
||||
|
||||
// Check if the role is already in the auto roles list
|
||||
if (profile.hasRole(role.getId())) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("The role %s is already in the auto roles list".formatted(role.getAsMention()))
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -64,7 +60,7 @@ public class AddSubCommand extends BatSubCommand {
|
||||
|
||||
// Check if the bot has permission to give the role
|
||||
if (!RoleUtils.hasPermissionToGiveRole(guild, guild.getDiscordGuild().getSelfMember(), role)) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("I do not have permission to give the role %s".formatted(role.getAsMention()))
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -72,7 +68,7 @@ public class AddSubCommand extends BatSubCommand {
|
||||
|
||||
// Check if the role is higher than the user adding the role
|
||||
if (!RoleUtils.hasPermissionToGiveRole(guild, member, role)) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You cannot add a role that is higher than you")
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -80,8 +76,7 @@ public class AddSubCommand extends BatSubCommand {
|
||||
|
||||
// Add the role to the auto roles list
|
||||
profile.addRole(role.getId());
|
||||
guildService.saveGuild(guild);
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("You have added %s to the auto roles list".formatted(role.getAsMention()))
|
||||
.build()).queue();
|
||||
}
|
||||
|
@ -6,12 +6,10 @@ import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.autorole.profile.AutoRoleProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@ -20,20 +18,12 @@ import org.springframework.stereotype.Component;
|
||||
@Component("autoroles:clear.sub")
|
||||
@CommandInfo(name = "clear", description = "Clears all auto roles")
|
||||
public class ClearSubCommand extends BatSubCommand {
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public ClearSubCommand(GuildService guildService) {
|
||||
this.guildService = guildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
AutoRoleProfile profile = guild.getProfile(AutoRoleProfile.class);
|
||||
|
||||
profile.reset();
|
||||
guildService.saveGuild(guild);
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully cleared all auto roles")
|
||||
.build()).queue();
|
||||
}
|
||||
|
@ -20,10 +20,10 @@ import org.springframework.stereotype.Component;
|
||||
@CommandInfo(name = "list", description = "Lists all auto roles")
|
||||
public class ListSubCommand extends BatSubCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
AutoRoleProfile profile = guild.getProfile(AutoRoleProfile.class);
|
||||
if (profile.getRoles().isEmpty()) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("There are no auto roles set")
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -41,6 +41,6 @@ public class ListSubCommand extends BatSubCommand {
|
||||
EmbedBuilder embed = EmbedUtils.genericEmbed();
|
||||
embed.setAuthor("Auto Role List");
|
||||
embed.setDescription(roles.toString());
|
||||
interaction.replyEmbeds(embed.build()).queue();
|
||||
event.replyEmbeds(embed.build()).queue();
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.autorole.profile.AutoRoleProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
@ -23,20 +22,17 @@ import org.springframework.stereotype.Component;
|
||||
@Component("autoroles:remove.sub")
|
||||
@CommandInfo(name = "remove", description = "Removes a role from the auto roles list")
|
||||
public class RemoveSubCommand extends BatSubCommand {
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public RemoveSubCommand(GuildService guildService) {
|
||||
public RemoveSubCommand() {
|
||||
super.addOption(OptionType.ROLE, "role", "The role to remove", true);
|
||||
this.guildService = guildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
AutoRoleProfile profile = guild.getProfile(AutoRoleProfile.class);
|
||||
OptionMapping option = interaction.getOption("role");
|
||||
OptionMapping option = event.getOption("role");
|
||||
if (option == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Please provide a role to remove")
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -44,15 +40,14 @@ public class RemoveSubCommand extends BatSubCommand {
|
||||
|
||||
Role role = option.getAsRole();
|
||||
if (!profile.hasRole(role.getId())) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("The role %s is not in the auto roles list".formatted(role.getAsMention()))
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
profile.removeRole(role.getId());
|
||||
guildService.saveGuild(guild);
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully removed the role %s from the auto roles list".formatted(role.getAsMention()))
|
||||
.build()).queue();
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
package cc.fascinated.bat.features.autorole.profile;
|
||||
|
||||
import cc.fascinated.bat.common.Profile;
|
||||
import cc.fascinated.bat.common.Serializable;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.service.DiscordService;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -15,7 +18,8 @@ import java.util.List;
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class AutoRoleProfile extends Profile {
|
||||
@NoArgsConstructor
|
||||
public class AutoRoleProfile extends Serializable {
|
||||
private static final int DEFAULT_MAX_ROLES = 10;
|
||||
private static final int PREMIUM_MAX_ROLES = 25;
|
||||
|
||||
@ -24,10 +28,6 @@ public class AutoRoleProfile extends Profile {
|
||||
*/
|
||||
private List<String> roleIds;
|
||||
|
||||
public AutoRoleProfile() {
|
||||
super("auto-role");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum amount of roles that can be set in the guild
|
||||
*
|
||||
@ -35,7 +35,7 @@ public class AutoRoleProfile extends Profile {
|
||||
* @return the amount of role slots
|
||||
*/
|
||||
public static int getMaxRoleSlots(BatGuild guild) {
|
||||
if (guild.getPremium().hasPremium()) {
|
||||
if (guild.getPremiumProfile().hasPremium()) {
|
||||
return PREMIUM_MAX_ROLES;
|
||||
}
|
||||
return DEFAULT_MAX_ROLES;
|
||||
@ -110,4 +110,16 @@ public class AutoRoleProfile extends Profile {
|
||||
public void reset() {
|
||||
roleIds.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Document document, Gson gson) {
|
||||
roleIds = document.getList("roleIds", String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document serialize(Gson gson) {
|
||||
Document document = new Document();
|
||||
document.put("roleIds", roleIds);
|
||||
return document;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,43 @@
|
||||
package cc.fascinated.bat.features.base;
|
||||
|
||||
import cc.fascinated.bat.command.Category;
|
||||
import cc.fascinated.bat.features.Feature;
|
||||
import cc.fascinated.bat.features.base.commands.botadmin.premium.PremiumAdminCommand;
|
||||
import cc.fascinated.bat.features.base.commands.fun.image.ImageCommand;
|
||||
import cc.fascinated.bat.features.base.commands.general.*;
|
||||
import cc.fascinated.bat.features.base.commands.general.avatar.AvatarCommand;
|
||||
import cc.fascinated.bat.features.base.commands.general.banner.BannerCommand;
|
||||
import cc.fascinated.bat.features.base.commands.server.MemberCountCommand;
|
||||
import cc.fascinated.bat.features.base.commands.server.PremiumCommand;
|
||||
import cc.fascinated.bat.features.base.commands.server.channel.ChannelCommand;
|
||||
import cc.fascinated.bat.features.base.commands.server.feature.FeatureCommand;
|
||||
import cc.fascinated.bat.service.CommandService;
|
||||
import lombok.NonNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
public class BaseFeature extends Feature {
|
||||
@Autowired
|
||||
public BaseFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService) {
|
||||
super("Base", false, Category.GENERAL);
|
||||
|
||||
super.registerCommand(commandService, context.getBean(PremiumCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(PremiumAdminCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(MemberCountCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(ChannelCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(VoteCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(PingCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(InviteCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(HelpCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(BotStatsCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(BannerCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(AvatarCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(ImageCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(FeatureCommand.class));
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.botadmin.premium;
|
||||
package cc.fascinated.bat.features.base.commands.botadmin.premium;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.Category;
|
@ -1,9 +1,10 @@
|
||||
package cc.fascinated.bat.command.impl.botadmin.premium;
|
||||
package cc.fascinated.bat.features.base.commands.botadmin.premium;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.premium.PremiumProfile;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
@ -29,26 +30,25 @@ public class RemoveSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
OptionMapping guildOption = interaction.getOption("guild");
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
OptionMapping guildOption = event.getOption("guild");
|
||||
if (guildOption == null) {
|
||||
interaction.reply("Please provide a guild id").queue();
|
||||
event.reply("Please provide a guild id").queue();
|
||||
return;
|
||||
}
|
||||
String guildId = guildOption.getAsString();
|
||||
BatGuild batGuild = guildService.getGuild(guildId);
|
||||
if (batGuild == null) {
|
||||
interaction.reply("The guild with the id %s does not exist".formatted(guildId)).queue();
|
||||
BatGuild targetGuild = guildService.getGuild(guildId);
|
||||
if (targetGuild == null) {
|
||||
event.reply("The guild with the id %s does not exist".formatted(guildId)).queue();
|
||||
return;
|
||||
}
|
||||
BatGuild.Premium premium = batGuild.getPremium();
|
||||
PremiumProfile premium = targetGuild.getPremiumProfile();
|
||||
if (!premium.hasPremium()) {
|
||||
interaction.reply("The guild does not have premium").queue();
|
||||
event.reply("The guild does not have premium").queue();
|
||||
return;
|
||||
}
|
||||
|
||||
premium.removePremium();
|
||||
guildService.saveGuild(batGuild);
|
||||
interaction.reply("The guild **%s** has had its premium removed".formatted(guild.getName())).queue();
|
||||
event.reply("The guild **%s** has had its premium removed".formatted(targetGuild.getName())).queue();
|
||||
}
|
||||
}
|
@ -1,9 +1,10 @@
|
||||
package cc.fascinated.bat.command.impl.botadmin.premium;
|
||||
package cc.fascinated.bat.features.base.commands.botadmin.premium;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.premium.PremiumProfile;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
@ -23,43 +24,42 @@ public class SetSubCommand extends BatSubCommand {
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public SetSubCommand(GuildService guildService) {
|
||||
public SetSubCommand(@NonNull GuildService guildService) {
|
||||
this.guildService = guildService;
|
||||
super.addOption(OptionType.STRING, "guild", "The guild id to set as premium", true);
|
||||
super.addOption(OptionType.BOOLEAN, "infinite", "Whether the premium length should be infinite", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
OptionMapping guildOption = interaction.getOption("guild");
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
OptionMapping guildOption = event.getOption("guild");
|
||||
if (guildOption == null) {
|
||||
interaction.reply("Please provide a guild id").queue();
|
||||
event.reply("Please provide a guild id").queue();
|
||||
return;
|
||||
}
|
||||
String guildId = guildOption.getAsString();
|
||||
OptionMapping infiniteOption = interaction.getOption("infinite");
|
||||
OptionMapping infiniteOption = event.getOption("infinite");
|
||||
if (infiniteOption == null) {
|
||||
interaction.reply("Please provide whether the premium length should be infinite").queue();
|
||||
event.reply("Please provide whether the premium length should be infinite").queue();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean infinite = infiniteOption.getAsBoolean();
|
||||
BatGuild batGuild = guildService.getGuild(guildId);
|
||||
if (batGuild == null) {
|
||||
interaction.reply("The guild with the id %s does not exist".formatted(guildId)).queue();
|
||||
BatGuild targetGuild = guildService.getGuild(guildId);
|
||||
if (targetGuild == null) {
|
||||
event.reply("The guild with the id %s does not exist".formatted(guildId)).queue();
|
||||
return;
|
||||
}
|
||||
BatGuild.Premium premium = batGuild.getPremium();
|
||||
PremiumProfile premium = targetGuild.getPremiumProfile();
|
||||
if (!infinite) {
|
||||
premium.addTime();
|
||||
} else {
|
||||
premium.addInfiniteTime();
|
||||
}
|
||||
guildService.saveGuild(batGuild);
|
||||
if (!infinite) {
|
||||
interaction.reply("The guild **%s** has been set as premium until <t:%s>".formatted(guild.getName(), premium.getExpiresAt().toInstant().toEpochMilli() / 1000)).queue();
|
||||
event.reply("The guild **%s** has been set as premium until <t:%s>".formatted(targetGuild.getName(), premium.getExpiresAt().toInstant().toEpochMilli() / 1000)).queue();
|
||||
} else {
|
||||
interaction.reply("The guild **%s** has been set as premium indefinitely".formatted(guild.getName())).queue();
|
||||
event.reply("The guild **%s** has been set as premium indefinitely".formatted(targetGuild.getName())).queue();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.fun.image;
|
||||
package cc.fascinated.bat.features.base.commands.fun.image;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
@ -20,14 +20,14 @@ import org.springframework.stereotype.Component;
|
||||
@CommandInfo(name = "cat", description = "Get a random cat image")
|
||||
public class CatSubCommand extends BatSubCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
CatImageToken[] responseEntity = WebRequest.getAsEntity("https://api.thecatapi.com/v1/images/search", CatImageToken[].class);
|
||||
if (responseEntity == null || responseEntity.length == 0) {
|
||||
interaction.reply("Failed to get a cat image!").queue();
|
||||
event.reply("Failed to get a cat image!").queue();
|
||||
return;
|
||||
}
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setAuthor("Here's a random cat image!")
|
||||
.setImage(responseEntity[0].getUrl())
|
||||
.build()).queue();
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.fun.image;
|
||||
package cc.fascinated.bat.features.base.commands.fun.image;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
@ -20,14 +20,14 @@ import org.springframework.stereotype.Component;
|
||||
@CommandInfo(name = "dog", description = "Get a random dog image")
|
||||
public class DogSubCommand extends BatSubCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
RandomImage responseEntity = WebRequest.getAsEntity("https://dog.ceo/api/breeds/image/random", RandomImage.class);
|
||||
if (responseEntity == null) {
|
||||
interaction.reply("Failed to get a dog image!").queue();
|
||||
event.reply("Failed to get a dog image!").queue();
|
||||
return;
|
||||
}
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setAuthor("Here's a random dog image!")
|
||||
.setImage(responseEntity.getMessage())
|
||||
.build()).queue();
|
@ -0,0 +1,35 @@
|
||||
package cc.fascinated.bat.features.base.commands.fun.image;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.common.WebRequest;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.model.token.randomd.RandomDuck;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
@CommandInfo(name = "duck", description = "Get a random duck image")
|
||||
public class DuckSubCommand extends BatSubCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
RandomDuck responseEntity = WebRequest.getAsEntity("https://random-d.uk/api/v2/random", RandomDuck.class);
|
||||
if (responseEntity == null) {
|
||||
event.reply("Failed to get a duck image!").queue();
|
||||
return;
|
||||
}
|
||||
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setAuthor("Here's a random duck image!")
|
||||
.setImage(responseEntity.getUrl())
|
||||
.build()).queue();
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.fun.image;
|
||||
package cc.fascinated.bat.features.base.commands.fun.image;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
@ -20,14 +20,14 @@ import org.springframework.stereotype.Component;
|
||||
@CommandInfo(name = "fox", description = "Get a random fox image")
|
||||
public class FoxSubCommand extends BatSubCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
RandomFoxToken responseEntity = WebRequest.getAsEntity("https://randomfox.ca/floof/", RandomFoxToken.class);
|
||||
if (responseEntity == null) {
|
||||
interaction.reply("Failed to get a fox image!").queue();
|
||||
event.reply("Failed to get a fox image!").queue();
|
||||
return;
|
||||
}
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setAuthor("Here's a random fox image!")
|
||||
.setImage(responseEntity.getImage())
|
||||
.build()).queue();
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.fun.image;
|
||||
package cc.fascinated.bat.features.base.commands.fun.image;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.Category;
|
||||
@ -19,5 +19,6 @@ public class ImageCommand extends BatCommand {
|
||||
super.addSubCommand(context.getBean(CatSubCommand.class));
|
||||
super.addSubCommand(context.getBean(DogSubCommand.class));
|
||||
super.addSubCommand(context.getBean(FoxSubCommand.class));
|
||||
super.addSubCommand(context.getBean(DuckSubCommand.class));
|
||||
}
|
||||
}
|
@ -1,8 +1,9 @@
|
||||
package cc.fascinated.bat.command.impl;
|
||||
package cc.fascinated.bat.features.base.commands.general;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.common.NumberFormatter;
|
||||
import cc.fascinated.bat.common.TimeUtils;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
@ -37,19 +38,19 @@ public class BotStatsCommand extends BatCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
JDA jda = DiscordService.JDA;
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed().setDescription(
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed().setDescription(
|
||||
"**Bot Statistics**\n" +
|
||||
"➜ Guilds: **%s**\n".formatted(jda.getGuilds().size()) +
|
||||
"➜ Users: **%s**\n".formatted(jda.getUsers().size()) +
|
||||
"➜ Guilds: **%s**\n".formatted(NumberFormatter.format(jda.getGuilds().size())) +
|
||||
"➜ Users: **%s**\n".formatted(NumberFormatter.format(jda.getUsers().size())) +
|
||||
"➜ Gateway Ping: **%sms**\n".formatted(jda.getGatewayPing()) +
|
||||
"\n" +
|
||||
"**Bat Statistics**\n" +
|
||||
"➜ Uptime: **%s**\n".formatted(TimeUtils.format(bean.getUptime())) +
|
||||
"➜ Cached Guilds: **%s**\n".formatted(guildService.getGuilds().size()) +
|
||||
"➜ Cached Users: **%s**".formatted(userService.getUsers().size())
|
||||
"➜ Cached Guilds: **%s**\n".formatted(NumberFormatter.format(guildService.getGuilds().size())) +
|
||||
"➜ Cached Users: **%s**".formatted(NumberFormatter.format(userService.getUsers().size()))
|
||||
).build()).queue();
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl;
|
||||
package cc.fascinated.bat.features.base.commands.general;
|
||||
|
||||
import cc.fascinated.bat.Consts;
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
@ -45,8 +45,8 @@ public class HelpCommand extends BatCommand implements EventListener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
interaction.replyEmbeds(createHomeEmbed()).addComponents(createHomeActions()).queue();
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
event.replyEmbeds(createHomeEmbed()).addComponents(createHomeActions()).queue();
|
||||
}
|
||||
|
||||
@Override
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl;
|
||||
package cc.fascinated.bat.features.base.commands.general;
|
||||
|
||||
import cc.fascinated.bat.Consts;
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
@ -19,8 +19,8 @@ import org.springframework.stereotype.Component;
|
||||
@CommandInfo(name = "invite", description = "Invite the bot to your server!", guildOnly = false)
|
||||
public class InviteCommand extends BatCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setDescription("You can invite the bot to your server by clicking [here](%s)".formatted(Consts.INVITE_URL))
|
||||
.build())
|
||||
.setEphemeral(true)
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl;
|
||||
package cc.fascinated.bat.features.base.commands.general;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
@ -18,9 +18,9 @@ import org.springframework.stereotype.Component;
|
||||
@CommandInfo(name = "ping", description = "Gets the ping of the bot", guildOnly = false)
|
||||
public class PingCommand extends BatCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
long time = System.currentTimeMillis();
|
||||
interaction.reply("Pinging...").queue(response -> {
|
||||
event.reply("Pinging...").queue(response -> {
|
||||
response.editOriginal("Gateway response time: `%sms`\nAPI response time `%sms`".formatted(
|
||||
DiscordService.JDA.getGatewayPing(),
|
||||
System.currentTimeMillis() - time
|
@ -0,0 +1,36 @@
|
||||
package cc.fascinated.bat.features.base.commands.general;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
@CommandInfo(name = "vote", description = "Vote for the bot", guildOnly = false)
|
||||
public class VoteCommand extends BatCommand {
|
||||
private static final String[] VOTE_LINKS = new String[]{
|
||||
"https://top.gg/bot/1254161119975833652/vote"
|
||||
};
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("You can vote for the bot by clicking the following links:\n\n");
|
||||
for (String link : VOTE_LINKS) {
|
||||
builder.append("%s\n".formatted(link));
|
||||
}
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setDescription(builder.toString())
|
||||
.build()
|
||||
).queue();
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.avatar;
|
||||
package cc.fascinated.bat.features.base.commands.general.avatar;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.avatar;
|
||||
package cc.fascinated.bat.features.base.commands.general.avatar;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
@ -19,18 +19,18 @@ import org.springframework.stereotype.Component;
|
||||
@CommandInfo(name = "guild", description = "View the avatar of the guild")
|
||||
public class GuildSubCommand extends BatSubCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
ImageProxy icon = guild.getDiscordGuild().getIcon();
|
||||
|
||||
if (icon == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("**%s** does not have an avatar!".formatted(guild.getName()))
|
||||
.build())
|
||||
.queue();
|
||||
return;
|
||||
}
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setAuthor("%s's Avatar".formatted(guild.getName()), null, guild.getDiscordGuild().getIconUrl())
|
||||
.setImage(icon.getUrl(4096))
|
||||
.build()
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.avatar;
|
||||
package cc.fascinated.bat.features.base.commands.general.avatar;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
@ -25,10 +25,10 @@ public class UserSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
OptionMapping userOption = interaction.getOption("user");
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
OptionMapping userOption = event.getOption("user");
|
||||
if (userOption == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You must provide a user to view the avatar of!")
|
||||
.build())
|
||||
.queue();
|
||||
@ -36,7 +36,7 @@ public class UserSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
User target = userOption.getAsUser();
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setAuthor("%s's Avatar".formatted(target.getName()), null, target.getEffectiveAvatarUrl())
|
||||
.setImage(target.getEffectiveAvatarUrl())
|
||||
.build()
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.banner;
|
||||
package cc.fascinated.bat.features.base.commands.general.banner;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.banner;
|
||||
package cc.fascinated.bat.features.base.commands.general.banner;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
@ -19,17 +19,17 @@ import org.springframework.stereotype.Component;
|
||||
@CommandInfo(name = "guild", description = "View the banner of the guild")
|
||||
public class GuildSubCommand extends BatSubCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
ImageProxy banner = guild.getDiscordGuild().getBanner();
|
||||
if (banner == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("**%s** does not have a banner!".formatted(guild.getName()))
|
||||
.build())
|
||||
.queue();
|
||||
return;
|
||||
}
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setAuthor("%s's Banner".formatted(guild.getName()))
|
||||
.setImage(banner.getUrl(512))
|
||||
.build()
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.banner;
|
||||
package cc.fascinated.bat.features.base.commands.general.banner;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
@ -26,10 +26,10 @@ public class UserSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
OptionMapping userOption = interaction.getOption("user");
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
OptionMapping userOption = event.getOption("user");
|
||||
if (userOption == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You must provide a user to view the banner of!")
|
||||
.build())
|
||||
.queue();
|
||||
@ -39,14 +39,14 @@ public class UserSubCommand extends BatSubCommand {
|
||||
User target = userOption.getAsUser();
|
||||
ImageProxy banner = target.retrieveProfile().complete().getBanner();
|
||||
if (banner == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("**%s** does not have a banner!".formatted(target.getName()))
|
||||
.build())
|
||||
.queue();
|
||||
return;
|
||||
}
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setAuthor("%s's Banner".formatted(target.getName()))
|
||||
.setImage(banner.getUrl(512))
|
||||
.build()
|
@ -0,0 +1,69 @@
|
||||
package cc.fascinated.bat.features.base.commands.server;
|
||||
|
||||
import cc.fascinated.bat.Emojis;
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.common.NumberFormatter;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.EmbedBuilder;
|
||||
import net.dv8tion.jda.api.OnlineStatus;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Nick (okNick)
|
||||
*/
|
||||
@Component
|
||||
@CommandInfo(name = "membercount", description = "View the member count of the server!")
|
||||
public class MemberCountCommand extends BatCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
Guild discordGuild = guild.getDiscordGuild();
|
||||
int totalMembers = 0, totalUsers = 0, totalBots = 0;
|
||||
Map<OnlineStatus, Integer> memberCounts = new HashMap<>();
|
||||
for (Member guildMember : discordGuild.getMembers()) {
|
||||
OnlineStatus status = guildMember.getOnlineStatus();
|
||||
memberCounts.put(status, memberCounts.getOrDefault(status, 0) + 1);
|
||||
|
||||
if (guildMember.getUser().isBot()) {
|
||||
totalBots++;
|
||||
} else {
|
||||
totalUsers++;
|
||||
}
|
||||
totalMembers++;
|
||||
}
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setDescription("""
|
||||
**Member Count**
|
||||
Total Members: `%s`
|
||||
Total Users: `%s`
|
||||
Total Bots: `%s`
|
||||
\s
|
||||
**Member Presence**
|
||||
%s Online: `%s`
|
||||
%s Idle: `%s`
|
||||
%s Do Not Disturb: `%s`
|
||||
%s Offline: `%s`""".formatted(
|
||||
NumberFormatter.format(totalMembers),
|
||||
NumberFormatter.format(totalUsers),
|
||||
NumberFormatter.format(totalBots),
|
||||
Emojis.ONLINE_EMOJI,
|
||||
NumberFormatter.format(memberCounts.getOrDefault(OnlineStatus.ONLINE, 0)),
|
||||
Emojis.IDLE_EMOJI,
|
||||
NumberFormatter.format(memberCounts.getOrDefault(OnlineStatus.IDLE, 0)),
|
||||
Emojis.DND_EMOJI,
|
||||
NumberFormatter.format(memberCounts.getOrDefault(OnlineStatus.DO_NOT_DISTURB, 0)),
|
||||
Emojis.OFFLINE_EMOJI,
|
||||
NumberFormatter.format(memberCounts.getOrDefault(OnlineStatus.OFFLINE, 0))))
|
||||
.build()).queue();
|
||||
}
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
package cc.fascinated.bat.command.impl.server;
|
||||
package cc.fascinated.bat.features.base.commands.server;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.premium.PremiumProfile;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.EmbedBuilder;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
@ -20,8 +21,8 @@ import org.springframework.stereotype.Component;
|
||||
@CommandInfo(name = "premium", description = "View the premium information for the guild", requiredPermissions = Permission.ADMINISTRATOR)
|
||||
public class PremiumCommand extends BatCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
BatGuild.Premium premium = guild.getPremium();
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
PremiumProfile premium = guild.getPremiumProfile();
|
||||
EmbedBuilder embed = EmbedUtils.genericEmbed().setAuthor("Premium Information");
|
||||
if (premium.hasPremium()) {
|
||||
embed.addField("Premium", premium.hasPremium() ? "Yes" : "No", true);
|
||||
@ -31,6 +32,6 @@ public class PremiumCommand extends BatCommand {
|
||||
} else {
|
||||
embed.setDescription("The guild does not have premium");
|
||||
}
|
||||
interaction.replyEmbeds(embed.build()).queue();
|
||||
event.replyEmbeds(embed.build()).queue();
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.server.channel;
|
||||
package cc.fascinated.bat.features.base.commands.server.channel;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.Category;
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.server.channel;
|
||||
package cc.fascinated.bat.features.base.commands.server.channel;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
@ -26,10 +26,10 @@ public class RemoveTopicSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
Channel target = interaction.getOption("channel") == null ? channel : interaction.getOption("channel").getAsChannel();
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
Channel target = event.getOption("channel") == null ? channel : event.getOption("channel").getAsChannel();
|
||||
if (!(target instanceof TextChannel textChannel)) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("<#%s> is not a text channel!".formatted(target.getId()))
|
||||
.build())
|
||||
.queue();
|
||||
@ -37,7 +37,7 @@ public class RemoveTopicSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
if (textChannel.getTopic() == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("<#%s> does not have a topic!".formatted(textChannel.getId()))
|
||||
.build())
|
||||
.queue();
|
||||
@ -45,7 +45,7 @@ public class RemoveTopicSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
textChannel.getManager().setTopic(null).queue();
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully removed the topic of <#%s>".formatted(textChannel.getId()))
|
||||
.build()
|
||||
).queue();
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.server.channel;
|
||||
package cc.fascinated.bat.features.base.commands.server.channel;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
@ -27,19 +27,19 @@ public class SetTopicSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
Channel target = interaction.getOption("channel") == null ? channel : interaction.getOption("channel").getAsChannel();
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
Channel target = event.getOption("channel") == null ? channel : event.getOption("channel").getAsChannel();
|
||||
if (!(target instanceof TextChannel textChannel)) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("<#%s> is not a text channel!".formatted(target.getId()))
|
||||
.build())
|
||||
.queue();
|
||||
return;
|
||||
}
|
||||
|
||||
String topic = interaction.getOption("topic").getAsString();
|
||||
String topic = event.getOption("topic").getAsString();
|
||||
if (topic.length() > 1024) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("The topic must be 1024 characters or less!")
|
||||
.build())
|
||||
.queue();
|
||||
@ -47,7 +47,7 @@ public class SetTopicSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
textChannel.getManager().setTopic(topic).queue();
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully set the topic of <#%s> to: \"%s\"".formatted(textChannel.getId(), topic))
|
||||
.build()
|
||||
).queue();
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.server.channel;
|
||||
package cc.fascinated.bat.features.base.commands.server.channel;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
@ -25,10 +25,10 @@ public class ViewTopicSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
Channel target = interaction.getOption("channel") == null ? channel : interaction.getOption("channel").getAsChannel();
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
Channel target = event.getOption("channel") == null ? channel : event.getOption("channel").getAsChannel();
|
||||
if (!(target instanceof TextChannel textChannel)) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("<#%s> is not a text channel!".formatted(target.getId()))
|
||||
.build())
|
||||
.queue();
|
||||
@ -37,14 +37,14 @@ public class ViewTopicSubCommand extends BatSubCommand {
|
||||
|
||||
String topic = textChannel.getTopic();
|
||||
if (topic == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("<#%s> does not have a topic!".formatted(textChannel.getId()))
|
||||
.build())
|
||||
.queue();
|
||||
return;
|
||||
}
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setDescription("The topic of <#%s> is: \"%s\"".formatted(textChannel.getId(), topic))
|
||||
.build()
|
||||
).queue();
|
@ -0,0 +1,61 @@
|
||||
package cc.fascinated.bat.features.base.commands.server.feature;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.Feature;
|
||||
import cc.fascinated.bat.features.base.profile.FeatureProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.FeatureService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component("feature:disable.sub")
|
||||
@CommandInfo(name = "disable", description = "Disables a feature")
|
||||
public class DisableSubCommand extends BatSubCommand {
|
||||
@Autowired
|
||||
public DisableSubCommand() {
|
||||
super.addOption(OptionType.STRING, "feature", "The feature to disable", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
FeatureProfile featureProfile = guild.getFeatureProfile();
|
||||
OptionMapping featureOption = event.getOption("feature");
|
||||
if (featureOption == null) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You must provide a feature to enabled")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
String featureName = featureOption.getAsString();
|
||||
if (!FeatureService.INSTANCE.isFeature(featureName)) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("That feature does not exist")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
Feature feature = FeatureService.INSTANCE.getFeature(featureName);
|
||||
if (featureProfile.isFeatureDisabled(feature)) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("The feature `%s` is already disabled".formatted(feature.getName()))
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
featureProfile.disableFeature(feature);
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Successfully disabled the `%s` feature".formatted(feature.getName()))
|
||||
.build()).queue();
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package cc.fascinated.bat.features.base.commands.server.feature;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.Feature;
|
||||
import cc.fascinated.bat.features.base.profile.FeatureProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.FeatureService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component("feature:enable.sub")
|
||||
@CommandInfo(name = "enable", description = "Enables a feature")
|
||||
public class EnableSubCommand extends BatSubCommand {
|
||||
@Autowired
|
||||
public EnableSubCommand() {
|
||||
super.addOption(OptionType.STRING, "feature", "The feature to enable", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
FeatureProfile featureProfile = guild.getFeatureProfile();
|
||||
OptionMapping featureOption = event.getOption("feature");
|
||||
if (featureOption == null) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You must provide a feature to enabled")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
String featureName = featureOption.getAsString();
|
||||
if (!FeatureService.INSTANCE.isFeature(featureName)) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("That feature does not exist")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
Feature feature = FeatureService.INSTANCE.getFeature(featureName);
|
||||
if (featureProfile.isFeatureEnabled(feature)) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("The feature `%s` is already enabled".formatted(feature.getName()))
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
featureProfile.enableFeature(feature);
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully enabled the `%s` feature".formatted(feature.getName()))
|
||||
.build()).queue();
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package cc.fascinated.bat.features.base.commands.server.feature;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.Category;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
@CommandInfo(name = "feature", description = "Configure features in your guild", requiredPermissions = Permission.ADMINISTRATOR, category = Category.SERVER)
|
||||
public class FeatureCommand extends BatCommand {
|
||||
@Autowired
|
||||
public FeatureCommand(@NonNull ApplicationContext context) {
|
||||
super.addSubCommand(context.getBean(EnableSubCommand.class));
|
||||
super.addSubCommand(context.getBean(DisableSubCommand.class));
|
||||
super.addSubCommand(context.getBean(ListSubCommand.class));
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package cc.fascinated.bat.features.base.commands.server.feature;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.Feature;
|
||||
import cc.fascinated.bat.features.base.profile.FeatureProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.FeatureService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component("feature:list.sub")
|
||||
@CommandInfo(name = "list", description = "Lists the features and their states")
|
||||
public class ListSubCommand extends BatSubCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
StringBuilder featureStates = new StringBuilder();
|
||||
for (Feature feature : FeatureService.INSTANCE.getFeaturesSorted()) {
|
||||
FeatureProfile featureProfile = guild.getFeatureProfile();
|
||||
featureStates.append("%s `%s`\n".formatted(
|
||||
featureProfile.getFeatureState(feature).getEmoji(),
|
||||
feature.getName()
|
||||
));
|
||||
}
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setTitle("Feature List")
|
||||
.setDescription(featureStates.toString())
|
||||
.build()
|
||||
).queue();
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
package cc.fascinated.bat.features.base.profile;
|
||||
|
||||
import cc.fascinated.bat.common.Serializable;
|
||||
import cc.fascinated.bat.features.Feature;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
public class FeatureProfile extends Serializable {
|
||||
private static final FeatureState DEFAULT_STATE = FeatureState.ENABLED;
|
||||
|
||||
/**
|
||||
* The feature states
|
||||
*/
|
||||
private Map<String, FeatureState> featureStates;
|
||||
|
||||
/**
|
||||
* Gets the feature states
|
||||
*
|
||||
* @return the feature states
|
||||
*/
|
||||
public FeatureState getFeatureState(Feature feature) {
|
||||
if (feature == null) {
|
||||
return DEFAULT_STATE;
|
||||
}
|
||||
String featureName = feature.getName().toUpperCase();
|
||||
if (!this.featureStates.containsKey(featureName)) {
|
||||
this.featureStates.put(featureName, DEFAULT_STATE);
|
||||
}
|
||||
return this.featureStates.get(featureName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the feature is enabled
|
||||
*
|
||||
* @return the feature state
|
||||
*/
|
||||
public boolean isFeatureEnabled(Feature feature) {
|
||||
return this.getFeatureState(feature) == FeatureState.ENABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the feature is disabled
|
||||
*
|
||||
* @return the feature state
|
||||
*/
|
||||
public boolean isFeatureDisabled(Feature feature) {
|
||||
return this.getFeatureState(feature) == FeatureState.DISABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the feature
|
||||
*
|
||||
* @param feature the feature to enable
|
||||
*/
|
||||
public void enableFeature(Feature feature) {
|
||||
this.setFeatureState(feature, FeatureState.ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the feature
|
||||
*
|
||||
* @param feature the feature to disable
|
||||
*/
|
||||
public void disableFeature(Feature feature) {
|
||||
this.setFeatureState(feature, FeatureState.DISABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the feature state
|
||||
*
|
||||
* @param feature the feature to set the state for
|
||||
* @param state the state to set
|
||||
*/
|
||||
public void setFeatureState(Feature feature, FeatureState state) {
|
||||
this.featureStates.put(feature.getName().toUpperCase(), state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.featureStates = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Document document, Gson gson) {
|
||||
this.featureStates = new HashMap<>();
|
||||
for (String key : document.keySet()) {
|
||||
this.featureStates.put(key, FeatureState.valueOf(document.getString(key)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document serialize(Gson gson) {
|
||||
Document document = new Document();
|
||||
for (String key : this.featureStates.keySet()) {
|
||||
document.put(key, this.featureStates.get(key).name());
|
||||
}
|
||||
return document;
|
||||
}
|
||||
|
||||
@AllArgsConstructor @Getter
|
||||
public enum FeatureState {
|
||||
ENABLED(":white_check_mark:"),
|
||||
DISABLED(":x:");
|
||||
|
||||
/**
|
||||
* The emoji for the feature state
|
||||
*/
|
||||
private final String emoji;
|
||||
}
|
||||
}
|
@ -1,13 +1,16 @@
|
||||
package cc.fascinated.bat.features.birthday;
|
||||
|
||||
import cc.fascinated.bat.command.Category;
|
||||
import cc.fascinated.bat.event.EventListener;
|
||||
import cc.fascinated.bat.features.Feature;
|
||||
import cc.fascinated.bat.features.birthday.command.BirthdayCommand;
|
||||
import cc.fascinated.bat.features.birthday.profile.BirthdayProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.service.CommandService;
|
||||
import cc.fascinated.bat.service.DiscordService;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
@ -16,11 +19,11 @@ import org.springframework.stereotype.Component;
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
public class BirthdayFeature extends Feature {
|
||||
public class BirthdayFeature extends Feature implements EventListener {
|
||||
private final GuildService guildService;
|
||||
|
||||
public BirthdayFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService, @NonNull GuildService guildService) {
|
||||
super("Birthday", Category.UTILITY);
|
||||
super("Birthday", true, Category.UTILITY);
|
||||
this.guildService = guildService;
|
||||
|
||||
registerCommand(commandService, context.getBean(BirthdayCommand.class));
|
||||
@ -29,11 +32,15 @@ public class BirthdayFeature extends Feature {
|
||||
/**
|
||||
* Check birthdays every day at midnight
|
||||
*/
|
||||
@Scheduled(cron = "0 0 0 * * *")
|
||||
@Scheduled(cron = "0 1 0 * * *")
|
||||
private void checkBirthdays() {
|
||||
for (BatGuild guild : guildService.getAllGuilds()) {
|
||||
BirthdayProfile profile = guild.getProfile(BirthdayProfile.class);
|
||||
profile.checkBirthdays(guild);
|
||||
for (Guild guild : DiscordService.JDA.getGuilds()) {
|
||||
BatGuild batGuild = guildService.getGuild(guild.getId());
|
||||
if (batGuild == null) {
|
||||
continue;
|
||||
}
|
||||
BirthdayProfile profile = batGuild.getBirthdayProfile();
|
||||
profile.checkBirthdays(batGuild);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,64 @@
|
||||
package cc.fascinated.bat.features.birthday;
|
||||
|
||||
import cc.fascinated.bat.common.Serializable;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class UserBirthday extends Serializable {
|
||||
/**
|
||||
* The user's birthday
|
||||
*/
|
||||
private Date birthday;
|
||||
|
||||
/**
|
||||
* If the birthday should be hidden
|
||||
*/
|
||||
private boolean hidden;
|
||||
|
||||
/**
|
||||
* Calculates the age of the user
|
||||
*
|
||||
* @return the age of the user
|
||||
*/
|
||||
public int calculateAge() {
|
||||
Calendar birthdayCalendar = Calendar.getInstance();
|
||||
birthdayCalendar.setTime(this.getBirthday());
|
||||
Calendar today = Calendar.getInstance();
|
||||
int age = today.get(Calendar.YEAR) - birthdayCalendar.get(Calendar.YEAR);
|
||||
|
||||
// Check if the birthday hasn't occurred yet this year
|
||||
if (today.get(Calendar.DAY_OF_YEAR) < birthdayCalendar.get(Calendar.DAY_OF_YEAR)) {
|
||||
age--;
|
||||
}
|
||||
return age;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Document document, Gson gson) {
|
||||
this.birthday = document.getDate("birthday");
|
||||
this.hidden = document.getBoolean("hidden", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document serialize(Gson gson) {
|
||||
Document document = new Document();
|
||||
document.put("birthday", this.birthday);
|
||||
document.put("hidden", this.hidden);
|
||||
return document;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
|
||||
}
|
||||
}
|
@ -19,5 +19,7 @@ public class BirthdayCommand extends BatCommand {
|
||||
super.addSubCommand(context.getBean(RemoveSubCommand.class));
|
||||
super.addSubCommand(context.getBean(ChannelSubCommand.class));
|
||||
super.addSubCommand(context.getBean(MessageSubCommand.class));
|
||||
super.addSubCommand(context.getBean(ViewSubCommand.class));
|
||||
super.addSubCommand(context.getBean(PrivateSubCommand.class));
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import cc.fascinated.bat.common.TextChannelUtils;
|
||||
import cc.fascinated.bat.features.birthday.profile.BirthdayProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
@ -26,26 +25,23 @@ import org.springframework.stereotype.Component;
|
||||
@Component("birthday:channel.sub")
|
||||
@CommandInfo(name = "channel", description = "Sets the birthday notification channel", requiredPermissions = Permission.MANAGE_SERVER)
|
||||
public class ChannelSubCommand extends BatSubCommand {
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public ChannelSubCommand(GuildService guildService) {
|
||||
public ChannelSubCommand() {
|
||||
super.addOption(OptionType.CHANNEL, "channel", "The channel birthdays will be sent in", false);
|
||||
this.guildService = guildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
BirthdayProfile profile = guild.getProfile(BirthdayProfile.class);
|
||||
OptionMapping option = interaction.getOption("channel");
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
BirthdayProfile profile = guild.getBirthdayProfile();
|
||||
OptionMapping option = event.getOption("channel");
|
||||
if (option == null) {
|
||||
if (!TextChannelUtils.isValidChannel(profile.getChannelId())) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("There is no channel set for birthday notifications. Please provide a channel to set the birthday channel to")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setDescription("The current birthday channel is %s".formatted(TextChannelUtils.getChannelMention(profile.getChannelId())))
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -53,16 +49,14 @@ public class ChannelSubCommand extends BatSubCommand {
|
||||
|
||||
GuildChannelUnion targetChannel = option.getAsChannel();
|
||||
if (targetChannel.getType() != ChannelType.TEXT) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Invalid channel type, please provide a text channel")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
profile.setChannelId(targetChannel.getId());
|
||||
guildService.saveGuild(guild);
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully set the birthday channel to %s".formatted(targetChannel.asTextChannel().getAsMention()))
|
||||
.build()).queue();
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.birthday.profile.BirthdayProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
@ -17,10 +16,6 @@ import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
@ -28,22 +23,17 @@ import java.util.Date;
|
||||
@Component("birthday:message.sub")
|
||||
@CommandInfo(name = "message", description = "Changes the message that is sent when it is a user's birthday", requiredPermissions = Permission.MANAGE_SERVER)
|
||||
public class MessageSubCommand extends BatSubCommand {
|
||||
private static final SimpleDateFormat FORMATTER = new SimpleDateFormat("dd/MM/yyyy");
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public MessageSubCommand(GuildService guildService) {
|
||||
public MessageSubCommand() {
|
||||
super.addOption(OptionType.STRING, "message", "The message that is sent. (Placeholders: {user}, {age})", true);
|
||||
this.guildService = guildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
BirthdayProfile profile = guild.getProfile(BirthdayProfile.class);
|
||||
|
||||
OptionMapping messageOption = interaction.getOption("message");
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
BirthdayProfile profile = guild.getBirthdayProfile();
|
||||
OptionMapping messageOption = event.getOption("message");
|
||||
if (messageOption == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You must provide a message")
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -51,37 +41,21 @@ public class MessageSubCommand extends BatSubCommand {
|
||||
|
||||
String message = messageOption.getAsString();
|
||||
if (message.length() > 2000) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("The message must be less than 2000 characters")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
if (!message.contains("{user}") || !message.contains("{age}")) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("The message must contain the placeholders {user} and {age}")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
profile.setMessage(message);
|
||||
guildService.saveGuild(guild);
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("You have updated the birthday message!\n\n**Message:** %s".formatted(profile.getBirthdayMessage(user.getDiscordUser())))
|
||||
.build()).queue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a birthday from the string
|
||||
*
|
||||
* @param birthday the date to parse
|
||||
* @return the birthday
|
||||
*/
|
||||
private Date parseBirthday(String birthday) {
|
||||
try {
|
||||
return FORMATTER.parse(birthday);
|
||||
} catch (ParseException ignored) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,56 @@
|
||||
package cc.fascinated.bat.features.birthday.command;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.birthday.UserBirthday;
|
||||
import cc.fascinated.bat.features.birthday.profile.BirthdayProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component("birthday:private.sub")
|
||||
@CommandInfo(name = "private", description = "Changes whether your birthday is private or not")
|
||||
public class PrivateSubCommand extends BatSubCommand {
|
||||
@Autowired
|
||||
public PrivateSubCommand() {
|
||||
super.addOption(OptionType.BOOLEAN, "enabled", "Whether your birthday is private or not", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
BirthdayProfile profile = guild.getBirthdayProfile();
|
||||
OptionMapping enabledOption = event.getOption("enabled");
|
||||
if (enabledOption == null) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You must provide whether your birthday is private or not")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean enabled = enabledOption.getAsBoolean();
|
||||
UserBirthday birthday = profile.getBirthday(user.getId());
|
||||
if (birthday == null) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You have not set your birthday yet")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
birthday.setHidden(enabled);
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Your birthday privacy settings have been updated\n\n**Private:** " + (enabled ? "Yes" : "No"))
|
||||
.build()).queue();
|
||||
}
|
||||
}
|
@ -6,12 +6,10 @@ import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.birthday.profile.BirthdayProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
@ -21,21 +19,12 @@ import org.springframework.stereotype.Component;
|
||||
@Component("birthday:remove.sub")
|
||||
@CommandInfo(name = "remove", description = "Remove your birthday from this guild")
|
||||
public class RemoveSubCommand extends BatSubCommand {
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public RemoveSubCommand(GuildService guildService) {
|
||||
this.guildService = guildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
BirthdayProfile profile = guild.getProfile(BirthdayProfile.class);
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
BirthdayProfile profile = guild.getBirthdayProfile();
|
||||
|
||||
profile.removeBirthday(user.getId());
|
||||
guildService.saveGuild(guild);
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Your birthday has been removed from this guild")
|
||||
.build()).queue();
|
||||
}
|
||||
|
@ -3,10 +3,10 @@ package cc.fascinated.bat.features.birthday.command;
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.birthday.UserBirthday;
|
||||
import cc.fascinated.bat.features.birthday.profile.BirthdayProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
@ -28,28 +28,25 @@ import java.util.Date;
|
||||
@CommandInfo(name = "set", description = "Add your birthday to this guild")
|
||||
public class SetSubCommand extends BatSubCommand {
|
||||
private static final SimpleDateFormat FORMATTER = new SimpleDateFormat("dd/MM/yyyy");
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public SetSubCommand(GuildService guildService) {
|
||||
public SetSubCommand() {
|
||||
super.addOption(OptionType.STRING, "birthday", "Your birthday (format: DAY/MONTH/YEAR - 01/05/2004)", true);
|
||||
this.guildService = guildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
BirthdayProfile profile = guild.getProfile(BirthdayProfile.class);
|
||||
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
BirthdayProfile profile = guild.getBirthdayProfile();
|
||||
if (!profile.hasChannelSetup()) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Birthdays have not been enabled in this guild. Please ask an administrator to enable them.")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
OptionMapping birthdayOption = interaction.getOption("birthday");
|
||||
OptionMapping birthdayOption = event.getOption("birthday");
|
||||
if (birthdayOption == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You must provide a birthday")
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -57,16 +54,20 @@ public class SetSubCommand extends BatSubCommand {
|
||||
String birthdayString = birthdayOption.getAsString();
|
||||
Date birthday = parseBirthday(birthdayString);
|
||||
if (birthday == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Invalid birthday format. Please use the format: DAY/MONTH/YEAR - 01/05/2004")
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("""
|
||||
Invalid birthday format. Please use the following format:
|
||||
DAY/MONTH/YEAR - 01/05/2004
|
||||
""")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
profile.addBirthday(member.getId(), birthday);
|
||||
guildService.saveGuild(guild);
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
UserBirthday userBirthday = new UserBirthday();
|
||||
userBirthday.setBirthday(birthday);
|
||||
userBirthday.setHidden(false);
|
||||
profile.addBirthday(member.getId(), userBirthday);
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("You have updated your birthday!")
|
||||
.build()).queue();
|
||||
}
|
||||
@ -79,9 +80,16 @@ public class SetSubCommand extends BatSubCommand {
|
||||
*/
|
||||
private Date parseBirthday(String birthday) {
|
||||
try {
|
||||
return FORMATTER.parse(birthday);
|
||||
} catch (ParseException ignored) {
|
||||
Date date = FORMATTER.parse(birthday);
|
||||
if (date.after(new Date())) {
|
||||
return null;
|
||||
}
|
||||
if (date.toInstant().toEpochMilli() < 0) {
|
||||
return null;
|
||||
}
|
||||
return date;
|
||||
} catch (ParseException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,74 @@
|
||||
package cc.fascinated.bat.features.birthday.command;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.birthday.UserBirthday;
|
||||
import cc.fascinated.bat.features.birthday.profile.BirthdayProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.UserService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component("birthday:view.sub")
|
||||
@CommandInfo(name = "view", description = "Add your birthday to this guild")
|
||||
public class ViewSubCommand extends BatSubCommand {
|
||||
private final UserService userService;
|
||||
|
||||
@Autowired
|
||||
public ViewSubCommand(@NonNull UserService userService) {
|
||||
this.userService = userService;
|
||||
super.addOption(OptionType.USER, "user", "The user to view the birthday of", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
BirthdayProfile profile = guild.getBirthdayProfile();
|
||||
if (!profile.hasChannelSetup()) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Birthdays have not been enabled in this guild. Please ask an administrator to enable them.")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
OptionMapping birthdayOption = event.getOption("user");
|
||||
BatUser target = birthdayOption == null ? user : userService.getUser(birthdayOption.getAsUser().getId());
|
||||
if (target == null) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You must provide a valid user")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
UserBirthday birthday = profile.getBirthday(target.getId());
|
||||
if (birthday == null) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("%s does not have a birthday set".formatted(target.getDiscordUser().getAsMention()))
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
if (birthday.isHidden() && !user.getId().equals(target.getId())) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("%s has their birthday set to private".formatted(target.getDiscordUser().getAsMention()))
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("%s was born on <t:%s:D> they are `%s` years old!".formatted(
|
||||
target.getDiscordUser().getAsMention(), birthday.getBirthday().toInstant().toEpochMilli()/1000,
|
||||
birthday.calculateAge()
|
||||
))
|
||||
.build()).queue();
|
||||
}
|
||||
}
|
@ -1,28 +1,36 @@
|
||||
package cc.fascinated.bat.features.birthday.profile;
|
||||
|
||||
import cc.fascinated.bat.common.Profile;
|
||||
import cc.fascinated.bat.common.Serializable;
|
||||
import cc.fascinated.bat.features.birthday.UserBirthday;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class BirthdayProfile extends Profile {
|
||||
@NoArgsConstructor
|
||||
public class BirthdayProfile extends Serializable {
|
||||
private static final String DEFAULT_MESSAGE = "Happy Birthday {user} :tada: :birthday: You are now {age} years old!";
|
||||
|
||||
/**
|
||||
* The list of birthdays that are being tracked
|
||||
*/
|
||||
private Map<String, Date> birthdays;
|
||||
private Map<String, UserBirthday> birthdays;
|
||||
|
||||
/**
|
||||
* The channel ID of the birthday feed
|
||||
@ -34,17 +42,13 @@ public class BirthdayProfile extends Profile {
|
||||
*/
|
||||
private String message = DEFAULT_MESSAGE;
|
||||
|
||||
public BirthdayProfile() {
|
||||
super("birthday");
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a birthday to be tracked
|
||||
*
|
||||
* @param userId the id of the user to track
|
||||
* @param birthday the birthday of the user
|
||||
*/
|
||||
public void addBirthday(String userId, Date birthday) {
|
||||
public void addBirthday(String userId, UserBirthday birthday) {
|
||||
if (birthdays == null) {
|
||||
birthdays = new HashMap<>();
|
||||
}
|
||||
@ -69,7 +73,7 @@ public class BirthdayProfile extends Profile {
|
||||
* @param userId the id of the user
|
||||
* @return the birthday of the user
|
||||
*/
|
||||
public Date getBirthday(String userId) {
|
||||
public UserBirthday getBirthday(String userId) {
|
||||
if (birthdays == null) {
|
||||
birthdays = new HashMap<>();
|
||||
}
|
||||
@ -85,33 +89,6 @@ public class BirthdayProfile extends Profile {
|
||||
return channelId != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the age of a user
|
||||
*
|
||||
* @param userId the id of the user
|
||||
* @return the age of the user
|
||||
*/
|
||||
public int calculateAge(String userId) {
|
||||
Date birthday = getBirthday(userId);
|
||||
if (birthday == null) {
|
||||
return 0; // or throw an exception
|
||||
}
|
||||
|
||||
Calendar birthdayCalendar = Calendar.getInstance();
|
||||
birthdayCalendar.setTime(birthday);
|
||||
|
||||
Calendar today = Calendar.getInstance();
|
||||
|
||||
int age = today.get(Calendar.YEAR) - birthdayCalendar.get(Calendar.YEAR);
|
||||
|
||||
// Check if the birthday hasn't occurred yet this year
|
||||
if (today.get(Calendar.DAY_OF_YEAR) < birthdayCalendar.get(Calendar.DAY_OF_YEAR)) {
|
||||
age--;
|
||||
}
|
||||
|
||||
return age;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the profiles configuration
|
||||
*
|
||||
@ -122,33 +99,10 @@ public class BirthdayProfile extends Profile {
|
||||
if (birthdays == null) {
|
||||
birthdays = new HashMap<>();
|
||||
}
|
||||
|
||||
List<String> toRemove = new ArrayList<>();
|
||||
Guild discordGuild = guild.getDiscordGuild();
|
||||
for (Map.Entry<String, Date> entry : birthdays.entrySet()) {
|
||||
String userId = entry.getKey();
|
||||
Date birthday = entry.getValue();
|
||||
|
||||
if (userId == null || birthday == null) { // this should never happen
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the user is still in the guild, if not remove them
|
||||
Member member = discordGuild.getMemberById(userId);
|
||||
if (member == null) {
|
||||
toRemove.add(userId);
|
||||
}
|
||||
}
|
||||
|
||||
for (String userId : toRemove) {
|
||||
birthdays.remove(userId);
|
||||
}
|
||||
|
||||
if (channelId == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (discordGuild.getTextChannelById(channelId) == null) {
|
||||
if (guild.getDiscordGuild().getTextChannelById(channelId) == null) {
|
||||
channelId = null;
|
||||
return false;
|
||||
}
|
||||
@ -170,13 +124,10 @@ public class BirthdayProfile extends Profile {
|
||||
int todayDay = today.get(Calendar.DAY_OF_MONTH);
|
||||
int todayMonth = today.get(Calendar.MONTH); // Note: January is 0
|
||||
|
||||
Iterator<Map.Entry<String, Date>> iterator = birthdays.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, Date> entry = iterator.next();
|
||||
Date birthday = entry.getValue();
|
||||
for (Map.Entry<String, UserBirthday> entry : birthdays.entrySet()) {
|
||||
Date birthday = entry.getValue().getBirthday();
|
||||
|
||||
if (birthday == null) {
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -223,7 +174,7 @@ public class BirthdayProfile extends Profile {
|
||||
public String getBirthdayMessage(User user) {
|
||||
return message
|
||||
.replace("{user}", user.getAsMention())
|
||||
.replace("{age}", String.valueOf(calculateAge(user.getId())));
|
||||
.replace("{age}", String.valueOf(birthdays.get(user.getId()).calculateAge()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -231,4 +182,27 @@ public class BirthdayProfile extends Profile {
|
||||
birthdays.clear();
|
||||
channelId = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Document document, Gson gson) {
|
||||
birthdays = new HashMap<>();
|
||||
for (String key : document.keySet()) {
|
||||
UserBirthday userBirthday = new UserBirthday();
|
||||
userBirthday.load((Document) document.get(key), gson);
|
||||
birthdays.put(key, userBirthday);
|
||||
}
|
||||
channelId = document.getString("channelId");
|
||||
message = (String) document.getOrDefault("message", DEFAULT_MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document serialize(Gson gson) {
|
||||
Document document = new Document();
|
||||
for (String key : birthdays.keySet()) {
|
||||
document.put(key, birthdays.get(key).serialize(gson));
|
||||
}
|
||||
document.put("channelId", channelId);
|
||||
document.put("message", message);
|
||||
return document;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
package cc.fascinated.bat.features.namehistory;
|
||||
|
||||
import cc.fascinated.bat.command.Category;
|
||||
import cc.fascinated.bat.features.Feature;
|
||||
import cc.fascinated.bat.features.namehistory.command.NameHistoryCommand;
|
||||
import cc.fascinated.bat.service.CommandService;
|
||||
import lombok.NonNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
public class NameHistoryFeature extends Feature {
|
||||
public static final int NAME_HISTORY_SIZE = 25;
|
||||
|
||||
@Autowired
|
||||
public NameHistoryFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService) {
|
||||
super("Name History", true,Category.UTILITY);
|
||||
|
||||
super.registerCommand(commandService, context.getBean(NameHistoryCommand.class));
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package cc.fascinated.bat.features.namehistory;
|
||||
|
||||
import cc.fascinated.bat.event.EventListener;
|
||||
import cc.fascinated.bat.features.namehistory.profile.user.NameHistoryProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.FeatureService;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateNicknameEvent;
|
||||
import net.dv8tion.jda.api.events.user.update.UserUpdateGlobalNameEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
public class NameHistoryListener implements EventListener {
|
||||
private final GuildService guildService;
|
||||
private final FeatureService featureService;
|
||||
|
||||
@Autowired
|
||||
public NameHistoryListener(@NonNull GuildService guildService, @NonNull FeatureService featureService) {
|
||||
this.guildService = guildService;
|
||||
this.featureService = featureService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserUpdateGlobalName(@NonNull BatUser user, String oldName, String newName, @NonNull UserUpdateGlobalNameEvent event) {
|
||||
NameHistoryProfile profile = user.getNameHistoryProfile();
|
||||
profile.addName(newName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuildMemberUpdateNickname(@NonNull BatGuild guild, @NonNull BatUser user, String oldName, String newName,
|
||||
@NonNull GuildMemberUpdateNicknameEvent event) {
|
||||
NameHistoryFeature nameHistoryFeature = featureService.getFeature(NameHistoryFeature.class);
|
||||
if (!guild.getFeatureProfile().isFeatureEnabled(nameHistoryFeature)) { // Check if the feature is enabled
|
||||
return;
|
||||
}
|
||||
|
||||
cc.fascinated.bat.features.namehistory.profile.guild.NameHistoryProfile profile = guild.getNameHistoryProfile();
|
||||
profile.addName(user, newName);
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package cc.fascinated.bat.features.namehistory;
|
||||
|
||||
import cc.fascinated.bat.common.Serializable;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Getter @Setter
|
||||
public class TrackedName extends Serializable {
|
||||
/**
|
||||
* The new name of the user
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The date the name was changed
|
||||
*/
|
||||
private Date changedDate;
|
||||
|
||||
@Override
|
||||
public void load(Document document, Gson gson) {
|
||||
this.name = document.getString("name");
|
||||
this.changedDate = document.getDate("changedDate");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document serialize(Gson gson) {
|
||||
Document document = new Document();
|
||||
document.put("name", this.name);
|
||||
document.put("changedDate", this.changedDate);
|
||||
return document;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package cc.fascinated.bat.features.namehistory.command;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.namehistory.TrackedName;
|
||||
import cc.fascinated.bat.features.namehistory.profile.guild.NameHistoryProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.UserService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component("namehistory:guild.sub")
|
||||
@CommandInfo(name = "guild", description = "View the guild nickname history of a user")
|
||||
public class GuildSubCommand extends BatSubCommand {
|
||||
private final UserService userService;
|
||||
|
||||
@Autowired
|
||||
public GuildSubCommand(@NonNull UserService userService) {
|
||||
this.userService = userService;
|
||||
super.addOption(OptionType.USER, "user", "The user to view the name history of", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
OptionMapping userOption = event.getOption("user");
|
||||
BatUser target = userOption == null ? user : userService.getUser(userOption.getAsUser().getId());
|
||||
if (target == null) {
|
||||
channel.sendMessage("User not found").queue();
|
||||
return;
|
||||
}
|
||||
|
||||
NameHistoryProfile profile = guild.getNameHistoryProfile();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (profile.getNameHistory(target).isEmpty()) {
|
||||
builder.append("%s has no name history".formatted(target.getDiscordUser().getAsMention()));
|
||||
} else {
|
||||
for (TrackedName trackedName : profile.getNameHistorySorted(target)) {
|
||||
builder.append("%s - <t:%s>\n".formatted(
|
||||
trackedName.getName() == null ? "Removed Nickname" : "`%s`".formatted(trackedName.getName()),
|
||||
trackedName.getChangedDate().toInstant().toEpochMilli()/1000
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setAuthor("%s's Nickname History in %s".formatted(target.getName(), guild.getName()))
|
||||
.setDescription(builder.toString())
|
||||
.build()
|
||||
).queue();
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package cc.fascinated.bat.features.namehistory.command;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import lombok.NonNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
@CommandInfo(name = "namehistory", description = "View the name history of a user")
|
||||
public class NameHistoryCommand extends BatCommand {
|
||||
@Autowired
|
||||
public NameHistoryCommand(@NonNull ApplicationContext context) {
|
||||
super.addSubCommand(context.getBean(UserSubCommand.class));
|
||||
super.addSubCommand(context.getBean(GuildSubCommand.class));
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package cc.fascinated.bat.features.namehistory.command;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.namehistory.TrackedName;
|
||||
import cc.fascinated.bat.features.namehistory.profile.user.NameHistoryProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.UserService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component("namehistory:user.sub")
|
||||
@CommandInfo(name = "user", description = "View the global name history of a user", guildOnly = false)
|
||||
public class UserSubCommand extends BatSubCommand {
|
||||
private final UserService userService;
|
||||
|
||||
@Autowired
|
||||
public UserSubCommand(@NonNull UserService userService) {
|
||||
this.userService = userService;
|
||||
super.addOption(OptionType.USER, "user", "The user to view the name history of", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
OptionMapping userOption = event.getOption("user");
|
||||
BatUser target = userOption == null ? user : userService.getUser(userOption.getAsUser().getId());
|
||||
if (target == null) {
|
||||
channel.sendMessage("User not found").queue();
|
||||
return;
|
||||
}
|
||||
|
||||
NameHistoryProfile profile = target.getNameHistoryProfile();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (profile.getNameHistory().isEmpty()) {
|
||||
builder.append("%s has no name history".formatted(target.getDiscordUser().getAsMention()));
|
||||
} else {
|
||||
for (TrackedName trackedName : profile.getNameHistorySorted()) {
|
||||
builder.append("`%s` - <t:%s>\n".formatted(trackedName.getName(), trackedName.getChangedDate().toInstant().toEpochMilli()/1000));
|
||||
}
|
||||
}
|
||||
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setAuthor("%s's Global Name History".formatted(target.getName()))
|
||||
.setDescription(builder.toString())
|
||||
.build()
|
||||
).queue();
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
package cc.fascinated.bat.features.namehistory.profile.guild;
|
||||
|
||||
import cc.fascinated.bat.common.Serializable;
|
||||
import cc.fascinated.bat.features.namehistory.NameHistoryFeature;
|
||||
import cc.fascinated.bat.features.namehistory.TrackedName;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
public class NameHistoryProfile extends Serializable {
|
||||
/**
|
||||
* The name history of the user
|
||||
*/
|
||||
private Map<String, List<TrackedName>> nameHistory;
|
||||
|
||||
/**
|
||||
* Gets the name history of the user
|
||||
*
|
||||
* @param user the user to get the name history of
|
||||
* @return the name history of the user
|
||||
*/
|
||||
public List<TrackedName> getNameHistory(BatUser user) {
|
||||
if (this.nameHistory == null) {
|
||||
this.nameHistory = new HashMap<>();
|
||||
}
|
||||
if (!this.nameHistory.containsKey(user.getId())) {
|
||||
this.nameHistory.put(user.getId(), new LinkedList<>());
|
||||
}
|
||||
return this.nameHistory.get(user.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name history of the user sorted
|
||||
*
|
||||
* @param user the user to get the name history of
|
||||
* @return the name history of the user sorted
|
||||
*/
|
||||
public List<TrackedName> getNameHistorySorted(BatUser user) {
|
||||
return getNameHistory(user).stream().sorted((o1, o2) -> o2.getChangedDate().compareTo(o1.getChangedDate())).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a name to the name history
|
||||
*
|
||||
* @param user the user to add the name to
|
||||
* @param name the name to add
|
||||
*/
|
||||
public void addName(BatUser user, String name) {
|
||||
TrackedName trackedName = new TrackedName();
|
||||
trackedName.setName(name);
|
||||
trackedName.setChangedDate(new Date());
|
||||
getNameHistory(user).add(trackedName);
|
||||
cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the name history
|
||||
* <p>
|
||||
* This will remove any names that are not within
|
||||
* the size limit of the name history
|
||||
* </p>
|
||||
*/
|
||||
private void cleanup() {
|
||||
for (String userId : this.nameHistory.keySet()) {
|
||||
List<TrackedName> trackedNames = this.nameHistory.get(userId);
|
||||
if (trackedNames.size() > NameHistoryFeature.NAME_HISTORY_SIZE) {
|
||||
trackedNames.sort((o1, o2) -> o2.getChangedDate().compareTo(o1.getChangedDate()));
|
||||
trackedNames.subList(NameHistoryFeature.NAME_HISTORY_SIZE, trackedNames.size()).clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.nameHistory = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Document document, Gson gson) {
|
||||
this.nameHistory = new HashMap<>();
|
||||
for (String key : document.keySet()) {
|
||||
List<TrackedName> trackedNames = new LinkedList<>();
|
||||
for (Document trackedNameDocument : (List<Document>) document.get(key)) {
|
||||
TrackedName trackedName = new TrackedName();
|
||||
trackedName.load(trackedNameDocument, gson);
|
||||
trackedNames.add(trackedName);
|
||||
}
|
||||
this.nameHistory.put(key, trackedNames);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document serialize(Gson gson) {
|
||||
Document document = new Document();
|
||||
for (String key : this.nameHistory.keySet()) {
|
||||
List<Document> trackedNames = new LinkedList<>();
|
||||
for (TrackedName trackedName : this.nameHistory.get(key)) {
|
||||
trackedNames.add(trackedName.serialize(gson));
|
||||
}
|
||||
document.put(key, trackedNames);
|
||||
}
|
||||
return document;
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
package cc.fascinated.bat.features.namehistory.profile.user;
|
||||
|
||||
import cc.fascinated.bat.common.Serializable;
|
||||
import cc.fascinated.bat.features.namehistory.NameHistoryFeature;
|
||||
import cc.fascinated.bat.features.namehistory.TrackedName;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
public class NameHistoryProfile extends Serializable {
|
||||
/**
|
||||
* The name history of the user
|
||||
*/
|
||||
private List<TrackedName> nameHistory;
|
||||
|
||||
/**
|
||||
* Gets the name history of the user
|
||||
*
|
||||
* @return the name history of the user
|
||||
*/
|
||||
public List<TrackedName> getNameHistory() {
|
||||
if (this.nameHistory == null) {
|
||||
this.nameHistory = new LinkedList<>();
|
||||
}
|
||||
return nameHistory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name history of the user sorted
|
||||
*
|
||||
* @return the name history of the user sorted
|
||||
*/
|
||||
public List<TrackedName> getNameHistorySorted() {
|
||||
return getNameHistory().stream().sorted((o1, o2) -> o2.getChangedDate().compareTo(o1.getChangedDate())).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a name to the name history
|
||||
*
|
||||
* @param name the name to add
|
||||
*/
|
||||
public void addName(String name) {
|
||||
if (this.nameHistory == null) {
|
||||
this.nameHistory = new LinkedList<>();
|
||||
}
|
||||
TrackedName trackedName = new TrackedName();
|
||||
trackedName.setName(name);
|
||||
trackedName.setChangedDate(new Date());
|
||||
this.nameHistory.add(trackedName);
|
||||
cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the name history
|
||||
* <p>
|
||||
* This will remove any names that are not within
|
||||
* the size limit of the name history
|
||||
* </p>
|
||||
*/
|
||||
private void cleanup() {
|
||||
if (this.nameHistory.size() > NameHistoryFeature.NAME_HISTORY_SIZE) {
|
||||
List<TrackedName> trackedNames = new ArrayList<>(this.nameHistory);
|
||||
trackedNames.sort((o1, o2) -> o2.getChangedDate().compareTo(o1.getChangedDate()));
|
||||
this.nameHistory = trackedNames.subList(0, NameHistoryFeature.NAME_HISTORY_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.nameHistory = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Document document, Gson gson) {
|
||||
this.nameHistory = new LinkedList<>();
|
||||
for (Document trackedNameDocument : document.getList("nameHistory", Document.class, new ArrayList<>())) {
|
||||
TrackedName trackedName = new TrackedName();
|
||||
trackedName.load(trackedNameDocument, gson);
|
||||
|
||||
this.nameHistory.add(trackedName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document serialize(Gson gson) {
|
||||
Document document = new Document();
|
||||
List<Document> trackedNames = new ArrayList<>();
|
||||
for (TrackedName trackedName : this.nameHistory) {
|
||||
Document trackedNameDocument = new Document();
|
||||
trackedNameDocument.put("name", trackedName.getName());
|
||||
trackedNameDocument.put("changedDate", trackedName.getChangedDate());
|
||||
trackedNames.add(trackedNameDocument);
|
||||
}
|
||||
document.put("nameHistory", trackedNames);
|
||||
return document;
|
||||
}
|
||||
}
|
@ -1,14 +1,16 @@
|
||||
package cc.fascinated.bat.features.scoresaber;
|
||||
|
||||
import cc.fascinated.bat.common.NumberUtils;
|
||||
import cc.fascinated.bat.common.NumberFormatter;
|
||||
import cc.fascinated.bat.event.EventListener;
|
||||
import cc.fascinated.bat.features.scoresaber.profile.GuildNumberOneScoreFeedProfile;
|
||||
import cc.fascinated.bat.features.scoresaber.profile.guild.NumberOneScoreFeedProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.token.beatsaber.scoresaber.ScoreSaberLeaderboardToken;
|
||||
import cc.fascinated.bat.model.token.beatsaber.scoresaber.ScoreSaberPlayerScoreToken;
|
||||
import cc.fascinated.bat.model.token.beatsaber.scoresaber.ScoreSaberScoreToken;
|
||||
import cc.fascinated.bat.service.DiscordService;
|
||||
import cc.fascinated.bat.service.FeatureService;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
@ -23,10 +25,12 @@ import org.springframework.stereotype.Component;
|
||||
@Log4j2
|
||||
public class NumberOneScoreFeedListener implements EventListener {
|
||||
private final GuildService guildService;
|
||||
private final FeatureService featureService;
|
||||
|
||||
@Autowired
|
||||
public NumberOneScoreFeedListener(GuildService guildService) {
|
||||
public NumberOneScoreFeedListener(@NonNull GuildService guildService, @NonNull FeatureService featureService) {
|
||||
this.guildService = guildService;
|
||||
this.featureService = featureService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -41,7 +45,7 @@ public class NumberOneScoreFeedListener implements EventListener {
|
||||
log.info("A new #1 score has been set by {} on {} ({})!",
|
||||
player.getName(),
|
||||
leaderboard.getSongName(),
|
||||
"%s⭐".formatted(NumberUtils.formatNumberCommas(leaderboard.getStars()))
|
||||
"%s⭐".formatted(NumberFormatter.formatCommas(leaderboard.getStars()))
|
||||
);
|
||||
|
||||
for (Guild guild : DiscordService.JDA.getGuilds()) {
|
||||
@ -49,16 +53,20 @@ public class NumberOneScoreFeedListener implements EventListener {
|
||||
if (batGuild == null) {
|
||||
continue;
|
||||
}
|
||||
GuildNumberOneScoreFeedProfile profile = batGuild.getProfile(GuildNumberOneScoreFeedProfile.class);
|
||||
ScoreSaberFeature scoreSaberFeature = featureService.getFeature(ScoreSaberFeature.class);
|
||||
if (!batGuild.getFeatureProfile().isFeatureEnabled(scoreSaberFeature)) { // Check if the feature is enabled
|
||||
return;
|
||||
}
|
||||
|
||||
NumberOneScoreFeedProfile profile = batGuild.getProfile(NumberOneScoreFeedProfile.class);
|
||||
if (profile == null || profile.getChannelId() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TextChannel channel = profile.getAsTextChannel();
|
||||
TextChannel channel = profile.getTextChannel();
|
||||
if (channel == null) {
|
||||
log.error("Scoresaber user feed channel is null for guild {}, removing the stored channel.", guild.getId());
|
||||
profile.setChannelId(null);
|
||||
guildService.saveGuild(batGuild);
|
||||
continue;
|
||||
}
|
||||
channel.sendMessageEmbeds(ScoreSaberFeature.buildScoreEmbed(score)).queue();
|
||||
|
@ -3,7 +3,7 @@ package cc.fascinated.bat.features.scoresaber;
|
||||
import cc.fascinated.bat.command.Category;
|
||||
import cc.fascinated.bat.common.DateUtils;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.common.NumberUtils;
|
||||
import cc.fascinated.bat.common.NumberFormatter;
|
||||
import cc.fascinated.bat.common.ScoreSaberUtils;
|
||||
import cc.fascinated.bat.features.Feature;
|
||||
import cc.fascinated.bat.features.scoresaber.command.numberone.NumberOneFeedCommand;
|
||||
@ -26,7 +26,7 @@ import org.springframework.stereotype.Component;
|
||||
public class ScoreSaberFeature extends Feature {
|
||||
@Autowired
|
||||
public ScoreSaberFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService) {
|
||||
super("ScoreSaber", Category.BEAT_SABER);
|
||||
super("ScoreSaber", true, Category.BEAT_SABER);
|
||||
|
||||
registerCommand(commandService, context.getBean(ScoreSaberCommand.class));
|
||||
registerCommand(commandService, context.getBean(UserFeedCommand.class));
|
||||
@ -55,10 +55,10 @@ public class ScoreSaberFeature extends Feature {
|
||||
);
|
||||
|
||||
String accuracy = leaderboardToken.getMaxScore() == 0 ? "N/A" :
|
||||
String.format("%s%%", NumberUtils.formatNumberCommas(((double) scoreToken.getBaseScore() / leaderboardToken.getMaxScore()) * 100));
|
||||
String.format("%s%%", NumberFormatter.formatCommas(((double) scoreToken.getBaseScore() / leaderboardToken.getMaxScore()) * 100));
|
||||
|
||||
String rawPp = scoreToken.getPp() == 0 ? "Unranked" : NumberUtils.formatNumberCommas(scoreToken.getPp());
|
||||
String rank = String.format("#%s", NumberUtils.formatNumberCommas(scoreToken.getRank()));
|
||||
String rawPp = scoreToken.getPp() == 0 ? "Unranked" : NumberFormatter.formatCommas(scoreToken.getPp());
|
||||
String rank = String.format("#%s", NumberFormatter.formatCommas(scoreToken.getRank()));
|
||||
String misses = String.format("%s", scoreToken.getMissedNotes());
|
||||
String badCuts = String.format("%s", scoreToken.getBadCuts());
|
||||
String maxCombo = String.format("%s %s",
|
||||
|
@ -1,13 +1,15 @@
|
||||
package cc.fascinated.bat.features.scoresaber;
|
||||
|
||||
import cc.fascinated.bat.event.EventListener;
|
||||
import cc.fascinated.bat.features.scoresaber.profile.GuildUserScoreFeedProfile;
|
||||
import cc.fascinated.bat.features.scoresaber.profile.guild.UserScoreFeedProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.token.beatsaber.scoresaber.ScoreSaberLeaderboardToken;
|
||||
import cc.fascinated.bat.model.token.beatsaber.scoresaber.ScoreSaberPlayerScoreToken;
|
||||
import cc.fascinated.bat.model.token.beatsaber.scoresaber.ScoreSaberScoreToken;
|
||||
import cc.fascinated.bat.service.DiscordService;
|
||||
import cc.fascinated.bat.service.FeatureService;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
@ -22,10 +24,12 @@ import org.springframework.stereotype.Component;
|
||||
@Log4j2
|
||||
public class UserScoreFeedListener implements EventListener {
|
||||
private final GuildService guildService;
|
||||
private final FeatureService featureService;
|
||||
|
||||
@Autowired
|
||||
public UserScoreFeedListener(GuildService guildService) {
|
||||
public UserScoreFeedListener(@NonNull GuildService guildService, @NonNull FeatureService featureService) {
|
||||
this.guildService = guildService;
|
||||
this.featureService = featureService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -36,16 +40,19 @@ public class UserScoreFeedListener implements EventListener {
|
||||
if (batGuild == null) {
|
||||
continue;
|
||||
}
|
||||
GuildUserScoreFeedProfile profile = batGuild.getProfile(GuildUserScoreFeedProfile.class);
|
||||
ScoreSaberFeature scoreSaberFeature = featureService.getFeature(ScoreSaberFeature.class);
|
||||
if (!batGuild.getFeatureProfile().isFeatureEnabled(scoreSaberFeature)) { // Check if the feature is enabled
|
||||
return;
|
||||
}
|
||||
UserScoreFeedProfile profile = batGuild.getProfile(UserScoreFeedProfile.class);
|
||||
if (profile == null || profile.getChannelId() == null || !profile.getTrackedUsers().contains(player.getId())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TextChannel channel = profile.getAsTextChannel();
|
||||
TextChannel channel = profile.getTextChannel();
|
||||
if (channel == null) {
|
||||
log.error("Scoresaber user feed channel is null for guild {}, removing the stored channel.", guild.getId());
|
||||
profile.setChannelId(null);
|
||||
guildService.saveGuild(batGuild);
|
||||
continue;
|
||||
}
|
||||
channel.sendMessageEmbeds(ScoreSaberFeature.buildScoreEmbed(score)).queue();
|
||||
|
@ -4,10 +4,9 @@ import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.common.TextChannelUtils;
|
||||
import cc.fascinated.bat.features.scoresaber.profile.GuildNumberOneScoreFeedProfile;
|
||||
import cc.fascinated.bat.features.scoresaber.profile.guild.NumberOneScoreFeedProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.ChannelType;
|
||||
@ -25,26 +24,23 @@ import org.springframework.stereotype.Component;
|
||||
@Component("scoresaber-number-one-feed:channel.sub")
|
||||
@CommandInfo(name = "channel", description = "Sets the feed channel")
|
||||
public class ChannelSubCommand extends BatSubCommand {
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public ChannelSubCommand(GuildService guildService) {
|
||||
public ChannelSubCommand() {
|
||||
super.addOption(OptionType.CHANNEL, "channel", "The channel scores are sent in", false);
|
||||
this.guildService = guildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
GuildNumberOneScoreFeedProfile profile = guild.getProfile(GuildNumberOneScoreFeedProfile.class);
|
||||
OptionMapping option = interaction.getOption("channel");
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
NumberOneScoreFeedProfile profile = guild.getProfile(NumberOneScoreFeedProfile.class);
|
||||
OptionMapping option = event.getOption("channel");
|
||||
if (option == null) {
|
||||
if (!TextChannelUtils.isValidChannel(profile.getChannelId())) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("There is no channel set for the feed notifications.")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setDescription("The current feed channel is %s".formatted(TextChannelUtils.getChannelMention(profile.getChannelId())))
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -52,16 +48,14 @@ public class ChannelSubCommand extends BatSubCommand {
|
||||
|
||||
GuildChannelUnion targetChannel = option.getAsChannel();
|
||||
if (targetChannel.getType() != ChannelType.TEXT) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Invalid channel type, please provide a text channel")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
profile.setChannelId(targetChannel.getId());
|
||||
guildService.saveGuild(guild);
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully set the feed channel to %s".formatted(targetChannel.asTextChannel().getAsMention()))
|
||||
.build()).queue();
|
||||
}
|
||||
|
@ -3,15 +3,13 @@ package cc.fascinated.bat.features.scoresaber.command.numberone;
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.scoresaber.profile.GuildNumberOneScoreFeedProfile;
|
||||
import cc.fascinated.bat.features.scoresaber.profile.guild.NumberOneScoreFeedProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@ -20,20 +18,12 @@ import org.springframework.stereotype.Component;
|
||||
@Component("scoresaber-number-one-feed:reset.sub")
|
||||
@CommandInfo(name = "reset", description = "Resets the settings")
|
||||
public class ResetSubCommand extends BatSubCommand {
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public ResetSubCommand(GuildService guildService) {
|
||||
this.guildService = guildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
GuildNumberOneScoreFeedProfile profile = guild.getProfile(GuildNumberOneScoreFeedProfile.class);
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
NumberOneScoreFeedProfile profile = guild.getProfile(NumberOneScoreFeedProfile.class);
|
||||
profile.reset();
|
||||
guildService.saveGuild(guild);
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully reset the settings.")
|
||||
.build()).queue();
|
||||
}
|
||||
|
@ -3,12 +3,10 @@ package cc.fascinated.bat.features.scoresaber.command.scoresaber;
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.scoresaber.profile.UserScoreSaberProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.model.token.beatsaber.scoresaber.ScoreSaberAccountToken;
|
||||
import cc.fascinated.bat.service.ScoreSaberService;
|
||||
import cc.fascinated.bat.service.UserService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
@ -25,20 +23,18 @@ import org.springframework.stereotype.Component;
|
||||
@CommandInfo(name = "link", description = "Links your ScoreSaber profile")
|
||||
public class LinkSubCommand extends BatSubCommand {
|
||||
private final ScoreSaberService scoreSaberService;
|
||||
private final UserService userService;
|
||||
|
||||
@Autowired
|
||||
public LinkSubCommand(@NonNull ScoreSaberService scoreSaberService, @NonNull UserService userService) {
|
||||
public LinkSubCommand(@NonNull ScoreSaberService scoreSaberService) {
|
||||
super.addOption(OptionType.STRING, "link", "Link your ScoreSaber profile", true);
|
||||
this.scoreSaberService = scoreSaberService;
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
OptionMapping option = interaction.getOption("link");
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
OptionMapping option = event.getOption("link");
|
||||
if (option == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Please provide a ScoreSaber profile link")
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -46,7 +42,7 @@ public class LinkSubCommand extends BatSubCommand {
|
||||
|
||||
String link = option.getAsString();
|
||||
if (!link.contains("scoresaber.com/u/")) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Invalid ScoreSaber profile link")
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -59,15 +55,14 @@ public class LinkSubCommand extends BatSubCommand {
|
||||
|
||||
ScoreSaberAccountToken account = scoreSaberService.getAccount(id);
|
||||
if (account == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Invalid ScoreSaber profile link")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
user.getProfile(UserScoreSaberProfile.class).setSteamId(id);
|
||||
userService.saveUser(user);
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
user.getScoreSaberProfile().setAccountId(id);
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully linked your [ScoreSaber](%s) profile".formatted("https://scoresaber.com/u/%s".formatted(id)))
|
||||
.build()).queue();
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ public class MeSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
ScoreSaberCommand.sendProfileEmbed(true, user, scoreSaberService, interaction);
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
ScoreSaberCommand.sendProfileEmbed(true, user, scoreSaberService, event);
|
||||
}
|
||||
}
|
||||
|
@ -3,15 +3,13 @@ package cc.fascinated.bat.features.scoresaber.command.scoresaber;
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.scoresaber.profile.UserScoreSaberProfile;
|
||||
import cc.fascinated.bat.features.scoresaber.profile.user.ScoreSaberProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.UserService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@ -20,20 +18,12 @@ import org.springframework.stereotype.Component;
|
||||
@Component("scoresaber:reset.sub")
|
||||
@CommandInfo(name = "reset", description = "Reset your settings")
|
||||
public class ResetSubCommand extends BatSubCommand {
|
||||
private final UserService userService;
|
||||
|
||||
@Autowired
|
||||
public ResetSubCommand(@NonNull UserService userService) {
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
UserScoreSaberProfile profile = guild.getProfile(UserScoreSaberProfile.class);
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
ScoreSaberProfile profile = user.getScoreSaberProfile();
|
||||
profile.reset();
|
||||
userService.saveUser(user);
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully reset your settings.")
|
||||
.build()).queue();
|
||||
}
|
||||
|
@ -5,9 +5,9 @@ import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.Colors;
|
||||
import cc.fascinated.bat.common.DateUtils;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.common.NumberUtils;
|
||||
import cc.fascinated.bat.common.NumberFormatter;
|
||||
import cc.fascinated.bat.exception.RateLimitException;
|
||||
import cc.fascinated.bat.features.scoresaber.profile.UserScoreSaberProfile;
|
||||
import cc.fascinated.bat.features.scoresaber.profile.user.ScoreSaberProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.model.token.beatsaber.scoresaber.ScoreSaberAccountToken;
|
||||
@ -49,8 +49,8 @@ public class ScoreSaberCommand extends BatCommand {
|
||||
* @param interaction The interaction
|
||||
*/
|
||||
public static void sendProfileEmbed(boolean isSelf, BatUser user, ScoreSaberService scoreSaberService, SlashCommandInteraction interaction) {
|
||||
UserScoreSaberProfile profile = user.getProfile(UserScoreSaberProfile.class);
|
||||
if (profile.getSteamId() == null) {
|
||||
ScoreSaberProfile profile = user.getScoreSaberProfile();
|
||||
if (profile.getAccountId() == null) {
|
||||
if (!isSelf) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("%s does not have a linked ScoreSaber account".formatted(user.getDiscordUser().getAsMention()))
|
||||
@ -64,7 +64,7 @@ public class ScoreSaberCommand extends BatCommand {
|
||||
|
||||
try {
|
||||
long before = System.currentTimeMillis();
|
||||
ScoreSaberAccountToken account = scoreSaberService.getAccount(profile.getSteamId());
|
||||
ScoreSaberAccountToken account = scoreSaberService.getAccount(profile.getAccountId());
|
||||
if (account == null) {
|
||||
if (!isSelf) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
@ -84,9 +84,9 @@ public class ScoreSaberCommand extends BatCommand {
|
||||
"https://cdn.scoresaber.com/avatars/%s.jpg".formatted(account.getId()))
|
||||
.addField("Name", account.getName(), true)
|
||||
.addField("Country", account.getCountry(), true)
|
||||
.addField("Rank", "#" + NumberUtils.formatNumberCommas(account.getRank()), true)
|
||||
.addField("Country Rank", "#" + NumberUtils.formatNumberCommas(account.getCountryRank()), true)
|
||||
.addField("PP", NumberUtils.formatNumberCommas(account.getPp()), true)
|
||||
.addField("Rank", "#" + NumberFormatter.formatCommas(account.getRank()), true)
|
||||
.addField("Country Rank", "#" + NumberFormatter.formatCommas(account.getCountryRank()), true)
|
||||
.addField("PP", NumberFormatter.formatCommas(account.getPp()), true)
|
||||
.addField("Joined", "<t:%s>".formatted(DateUtils.getDateFromString(account.getFirstSeen()).toInstant().toEpochMilli() / 1000), true)
|
||||
.setTimestamp(LocalDateTime.now())
|
||||
.setFooter(fetchTime > 3 ? "Fetched in %sms".formatted(fetchTime) : "Cached", "https://flagcdn.com/h120/%s.png".formatted(account.getCountry().toLowerCase()))
|
||||
@ -100,7 +100,7 @@ public class ScoreSaberCommand extends BatCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
sendProfileEmbed(true, user, scoreSaberService, interaction);
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
sendProfileEmbed(true, user, scoreSaberService, event);
|
||||
}
|
||||
}
|
||||
|
@ -33,17 +33,17 @@ public class UserSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
OptionMapping option = interaction.getOption("user");
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
OptionMapping option = event.getOption("user");
|
||||
if (option == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Please provide a user to view the ScoreSaber profile of")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
if (option.getAsUser().isBot()) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You cannot view the ScoreSaber profile for a Bot")
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -51,11 +51,11 @@ public class UserSubCommand extends BatSubCommand {
|
||||
|
||||
BatUser target = userService.getUser(option.getAsUser().getId());
|
||||
if (target == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Unknown user")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
ScoreSaberCommand.sendProfileEmbed(false, target, scoreSaberService, interaction);
|
||||
ScoreSaberCommand.sendProfileEmbed(false, target, scoreSaberService, event);
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,9 @@ import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.common.TextChannelUtils;
|
||||
import cc.fascinated.bat.features.scoresaber.profile.GuildUserScoreFeedProfile;
|
||||
import cc.fascinated.bat.features.scoresaber.profile.guild.UserScoreFeedProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.ChannelType;
|
||||
@ -25,26 +24,23 @@ import org.springframework.stereotype.Component;
|
||||
@Component("scoresaber-user-feed:channel.sub")
|
||||
@CommandInfo(name = "channel", description = "Sets the feed channel")
|
||||
public class ChannelSubCommand extends BatSubCommand {
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public ChannelSubCommand(GuildService guildService) {
|
||||
public ChannelSubCommand() {
|
||||
super.addOption(OptionType.CHANNEL, "channel", "The channel scores are sent in", false);
|
||||
this.guildService = guildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
GuildUserScoreFeedProfile profile = guild.getProfile(GuildUserScoreFeedProfile.class);
|
||||
OptionMapping option = interaction.getOption("channel");
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
UserScoreFeedProfile profile = guild.getProfile(UserScoreFeedProfile.class);
|
||||
OptionMapping option = event.getOption("channel");
|
||||
if (option == null) {
|
||||
if (!TextChannelUtils.isValidChannel(profile.getChannelId())) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("There is no channel set for the feed notifications.")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setDescription("The current feed channel is %s".formatted(TextChannelUtils.getChannelMention(profile.getChannelId())))
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -52,16 +48,14 @@ public class ChannelSubCommand extends BatSubCommand {
|
||||
|
||||
GuildChannelUnion targetChannel = option.getAsChannel();
|
||||
if (targetChannel.getType() != ChannelType.TEXT) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Invalid channel type, please provide a text channel")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
profile.setChannelId(targetChannel.getId());
|
||||
guildService.saveGuild(guild);
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully set the feed channel to %s".formatted(targetChannel.asTextChannel().getAsMention()))
|
||||
.build()).queue();
|
||||
}
|
||||
|
@ -3,15 +3,13 @@ package cc.fascinated.bat.features.scoresaber.command.userfeed;
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.scoresaber.profile.GuildUserScoreFeedProfile;
|
||||
import cc.fascinated.bat.features.scoresaber.profile.guild.UserScoreFeedProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@ -20,20 +18,11 @@ import org.springframework.stereotype.Component;
|
||||
@Component("scoresaber-user-feed:reset.sub")
|
||||
@CommandInfo(name = "reset", description = "Resets the settings")
|
||||
public class ResetSubCommand extends BatSubCommand {
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public ResetSubCommand(GuildService guildService) {
|
||||
this.guildService = guildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
GuildUserScoreFeedProfile profile = guild.getProfile(GuildUserScoreFeedProfile.class);
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
UserScoreFeedProfile profile = guild.getProfile(UserScoreFeedProfile.class);
|
||||
profile.reset();
|
||||
guildService.saveGuild(guild);
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully reset the settings.")
|
||||
.build()).queue();
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ package cc.fascinated.bat.features.scoresaber.command.userfeed;
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.scoresaber.profile.GuildUserScoreFeedProfile;
|
||||
import cc.fascinated.bat.features.scoresaber.profile.UserScoreSaberProfile;
|
||||
import cc.fascinated.bat.features.scoresaber.profile.guild.UserScoreFeedProfile;
|
||||
import cc.fascinated.bat.features.scoresaber.profile.user.ScoreSaberProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
@ -36,12 +36,12 @@ public class UserSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
GuildUserScoreFeedProfile profile = guild.getProfile(GuildUserScoreFeedProfile.class);
|
||||
OptionMapping option = interaction.getOption("user");
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
UserScoreFeedProfile profile = guild.getProfile(UserScoreFeedProfile.class);
|
||||
OptionMapping option = event.getOption("user");
|
||||
if (option == null) {
|
||||
if (profile.getTrackedUsers().isEmpty()) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("There are no users being tracked in the feed")
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -53,7 +53,7 @@ public class UserSubCommand extends BatSubCommand {
|
||||
"https://scoresaber.com/u/%s".formatted(accountId)
|
||||
));
|
||||
}
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setDescription("The current users being tracked in the feed are:\n%s".formatted(stringBuilder.toString()))
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -61,25 +61,27 @@ public class UserSubCommand extends BatSubCommand {
|
||||
|
||||
User target = option.getAsUser();
|
||||
BatUser targetUser = userService.getUser(target.getId());
|
||||
UserScoreSaberProfile targetProfile = targetUser.getProfile(UserScoreSaberProfile.class);
|
||||
if (targetProfile.getSteamId() == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
ScoreSaberProfile targetProfile = targetUser.getScoreSaberProfile();
|
||||
if (targetProfile.getAccountId() == null) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("The user you are trying to track does not have a linked ScoreSaber profile")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
if (profile.getTrackedUsers().contains(targetProfile.getSteamId())) {
|
||||
profile.getTrackedUsers().remove(targetProfile.getSteamId());
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully removed %s from the feed".formatted(target.getAsMention()))
|
||||
.build()).queue();
|
||||
boolean added = false;
|
||||
if (profile.isUserTracked(targetProfile.getAccountId())) {
|
||||
profile.removeTrackedUser(targetProfile.getAccountId());
|
||||
} else {
|
||||
profile.getTrackedUsers().add(targetProfile.getSteamId());
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully added %s to the feed".formatted(target.getAsMention()))
|
||||
profile.addTrackedUser(targetProfile.getAccountId());
|
||||
added = true;
|
||||
}
|
||||
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully %s %s from the feed".formatted(
|
||||
added ? "added" : "removed",
|
||||
target.getAsMention()
|
||||
))
|
||||
.build()).queue();
|
||||
}
|
||||
guildService.saveGuild(guild);
|
||||
}
|
||||
}
|
||||
|
@ -1,37 +0,0 @@
|
||||
package cc.fascinated.bat.features.scoresaber.profile;
|
||||
|
||||
import cc.fascinated.bat.common.Profile;
|
||||
import cc.fascinated.bat.service.DiscordService;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class GuildNumberOneScoreFeedProfile extends Profile {
|
||||
/**
|
||||
* The channel ID of the score feed
|
||||
*/
|
||||
private String channelId;
|
||||
|
||||
public GuildNumberOneScoreFeedProfile() {
|
||||
super("scoresaber-number-one-score-feed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the channel as a TextChannel
|
||||
*
|
||||
* @return the channel as a TextChannel
|
||||
*/
|
||||
public TextChannel getAsTextChannel() {
|
||||
return DiscordService.JDA.getTextChannelById(channelId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.channelId = null;
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package cc.fascinated.bat.features.scoresaber.profile;
|
||||
|
||||
import cc.fascinated.bat.common.Profile;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class UserScoreSaberProfile extends Profile {
|
||||
/**
|
||||
* The Account ID of the ScoreSaber profile
|
||||
*/
|
||||
private String steamId;
|
||||
|
||||
public UserScoreSaberProfile() {
|
||||
super("scoresaber");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.steamId = null;
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package cc.fascinated.bat.features.scoresaber.profile.guild;
|
||||
|
||||
import cc.fascinated.bat.common.Serializable;
|
||||
import cc.fascinated.bat.service.DiscordService;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
import org.bson.Document;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class NumberOneScoreFeedProfile extends Serializable {
|
||||
/**
|
||||
* The channel ID of the score feed
|
||||
*/
|
||||
private String channelId;
|
||||
|
||||
/**
|
||||
* Gets the channel as a TextChannel
|
||||
*
|
||||
* @return the channel as a TextChannel
|
||||
*/
|
||||
public TextChannel getTextChannel() {
|
||||
return DiscordService.JDA.getTextChannelById(channelId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.channelId = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Document document, Gson gson) {
|
||||
this.channelId = document.getString("channelId");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document serialize(Gson gson) {
|
||||
Document document = new Document();
|
||||
document.put("channelId", this.channelId);
|
||||
return document;
|
||||
}
|
||||
}
|
@ -1,10 +1,13 @@
|
||||
package cc.fascinated.bat.features.scoresaber.profile;
|
||||
package cc.fascinated.bat.features.scoresaber.profile.guild;
|
||||
|
||||
import cc.fascinated.bat.common.Profile;
|
||||
import cc.fascinated.bat.common.Serializable;
|
||||
import cc.fascinated.bat.service.DiscordService;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -14,7 +17,8 @@ import java.util.List;
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class GuildUserScoreFeedProfile extends Profile {
|
||||
@NoArgsConstructor
|
||||
public class UserScoreFeedProfile extends Serializable {
|
||||
/**
|
||||
* The channel ID of the score feed
|
||||
*/
|
||||
@ -25,10 +29,6 @@ public class GuildUserScoreFeedProfile extends Profile {
|
||||
*/
|
||||
private List<String> trackedUsers;
|
||||
|
||||
public GuildUserScoreFeedProfile() {
|
||||
super("scoresaber-user-score-feed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the tracked users
|
||||
*
|
||||
@ -38,7 +38,20 @@ public class GuildUserScoreFeedProfile extends Profile {
|
||||
if (this.trackedUsers == null) {
|
||||
this.trackedUsers = new ArrayList<>();
|
||||
}
|
||||
return this.trackedUsers;
|
||||
return trackedUsers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a user is being tracked
|
||||
*
|
||||
* @param userId the user ID to check
|
||||
* @return if the user is being tracked
|
||||
*/
|
||||
public boolean isUserTracked(String userId) {
|
||||
if (this.trackedUsers == null) {
|
||||
this.trackedUsers = new ArrayList<>();
|
||||
}
|
||||
return trackedUsers.contains(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -70,7 +83,7 @@ public class GuildUserScoreFeedProfile extends Profile {
|
||||
*
|
||||
* @return the channel as a TextChannel
|
||||
*/
|
||||
public TextChannel getAsTextChannel() {
|
||||
public TextChannel getTextChannel() {
|
||||
return DiscordService.JDA.getTextChannelById(channelId);
|
||||
}
|
||||
|
||||
@ -79,4 +92,18 @@ public class GuildUserScoreFeedProfile extends Profile {
|
||||
this.channelId = null;
|
||||
this.trackedUsers = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Document document, Gson gson) {
|
||||
this.channelId = document.getString("channelId");
|
||||
this.trackedUsers = document.getList("trackedUsers", String.class, new ArrayList<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document serialize(Gson gson) {
|
||||
Document document = new Document();
|
||||
document.put("channelId", this.channelId);
|
||||
document.put("trackedUsers", this.trackedUsers);
|
||||
return document;
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package cc.fascinated.bat.features.scoresaber.profile.user;
|
||||
|
||||
import cc.fascinated.bat.common.Serializable;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.bson.Document;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class ScoreSaberProfile extends Serializable {
|
||||
/**
|
||||
* The Account ID of the ScoreSaber profile
|
||||
*/
|
||||
private String accountId;
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.accountId = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Document document, Gson gson) {
|
||||
this.accountId = document.getString("accountId");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document serialize(Gson gson) {
|
||||
Document document = new Document();
|
||||
document.put("accountId", this.accountId);
|
||||
return document;
|
||||
}
|
||||
}
|
@ -1,11 +1,26 @@
|
||||
package cc.fascinated.bat.features.spotify;
|
||||
|
||||
import cc.fascinated.bat.Emojis;
|
||||
import cc.fascinated.bat.command.Category;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.common.SpotifyUtils;
|
||||
import cc.fascinated.bat.exception.BatException;
|
||||
import cc.fascinated.bat.features.Feature;
|
||||
import net.dv8tion.jda.api.entities.MessageEmbed;
|
||||
import cc.fascinated.bat.features.spotify.command.SpotifyCommand;
|
||||
import cc.fascinated.bat.features.spotify.profile.SpotifyProfile;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.CommandService;
|
||||
import cc.fascinated.bat.service.SpotifyService;
|
||||
import lombok.NonNull;
|
||||
import lombok.SneakyThrows;
|
||||
import net.dv8tion.jda.api.EmbedBuilder;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
import se.michaelthelin.spotify.model_objects.miscellaneous.CurrentlyPlaying;
|
||||
import se.michaelthelin.spotify.model_objects.specification.AlbumSimplified;
|
||||
import se.michaelthelin.spotify.model_objects.specification.Image;
|
||||
import se.michaelthelin.spotify.model_objects.specification.Track;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
@ -13,18 +28,153 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class SpotifyFeature extends Feature {
|
||||
@Autowired
|
||||
public SpotifyFeature() {
|
||||
super("Spotify", Category.MUSIC);
|
||||
public SpotifyFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService) {
|
||||
super("Spotify", true,Category.MUSIC);
|
||||
|
||||
super.registerCommand(commandService, context.getBean(SpotifyCommand.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* The embed for when a user needs to link their Spotify account.
|
||||
* Gets the currently playing song.
|
||||
*
|
||||
* @return The embed.
|
||||
* @param spotifyService The Spotify service.
|
||||
* @param user The user.
|
||||
*/
|
||||
public static MessageEmbed linkAccountEmbed() {
|
||||
@SneakyThrows
|
||||
public static EmbedBuilder currentSong(@NonNull SpotifyService spotifyService, @NonNull BatUser user) {
|
||||
SpotifyProfile profile = user.getProfile(SpotifyProfile.class);
|
||||
if (!profile.hasLinkedAccount()) {
|
||||
throw new BatException("%s You need to link your Spotify account before you can use this command.".formatted(Emojis.CROSS_MARK_EMOJI));
|
||||
}
|
||||
|
||||
if (!spotifyService.hasTrackPlaying(user)) {
|
||||
throw new BatException("%s You are not currently playing a track.".formatted(Emojis.CROSS_MARK_EMOJI));
|
||||
}
|
||||
|
||||
CurrentlyPlaying currentlyPlaying = spotifyService.getCurrentlyPlayingTrack(user);
|
||||
Track track = (Track) currentlyPlaying.getItem();
|
||||
AlbumSimplified album = track.getAlbum();
|
||||
String trackUrl = SpotifyUtils.getTrackUrl(currentlyPlaying);
|
||||
String albumUrl = "https://open.spotify.com/album/" + album.getId();
|
||||
|
||||
StringBuilder artists = new StringBuilder();
|
||||
for (int i = 0; i < track.getArtists().length; i++) {
|
||||
artists.append("**[%s](%s)**".formatted(track.getArtists()[i].getName(), "https://open.spotify.com/artist/" + track.getArtists()[i].getId()));
|
||||
if (i != track.getArtists().length - 1) {
|
||||
artists.append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
Image albumCover = album.getImages()[0];
|
||||
|
||||
return EmbedUtils.genericEmbed()
|
||||
.setDescription("You need to link your Spotify account before you can use this command.")
|
||||
.build();
|
||||
.setAuthor("Listening to %s | %s".formatted(track.getName(), track.getArtists()[0].getName()), trackUrl)
|
||||
.setThumbnail(albumCover.getUrl())
|
||||
.setDescription("""
|
||||
➜ Song: **[%s](%s)**
|
||||
➜ Album: **[%s](%s)**
|
||||
➜ Artist%s: %s
|
||||
➜ Position: %s
|
||||
""".formatted(
|
||||
track.getName(), trackUrl,
|
||||
album.getName(), albumUrl,
|
||||
track.getArtists().length > 1 ? "s" : "", artists,
|
||||
SpotifyUtils.getFormattedTime(currentlyPlaying)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips the current song.
|
||||
*
|
||||
* @param spotifyService The Spotify service.
|
||||
* @param user The user.
|
||||
*/
|
||||
@SneakyThrows
|
||||
public static EmbedBuilder skipSong(@NonNull SpotifyService spotifyService, @NonNull BatUser user) {
|
||||
SpotifyProfile profile = user.getProfile(SpotifyProfile.class);
|
||||
if (!profile.hasLinkedAccount()) {
|
||||
throw new BatException("%s You need to link your Spotify account before you can use this command.".formatted(Emojis.CROSS_MARK_EMOJI));
|
||||
}
|
||||
|
||||
if (!spotifyService.hasTrackPlaying(user)) {
|
||||
throw new BatException("%s You are not currently playing a track.".formatted(Emojis.CROSS_MARK_EMOJI));
|
||||
}
|
||||
|
||||
CurrentlyPlaying currentlyPlaying = spotifyService.getCurrentlyPlayingTrack(user);
|
||||
Track track = (Track) currentlyPlaying.getItem();
|
||||
String trackName = track.getName();
|
||||
|
||||
spotifyService.skipTrack(user);
|
||||
CurrentlyPlaying newCurrentlyPlaying = SpotifyUtils.getNewTrack(spotifyService, user, trackName);
|
||||
if (newCurrentlyPlaying == null) {
|
||||
return EmbedUtils.errorEmbed()
|
||||
.setDescription("%s There are no more tracks in the queue.".formatted(Emojis.CROSS_MARK_EMOJI));
|
||||
}
|
||||
Track newTrack = (Track) newCurrentlyPlaying.getItem();
|
||||
|
||||
return EmbedUtils.successEmbed()
|
||||
.setDescription("""
|
||||
:track_next: Skipped the track: **[%s | %s](%s)**
|
||||
%s New Track: **[%s | %s](%s)**
|
||||
""".formatted(
|
||||
trackName, track.getArtists()[0].getName(), SpotifyUtils.getTrackUrl(currentlyPlaying),
|
||||
Emojis.CHECK_MARK_EMOJI, newTrack.getName(), newTrack.getArtists()[0].getName(), SpotifyUtils.getTrackUrl(newCurrentlyPlaying)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses the current song.
|
||||
*
|
||||
* @param spotifyService The Spotify service.
|
||||
* @param user The user.
|
||||
*/
|
||||
@SneakyThrows
|
||||
public static EmbedBuilder pauseSong(@NonNull SpotifyService spotifyService, @NonNull BatUser user) {
|
||||
SpotifyProfile profile = user.getProfile(SpotifyProfile.class);
|
||||
if (!profile.hasLinkedAccount()) {
|
||||
throw new BatException("%s You need to link your Spotify account before you can use this command.".formatted(Emojis.CROSS_MARK_EMOJI));
|
||||
}
|
||||
|
||||
if (!spotifyService.hasTrackPlaying(user)) {
|
||||
throw new BatException("%s You are not currently playing a track.".formatted(Emojis.CROSS_MARK_EMOJI));
|
||||
}
|
||||
|
||||
boolean didPause = spotifyService.pausePlayback(user);
|
||||
CurrentlyPlaying currentlyPlaying = spotifyService.getCurrentlyPlayingTrack(user);
|
||||
Track track = (Track) currentlyPlaying.getItem();
|
||||
return EmbedUtils.successEmbed()
|
||||
.setDescription(didPause ? ":pause_button: Paused the track **[%s | %s](%s)**".formatted(
|
||||
track.getName(),
|
||||
track.getArtists()[0].getName(),
|
||||
SpotifyUtils.getTrackUrl(currentlyPlaying))
|
||||
: "%s The current track is already paused.".formatted(Emojis.CROSS_MARK_EMOJI));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes the current song.
|
||||
*
|
||||
* @param spotifyService The Spotify service.
|
||||
* @param user The user.
|
||||
*/
|
||||
@SneakyThrows
|
||||
public static EmbedBuilder resumeSong(@NonNull SpotifyService spotifyService, @NonNull BatUser user) {
|
||||
SpotifyProfile profile = user.getProfile(SpotifyProfile.class);
|
||||
if (!profile.hasLinkedAccount()) {
|
||||
throw new BatException("%s You need to link your Spotify account before you can use this command.".formatted(Emojis.CROSS_MARK_EMOJI));
|
||||
}
|
||||
|
||||
if (!spotifyService.hasTrackPlaying(user)) {
|
||||
throw new BatException("%s You are not currently playing a track.".formatted(Emojis.CROSS_MARK_EMOJI));
|
||||
}
|
||||
|
||||
boolean didResume = spotifyService.resumePlayback(user);
|
||||
CurrentlyPlaying currentlyPlaying = spotifyService.getCurrentlyPlayingTrack(user);
|
||||
Track track = (Track) currentlyPlaying.getItem();
|
||||
return EmbedUtils.successEmbed()
|
||||
.setDescription(didResume ? ":play_pause: Resumed the track **[%s | %s](%s)**".formatted(
|
||||
track.getName(),
|
||||
track.getArtists()[0].getName(),
|
||||
SpotifyUtils.getTrackUrl(currentlyPlaying))
|
||||
: "%s The current track is already playing.".formatted(Emojis.CROSS_MARK_EMOJI));
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user