Skip to content

Commit

Permalink
Merge pull request #308 from danthe1st/hugs
Browse files Browse the repository at this point in the history
replace f*cks with hugs
  • Loading branch information
jasonlessenich committed Jul 21, 2022
2 parents 85f579f + 05beef6 commit ef4af86
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 1 deletion.
3 changes: 3 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ dependencies {

// Quartz scheduler
implementation("org.quartz-scheduler:quartz:2.3.2")

// Webhooks
implementation("club.minnced:discord-webhooks:0.8.0")

// Lombok Annotations
compileOnly("org.projectlombok:lombok:1.18.24")
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/net/javadiscord/javabot/Bot.java
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ private static void addEventListeners(JDA jda) {
new HelpChannelListener(),
new ShareKnowledgeVoteListener(),
new JobChannelVoteListener(),
new PingableNameListener()
new PingableNameListener(),
new HugListener()
);
}
}
Expand Down
100 changes: 100 additions & 0 deletions src/main/java/net/javadiscord/javabot/listener/HugListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package net.javadiscord.javabot.listener;

import javax.annotation.Nonnull;

import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.ChannelType;
import net.dv8tion.jda.api.entities.GuildMessageChannel;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.entities.Webhook;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.javadiscord.javabot.Bot;
import net.javadiscord.javabot.util.WebhookUtil;

/**
* Replaces all occurences of 'fuck' in incoming messages with 'hug'.
*/
@Slf4j
public class HugListener extends ListenerAdapter {
@Override
public void onMessageReceived(@Nonnull MessageReceivedEvent event) {
if (!event.isFromGuild()) {
return;
}
if (Bot.autoMod.hasSuspiciousLink(event.getMessage()) || Bot.autoMod.hasAdvertisingLink(event.getMessage())) {
return;
}
if (!event.getMessage().getMentions().getUsers().isEmpty()) {
return;
}
if (event.isWebhookMessage()) {
return;
}
if (event.getChannel().getIdLong() == Bot.config.get(event.getGuild()).getModeration()
.getSuggestionChannelId()) {
return;
}
TextChannel tc = null;
if (event.isFromType(ChannelType.TEXT)) {
tc = event.getTextChannel();
}
if (event.isFromThread()) {
GuildMessageChannel parentChannel = event.getThreadChannel().getParentMessageChannel();
if (parentChannel instanceof TextChannel textChannel) {
tc = textChannel;
}
}
if (tc == null) {
return;
}
final TextChannel textChannel = tc;
String content = event.getMessage().getContentRaw();
String lowerCaseContent = content.toLowerCase();
if (lowerCaseContent.contains("fuck")) {
long threadId = event.isFromThread() ? event.getThreadChannel().getIdLong() : 0;
StringBuilder sb = new StringBuilder(content.length());
int index = 0;
int indexBkp = index;
while ((index = lowerCaseContent.indexOf("fuck", index)) != -1) {
sb.append(content.substring(indexBkp, index));
sb.append(loadHug(content, index));
indexBkp = index++ + 4;
if (content.length() >= indexBkp + 3 && "ing".equals(lowerCaseContent.substring(indexBkp, indexBkp + 3))) {
sb.append(copyCase(content, indexBkp-1, 'g'));
sb.append(content.substring(indexBkp, indexBkp + 3));
index+=3;
indexBkp+=3;
}
}

sb.append(content.substring(indexBkp, content.length()));
WebhookUtil.ensureWebhookExists(textChannel,
wh -> sendWebhookMessage(wh, event.getMessage(), sb.toString(), threadId),
e -> log.error("Webhook lookup/creation failed", e));
}
}

private String loadHug(String originalText, int startIndex) {
return copyCase(originalText, startIndex, 'h') + ""
+ copyCase(originalText, startIndex + 1, 'u') + ""
+ copyCase(originalText, startIndex + 3, 'g');
}

private char copyCase(String original, int index, char newChar) {
if (Character.isUpperCase(original.charAt(index))) {
return Character.toUpperCase(newChar);
} else {
return newChar;
}
}

private void sendWebhookMessage(Webhook webhook, Message originalMessage, String newMessageContent, long threadId) {
WebhookUtil.mirrorMessageToWebhook(webhook, originalMessage, newMessageContent, threadId)
.thenAccept(unused -> originalMessage.delete().queue()).exceptionally(e -> {
log.error("replacing the content 'fuck' with 'hug' in an incoming message failed", e);
return null;
});
}
}
93 changes: 93 additions & 0 deletions src/main/java/net/javadiscord/javabot/util/WebhookUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package net.javadiscord.javabot.util;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;

import club.minnced.discord.webhook.WebhookClientBuilder;
import club.minnced.discord.webhook.external.JDAWebhookClient;
import club.minnced.discord.webhook.send.AllowedMentions;
import club.minnced.discord.webhook.send.WebhookMessageBuilder;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.entities.Webhook;
import net.dv8tion.jda.api.entities.Message.Attachment;

/**
* Contains utility methods for dealing with Discord Webhooks.
*/
public class WebhookUtil {
private WebhookUtil() {
}

/**
* Makes sure that a writable webhook exists in a specific channel. if no
* suitable webhook is found, one is created.
*
* @param channel the {@link TextChannel} the webhook should exist in
* @param callback an action that is executed once a webhook is
* found/created
*/
public static void ensureWebhookExists(TextChannel channel, Consumer<? super Webhook> callback) {
ensureWebhookExists(channel, callback, err -> {
});
}

/**
* Makes sure that a writable webhook exists in a specific channel. if no
* suitable webhook is found, one is created.
*
* @param channel the {@link TextChannel} the webhook should exist in
* @param callback an action that is executed once a webhook is
* found/created
* @param failureCallback an action that is executed if the webhook
* lookup/creation failed
*/
public static void ensureWebhookExists(TextChannel channel, Consumer<? super Webhook> callback,
Consumer<? super Throwable> failureCallback) {

channel.retrieveWebhooks().queue(webhooks -> {
Optional<Webhook> hook = webhooks.stream()
.filter(webhook -> webhook.getChannel().getIdLong() == channel.getIdLong())
.filter(wh -> wh.getToken() != null).findAny();
if (hook.isPresent()) {
callback.accept(hook.get());
} else {
channel.createWebhook("JavaBot-webhook").queue(callback, failureCallback);
}
}, failureCallback);
}

/**
* Resends a specific message using a webhook with a custom content.
*
* @param webhook the webhook used for sending the message
* @param originalMessage the message to copy
* @param newMessageContent the new (custom) content
* @param threadId the thread to send the message in or {@code 0} if the
* message should be sent directly
* @return a {@link CompletableFuture} representing the action of sending
* the message
*/
public static CompletableFuture<Void> mirrorMessageToWebhook(Webhook webhook, Message originalMessage,
String newMessageContent, long threadId) {
JDAWebhookClient client = new WebhookClientBuilder(webhook.getIdLong(), webhook.getToken())
.setThreadId(threadId).buildJDA();
WebhookMessageBuilder message = new WebhookMessageBuilder().setContent(newMessageContent)
.setAllowedMentions(AllowedMentions.none())
.setAvatarUrl(originalMessage.getMember().getEffectiveAvatarUrl())
.setUsername(originalMessage.getMember().getEffectiveName());

List<Attachment> attachments = originalMessage.getAttachments();
@SuppressWarnings("unchecked")
CompletableFuture<?>[] futures = new CompletableFuture<?>[attachments.size()];
for (int i = 0; i < attachments.size(); i++) {
Attachment attachment = attachments.get(i);
futures[i] = attachment.getProxy().download().thenAccept(
is -> message.addFile((attachment.isSpoiler() ? "SPOILER_" : "") + attachment.getFileName(), is));
}
return CompletableFuture.allOf(futures).thenAccept(unused -> client.send(message.build()))
.whenComplete((result, err) -> client.close());
}
}

0 comments on commit ef4af86

Please sign in to comment.