33import net .dv8tion .jda .api .entities .*;
44import net .dv8tion .jda .api .entities .channel .concrete .TextChannel ;
55import net .dv8tion .jda .api .entities .channel .middleman .MessageChannel ;
6+ import net .dv8tion .jda .api .entities .channel .unions .MessageChannelUnion ;
67import net .dv8tion .jda .api .events .interaction .command .SlashCommandInteractionEvent ;
78import net .dv8tion .jda .api .interactions .commands .OptionMapping ;
89import net .dv8tion .jda .api .interactions .commands .OptionType ;
2728import java .time .OffsetDateTime ;
2829import java .time .format .DateTimeFormatter ;
2930import java .util .List ;
31+ import java .util .Map ;
32+ import java .util .Map .Entry ;
3033import java .util .concurrent .ExecutorService ;
34+ import java .util .stream .Collectors ;
3135
3236/**
3337 * <h3>This class represents the /purge command.</h3>
@@ -60,7 +64,7 @@ protected ReplyCallbackAction handleModerationCommand(@NotNull SlashCommandInter
6064 boolean archive = event .getOption ("archive" , true , OptionMapping ::getAsBoolean );
6165
6266 ModerationConfig config = botConfig .get (event .getGuild ()).getModerationConfig ();
63- Long amount = (amountOption == null ) ? null : amountOption .getAsLong ();
67+ Long amount = (amountOption == null ) ? 1 : amountOption .getAsLong ();
6468 User user = (userOption == null ) ? null : userOption .getAsUser ();
6569 int maxAmount = config .getPurgeMaxMessageCount ();
6670 if (amount == null || amount < 1 || amount > maxAmount ) {
@@ -87,7 +91,7 @@ protected ReplyCallbackAction handleModerationCommand(@NotNull SlashCommandInter
8791 * @param channel The channel to remove messages from.
8892 * @param logChannel The channel to write log messages to during the purge.
8993 */
90- private void purge (@ Nullable Long amount , @ Nullable User user , User initiatedBy , boolean archive , MessageChannel channel , TextChannel logChannel ) {
94+ private void purge (long amount , @ Nullable User user , User initiatedBy , boolean archive , MessageChannel channel , TextChannel logChannel ) {
9195 MessageHistory history = channel .getHistory ();
9296 String timestamp = LocalDateTime .now ().format (DateTimeFormatter .ofPattern ("yyyy-MM-dd_HH-mm-ss" ));
9397 String file = String .format ("purge_%s_%s.txt" , channel .getName (), timestamp );
@@ -97,19 +101,25 @@ private void purge(@Nullable Long amount, @Nullable User user, User initiatedBy,
97101 long count = 0 ;
98102 logChannel .sendMessageFormat ("Starting purge of channel %s, initiated by %s" , channel .getAsMention (), initiatedBy .getAsMention ())
99103 .queue ();
104+ int lastEmptyIterations = 0 ;
100105 do {
101- messages = history .retrievePast (amount == null ? 100 : ( int ) Math .min ( 100 , amount )).complete ();
106+ messages = history .retrievePast (( int ) Math . min ( 100 , user == null ? amount : Math .max ( amount , 10 ) )).complete ();
102107 if (!messages .isEmpty ()) {
103- int messagesRemoved = removeMessages (messages , user , archiveWriter );
108+ int messagesRemoved = removeMessages (messages , user , archiveWriter , amount - count );
104109 count += messagesRemoved ;
105110 logChannel .sendMessage (String .format (
106111 "Removed **%d** messages from %s; a total of **%d** messages have been removed in this purge so far." ,
107112 messagesRemoved ,
108113 channel .getAsMention (),
109114 count
110115 )).queue ();
116+ if (messagesRemoved == 0 ) {
117+ lastEmptyIterations ++;
118+ }else {
119+ lastEmptyIterations = 0 ;
120+ }
111121 }
112- } while (!messages .isEmpty () && ( amount == null || amount > count ) );
122+ } while (!messages .isEmpty () && amount > count && lastEmptyIterations <= 20 );
113123 if (archiveWriter != null ) {
114124 archiveWriter .close ();
115125 }
@@ -133,20 +143,27 @@ private void purge(@Nullable Long amount, @Nullable User user, User initiatedBy,
133143 * @param messages The messages to remove.
134144 * @param user The user to remove messages for.
135145 * @param archiveWriter The writer to write message archive info to.
146+ * @param max The maximum number of messages to delete
136147 * @return The number of messages that were actually deleted.
137148 */
138- private int removeMessages (List <Message > messages , @ Nullable User user , @ Nullable PrintWriter archiveWriter ) {
139- int messagesRemoved = 0 ;
140- for (Message msg : messages ) {
141- if (user == null || msg .getAuthor ().equals (user )) {
142- msg .delete ().complete ();
143- messagesRemoved ++;
144- if (archiveWriter != null ) {
149+ private int removeMessages (List <Message > messages , @ Nullable User user , @ Nullable PrintWriter archiveWriter , long max ) {
150+ Map <MessageChannelUnion , List <Message >> toRemove = messages
151+ .stream ()
152+ .filter (msg -> user == null || msg .getAuthor ().equals (user ))
153+ .limit (max )
154+ .collect (Collectors .groupingBy (Message ::getChannel ));
155+ int count = 0 ;
156+ if (archiveWriter != null ) {
157+ for (Entry <MessageChannelUnion , List <Message >> entry : toRemove .entrySet ()) {
158+ List <Message > msgs = entry .getValue ();
159+ count += msgs .size ();
160+ for (Message msg : msgs ) {
145161 archiveMessage (archiveWriter , msg );
146162 }
163+ entry .getKey ().purgeMessages (messages );
147164 }
148165 }
149- return messagesRemoved ;
166+ return count ;
150167 }
151168
152169 /**
0 commit comments