2024-09-08 10:50:45 -04:00
let isDeleting = false ;
let cancelDelete = false ;
2025-04-10 15:09:11 -04:00
let deletedMessages = new Set ( ) ;
const CACHE _CLEANUP _INTERVAL = 30 * 60 * 1000 ;
setInterval ( ( ) => {
if ( deletedMessages . size > 1000 ) {
console . log ( ` [DELETE] Cleaning message cache (size: ${ deletedMessages . size } ) ` ) ;
deletedMessages . clear ( ) ;
}
} , CACHE _CLEANUP _INTERVAL ) ;
2024-09-08 10:50:45 -04:00
2024-02-05 19:18:42 -05:00
module . exports = {
name : 'delete' ,
2024-09-08 10:50:45 -04:00
description : 'Delete a specified number of your messages or all messages from a server with human-like delays.' ,
2024-02-05 19:18:42 -05:00
async execute ( message , args , deleteTimeout ) {
2024-09-08 10:50:45 -04:00
if ( args [ 0 ] && args [ 0 ] . toLowerCase ( ) === 'cancel' ) {
cancelDelete = true ;
const cancelMsg = await message . channel . send ( 'Delete operation canceled.' ) ;
setTimeout ( ( ) => cancelMsg . delete ( ) . catch ( console . error ) , deleteTimeout ) ;
return ;
}
if ( isDeleting ) {
const inProgressMsg = await message . channel . send ( 'A delete operation is already in progress. Please wait or cancel it with `.delete cancel`.' ) ;
setTimeout ( ( ) => inProgressMsg . delete ( ) . catch ( console . error ) , deleteTimeout ) ;
return ;
}
isDeleting = true ;
cancelDelete = false ;
2025-04-10 15:09:11 -04:00
let speed = 'medium' ;
if ( args [ 0 ] && [ 'slow' , 'medium' , 'fast' ] . includes ( args [ 0 ] . toLowerCase ( ) ) ) {
speed = args [ 0 ] . toLowerCase ( ) ;
2025-04-10 15:34:40 -04:00
args . shift ( ) ;
2025-04-10 15:09:11 -04:00
}
2024-02-05 19:18:42 -05:00
const deleteCount = parseInt ( args [ 0 ] , 10 ) ;
2024-09-08 10:50:45 -04:00
const targetGuildId = args [ 1 ] ;
2024-02-05 19:18:42 -05:00
2024-09-08 10:50:45 -04:00
if ( ! isNaN ( deleteCount ) && deleteCount > 0 ) {
2025-04-10 15:09:11 -04:00
await deleteMessagesFromChannel ( message , deleteCount , deleteTimeout , speed ) ;
2024-09-08 10:50:45 -04:00
} else if ( targetGuildId ) {
2025-04-10 15:09:11 -04:00
await deleteMessagesFromServer ( message , targetGuildId , deleteTimeout , speed ) ;
2024-09-08 10:50:45 -04:00
} else {
2025-04-10 15:09:11 -04:00
const errorMsg = await message . channel . send ( 'Please specify how many messages to delete or a server ID. You can also set speed: `.delete [slow/medium/fast] [count/server]`' ) ;
2024-02-05 19:18:42 -05:00
setTimeout ( ( ) => errorMsg . delete ( ) . catch ( console . error ) , deleteTimeout ) ;
}
2024-09-08 10:50:45 -04:00
isDeleting = false ;
} ,
} ;
2025-04-10 15:09:11 -04:00
async function deleteMessagesFromChannel ( message , deleteCount , deleteTimeout , speed = 'medium' ) {
let deleteIntervalMin , deleteIntervalMax , jitterFactor , pauseChance , pauseLengthMin , pauseLengthMax , batchSize ;
switch ( speed ) {
case 'slow' :
deleteIntervalMin = 3000 ;
deleteIntervalMax = 6000 ;
jitterFactor = 0.5 ;
pauseChance = 0.25 ;
pauseLengthMin = 15000 ;
pauseLengthMax = 45000 ;
batchSize = 5 ;
break ;
case 'fast' :
deleteIntervalMin = 1500 ;
deleteIntervalMax = 3000 ;
jitterFactor = 0.3 ;
pauseChance = 0.05 ;
pauseLengthMin = 5000 ;
pauseLengthMax = 15000 ;
batchSize = 15 ;
break ;
case 'medium' :
default :
deleteIntervalMin = 2000 ;
deleteIntervalMax = 4500 ;
jitterFactor = 0.4 ;
pauseChance = 0.15 ;
pauseLengthMin = 10000 ;
pauseLengthMax = 30000 ;
batchSize = 10 ;
}
const getHumanlikeDelay = ( ) => {
const baseInterval = Math . floor ( Math . random ( ) * ( deleteIntervalMax - deleteIntervalMin + 1 ) ) + deleteIntervalMin ;
const jitterAmount = baseInterval * jitterFactor ;
const jitter = Math . random ( ) * jitterAmount * 2 - jitterAmount ;
return Math . max ( 1000 , Math . floor ( baseInterval + jitter ) ) ;
} ;
2025-04-10 15:34:40 -04:00
const getReadingDelay = ( ) => Math . floor ( Math . random ( ) * 3000 ) + 1000 ;
2024-09-08 10:50:45 -04:00
try {
2025-04-10 15:09:11 -04:00
console . log ( ` [DELETE] Starting deletion of up to ${ deleteCount } messages with ${ speed } speed ` ) ;
let deletedCount = 0 ;
let batchCount = 0 ;
while ( deletedCount < deleteCount && ! cancelDelete ) {
if ( deletedCount > 0 && deletedCount % 25 === 0 ) {
console . log ( ` [DELETE] Progress: ${ deletedCount } / ${ deleteCount } messages deleted ` ) ;
}
const fetchLimit = Math . min ( deleteCount - deletedCount , batchSize ) ;
2025-04-10 15:34:40 -04:00
const messages = await message . channel . messages . fetch ( { limit : 100 } ) ;
2025-04-10 15:09:11 -04:00
const filteredMessages = messages . filter ( msg =>
msg . author . id === message . author . id &&
! deletedMessages . has ( msg . id )
) ;
if ( filteredMessages . size === 0 ) {
console . log ( ` [DELETE] No more messages found in this channel ` ) ;
break ;
}
batchCount ++ ;
let messagesInThisBatch = 0 ;
2024-09-08 10:50:45 -04:00
for ( const msg of filteredMessages . values ( ) ) {
2025-04-10 15:09:11 -04:00
if ( cancelDelete ) {
console . log ( ` [DELETE] Operation canceled by user ` ) ;
return ;
}
if ( deletedCount >= deleteCount ) break ;
2024-09-08 10:50:45 -04:00
try {
2025-04-10 15:09:11 -04:00
if ( msg . deletable && ! msg . deleted && ! deletedMessages . has ( msg . id ) ) {
if ( Math . random ( ) < 0.25 ) {
const readingDelay = getReadingDelay ( ) ;
console . log ( ` [DELETE] Taking ${ readingDelay } ms to "read" before deleting message ${ msg . id } ` ) ;
await new Promise ( resolve => setTimeout ( resolve , readingDelay ) ) ;
}
const preDeleteDelay = Math . floor ( Math . random ( ) * 1000 ) + 250 ;
await new Promise ( resolve => setTimeout ( resolve , preDeleteDelay ) ) ;
2024-09-08 10:50:45 -04:00
await msg . delete ( ) . catch ( err => {
2025-04-10 15:09:11 -04:00
if ( err . code === 10008 ) {
console . log ( ` [DELETE] Message ${ msg . id } already deleted ` ) ;
deletedMessages . add ( msg . id ) ;
} else if ( err . code === 429 ) {
console . log ( ` [DELETE] Rate limited. Taking a longer break... ` ) ;
return ;
} else {
console . error ( ` [DELETE] Failed to delete message: ` , err ) ;
2024-09-08 10:50:45 -04:00
}
} ) ;
2025-04-10 15:09:11 -04:00
deletedMessages . add ( msg . id ) ;
deletedCount ++ ;
messagesInThisBatch ++ ;
const delay = getHumanlikeDelay ( ) ;
console . log ( ` [DELETE] Waiting ${ delay } ms before next deletion ` ) ;
await new Promise ( resolve => setTimeout ( resolve , delay ) ) ;
2024-09-08 10:50:45 -04:00
}
} catch ( error ) {
2025-04-10 15:09:11 -04:00
console . error ( '[DELETE] Error deleting message:' , error ) ;
2024-09-08 10:50:45 -04:00
}
}
2025-04-10 15:09:11 -04:00
if ( messagesInThisBatch === 0 ) {
console . log ( ` [DELETE] No deletable messages found in batch ` ) ;
break ;
2024-09-08 10:50:45 -04:00
}
2025-04-10 15:09:11 -04:00
if ( ! cancelDelete && deletedCount < deleteCount ) {
const adjustedPauseChance = pauseChance * ( 1 + ( Math . min ( batchCount , 5 ) / 10 ) ) ;
if ( Math . random ( ) < adjustedPauseChance ) {
const pauseDuration = Math . floor ( Math . random ( ) * ( pauseLengthMax - pauseLengthMin + 1 ) ) + pauseLengthMin ;
console . log ( ` [DELETE] Taking a break for ${ Math . round ( pauseDuration / 1000 ) } seconds. Progress: ${ deletedCount } / ${ deleteCount } ` ) ;
await new Promise ( resolve => setTimeout ( resolve , pauseDuration ) ) ;
2025-04-10 15:34:40 -04:00
batchCount = 0 ;
2025-04-10 15:09:11 -04:00
}
}
}
if ( cancelDelete ) {
const canceledMsg = await message . channel . send ( ` Delete operation canceled after removing ${ deletedCount } messages. ` ) ;
setTimeout ( ( ) => canceledMsg . delete ( ) . catch ( console . error ) , deleteTimeout ) ;
} else {
const completedMsg = await message . channel . send ( ` Finished deleting ${ deletedCount } messages. ` ) ;
setTimeout ( ( ) => completedMsg . delete ( ) . catch ( console . error ) , deleteTimeout ) ;
2024-09-08 10:50:45 -04:00
}
} catch ( error ) {
2025-04-10 15:09:11 -04:00
console . error ( '[DELETE] Failed to delete messages:' , error ) ;
2024-09-08 10:50:45 -04:00
const errorMsg = await message . channel . send ( 'There was an error while trying to delete messages.' ) ;
setTimeout ( ( ) => errorMsg . delete ( ) . catch ( console . error ) , deleteTimeout ) ;
}
}
2025-04-10 15:09:11 -04:00
async function deleteMessagesFromServer ( message , guildId , deleteTimeout , speed = 'medium' ) {
2024-09-08 10:50:45 -04:00
const guild = message . client . guilds . cache . get ( guildId ) ;
2024-09-08 10:35:46 -04:00
2024-09-08 10:50:45 -04:00
if ( ! guild ) {
const errorMsg = await message . channel . send ( 'I am not in the server with the specified ID.' ) ;
setTimeout ( ( ) => errorMsg . delete ( ) . catch ( console . error ) , deleteTimeout ) ;
return ;
}
2025-04-10 15:09:11 -04:00
let deleteIntervalMin , deleteIntervalMax , jitterFactor , pauseChance , pauseLengthMin , pauseLengthMax , batchSize ;
switch ( speed ) {
case 'slow' :
deleteIntervalMin = 3000 ;
deleteIntervalMax = 6000 ;
jitterFactor = 0.5 ;
2025-04-10 15:34:40 -04:00
pauseChance = 0.4 ;
2025-04-10 15:09:11 -04:00
pauseLengthMin = 30000 ;
pauseLengthMax = 90000 ;
batchSize = 5 ;
break ;
case 'fast' :
deleteIntervalMin = 1500 ;
deleteIntervalMax = 3000 ;
jitterFactor = 0.3 ;
pauseChance = 0.2 ;
pauseLengthMin = 15000 ;
pauseLengthMax = 45000 ;
batchSize = 15 ;
break ;
case 'medium' :
default :
deleteIntervalMin = 2000 ;
deleteIntervalMax = 4500 ;
jitterFactor = 0.4 ;
pauseChance = 0.3 ;
pauseLengthMin = 20000 ;
pauseLengthMax = 60000 ;
batchSize = 10 ;
}
const getHumanlikeDelay = ( ) => {
const baseInterval = Math . floor ( Math . random ( ) * ( deleteIntervalMax - deleteIntervalMin + 1 ) ) + deleteIntervalMin ;
const jitterAmount = baseInterval * jitterFactor ;
const jitter = Math . random ( ) * jitterAmount * 2 - jitterAmount ;
return Math . max ( 1000 , Math . floor ( baseInterval + jitter ) ) ;
} ;
2024-09-08 10:35:46 -04:00
2025-04-10 15:09:11 -04:00
console . log ( ` [DELETE] Starting server-wide deletion in server: ${ guild . name } ` ) ;
let totalDeleted = 0 ;
2024-09-08 10:35:46 -04:00
2024-09-08 10:50:45 -04:00
try {
const channels = guild . channels . cache . filter ( channel => channel . isText ( ) ) ;
2025-04-10 15:09:11 -04:00
let processedChannels = 0 ;
2024-09-08 10:50:45 -04:00
for ( const [ channelId , channel ] of channels ) {
2025-04-10 15:09:11 -04:00
if ( cancelDelete ) {
console . log ( ` [DELETE] Operation canceled by user ` ) ;
break ;
}
processedChannels ++ ;
console . log ( ` [DELETE] Processing channel ${ processedChannels } / ${ channels . size } : ${ channel . name } ` ) ;
2024-09-08 10:50:45 -04:00
let hasMoreMessages = true ;
2025-04-10 15:09:11 -04:00
let messagesDeletedInChannel = 0 ;
let batchCount = 0 ;
2024-09-08 10:50:45 -04:00
while ( hasMoreMessages && ! cancelDelete ) {
2025-04-10 15:09:11 -04:00
const messages = await channel . messages . fetch ( { limit : 100 } ) ;
2024-09-08 10:35:46 -04:00
2024-09-08 10:50:45 -04:00
if ( messages . size === 0 ) {
hasMoreMessages = false ;
continue ;
}
2024-09-08 10:35:46 -04:00
2025-04-10 15:09:11 -04:00
const filteredMessages = messages . filter ( msg =>
msg . author . id === message . author . id &&
! deletedMessages . has ( msg . id )
) ;
if ( filteredMessages . size === 0 ) {
hasMoreMessages = false ;
continue ;
}
batchCount ++ ;
let messagesInThisBatch = 0 ;
2024-09-08 10:35:46 -04:00
for ( const msg of filteredMessages . values ( ) ) {
2024-09-08 10:50:45 -04:00
if ( cancelDelete ) return ;
2025-04-10 15:09:11 -04:00
2024-09-08 10:35:46 -04:00
try {
2025-04-10 15:09:11 -04:00
if ( msg . deletable && ! msg . deleted && ! deletedMessages . has ( msg . id ) ) {
const preDeleteDelay = Math . floor ( Math . random ( ) * 1000 ) + 250 ;
await new Promise ( resolve => setTimeout ( resolve , preDeleteDelay ) ) ;
2024-09-08 10:35:46 -04:00
await msg . delete ( ) . catch ( err => {
2025-04-10 15:09:11 -04:00
if ( err . code === 10008 ) {
console . log ( ` [DELETE] Message ${ msg . id } already deleted ` ) ;
deletedMessages . add ( msg . id ) ;
} else if ( err . code === 429 ) {
console . log ( ` [DELETE] Rate limited. Taking a longer break... ` ) ;
return new Promise ( resolve => setTimeout ( resolve , 30000 + Math . random ( ) * 30000 ) ) ;
} else {
console . error ( ` [DELETE] Failed to delete message: ` , err ) ;
2024-09-08 10:35:46 -04:00
}
} ) ;
2025-04-10 15:09:11 -04:00
deletedMessages . add ( msg . id ) ;
totalDeleted ++ ;
messagesDeletedInChannel ++ ;
messagesInThisBatch ++ ;
const delay = getHumanlikeDelay ( ) ;
await new Promise ( resolve => setTimeout ( resolve , delay ) ) ;
2024-09-08 10:35:46 -04:00
}
} catch ( error ) {
2025-04-10 15:09:11 -04:00
console . error ( '[DELETE] Error deleting message:' , error ) ;
2024-09-08 10:35:46 -04:00
}
2025-04-10 15:09:11 -04:00
if ( messagesInThisBatch >= batchSize ) break ;
2024-09-08 10:35:46 -04:00
}
2025-04-10 15:09:11 -04:00
if ( messagesInThisBatch < batchSize ) {
2024-09-08 10:50:45 -04:00
hasMoreMessages = false ;
} else {
2025-04-10 15:09:11 -04:00
const shouldPause = Math . random ( ) < pauseChance ;
if ( shouldPause && ! cancelDelete ) {
const pauseDuration = Math . floor ( Math . random ( ) * ( pauseLengthMin - pauseLengthMin / 2 + 1 ) ) + pauseLengthMin / 2 ;
console . log ( ` [DELETE] Taking a short break for ${ Math . round ( pauseDuration / 1000 ) } seconds in channel ${ channel . name } . Deleted so far: ${ messagesDeletedInChannel } ` ) ;
await new Promise ( resolve => setTimeout ( resolve , pauseDuration ) ) ;
}
2024-09-08 10:35:46 -04:00
}
}
2025-04-10 15:09:11 -04:00
console . log ( ` [DELETE] Completed channel ${ channel . name } : ${ messagesDeletedInChannel } messages deleted ` ) ;
if ( ! cancelDelete && processedChannels < channels . size ) {
const pauseDuration = Math . floor ( Math . random ( ) * ( pauseLengthMax - pauseLengthMin + 1 ) ) + pauseLengthMin ;
console . log ( ` [DELETE] Moving to next channel in ${ Math . round ( pauseDuration / 1000 ) } seconds. Total deleted so far: ${ totalDeleted } ` ) ;
await new Promise ( resolve => setTimeout ( resolve , pauseDuration ) ) ;
}
}
if ( cancelDelete ) {
const canceledMsg = await message . channel . send ( ` Server cleanup canceled after removing ${ totalDeleted } messages across ${ processedChannels } channels. ` ) ;
setTimeout ( ( ) => canceledMsg . delete ( ) . catch ( console . error ) , deleteTimeout ) ;
} else {
const completedMsg = await message . channel . send ( ` Finished cleaning up ${ guild . name } : ${ totalDeleted } messages deleted across ${ processedChannels } channels. ` ) ;
setTimeout ( ( ) => completedMsg . delete ( ) . catch ( console . error ) , deleteTimeout ) ;
2024-09-08 10:35:46 -04:00
}
2024-09-08 10:50:45 -04:00
} catch ( error ) {
2025-04-10 15:09:11 -04:00
console . error ( '[DELETE] Failed to delete messages in the server:' , error ) ;
2024-09-08 10:50:45 -04:00
const errorMsg = await message . channel . send ( 'There was an error while trying to delete messages from the server.' ) ;
setTimeout ( ( ) => errorMsg . delete ( ) . catch ( console . error ) , deleteTimeout ) ;
}
2025-02-05 21:02:07 -05:00
}