use of net.dv8tion.jda.api.entities.Message in project MantaroBot by Mantaro.
the class ReactionOperations method addReactions.
private static void addReactions(Future<Void> future, Message message, String... defaultReactions) {
AtomicInteger index = new AtomicInteger();
AtomicReference<Consumer<Void>> c = new AtomicReference<>();
Consumer<Throwable> ignore = (t) -> {
};
c.set(ignored -> {
// Ignore this if we already cancelled this operation.
if (future.isCancelled()) {
return;
}
int i = index.incrementAndGet();
if (i < defaultReactions.length) {
message.addReaction(reaction(defaultReactions[i])).queue(c.get(), ignore);
}
});
message.addReaction(reaction(defaultReactions[0])).queue(c.get(), ignore);
}
use of net.dv8tion.jda.api.entities.Message in project MantaroBot by Mantaro.
the class BirthdayTask method handle.
public static void handle(int shardId) {
final var bot = MantaroBot.getInstance();
final var instant = Instant.now();
try {
final var cache = bot.getBirthdayCacher();
// There's no cache to be seen here
if (cache == null) {
return;
}
// We haven't finished caching all members, somehow?
if (!cache.isDone) {
return;
}
final var start = System.currentTimeMillis();
var membersAssigned = 0;
var membersDivested = 0;
final var jda = bot.getShardManager().getShardById(shardId);
if (jda == null) {
// To be fair, this shouldn't be possible as it only starts it with the shards it knows...
return;
}
log.info("Checking birthdays in shard {} to assign roles...", jda.getShardInfo().getShardId());
// Well, fuck, this was a day off. NYC time was 23:00 when Chicago time was at 00:00, so it checked the
// birthdays for THE WRONG DAY. Heck.
// 17-02-2022: Fuck again, I was using the wrong thing. Now it works, lol.
final var timezone = ZonedDateTime.ofInstant(instant, ZoneId.of("America/Chicago"));
// Example: 25-02
final var now = timezone.format(dayMonthFormat);
// Example: 02
final var month = timezone.format(monthFormat);
// Example: 01
final var lastMonthTz = ZonedDateTime.ofInstant(instant, ZoneId.of("America/Chicago")).minusMonths(1);
final var lastMonth = lastMonthTz.format(dateFormat);
final var cached = cache.getCachedBirthdays();
final var guilds = jda.getGuildCache();
// Backoff sending: we need to backoff the birthday requests,
// else we're gonna find ourselves quite often hitting ratelimits, which might slow the whole
// bot down. Therefore, we're just gonna get all of the messages we need to send and *slowly*
// send them over the course of a few minutes, instead of trying to send them all at once.
Map<BirthdayGuildInfo, Queue<Message>> toSend = new HashMap<>();
List<BirthdayRoleInfo> roleBackoffAdd = new ArrayList<>();
List<BirthdayRoleInfo> roleBackoffRemove = new ArrayList<>();
// For all current -cached- guilds.
for (final var guild : guilds) {
// This is quite a db spam, lol
final var dbGuild = MantaroData.db().getGuild(guild);
final var guildData = dbGuild.getData();
// If we have a birthday guild and channel here, continue
if (guildData.getBirthdayChannel() != null && guildData.getBirthdayRole() != null) {
final var birthdayRole = guild.getRoleById(guildData.getBirthdayRole());
final var channel = guild.getTextChannelById(guildData.getBirthdayChannel());
if (channel != null && birthdayRole != null) {
if (!guild.getSelfMember().canInteract(birthdayRole))
// Go to next guild...
continue;
if (!channel.canTalk())
// cannot talk here...
continue;
if (guildData.getGuildAutoRole() != null && birthdayRole.getId().equals(guildData.getGuildAutoRole()))
// Birthday role is autorole role
continue;
if (birthdayRole.isPublicRole())
// Birthday role is public role
continue;
if (birthdayRole.isManaged())
// This was meant to be a bot role?
continue;
// Guild map is now created from allowed birthdays. This is a little hacky, but we don't really care.
// The other solution would have been just disabling this completely, which would have been worse.
// @formatter:off
Map<Long, BirthdayCacher.BirthdayData> guildMap = cached.entrySet().stream().filter(map -> guildData.getAllowedBirthdays().contains(String.valueOf(map.getKey()))).filter(map -> map.getValue().getBirthday().substring(3, 5).equals(month) || map.getValue().getBirthday().substring(3, 5).equals(lastMonth)).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
// @formatter:on
var birthdayAnnouncerText = new MessageBuilder();
birthdayAnnouncerText.append("**New birthdays for today, wish them Happy Birthday!**").append("\n\n");
int birthdayNumber = 0;
List<Long> nullMembers = new ArrayList<>();
for (var data : guildMap.entrySet()) {
var birthday = data.getValue().getBirthday();
if (guildData.getBirthdayBlockedIds().contains(String.valueOf(data.getKey()))) {
continue;
}
if (birthday == null) {
log.debug("Birthday is null? Continuing...");
nullMembers.add(data.getKey());
continue;
}
// This needs to be a retrieveMemberById call, sadly. This will get cached, though.
Member member;
try {
// This is expensive!
member = guild.retrieveMemberById(data.getKey(), false).complete();
} catch (Exception ex) {
nullMembers.add(data.getKey());
continue;
}
// Make sure we announce on March 1st for birthdays on February 29 if the current
// year is not a leap year.
var compare = birthday.substring(0, 5);
if (compare.equals("29-02") && !Year.isLeap(LocalDate.now().getYear())) {
compare = "28-02";
}
if (compare.equals(now)) {
log.debug("Assigning birthday role on guild {} (M: {})", guild.getId(), member.getEffectiveName());
var tempBirthdayMessage = String.format(EmoteReference.POPPER + "**%s is a year older now! Wish them a happy birthday.** :tada:", member.getEffectiveName());
if (guildData.getBirthdayMessage() != null) {
tempBirthdayMessage = guildData.getBirthdayMessage().replace("$(user)", member.getEffectiveName()).replace("$(usermention)", member.getAsMention()).replace("$(tag)", member.getUser().getAsTag());
}
// Variable used in lambda expression should be final or effectively final...
final var birthdayMessage = tempBirthdayMessage;
if (!member.getRoles().contains(birthdayRole)) {
log.debug("Backing off adding birthday role on guild {} (M: {})", guild.getId(), member.getEffectiveName());
// We can pretty much do all of this only based on the IDs
roleBackoffAdd.add(new BirthdayRoleInfo(guild.getId(), member.getId(), birthdayRole));
birthdayAnnouncerText.append(birthdayMessage).append("\n");
membersAssigned++;
birthdayNumber++;
Metrics.BIRTHDAY_COUNTER.inc();
}
} else {
// day passed
if (member.getRoles().contains(birthdayRole)) {
log.debug("Backing off removing birthday role on guild {} (M: {})", guild.getId(), member.getEffectiveName());
roleBackoffRemove.add(new BirthdayRoleInfo(guild.getId(), member.getId(), birthdayRole));
membersDivested++;
}
}
}
if (birthdayNumber != 0) {
toSend.put(new BirthdayGuildInfo(guild.getId(), channel.getId()), birthdayAnnouncerText.buildAll(MessageBuilder.SplitPolicy.NEWLINE));
}
// If any of the member lookups to discord returned null, remove them.
if (!nullMembers.isEmpty()) {
guildData.getAllowedBirthdays().removeAll(nullMembers.stream().map(String::valueOf).collect(Collectors.toList()));
dbGuild.save();
}
}
}
}
final var end = System.currentTimeMillis();
log.info("{} (birthdays): people assigned: {}, people divested: {}, took {}ms", jda.getShardInfo(), membersAssigned, membersDivested, (end - start));
// A poll inside a pool?
// Send the backoff sending comment above, this basically avoids hitting
// discord with one billion requests at once.
final var backoff = 400;
final var roleBackoff = 100;
backOffPool.submit(() -> {
log.info("{} (birthdays): Backoff messages: {}. Sending them with {}ms backoff.", jda.getShardInfo(), toSend.size(), backoff);
final var startMessage = System.currentTimeMillis();
for (var entry : toSend.entrySet()) {
try {
final var info = entry.getKey();
final var guildId = info.guildId;
final var channelId = info.channelId;
final var messages = entry.getValue();
final var guild = bot.getShardManager().getGuildById(guildId);
if (guild == null)
continue;
final var channel = guild.getTextChannelById(channelId);
if (channel == null)
continue;
messages.forEach(message -> channel.sendMessage(message).allowedMentions(EnumSet.of(Message.MentionType.USER, Message.MentionType.CHANNEL, Message.MentionType.ROLE, Message.MentionType.EMOTE)).queue());
// If 100 guilds (about 1/10th of all the shard guilds! so very unlikely) do
// get a birthday now, the maximum delay will be 40,000ms, which is 40 seconds.
// Not much of an issue for the end user, but avoid sending too many requests
// to discord at once. If half of all the guilds in the shard do, the delay
// will be about 200,000ms, so 2 minutes.
Thread.sleep(backoff);
} catch (Exception e) {
e.printStackTrace();
}
}
final var endMessage = System.currentTimeMillis();
toSend.clear();
log.info("Sent all birthday backoff messages, backoff was {}ms, took {}ms", backoff, endMessage - startMessage);
});
backOffRolePool.submit(() -> {
log.info("{} (birthdays): Backoff roles (add): {}. Sending them with {}ms backoff.", jda.getShardInfo(), roleBackoffAdd.size(), roleBackoff);
final var startRole = System.currentTimeMillis();
for (var roleInfo : roleBackoffAdd) {
try {
var guild = bot.getShardManager().getGuildById(roleInfo.guildId);
if (guild == null)
continue;
guild.addRoleToMember(roleInfo.memberId, roleInfo.role).reason(modLogMessage).queue();
Thread.sleep(roleBackoff);
} catch (Exception e) {
e.printStackTrace();
}
}
log.info("{} (birthdays): Backoff roles (remove): {}. Sending them with {}ms backoff.", jda.getShardInfo(), roleBackoffRemove.size(), roleBackoff);
for (var roleInfo : roleBackoffRemove) {
try {
var guild = bot.getShardManager().getGuildById(roleInfo.guildId);
if (guild == null)
continue;
guild.removeRoleFromMember(roleInfo.memberId, roleInfo.role).reason(modLogMessage).queue();
Thread.sleep(roleBackoff);
} catch (Exception e) {
e.printStackTrace();
}
}
final var endRole = System.currentTimeMillis();
roleBackoffAdd.clear();
roleBackoffRemove.clear();
log.info("{} (birthdays): All roles done (add and removal), backoff was {}ms. Took {}ms", jda.getShardInfo(), roleBackoff, endRole - startRole);
});
} catch (Exception e) {
e.printStackTrace();
}
}
use of net.dv8tion.jda.api.entities.Message in project MantaroBot by Mantaro.
the class MessageCmds method prune.
@Subscribe
public void prune(CommandRegistry cr) {
var pruneCmd = cr.register("prune", new TreeCommand(CommandCategory.MODERATION) {
@Override
public Command defaultTrigger(Context context, String mainCommand, String commandName) {
return new SubCommand() {
@Override
protected void call(Context ctx, I18nContext languageContext, String content) {
var args = ctx.getArguments();
if (content.isEmpty()) {
ctx.sendLocalized("commands.prune.no_messages_specified", EmoteReference.ERROR);
return;
}
var mentionedUsers = ctx.getMentionedUsers();
var amount = 5;
if (args.length > 0) {
try {
amount = Integer.parseInt(args[0]);
if (amount < 3) {
amount = 3;
}
} catch (Exception e) {
ctx.sendLocalized("commands.prune.not_valid", EmoteReference.ERROR);
return;
}
}
if (!mentionedUsers.isEmpty()) {
List<Long> users = mentionedUsers.stream().map(User::getIdLong).collect(Collectors.toList());
final var finalAmount = amount;
ctx.getChannel().getHistory().retrievePast(100).queue(messageHistory -> getMessageHistory(ctx, messageHistory, finalAmount, "commands.prune.mention_no_messages", message -> users.contains(message.getAuthor().getIdLong())), error -> ctx.sendLocalized("commands.prune.error_retrieving", EmoteReference.ERROR, error.getClass().getSimpleName(), error.getMessage()));
return;
}
ctx.getChannel().getHistory().retrievePast(Math.min(amount, 100)).queue(messageHistory -> prune(ctx, messageHistory), error -> {
ctx.sendLocalized("commands.prune.error_retrieving", EmoteReference.ERROR, error.getClass().getSimpleName(), error.getMessage());
error.printStackTrace();
});
}
};
}
@Override
public HelpContent help() {
return new HelpContent.Builder().setDescription("Prunes X amount of messages from a channel. Requires Message Manage permission.").setUsage("`~>prune <messages> [@user...]`").addParameter("messages", "Number of messages from 4 to 100.").addParameterOptional("@user...", "Prunes messages only from mentioned users.").build();
}
});
pruneCmd.setPredicate(ctx -> {
if (!ctx.getMember().hasPermission(Permission.MESSAGE_MANAGE)) {
ctx.sendLocalized("commands.prune.no_permissions_user", EmoteReference.ERROR);
return false;
}
if (!ctx.getSelfMember().hasPermission(Permission.MESSAGE_MANAGE)) {
ctx.sendLocalized("commands.prune.no_permissions", EmoteReference.ERROR);
return false;
}
return true;
});
pruneCmd.addSubCommand("bot", new SubCommand() {
@Override
public String description() {
return "Prune bot messages. It takes the number of messages as an argument.";
}
@Override
protected void call(Context ctx, I18nContext languageContext, String content) {
var args = ctx.getArguments();
var amount = 100;
if (args.length >= 1) {
try {
amount = Integer.parseInt(args[0]);
if (amount < 3) {
amount = 3;
}
} catch (Exception e) {
ctx.sendLocalized("commands.prune.not_valid", EmoteReference.ERROR);
return;
}
}
final var finalAmount = amount;
ctx.getChannel().getHistory().retrievePast(100).queue(messageHistory -> {
String prefix = MantaroData.db().getGuild(ctx.getGuild()).getData().getGuildCustomPrefix();
getMessageHistory(ctx, messageHistory, finalAmount, "commands.prune.bots_no_messages", message -> message.getAuthor().isBot() || message.getContentRaw().startsWith(prefix == null ? "~>" : prefix));
}, error -> {
ctx.sendLocalized("commands.prune.error_retrieving", EmoteReference.ERROR, error.getClass().getSimpleName(), error.getMessage());
error.printStackTrace();
});
}
});
pruneCmd.addSubCommand("nopins", new SubCommand() {
@Override
public String description() {
return "Prune messages that aren't pinned. It takes the number of messages as an argument.";
}
@Override
protected void call(Context ctx, I18nContext languageContext, String content) {
var args = ctx.getArguments();
var amount = 100;
if (args.length >= 1) {
try {
amount = Integer.parseInt(args[0]);
if (amount < 3) {
amount = 3;
}
} catch (Exception e) {
ctx.sendLocalized("commands.prune.not_valid", EmoteReference.ERROR);
return;
}
}
final var finalAmount = amount;
ctx.getChannel().getHistory().retrievePast(100).queue(messageHistory -> getMessageHistory(ctx, messageHistory, finalAmount, "commands.prune.no_pins_no_messages", message -> !message.isPinned()), error -> {
ctx.sendLocalized("commands.prune.error_retrieving", EmoteReference.ERROR, error.getClass().getSimpleName(), error.getMessage());
error.printStackTrace();
});
}
});
}
use of net.dv8tion.jda.api.entities.Message in project c0debaseBot by Biospheere.
the class RoleStatsCommand method execute.
@Override
public void execute(final String[] args, final Message message) {
final Guild guild = message.getGuild();
final EmbedBuilder embedBuilder = getEmbed(guild, message.getAuthor()).setTitle("Rollen Statistiken");
final Map<Role, Long> roles = guild.getMembers().stream().filter(member -> PermissionUtil.canInteract(guild.getSelfMember(), member)).map(member -> member.getRoles()).flatMap(stream -> stream.stream().filter(role -> (!role.isManaged() && !FORBIDDEN.contains(role.getName())))).collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
embedBuilder.appendDescription("\n__**Rollen:**__\n\n");
appendStats(roles, embedBuilder, false);
embedBuilder.appendDescription("\n__**Farb-Rollen:**__\n\n");
appendStats(roles, embedBuilder, true);
message.getTextChannel().sendMessage(embedBuilder.build()).queue();
}
use of net.dv8tion.jda.api.entities.Message in project c0debaseBot by Biospheere.
the class SetColorCommand method listAvailableColors.
private void listAvailableColors(Message message) {
final EmbedBuilder embedBuilder = getEmbed(message.getGuild(), message.getAuthor());
embedBuilder.setFooter("!setColor <Farbe>", message.getMember().getUser().getEffectiveAvatarUrl());
embedBuilder.appendDescription("__**Es gibt diese Farben:**__\n\n");
message.getGuild().getRoles().stream().map(Role::getName).filter(roleName -> roleName.startsWith("Color")).forEach(roleName -> embedBuilder.appendDescription(String.format("***%s***\n", roleName.replace("Color-", ""))));
message.getTextChannel().sendMessage(embedBuilder.build()).queue();
}
Aggregations