From d20f9846128319d31748f169c7e3eaf662b36073 Mon Sep 17 00:00:00 2001 From: billpapat <50835814+billpapat@users.noreply.github.com> Date: Sat, 28 Jun 2025 23:43:15 +0300 Subject: [PATCH 1/4] Allow forwarding of media, to media channels --- .../mediaonly/MediaOnlyChannelListener.java | 60 +++++++++++++++++-- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java b/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java index 083dd193ec..d22186f8a6 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java @@ -4,6 +4,7 @@ import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.MessageType; +import net.dv8tion.jda.api.entities.messages.MessageSnapshot; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; @@ -13,6 +14,7 @@ import org.togetherjava.tjbot.features.MessageReceiverAdapter; import java.awt.Color; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; @@ -25,6 +27,13 @@ */ public final class MediaOnlyChannelListener extends MessageReceiverAdapter { + private static final Pattern MEDIA_URL_PATTERN = Pattern.compile( + ".*https?://\\S+\\.(png|jpe?g|gif|bmp|webp|mp4|mov|avi|webm|mp3|wav|ogg|youtube\\.com/|youtu\\.com|imgur\\.com/).*", + Pattern.CASE_INSENSITIVE); + + private final ConcurrentHashMap lastValidForwardedMediaMessageTime = + new ConcurrentHashMap<>(); + /** * Creates a MediaOnlyChannelListener to receive all message sent in MediaOnly channel. * @@ -45,19 +54,60 @@ public void onMessageReceived(MessageReceivedEvent event) { return; } - if (messageHasNoMediaAttached(message)) { - message.delete().flatMap(any -> dmUser(message)).queue(any -> { - }, failure -> tempNotifyUserInChannel(message)); + long userId = event.getAuthor().getIdLong(); + + boolean isForwardedWithMedia = + !message.getMessageSnapshots().isEmpty() && !messageHasNoMediaAttached(message); + + if (isForwardedWithMedia) { + lastValidForwardedMediaMessageTime.put(userId, System.currentTimeMillis()); + return; + } + + boolean isNormalMediaUpload = + message.getMessageSnapshots().isEmpty() && !messageHasNoMediaAttached(message); + if (isNormalMediaUpload) { + return; + } + + Long lastForwardedMediaTime = lastValidForwardedMediaMessageTime.get(userId); + long gracePeriodMillis = TimeUnit.SECONDS.toMillis(1); + + if (lastForwardedMediaTime != null + && (System.currentTimeMillis() - lastForwardedMediaTime) <= gracePeriodMillis) { + lastValidForwardedMediaMessageTime.remove(userId); + return; } + + message.delete().queue(deleteSuccess -> dmUser(message).queue(dmSuccess -> { + }, dmFailure -> tempNotifyUserInChannel(message)), + deleteFailure -> tempNotifyUserInChannel(message)); } private boolean messageHasNoMediaAttached(Message message) { - return message.getAttachments().isEmpty() && message.getEmbeds().isEmpty() - && !message.getContentRaw().contains("http"); + if (!message.getAttachments().isEmpty() || !message.getEmbeds().isEmpty() + || MEDIA_URL_PATTERN.matcher(message.getContentRaw()).matches()) { + return false; + } + + if (!message.getMessageSnapshots().isEmpty()) { + for (MessageSnapshot snapshot : message.getMessageSnapshots()) { + if (!snapshot.getAttachments().isEmpty() || !snapshot.getEmbeds().isEmpty() + || MEDIA_URL_PATTERN.matcher(snapshot.getContentRaw()).matches()) { + return false; + } + } + return true; + } + + return true; } private MessageCreateData createNotificationMessage(Message message) { String originalMessageContent = message.getContentRaw(); + if (originalMessageContent.trim().isEmpty()) { + originalMessageContent = "(Original message had no visible text content)"; + } MessageEmbed originalMessageEmbed = new EmbedBuilder().setDescription(originalMessageContent) From 2742573789ac7fbfcf6da6d3b04e3cc9b9b3c4df Mon Sep 17 00:00:00 2001 From: billpapat <50835814+billpapat@users.noreply.github.com> Date: Sun, 29 Jun 2025 16:53:07 +0300 Subject: [PATCH 2/4] fix: Grace period & clean up - Changed TimeUnit implementation to java.time.Instant for grace period. - Cleaned up and improved readability of the onMessageReceived method. --- .../mediaonly/MediaOnlyChannelListener.java | 39 +++++++++---------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java b/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java index d22186f8a6..7239f25805 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java @@ -14,6 +14,8 @@ import org.togetherjava.tjbot.features.MessageReceiverAdapter; import java.awt.Color; +import java.time.Duration; +import java.time.Instant; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; @@ -31,7 +33,7 @@ public final class MediaOnlyChannelListener extends MessageReceiverAdapter { ".*https?://\\S+\\.(png|jpe?g|gif|bmp|webp|mp4|mov|avi|webm|mp3|wav|ogg|youtube\\.com/|youtu\\.com|imgur\\.com/).*", Pattern.CASE_INSENSITIVE); - private final ConcurrentHashMap lastValidForwardedMediaMessageTime = + private final ConcurrentHashMap lastValidForwardedMediaMessageTime = new ConcurrentHashMap<>(); /** @@ -45,40 +47,35 @@ public MediaOnlyChannelListener(Config config) { @Override public void onMessageReceived(MessageReceivedEvent event) { - if (event.getAuthor().isBot() || event.isWebhookMessage()) { + if (event.getAuthor().isBot() || event.isWebhookMessage() + || event.getMessage().getType() == MessageType.THREAD_CREATED) { return; } Message message = event.getMessage(); - if (message.getType() == MessageType.THREAD_CREATED) { - return; - } - long userId = event.getAuthor().getIdLong(); - boolean isForwardedWithMedia = - !message.getMessageSnapshots().isEmpty() && !messageHasNoMediaAttached(message); - - if (isForwardedWithMedia) { - lastValidForwardedMediaMessageTime.put(userId, System.currentTimeMillis()); - return; - } - - boolean isNormalMediaUpload = - message.getMessageSnapshots().isEmpty() && !messageHasNoMediaAttached(message); - if (isNormalMediaUpload) { + if (!messageHasNoMediaAttached(message)) { + if (!message.getMessageSnapshots().isEmpty()) { + lastValidForwardedMediaMessageTime.put(userId, Instant.now()); + } return; } - Long lastForwardedMediaTime = lastValidForwardedMediaMessageTime.get(userId); - long gracePeriodMillis = TimeUnit.SECONDS.toMillis(1); + Instant lastForwardedMediaTime = lastValidForwardedMediaMessageTime.get(userId); + Duration gracePeriod = Duration.ofSeconds(1); if (lastForwardedMediaTime != null - && (System.currentTimeMillis() - lastForwardedMediaTime) <= gracePeriodMillis) { + && Duration.between(lastForwardedMediaTime, Instant.now()) + .compareTo(gracePeriod) <= 0) { lastValidForwardedMediaMessageTime.remove(userId); return; } + deleteAndNotify(message); + } + + private void deleteAndNotify(Message message) { message.delete().queue(deleteSuccess -> dmUser(message).queue(dmSuccess -> { }, dmFailure -> tempNotifyUserInChannel(message)), deleteFailure -> tempNotifyUserInChannel(message)); @@ -106,7 +103,7 @@ private boolean messageHasNoMediaAttached(Message message) { private MessageCreateData createNotificationMessage(Message message) { String originalMessageContent = message.getContentRaw(); if (originalMessageContent.trim().isEmpty()) { - originalMessageContent = "(Original message had no visible text content)"; + originalMessageContent = "Original message had no visible text content"; } MessageEmbed originalMessageEmbed = From a21f294a26a0487d6007484c0d88d2b73046d052 Mon Sep 17 00:00:00 2001 From: billpapat <50835814+billpapat@users.noreply.github.com> Date: Tue, 1 Jul 2025 03:39:23 +0300 Subject: [PATCH 3/4] Embed only when !content.isEmpty() Conditionally add the embed only if the original message content is NOT empty --- .../mediaonly/MediaOnlyChannelListener.java | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java b/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java index 7239f25805..0403e7b880 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java @@ -102,19 +102,21 @@ private boolean messageHasNoMediaAttached(Message message) { private MessageCreateData createNotificationMessage(Message message) { String originalMessageContent = message.getContentRaw(); - if (originalMessageContent.trim().isEmpty()) { - originalMessageContent = "Original message had no visible text content"; - } - MessageEmbed originalMessageEmbed = - new EmbedBuilder().setDescription(originalMessageContent) - .setColor(Color.ORANGE) - .build(); + MessageCreateBuilder messageBuilder = new MessageCreateBuilder(); + messageBuilder.setContent(message.getAuthor().getAsMention() + + " Hey there, you posted a message without media (image, video, link) in a media-only channel. Please see the description of the channel for details and then repost with media attached, thanks 😀"); + + // Conditionally add the embed only if the original message content is NOT empty + if (!originalMessageContent.trim().isEmpty()) { + MessageEmbed originalMessageEmbed = + new EmbedBuilder().setDescription(originalMessageContent) + .setColor(Color.ORANGE) + .build(); + messageBuilder.setEmbeds(originalMessageEmbed); + } - return new MessageCreateBuilder().setContent(message.getAuthor().getAsMention() - + " Hey there, you posted a message without media (image, video, link) in a media-only channel. Please see the description of the channel for details and then repost with media attached, thanks 😀") - .setEmbeds(originalMessageEmbed) - .build(); + return messageBuilder.build(); } private RestAction dmUser(Message message) { From 869da01e8b0d46e63ba6d6a897e3f0ea4b5d5e47 Mon Sep 17 00:00:00 2001 From: billpapat <50835814+billpapat@users.noreply.github.com> Date: Tue, 1 Jul 2025 23:20:50 +0300 Subject: [PATCH 4/4] I reversed the code (removed the timer and the id list) until I find a better way to implement that behavior, and motivation. --- .../mediaonly/MediaOnlyChannelListener.java | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java b/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java index 0403e7b880..07679c644b 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java @@ -14,9 +14,6 @@ import org.togetherjava.tjbot.features.MessageReceiverAdapter; import java.awt.Color; -import java.time.Duration; -import java.time.Instant; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; @@ -33,9 +30,6 @@ public final class MediaOnlyChannelListener extends MessageReceiverAdapter { ".*https?://\\S+\\.(png|jpe?g|gif|bmp|webp|mp4|mov|avi|webm|mp3|wav|ogg|youtube\\.com/|youtu\\.com|imgur\\.com/).*", Pattern.CASE_INSENSITIVE); - private final ConcurrentHashMap lastValidForwardedMediaMessageTime = - new ConcurrentHashMap<>(); - /** * Creates a MediaOnlyChannelListener to receive all message sent in MediaOnly channel. * @@ -53,22 +47,8 @@ public void onMessageReceived(MessageReceivedEvent event) { } Message message = event.getMessage(); - long userId = event.getAuthor().getIdLong(); if (!messageHasNoMediaAttached(message)) { - if (!message.getMessageSnapshots().isEmpty()) { - lastValidForwardedMediaMessageTime.put(userId, Instant.now()); - } - return; - } - - Instant lastForwardedMediaTime = lastValidForwardedMediaMessageTime.get(userId); - Duration gracePeriod = Duration.ofSeconds(1); - - if (lastForwardedMediaTime != null - && Duration.between(lastForwardedMediaTime, Instant.now()) - .compareTo(gracePeriod) <= 0) { - lastValidForwardedMediaMessageTime.remove(userId); return; }