Compare commits
	
		
			33 Commits
		
	
	
		
			50438bf2c8
			...
			master
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 1d8017e5b5 | |||
| 887ebb0c64 | |||
| 73149b8d6d | |||
| 5f750b0666 | |||
| b15f7097f8 | |||
| 7ca36a4938 | |||
| 235398d200 | |||
| 1f8dced90e | |||
| ddf4c6ae15 | |||
| c16e55d56c | |||
| 38147c46a2 | |||
| 90df6177ed | |||
| 26e7b8f706 | |||
| 4d2521441d | |||
| 3c055c53d2 | |||
| 259ed424dd | |||
| 59570259d6 | |||
| c287382bd2 | |||
| af3dbe625b | |||
| 4b1740ac07 | |||
| 92e1984cbf | |||
| 0e32bc2fb4 | |||
| c42d519a06 | |||
| 5912b1fbca | |||
| a2acaa42f1 | |||
| 13b31d4fc3 | |||
| 52b6e1b148 | |||
| 47eb919c0a | |||
| db63ef6827 | |||
| 305b6cc683 | |||
| 4943964b77 | |||
| 129a20c894 | |||
| 4bc2a55a39 | 
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1 +1,3 @@ | |||||||
| .env | .env | ||||||
|  | node_modules/* | ||||||
|  | *.json | ||||||
							
								
								
									
										33
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								README.md
									
									
									
									
									
								
							| @@ -2,6 +2,39 @@ | |||||||
|  |  | ||||||
| `discord-selfbot` is a simple selfbot for discord using [discord.js-selfbot-v13](https://github.com/aiko-chan-ai/discord.js-selfbot-v13). | `discord-selfbot` is a simple selfbot for discord using [discord.js-selfbot-v13](https://github.com/aiko-chan-ai/discord.js-selfbot-v13). | ||||||
|  |  | ||||||
|  | # Discord Selfbot Setup | ||||||
|  |  | ||||||
|  | ## 1. Clone the Repository | ||||||
|  | Open your terminal and run: | ||||||
|  | ```bash | ||||||
|  | git clone https://git.deadzone.lol/Wizzard/discord-selfbot/ | ||||||
|  | cd discord-selfbot | ||||||
|  | ``` | ||||||
|  | Run start.sh / start.bat | ||||||
|  |  | ||||||
|  | ## 2. Get your token | ||||||
|  | Open the file `tokengrab.js` in a text editor. | ||||||
|  |  | ||||||
|  | Copy its entire contents. | ||||||
|  |  | ||||||
|  | Open the Discord client and press Ctrl+Shift+I to open Developer Tools. | ||||||
|  |  | ||||||
|  | Navigate to the Console tab. | ||||||
|  |  | ||||||
|  | Paste the copied contents into the console and press Enter. | ||||||
|  |  | ||||||
|  | ## 3. Configuration | ||||||
|  | Create your configuration file by copying the example file: | ||||||
|  |  | ||||||
|  | `cp EXAMPLE.env .env` (copy file on windows) | ||||||
|  |  | ||||||
|  | Replace the placeholder for DISCORD_TOKEN with your actual Discord token. For example: | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | DISCORD_TOKEN=discord_token | ||||||
|  | PREFIX=. | ||||||
|  | ``` | ||||||
|  |  | ||||||
| ## Disclaimer | ## Disclaimer | ||||||
|  |  | ||||||
| I don't take any responsibility for blocked Discord accounts that used this program. | I don't take any responsibility for blocked Discord accounts that used this program. | ||||||
|   | |||||||
							
								
								
									
										563
									
								
								commands/autodelete.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										563
									
								
								commands/autodelete.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,563 @@ | |||||||
|  | let isAutoDeleteActive = false; | ||||||
|  | let deleteQueue = []; | ||||||
|  | let isProcessingQueue = false; | ||||||
|  | let messageTimers = new Map(); | ||||||
|  | let ignoredMessages = new Set(); | ||||||
|  | let ignoredChannels = new Set(); | ||||||
|  | let ignoredUsers = new Set(); | ||||||
|  | let ignoredGuilds = new Set(); | ||||||
|  | let isFirstDeletion = true; | ||||||
|  | let deletedMessages = new Set(); | ||||||
|  | const CACHE_CLEANUP_INTERVAL = 30 * 60 * 1000; | ||||||
|  | const { sendCommandResponse } = require('../utils/messageUtils'); | ||||||
|  | const fs = require('fs'); | ||||||
|  | const path = require('path'); | ||||||
|  |  | ||||||
|  | const DATA_DIR = path.join(__dirname, '..', 'data'); | ||||||
|  | const IGNORE_FILE = path.join(DATA_DIR, 'autodelete_ignores.json'); | ||||||
|  |  | ||||||
|  | if (!fs.existsSync(DATA_DIR)) { | ||||||
|  |     try { | ||||||
|  |         fs.mkdirSync(DATA_DIR, { recursive: true }); | ||||||
|  |         console.log('[AUTODELETE] Created data directory'); | ||||||
|  |     } catch (error) { | ||||||
|  |         console.error('[AUTODELETE] Error creating data directory:', error); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function loadIgnoreLists() { | ||||||
|  |     try { | ||||||
|  |         if (fs.existsSync(IGNORE_FILE)) { | ||||||
|  |             const data = JSON.parse(fs.readFileSync(IGNORE_FILE, 'utf8')); | ||||||
|  |              | ||||||
|  |             if (data.ignoredChannels) ignoredChannels = new Set(data.ignoredChannels); | ||||||
|  |             if (data.ignoredUsers) ignoredUsers = new Set(data.ignoredUsers); | ||||||
|  |             if (data.ignoredGuilds) ignoredGuilds = new Set(data.ignoredGuilds); | ||||||
|  |              | ||||||
|  |             console.log('[AUTODELETE] Loaded ignore lists from file'); | ||||||
|  |         } | ||||||
|  |     } catch (error) { | ||||||
|  |         console.error('[AUTODELETE] Error loading ignore lists:', error); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function saveIgnoreLists() { | ||||||
|  |     try { | ||||||
|  |         const data = { | ||||||
|  |             ignoredChannels: Array.from(ignoredChannels), | ||||||
|  |             ignoredUsers: Array.from(ignoredUsers), | ||||||
|  |             ignoredGuilds: Array.from(ignoredGuilds) | ||||||
|  |         }; | ||||||
|  |          | ||||||
|  |         fs.writeFileSync(IGNORE_FILE, JSON.stringify(data, null, 2), 'utf8'); | ||||||
|  |         console.log('[AUTODELETE] Saved ignore lists to file'); | ||||||
|  |     } catch (error) { | ||||||
|  |         console.error('[AUTODELETE] Error saving ignore lists:', error); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | loadIgnoreLists(); | ||||||
|  |  | ||||||
|  | const DELETION_DELAY = 5 * 60 * 1000; | ||||||
|  | let DELETE_INTERVAL_MIN = 8000; | ||||||
|  | let DELETE_INTERVAL_MAX = 15000; | ||||||
|  | let JITTER_FACTOR = 0.4; | ||||||
|  | let PAUSE_CHANCE = 0.15; | ||||||
|  | let PAUSE_LENGTH_MIN = 30000; | ||||||
|  | let PAUSE_LENGTH_MAX = 120000; | ||||||
|  | let BATCH_SIZE = 3; | ||||||
|  | let currentBatchCount = 0; | ||||||
|  |  | ||||||
|  | setInterval(() => { | ||||||
|  |     if (deletedMessages.size > 1000) { | ||||||
|  |         console.log(`[AUTODELETE] Cleaning message cache (size: ${deletedMessages.size})`); | ||||||
|  |         deletedMessages.clear(); | ||||||
|  |     } | ||||||
|  | }, CACHE_CLEANUP_INTERVAL); | ||||||
|  |  | ||||||
|  | const getHumanlikeDelay = () => { | ||||||
|  |     const baseInterval = Math.floor(Math.random() * (DELETE_INTERVAL_MAX - DELETE_INTERVAL_MIN + 1)) + DELETE_INTERVAL_MIN; | ||||||
|  |  | ||||||
|  |     const jitterAmount = baseInterval * JITTER_FACTOR; | ||||||
|  |     const jitter = Math.random() * jitterAmount * 2 - jitterAmount; | ||||||
|  |  | ||||||
|  |     return Math.max(1000, Math.floor(baseInterval + jitter)); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const shouldTakePause = () => { | ||||||
|  |     currentBatchCount++; | ||||||
|  |  | ||||||
|  |     if (currentBatchCount >= BATCH_SIZE) { | ||||||
|  |         currentBatchCount = 0; | ||||||
|  |         return Math.random() < PAUSE_CHANCE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return false; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const getPauseDuration = () => { | ||||||
|  |     return Math.floor(Math.random() * (PAUSE_LENGTH_MAX - PAUSE_LENGTH_MIN + 1)) + PAUSE_LENGTH_MIN; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const processDeleteQueue = async () => { | ||||||
|  |     if (!isProcessingQueue || deleteQueue.length === 0) return; | ||||||
|  |  | ||||||
|  |     try { | ||||||
|  |         const messageToDelete = deleteQueue.shift(); | ||||||
|  |         if (!messageToDelete) return; | ||||||
|  |  | ||||||
|  |         if (deletedMessages.has(messageToDelete.id)) { | ||||||
|  |             console.log(`[AUTODELETE] Message ${messageToDelete.id} already deleted (cached), skipping`); | ||||||
|  |  | ||||||
|  |             if (deleteQueue.length > 0 && isProcessingQueue) { | ||||||
|  |                 scheduleNextDeletion(); | ||||||
|  |             } else { | ||||||
|  |                 isProcessingQueue = false; | ||||||
|  |             } | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const preDeleteDelay = Math.floor(Math.random() * 1500) + 500; // 500-2000ms | ||||||
|  |         await new Promise(resolve => setTimeout(resolve, preDeleteDelay)); | ||||||
|  |  | ||||||
|  |         if (isFirstDeletion || Math.random() < 0.35) { | ||||||
|  |             console.log(`[AUTODELETE] Checking message ${messageToDelete.id} existence${isFirstDeletion ? ' (first deletion)' : ''}`); | ||||||
|  |             const exists = await messageToDelete.fetch().catch(() => null); | ||||||
|  |             if (!exists) { | ||||||
|  |                 console.log(`[AUTODELETE] Message ${messageToDelete.id} no longer exists, adding to cache`); | ||||||
|  |                 deletedMessages.add(messageToDelete.id); | ||||||
|  |                 isFirstDeletion = false; | ||||||
|  |  | ||||||
|  |                 if (deleteQueue.length > 0 && isProcessingQueue) { | ||||||
|  |                     scheduleNextDeletion(); | ||||||
|  |                 } else { | ||||||
|  |                     isProcessingQueue = false; | ||||||
|  |                 } | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (Math.random() < 0.25) { | ||||||
|  |             const readingDelay = Math.floor(Math.random() * 3000) + 1000; // 1-4 seconds "reading" delay | ||||||
|  |             console.log(`[AUTODELETE] Taking ${readingDelay}ms to "read" before deleting`); | ||||||
|  |             await new Promise(resolve => setTimeout(resolve, readingDelay)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         await messageToDelete.delete().catch((error) => { | ||||||
|  |             if (error.code === 10008) { | ||||||
|  |                 console.log(`[AUTODELETE] Message ${messageToDelete.id} already deleted, adding to cache`); | ||||||
|  |                 deletedMessages.add(messageToDelete.id); | ||||||
|  |             } else if (error.code === 429) { | ||||||
|  |                 console.log(`[AUTODELETE] Rate limited when deleting ${messageToDelete.id}. Will retry later.`); | ||||||
|  |  | ||||||
|  |                 deleteQueue.push(messageToDelete); | ||||||
|  |  | ||||||
|  |                 DELETE_INTERVAL_MIN = Math.min(DELETE_INTERVAL_MIN * 1.5, 25000); | ||||||
|  |                 DELETE_INTERVAL_MAX = Math.min(DELETE_INTERVAL_MAX * 1.5, 45000); | ||||||
|  |                 console.log(`[AUTODELETE] Increased deletion intervals to ${DELETE_INTERVAL_MIN}-${DELETE_INTERVAL_MAX}ms`); | ||||||
|  |             } else { | ||||||
|  |                 console.log(`[AUTODELETE] Couldn't delete message ${messageToDelete.id}:`, error); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         if (!deletedMessages.has(messageToDelete.id)) { | ||||||
|  |             deletedMessages.add(messageToDelete.id); | ||||||
|  |             console.log(`[AUTODELETE] Successfully deleted message ${messageToDelete.id}`); | ||||||
|  |  | ||||||
|  |             if (Math.random() < 0.1) { | ||||||
|  |                 DELETE_INTERVAL_MIN = Math.max(DELETE_INTERVAL_MIN * 0.95, 8000); | ||||||
|  |                 DELETE_INTERVAL_MAX = Math.max(DELETE_INTERVAL_MAX * 0.95, 15000); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         isFirstDeletion = false; | ||||||
|  |  | ||||||
|  |     } catch (error) { | ||||||
|  |         console.log('[AUTODELETE] Error processing queue:', error); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (deleteQueue.length > 0 && isProcessingQueue) { | ||||||
|  |         scheduleNextDeletion(); | ||||||
|  |     } else { | ||||||
|  |         isProcessingQueue = false; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const scheduleNextDeletion = () => { | ||||||
|  |     if (shouldTakePause()) { | ||||||
|  |         const pauseDuration = getPauseDuration(); | ||||||
|  |         console.log(`[AUTODELETE] Taking a break for ${Math.round(pauseDuration / 1000)} seconds before continuing deletion. Queue size: ${deleteQueue.length}`); | ||||||
|  |         setTimeout(processDeleteQueue, pauseDuration); | ||||||
|  |     } else { | ||||||
|  |         let nextInterval = getHumanlikeDelay(); | ||||||
|  |  | ||||||
|  |         if (deleteQueue.length > 15) { | ||||||
|  |             nextInterval = Math.max(Math.floor(nextInterval * 0.8), 5000); | ||||||
|  |         } | ||||||
|  |         else if (deleteQueue.length <= 2) { | ||||||
|  |             nextInterval = Math.floor(nextInterval * 1.2); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         console.log(`[AUTODELETE] Next deletion in ${nextInterval}ms | Queue size: ${deleteQueue.length}`); | ||||||
|  |         setTimeout(processDeleteQueue, nextInterval); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const startQueueProcessing = () => { | ||||||
|  |     if (!isProcessingQueue && deleteQueue.length > 0) { | ||||||
|  |         isProcessingQueue = true; | ||||||
|  |         currentBatchCount = 0; | ||||||
|  |         processDeleteQueue(); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const handleNewMessage = (message) => { | ||||||
|  |     if (!isAutoDeleteActive || message.author.id !== message.client.user.id) return; | ||||||
|  |  | ||||||
|  |     if (ignoredMessages.has(message.id) || deletedMessages.has(message.id)) { | ||||||
|  |         console.log(`[AUTODELETE] Skipping cached/ignored message: ${message.id}`); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     if (message.content.startsWith('.autodelete')) { | ||||||
|  |         console.log(`[AUTODELETE] Skipping command message: ${message.id}`); | ||||||
|  |         ignoredMessages.add(message.id); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if (message.content.includes('```') && message.content.length > 100) { | ||||||
|  |         console.log(`[AUTODELETE] Skipping command response message: ${message.id}`); | ||||||
|  |         ignoredMessages.add(message.id); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if (message.scheduledForDeletion) { | ||||||
|  |         console.log(`[AUTODELETE] Skipping message already scheduled for deletion: ${message.id}`); | ||||||
|  |         ignoredMessages.add(message.id); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (message.channel && ignoredChannels.has(message.channel.id)) { | ||||||
|  |         console.log(`[AUTODELETE] Skipping message in ignored channel: ${message.channel.id}`); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if (message.guild && ignoredGuilds.has(message.guild.id)) { | ||||||
|  |         console.log(`[AUTODELETE] Skipping message in ignored guild: ${message.guild.id}`); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if (!message.guild && message.channel && ignoredUsers.has(message.channel.recipient?.id)) { | ||||||
|  |         console.log(`[AUTODELETE] Skipping message to ignored user: ${message.channel.recipient.id}`); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     console.log(`[AUTODELETE] New message tracked: ${message.id}`); | ||||||
|  |     console.log(`[AUTODELETE] Content preview: ${message.content.slice(0, 30)}...`); | ||||||
|  |  | ||||||
|  |     const variableDelay = DELETION_DELAY + (Math.random() * 60000) - 30000; // +/- 30 seconds | ||||||
|  |  | ||||||
|  |     const timer = setTimeout(() => { | ||||||
|  |         if (isAutoDeleteActive) { | ||||||
|  |             console.log(`[AUTODELETE] Timer completed for message: ${message.id} after ~${Math.round(variableDelay / 1000 / 60)} minutes`); | ||||||
|  |             if (!deletedMessages.has(message.id)) { | ||||||
|  |                 deleteQueue.push(message); | ||||||
|  |                 messageTimers.delete(message.id); | ||||||
|  |                 startQueueProcessing(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }, variableDelay); | ||||||
|  |  | ||||||
|  |     messageTimers.set(message.id, timer); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | module.exports = { | ||||||
|  |     name: 'autodelete', | ||||||
|  |     description: 'Automatically deletes your messages after a set time', | ||||||
|  |     async execute(message, args, deleteTimeout) { | ||||||
|  |         ignoredMessages.add(message.id); | ||||||
|  |  | ||||||
|  |         if (args.length === 0 || args[0].toLowerCase() === 'status') { | ||||||
|  |             let ignoreStatus = ''; | ||||||
|  |             if (ignoredChannels.size > 0 || ignoredGuilds.size > 0 || ignoredUsers.size > 0) { | ||||||
|  |                 ignoreStatus = `\nIgnored: ${ignoredChannels.size} channels, ${ignoredGuilds.size} servers, ${ignoredUsers.size} users`; | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             const statusText = isAutoDeleteActive | ||||||
|  |                 ? `Auto-delete is ON - Messages will be deleted after approximately ${Math.round(DELETION_DELAY / 1000 / 60)} minutes.` | ||||||
|  |                 : 'Auto-delete is OFF.'; | ||||||
|  |  | ||||||
|  |             await sendCommandResponse( | ||||||
|  |                 message, | ||||||
|  |                 `${statusText}\nQueue size: ${deleteQueue.length} messages | Tracked messages: ${messageTimers.size}${ignoreStatus}`, | ||||||
|  |                 deleteTimeout,  | ||||||
|  |                 true | ||||||
|  |             ); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const command = args[0].toLowerCase(); | ||||||
|  |  | ||||||
|  |         if (command === 'on' || command === 'start' || command === 'enable') { | ||||||
|  |             if (isAutoDeleteActive) { | ||||||
|  |                 await sendCommandResponse(message, 'Auto-delete is already active.', deleteTimeout, true); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             isAutoDeleteActive = true; | ||||||
|  |             message.client.on('messageCreate', handleNewMessage); | ||||||
|  |  | ||||||
|  |             await sendCommandResponse( | ||||||
|  |                 message, | ||||||
|  |                 `Auto-delete enabled. Your messages will be deleted after approximately ${Math.round(DELETION_DELAY / 1000 / 60)} minutes.`, | ||||||
|  |                 deleteTimeout, | ||||||
|  |                 true | ||||||
|  |             ); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (command === 'off' || command === 'stop' || command === 'disable') { | ||||||
|  |             if (!isAutoDeleteActive) { | ||||||
|  |                 await sendCommandResponse(message, 'Auto-delete is not active.', deleteTimeout, true); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             isAutoDeleteActive = false; | ||||||
|  |             message.client.off('messageCreate', handleNewMessage); | ||||||
|  |  | ||||||
|  |             for (const timer of messageTimers.values()) { | ||||||
|  |                 clearTimeout(timer); | ||||||
|  |             } | ||||||
|  |             messageTimers.clear(); | ||||||
|  |  | ||||||
|  |             await sendCommandResponse(message, 'Auto-delete disabled. Messages will no longer be automatically deleted.', deleteTimeout, true); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (command === 'clear') { | ||||||
|  |             const queueSize = deleteQueue.length; | ||||||
|  |             const trackCount = messageTimers.size; | ||||||
|  |              | ||||||
|  |             deleteQueue = []; | ||||||
|  |             for (const timer of messageTimers.values()) { | ||||||
|  |                 clearTimeout(timer); | ||||||
|  |             } | ||||||
|  |             messageTimers.clear(); | ||||||
|  |             currentBatchCount = 0; | ||||||
|  |              | ||||||
|  |             await sendCommandResponse(message, `Cleared auto-delete queue (${queueSize} pending, ${trackCount} tracked).`, deleteTimeout, true); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (command === 'speed') { | ||||||
|  |             const speedOption = args[1]?.toLowerCase(); | ||||||
|  |              | ||||||
|  |             if (!speedOption || !['slow', 'normal', 'fast'].includes(speedOption)) { | ||||||
|  |                 await sendCommandResponse(message, 'Please specify a valid speed: slow, normal, or fast.', deleteTimeout, true); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             if (speedOption === 'slow') { | ||||||
|  |                 DELETE_INTERVAL_MIN = 12000; | ||||||
|  |                 DELETE_INTERVAL_MAX = 25000; | ||||||
|  |                 JITTER_FACTOR = 0.5; | ||||||
|  |                 PAUSE_CHANCE = 0.25; | ||||||
|  |                 PAUSE_LENGTH_MIN = 45000; | ||||||
|  |                 PAUSE_LENGTH_MAX = 180000; | ||||||
|  |                 BATCH_SIZE = 2; | ||||||
|  |             } else if (speedOption === 'fast') { | ||||||
|  |                 DELETE_INTERVAL_MIN = 5000; | ||||||
|  |                 DELETE_INTERVAL_MAX = 10000; | ||||||
|  |                 JITTER_FACTOR = 0.3; | ||||||
|  |                 PAUSE_CHANCE = 0.1; | ||||||
|  |                 PAUSE_LENGTH_MIN = 15000; | ||||||
|  |                 PAUSE_LENGTH_MAX = 60000; | ||||||
|  |                 BATCH_SIZE = 5; | ||||||
|  |             } else { | ||||||
|  |                 DELETE_INTERVAL_MIN = 8000; | ||||||
|  |                 DELETE_INTERVAL_MAX = 15000; | ||||||
|  |                 JITTER_FACTOR = 0.4; | ||||||
|  |                 PAUSE_CHANCE = 0.15; | ||||||
|  |                 PAUSE_LENGTH_MIN = 30000; | ||||||
|  |                 PAUSE_LENGTH_MAX = 120000; | ||||||
|  |                 BATCH_SIZE = 3; | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             await sendCommandResponse(message, `Auto-delete speed set to ${speedOption}.`, deleteTimeout, true); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (command === 'ignore') { | ||||||
|  |             if (args.length < 2) { | ||||||
|  |                 await sendCommandResponse( | ||||||
|  |                     message, | ||||||
|  |                     'Please specify what to ignore. Usage: `.autodelete ignore [channel/server/user] [ID]`', | ||||||
|  |                     deleteTimeout, | ||||||
|  |                     true | ||||||
|  |                 ); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             const ignoreType = args[1].toLowerCase(); | ||||||
|  |             const id = args[2]; | ||||||
|  |              | ||||||
|  |             if (!id || !/^\d{17,19}$/.test(id)) { | ||||||
|  |                 await sendCommandResponse( | ||||||
|  |                     message, | ||||||
|  |                     'Please provide a valid ID (channel, server, or user ID).', | ||||||
|  |                     deleteTimeout, | ||||||
|  |                     true | ||||||
|  |                 ); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             if (ignoreType === 'channel' || ignoreType === 'c') { | ||||||
|  |                 ignoredChannels.add(id); | ||||||
|  |                 saveIgnoreLists(); | ||||||
|  |                 await sendCommandResponse( | ||||||
|  |                     message, | ||||||
|  |                     `Channel ${id} will now be ignored by auto-delete.`, | ||||||
|  |                     deleteTimeout, | ||||||
|  |                     true | ||||||
|  |                 ); | ||||||
|  |             } else if (ignoreType === 'server' || ignoreType === 'guild' || ignoreType === 's' || ignoreType === 'g') { | ||||||
|  |                 ignoredGuilds.add(id); | ||||||
|  |                 saveIgnoreLists(); | ||||||
|  |                 await sendCommandResponse( | ||||||
|  |                     message, | ||||||
|  |                     `Server ${id} will now be ignored by auto-delete.`, | ||||||
|  |                     deleteTimeout, | ||||||
|  |                     true | ||||||
|  |                 ); | ||||||
|  |             } else if (ignoreType === 'user' || ignoreType === 'u' || ignoreType === 'dm') { | ||||||
|  |                 ignoredUsers.add(id); | ||||||
|  |                 saveIgnoreLists(); | ||||||
|  |                 await sendCommandResponse( | ||||||
|  |                     message, | ||||||
|  |                     `User ${id} (DMs) will now be ignored by auto-delete.`, | ||||||
|  |                     deleteTimeout, | ||||||
|  |                     true | ||||||
|  |                 ); | ||||||
|  |             } else { | ||||||
|  |                 await sendCommandResponse( | ||||||
|  |                     message, | ||||||
|  |                     'Invalid ignore type. Use "channel", "server", or "user".', | ||||||
|  |                     deleteTimeout, | ||||||
|  |                     true | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         if (command === 'unignore') { | ||||||
|  |             if (args.length < 2) { | ||||||
|  |                 await sendCommandResponse( | ||||||
|  |                     message, | ||||||
|  |                     'Please specify what to unignore. Usage: `.autodelete unignore [channel/server/user] [ID]`', | ||||||
|  |                     deleteTimeout, | ||||||
|  |                     true | ||||||
|  |                 ); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             const ignoreType = args[1].toLowerCase(); | ||||||
|  |             const id = args[2]; | ||||||
|  |              | ||||||
|  |             if (!id || !/^\d{17,19}$/.test(id)) { | ||||||
|  |                 await sendCommandResponse( | ||||||
|  |                     message, | ||||||
|  |                     'Please provide a valid ID (channel, server, or user ID).', | ||||||
|  |                     deleteTimeout, | ||||||
|  |                     true | ||||||
|  |                 ); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             if (ignoreType === 'channel' || ignoreType === 'c') { | ||||||
|  |                 if (ignoredChannels.has(id)) { | ||||||
|  |                     ignoredChannels.delete(id); | ||||||
|  |                     saveIgnoreLists(); | ||||||
|  |                     await sendCommandResponse( | ||||||
|  |                         message, | ||||||
|  |                         `Channel ${id} will no longer be ignored by auto-delete.`, | ||||||
|  |                         deleteTimeout, | ||||||
|  |                         true | ||||||
|  |                     ); | ||||||
|  |                 } else { | ||||||
|  |                     await sendCommandResponse( | ||||||
|  |                         message, | ||||||
|  |                         `Channel ${id} is not in the ignore list.`, | ||||||
|  |                         deleteTimeout, | ||||||
|  |                         true | ||||||
|  |                     ); | ||||||
|  |                 } | ||||||
|  |             } else if (ignoreType === 'server' || ignoreType === 'guild' || ignoreType === 's' || ignoreType === 'g') { | ||||||
|  |                 if (ignoredGuilds.has(id)) { | ||||||
|  |                     ignoredGuilds.delete(id); | ||||||
|  |                     saveIgnoreLists(); | ||||||
|  |                     await sendCommandResponse( | ||||||
|  |                         message, | ||||||
|  |                         `Server ${id} will no longer be ignored by auto-delete.`, | ||||||
|  |                         deleteTimeout, | ||||||
|  |                         true | ||||||
|  |                     ); | ||||||
|  |                 } else { | ||||||
|  |                     await sendCommandResponse( | ||||||
|  |                         message, | ||||||
|  |                         `Server ${id} is not in the ignore list.`, | ||||||
|  |                         deleteTimeout, | ||||||
|  |                         true | ||||||
|  |                     ); | ||||||
|  |                 } | ||||||
|  |             } else if (ignoreType === 'user' || ignoreType === 'u' || ignoreType === 'dm') { | ||||||
|  |                 if (ignoredUsers.has(id)) { | ||||||
|  |                     ignoredUsers.delete(id); | ||||||
|  |                     saveIgnoreLists(); | ||||||
|  |                     await sendCommandResponse( | ||||||
|  |                         message, | ||||||
|  |                         `User ${id} (DMs) will no longer be ignored by auto-delete.`, | ||||||
|  |                         deleteTimeout, | ||||||
|  |                         true | ||||||
|  |                     ); | ||||||
|  |                 } else { | ||||||
|  |                     await sendCommandResponse( | ||||||
|  |                         message, | ||||||
|  |                         `User ${id} is not in the ignore list.`, | ||||||
|  |                         deleteTimeout, | ||||||
|  |                         true | ||||||
|  |                     ); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 await sendCommandResponse( | ||||||
|  |                     message, | ||||||
|  |                     'Invalid ignore type. Use "channel", "server", or "user".', | ||||||
|  |                     deleteTimeout, | ||||||
|  |                     true | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         if (command === 'ignorelist' || command === 'list') { | ||||||
|  |             let ignoredChannelsList = Array.from(ignoredChannels).join(', '); | ||||||
|  |             let ignoredGuildsList = Array.from(ignoredGuilds).join(', '); | ||||||
|  |             let ignoredUsersList = Array.from(ignoredUsers).join(', '); | ||||||
|  |              | ||||||
|  |             const ignoredInfo = `**Ignored Channels:** ${ignoredChannels.size > 0 ? ignoredChannelsList : 'None'}\n**Ignored Servers:** ${ignoredGuilds.size > 0 ? ignoredGuildsList : 'None'}\n**Ignored Users (DMs):** ${ignoredUsers.size > 0 ? ignoredUsersList : 'None'}`; | ||||||
|  |              | ||||||
|  |             await sendCommandResponse( | ||||||
|  |                 message, | ||||||
|  |                 `**Auto-delete Ignore List**\n\n${ignoredInfo}`, | ||||||
|  |                 deleteTimeout, | ||||||
|  |                 true | ||||||
|  |             ); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         await sendCommandResponse( | ||||||
|  |             message, | ||||||
|  |             'Unknown command. Valid commands: on, off, status, ignore, unignore, ignorelist', | ||||||
|  |             deleteTimeout, | ||||||
|  |             true | ||||||
|  |         ); | ||||||
|  |     }, | ||||||
|  | }; | ||||||
| @@ -1,5 +1,15 @@ | |||||||
| let isDeleting = false; | let isDeleting = false; | ||||||
| let cancelDelete = false; | let cancelDelete = false; | ||||||
|  | let deletedMessages = new Set(); | ||||||
|  | const CACHE_CLEANUP_INTERVAL = 30 * 60 * 1000; | ||||||
|  | const { sendCommandResponse } = require('../utils/messageUtils'); | ||||||
|  |  | ||||||
|  | setInterval(() => { | ||||||
|  |   if (deletedMessages.size > 1000) { | ||||||
|  |     console.log(`[DELETE] Cleaning message cache (size: ${deletedMessages.size})`); | ||||||
|  |     deletedMessages.clear(); | ||||||
|  |   } | ||||||
|  | }, CACHE_CLEANUP_INTERVAL); | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|   name: 'delete', |   name: 'delete', | ||||||
| @@ -7,135 +17,330 @@ module.exports = { | |||||||
|   async execute(message, args, deleteTimeout) { |   async execute(message, args, deleteTimeout) { | ||||||
|     if (args[0] && args[0].toLowerCase() === 'cancel') { |     if (args[0] && args[0].toLowerCase() === 'cancel') { | ||||||
|       cancelDelete = true; |       cancelDelete = true; | ||||||
|       const cancelMsg = await message.channel.send('Delete operation canceled.'); |       await sendCommandResponse(message, 'Delete operation canceled.', deleteTimeout, true); | ||||||
|       setTimeout(() => cancelMsg.delete().catch(console.error), deleteTimeout); |  | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (isDeleting) { |     if (isDeleting) { | ||||||
|       const inProgressMsg = await message.channel.send('A delete operation is already in progress. Please wait or cancel it with `.delete cancel`.'); |       await sendCommandResponse(message, 'A delete operation is already in progress. Please wait or cancel it with `.delete cancel`.', deleteTimeout, true); | ||||||
|       setTimeout(() => inProgressMsg.delete().catch(console.error), deleteTimeout); |  | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     isDeleting = true; |     isDeleting = true; | ||||||
|     cancelDelete = false; |     cancelDelete = false; | ||||||
|  |  | ||||||
|  |     let speed = 'medium'; | ||||||
|  |     if (args[0] && ['slow', 'medium', 'fast'].includes(args[0].toLowerCase())) { | ||||||
|  |       speed = args[0].toLowerCase(); | ||||||
|  |       args.shift(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     const deleteCount = parseInt(args[0], 10); |     const deleteCount = parseInt(args[0], 10); | ||||||
|     const targetGuildId = args[1]; |     const targetGuildId = args[1]; | ||||||
|  |  | ||||||
|     if (!isNaN(deleteCount) && deleteCount > 0) { |     if (!isNaN(deleteCount) && deleteCount > 0) { | ||||||
|       await deleteMessagesFromChannel(message, deleteCount, deleteTimeout); |       await deleteMessagesFromChannel(message, deleteCount, deleteTimeout, speed); | ||||||
|     } else if (targetGuildId) { |     } else if (targetGuildId) { | ||||||
|       await deleteMessagesFromServer(message, targetGuildId, deleteTimeout); |       await deleteMessagesFromServer(message, targetGuildId, deleteTimeout, speed); | ||||||
|     } else { |     } else { | ||||||
|       const errorMsg = await message.channel.send('Please provide a valid number of messages or server ID.'); |       await sendCommandResponse(message, 'Please specify how many messages to delete or a server ID. You can also set speed: `.delete [slow/medium/fast] [count/server]`', deleteTimeout, true); | ||||||
|       setTimeout(() => errorMsg.delete().catch(console.error), deleteTimeout); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     isDeleting = false; |     isDeleting = false; | ||||||
|   }, |   }, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| async function deleteMessagesFromChannel(message, deleteCount, deleteTimeout) { | async function deleteMessagesFromChannel(message, deleteCount, deleteTimeout, speed = 'medium') { | ||||||
|   const getRandomDelay = () => Math.floor(Math.random() * (3000 - 1000 + 1)) + 1000; |   let deleteIntervalMin, deleteIntervalMax, jitterFactor, pauseChance, pauseLengthMin, pauseLengthMax, batchSize; | ||||||
|   const getBatchDelay = () => Math.floor(Math.random() * (10000 - 5000 + 1)) + 5000; |    | ||||||
|   const BATCH_SIZE = 10; |   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)); | ||||||
|  |   }; | ||||||
|  |    | ||||||
|  |   const getReadingDelay = () => Math.floor(Math.random() * 3000) + 1000; | ||||||
|  |  | ||||||
|   try { |   try { | ||||||
|     let remainingMessages = deleteCount; |     console.log(`[DELETE] Starting deletion of up to ${deleteCount} messages with ${speed} speed`); | ||||||
|  |     let deletedCount = 0; | ||||||
|     while (remainingMessages > 0 && !cancelDelete) { |     let batchCount = 0; | ||||||
|       const fetchLimit = Math.min(remainingMessages, BATCH_SIZE); |      | ||||||
|       const messages = await message.channel.messages.fetch({ limit: fetchLimit + 1 }); |     while (deletedCount < deleteCount && !cancelDelete) { | ||||||
|  |       if (deletedCount > 0 && deletedCount % 25 === 0) { | ||||||
|       const filteredMessages = messages.filter(msg => msg.author.id === message.author.id); |         console.log(`[DELETE] Progress: ${deletedCount}/${deleteCount} messages deleted`); | ||||||
|  |       } | ||||||
|  |        | ||||||
|  |       const fetchLimit = Math.min(deleteCount - deletedCount, batchSize); | ||||||
|  |       const messages = await message.channel.messages.fetch({ limit: 100 }); | ||||||
|  |        | ||||||
|  |       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; | ||||||
|  |        | ||||||
|       for (const msg of filteredMessages.values()) { |       for (const msg of filteredMessages.values()) { | ||||||
|         if (cancelDelete) return; |         if (cancelDelete) { | ||||||
|  |           console.log(`[DELETE] Operation canceled by user`); | ||||||
|  |           return; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         if (deletedCount >= deleteCount) break; | ||||||
|  |          | ||||||
|         try { |         try { | ||||||
|           if (msg.deletable && !msg.deleted) { |           if (msg.deletable && !msg.deleted && !deletedMessages.has(msg.id)) { | ||||||
|             const delay = getRandomDelay(); |             if (Math.random() < 0.25) { | ||||||
|             await new Promise(resolve => setTimeout(resolve, delay)); |               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)); | ||||||
|  |              | ||||||
|             await msg.delete().catch(err => { |             await msg.delete().catch(err => { | ||||||
|               if (err.code !== 10008) { |               if (err.code === 10008) { | ||||||
|                 console.error('Failed to delete message:', err); |                 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); | ||||||
|               } |               } | ||||||
|             }); |             }); | ||||||
|  |              | ||||||
|  |             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)); | ||||||
|           } |           } | ||||||
|         } catch (error) { |         } catch (error) { | ||||||
|           console.error('Error deleting message:', error); |           console.error('[DELETE] Error deleting message:', error); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  |        | ||||||
|       remainingMessages -= filteredMessages.size; |       if (messagesInThisBatch === 0) { | ||||||
|  |         console.log(`[DELETE] No deletable messages found in batch`); | ||||||
|       if (remainingMessages > 0 && !cancelDelete) { |         break; | ||||||
|         const batchDelay = getBatchDelay(); |       } | ||||||
|         await new Promise(resolve => setTimeout(resolve, batchDelay)); |        | ||||||
|  |       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)); | ||||||
|  |           batchCount = 0; | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |      | ||||||
|  |     if (cancelDelete) { | ||||||
|  |       await sendCommandResponse(message, `Delete operation canceled after removing ${deletedCount} messages.`, deleteTimeout, true); | ||||||
|  |     } else { | ||||||
|  |       await sendCommandResponse(message, `Finished deleting ${deletedCount} messages.`, deleteTimeout, true); | ||||||
|  |     } | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     console.error('Failed to delete messages:', error); |     console.error('[DELETE] Failed to delete messages:', error); | ||||||
|     const errorMsg = await message.channel.send('There was an error while trying to delete messages.'); |     await sendCommandResponse(message, 'There was an error while trying to delete messages.', deleteTimeout, true); | ||||||
|     setTimeout(() => errorMsg.delete().catch(console.error), deleteTimeout); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| async function deleteMessagesFromServer(message, guildId, deleteTimeout) { | async function deleteMessagesFromServer(message, guildId, deleteTimeout, speed = 'medium') { | ||||||
|   const guild = message.client.guilds.cache.get(guildId); |   const guild = message.client.guilds.cache.get(guildId); | ||||||
|  |  | ||||||
|   if (!guild) { |   if (!guild) { | ||||||
|     const errorMsg = await message.channel.send('I am not in the server with the specified ID.'); |     await sendCommandResponse(message, `Guild with ID ${guildId} not found.`, deleteTimeout, true); | ||||||
|     setTimeout(() => errorMsg.delete().catch(console.error), deleteTimeout); |  | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |    | ||||||
|  |   let deleteIntervalMin, deleteIntervalMax, jitterFactor, pauseChance, pauseLengthMin, pauseLengthMax, batchSize; | ||||||
|  |    | ||||||
|  |   switch(speed) { | ||||||
|  |     case 'slow': | ||||||
|  |       deleteIntervalMin = 3000; | ||||||
|  |       deleteIntervalMax = 6000; | ||||||
|  |       jitterFactor = 0.5; | ||||||
|  |       pauseChance = 0.4; | ||||||
|  |       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)); | ||||||
|  |   }; | ||||||
|  |  | ||||||
|   const getRandomDelay = () => Math.floor(Math.random() * (3000 - 1000 + 1)) + 1000; |   console.log(`[DELETE] Starting server-wide deletion in server: ${guild.name}`); | ||||||
|   const getBatchDelay = () => Math.floor(Math.random() * (10000 - 5000 + 1)) + 5000; |   let totalDeleted = 0; | ||||||
|   const BATCH_SIZE = 10; |  | ||||||
|  |  | ||||||
|   try { |   try { | ||||||
|     const channels = guild.channels.cache.filter(channel => channel.isText()); |     const channels = guild.channels.cache.filter(channel => channel.isText()); | ||||||
|  |     let processedChannels = 0; | ||||||
|  |      | ||||||
|     for (const [channelId, channel] of channels) { |     for (const [channelId, channel] of channels) { | ||||||
|       if (cancelDelete) return; |       if (cancelDelete) { | ||||||
|  |         console.log(`[DELETE] Operation canceled by user`); | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |        | ||||||
|  |       processedChannels++; | ||||||
|  |       console.log(`[DELETE] Processing channel ${processedChannels}/${channels.size}: ${channel.name}`); | ||||||
|  |        | ||||||
|       let hasMoreMessages = true; |       let hasMoreMessages = true; | ||||||
|  |       let messagesDeletedInChannel = 0; | ||||||
|  |       let batchCount = 0; | ||||||
|  |        | ||||||
|       while (hasMoreMessages && !cancelDelete) { |       while (hasMoreMessages && !cancelDelete) { | ||||||
|         const messages = await channel.messages.fetch({ limit: BATCH_SIZE }); |         const messages = await channel.messages.fetch({ limit: 100 }); | ||||||
|  |  | ||||||
|         if (messages.size === 0) { |         if (messages.size === 0) { | ||||||
|           hasMoreMessages = false; |           hasMoreMessages = false; | ||||||
|           continue; |           continue; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         const filteredMessages = messages.filter(msg => msg.author.id === message.author.id); |         const filteredMessages = messages.filter(msg =>  | ||||||
|         for (const msg of filteredMessages.values()) { |           msg.author.id === message.author.id &&  | ||||||
|           if (cancelDelete) return; |           !deletedMessages.has(msg.id) | ||||||
|           try { |         ); | ||||||
|             if (msg.deletable && !msg.deleted) { |          | ||||||
|               const delay = getRandomDelay(); |         if (filteredMessages.size === 0) { | ||||||
|               await new Promise(resolve => setTimeout(resolve, delay)); |           hasMoreMessages = false; | ||||||
|               await msg.delete().catch(err => { |           continue; | ||||||
|                 if (err.code !== 10008) { |  | ||||||
|                   console.error('Failed to delete message:', err); |  | ||||||
|                 } |  | ||||||
|               }); |  | ||||||
|             } |  | ||||||
|           } catch (error) { |  | ||||||
|             console.error('Error deleting message:', error); |  | ||||||
|           } |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (filteredMessages.size < BATCH_SIZE) { |         batchCount++; | ||||||
|  |         let messagesInThisBatch = 0; | ||||||
|  |          | ||||||
|  |         for (const msg of filteredMessages.values()) { | ||||||
|  |           if (cancelDelete) return; | ||||||
|  |            | ||||||
|  |           try { | ||||||
|  |             if (msg.deletable && !msg.deleted && !deletedMessages.has(msg.id)) { | ||||||
|  |               const preDeleteDelay = Math.floor(Math.random() * 1000) + 250; | ||||||
|  |               await new Promise(resolve => setTimeout(resolve, preDeleteDelay)); | ||||||
|  |                | ||||||
|  |               await msg.delete().catch(err => { | ||||||
|  |                 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); | ||||||
|  |                 } | ||||||
|  |               }); | ||||||
|  |                | ||||||
|  |               deletedMessages.add(msg.id); | ||||||
|  |               totalDeleted++; | ||||||
|  |               messagesDeletedInChannel++; | ||||||
|  |               messagesInThisBatch++; | ||||||
|  |                | ||||||
|  |               const delay = getHumanlikeDelay(); | ||||||
|  |               await new Promise(resolve => setTimeout(resolve, delay)); | ||||||
|  |             } | ||||||
|  |           } catch (error) { | ||||||
|  |             console.error('[DELETE] Error deleting message:', error); | ||||||
|  |           } | ||||||
|  |            | ||||||
|  |           if (messagesInThisBatch >= batchSize) break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (messagesInThisBatch < batchSize) { | ||||||
|           hasMoreMessages = false; |           hasMoreMessages = false; | ||||||
|         } else { |         } else { | ||||||
|           const batchDelay = getBatchDelay(); |           const shouldPause = Math.random() < pauseChance; | ||||||
|           await new Promise(resolve => setTimeout(resolve, batchDelay)); |           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)); | ||||||
|  |           } | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  |        | ||||||
|  |       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) { | ||||||
|  |       await sendCommandResponse(message, `Delete operation canceled after removing ${totalDeleted} messages across ${processedChannels} channels.`, deleteTimeout, true); | ||||||
|  |     } else { | ||||||
|  |       await sendCommandResponse(message, `Finished cleaning up ${guild.name}: ${totalDeleted} messages deleted across ${processedChannels} channels.`, deleteTimeout, true); | ||||||
|     } |     } | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     console.error('Failed to delete messages in the server:', error); |     console.error('[DELETE] Failed to delete messages in the server:', error); | ||||||
|     const errorMsg = await message.channel.send('There was an error while trying to delete messages from the server.'); |     await sendCommandResponse(message, 'There was an error while trying to delete messages from the server.', deleteTimeout, true); | ||||||
|     setTimeout(() => errorMsg.delete().catch(console.error), deleteTimeout); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
							
								
								
									
										159
									
								
								commands/groupadd.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								commands/groupadd.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,159 @@ | |||||||
|  | let targetUserIds = new Set(); | ||||||
|  | let isActive = false; | ||||||
|  | let channelToWatch = null; | ||||||
|  | let lastAddTimes = new Map(); | ||||||
|  | let failedAttempts = new Map(); | ||||||
|  | let recentAdds = new Map(); | ||||||
|  | const { sendCommandResponse } = require('../utils/messageUtils'); | ||||||
|  |  | ||||||
|  | const getBackoffDelay = (userId) => { | ||||||
|  |     const attempts = failedAttempts.get(userId) || 0; | ||||||
|  |      | ||||||
|  |     if (attempts <= 1) return 2000; | ||||||
|  |     if (attempts <= 3) return 4000; | ||||||
|  |     if (attempts <= 5) return 7000; | ||||||
|  |     if (attempts <= 10) return 15000; | ||||||
|  |     return 30000; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const getAddDelay = () => { | ||||||
|  |     const baseDelay = Math.floor(Math.random() * 700) + 800; | ||||||
|  |     const jitter = Math.floor(Math.random() * 300) - 150; | ||||||
|  |     return Math.max(500, baseDelay + jitter); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | module.exports = { | ||||||
|  |     name: 'groupadd', | ||||||
|  |     description: 'Automatically re-adds users to group when they leave.', | ||||||
|  |     async execute(message, args, deleteTimeout) { | ||||||
|  |         const { extractUserId } = require('../utils/userUtils'); | ||||||
|  |          | ||||||
|  |         if (message.channel.type !== 'GROUP_DM') { | ||||||
|  |             await sendCommandResponse(message, 'This command only works in group DMs.', deleteTimeout, true); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (args[0]?.toLowerCase() === 'stop') { | ||||||
|  |             isActive = false; | ||||||
|  |             targetUserIds.clear(); | ||||||
|  |             lastAddTimes.clear(); | ||||||
|  |             failedAttempts.clear(); | ||||||
|  |             recentAdds.clear(); | ||||||
|  |             channelToWatch = null; | ||||||
|  |             console.log('[GROUPADD] System deactivated'); | ||||||
|  |  | ||||||
|  |             await sendCommandResponse(message, 'Group auto-add deactivated.', deleteTimeout, true); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const validIds = args | ||||||
|  |             .map(arg => extractUserId(arg)) | ||||||
|  |             .filter(id => id !== null); | ||||||
|  |              | ||||||
|  |         if (validIds.length === 0) { | ||||||
|  |             await sendCommandResponse(message, 'Please provide at least one valid user ID or @mention.', deleteTimeout, true); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         channelToWatch = message.channel; | ||||||
|  |         targetUserIds = new Set(validIds); | ||||||
|  |         isActive = true; | ||||||
|  |         failedAttempts.clear(); | ||||||
|  |         recentAdds.clear(); | ||||||
|  |  | ||||||
|  |         console.log(`[GROUPADD] System activated - Targeting users: ${Array.from(targetUserIds).join(', ')}`); | ||||||
|  |  | ||||||
|  |         for (const userId of targetUserIds) { | ||||||
|  |             try { | ||||||
|  |                 if (!channelToWatch.recipients.has(userId)) { | ||||||
|  |                     console.log(`[GROUPADD] Target ${userId} not in group, attempting initial add`); | ||||||
|  |                      | ||||||
|  |                     const initialDelay = Math.floor(Math.random() * 500) + 300; | ||||||
|  |                     await new Promise(resolve => setTimeout(resolve, initialDelay)); | ||||||
|  |                      | ||||||
|  |                     await channelToWatch.addUser(userId); | ||||||
|  |                     lastAddTimes.set(userId, Date.now()); | ||||||
|  |                     recentAdds.set(userId, true); | ||||||
|  |                      | ||||||
|  |                     setTimeout(() => { | ||||||
|  |                         recentAdds.delete(userId); | ||||||
|  |                     }, 10000); | ||||||
|  |                      | ||||||
|  |                     console.log(`[GROUPADD] Initial add successful for ${userId}`); | ||||||
|  |                 } | ||||||
|  |             } catch (error) { | ||||||
|  |                 console.log(`[GROUPADD] Initial add failed for ${userId}:`, error); | ||||||
|  |                 failedAttempts.set(userId, (failedAttempts.get(userId) || 0) + 1); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const handleRecipientRemove = async (channel, user) => { | ||||||
|  |             if (!isActive || channel.id !== channelToWatch.id || !targetUserIds.has(user.id)) return; | ||||||
|  |  | ||||||
|  |             const currentTime = Date.now(); | ||||||
|  |             const lastAddTime = lastAddTimes.get(user.id) || 0; | ||||||
|  |             const timeSinceLastAdd = currentTime - lastAddTime; | ||||||
|  |              | ||||||
|  |             const isRecentlyAdded = recentAdds.has(user.id); | ||||||
|  |             const failCount = failedAttempts.get(user.id) || 0; | ||||||
|  |  | ||||||
|  |             console.log(`[GROUPADD] User ${user.id} left. Time since last add: ${timeSinceLastAdd}ms, Recent add: ${isRecentlyAdded}, Failed attempts: ${failCount}`); | ||||||
|  |              | ||||||
|  |             if (isRecentlyAdded) { | ||||||
|  |                 console.log(`[GROUPADD] User ${user.id} was recently added and left immediately. Waiting longer.`); | ||||||
|  |                 await new Promise(resolve => setTimeout(resolve, 5000 + Math.random() * 5000)); | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             if (timeSinceLastAdd < 2000) { | ||||||
|  |                 const backoffTime = getBackoffDelay(user.id); | ||||||
|  |                 console.log(`[GROUPADD] Rate limiting for ${user.id}, waiting ${backoffTime}ms...`); | ||||||
|  |                 await new Promise(resolve => setTimeout(resolve, backoffTime)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             const addDelay = getAddDelay(); | ||||||
|  |             console.log(`[GROUPADD] Will readd user ${user.id} after ${addDelay}ms`); | ||||||
|  |              | ||||||
|  |             await new Promise(resolve => setTimeout(resolve, addDelay)); | ||||||
|  |              | ||||||
|  |             if (!isActive) { | ||||||
|  |                 console.log(`[GROUPADD] Command was deactivated during delay, cancelling re-add for ${user.id}`); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             try { | ||||||
|  |                 await channel.addUser(user.id); | ||||||
|  |                 lastAddTimes.set(user.id, Date.now()); | ||||||
|  |                 recentAdds.set(user.id, true); | ||||||
|  |                  | ||||||
|  |                 setTimeout(() => { | ||||||
|  |                     recentAdds.delete(user.id); | ||||||
|  |                 }, 10000); | ||||||
|  |                  | ||||||
|  |                 console.log(`[GROUPADD] Successfully re-added user ${user.id}`); | ||||||
|  |                  | ||||||
|  |                 if (failedAttempts.get(user.id) > 0) { | ||||||
|  |                     failedAttempts.set(user.id, Math.max(0, failedAttempts.get(user.id) - 1)); | ||||||
|  |                 } | ||||||
|  |             } catch (error) { | ||||||
|  |                 console.log(`[GROUPADD] Failed to re-add user ${user.id}:`, error); | ||||||
|  |                 failedAttempts.set(user.id, (failedAttempts.get(user.id) || 0) + 1); | ||||||
|  |                  | ||||||
|  |                 if (Math.random() < 0.4 && timeSinceLastAdd > 5000) { | ||||||
|  |                     console.log(`[GROUPADD] Will try again after a pause`); | ||||||
|  |                     setTimeout(() => { | ||||||
|  |                         if (isActive && !channel.recipients.has(user.id)) { | ||||||
|  |                             channel.addUser(user.id).catch(e =>  | ||||||
|  |                                 console.log(`[GROUPADD] Retry failed for ${user.id}:`, e) | ||||||
|  |                             ); | ||||||
|  |                         } | ||||||
|  |                     }, 3000 + Math.random() * 2000); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         message.client.on('channelRecipientRemove', handleRecipientRemove); | ||||||
|  |  | ||||||
|  |         const targetCount = targetUserIds.size; | ||||||
|  |         await sendCommandResponse(message, `Now watching for ${targetCount} user${targetCount > 1 ? 's' : ''} to leave the group.`, deleteTimeout, true); | ||||||
|  |     }, | ||||||
|  | }; | ||||||
| @@ -1,7 +1,9 @@ | |||||||
|  | const { sendCommandResponse } = require('../utils/messageUtils'); | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|   name: 'help', |   name: 'help', | ||||||
|   description: 'List all of my commands or info about a specific command.', |   description: 'List all of my commands or info about a specific command.', | ||||||
|   execute(message, args, deleteTimeout) { |   async execute(message, args, deleteTimeout) { | ||||||
|     let reply = '```'; |     let reply = '```'; | ||||||
|     reply += 'Here are the available commands:\n\n'; |     reply += 'Here are the available commands:\n\n'; | ||||||
|  |  | ||||||
| @@ -12,9 +14,7 @@ module.exports = { | |||||||
|  |  | ||||||
|     reply += '```'; |     reply += '```'; | ||||||
|  |  | ||||||
|     message.channel.send(reply).then(sentMessage => { |     await sendCommandResponse(message, reply, deleteTimeout, false); | ||||||
|       setTimeout(() => sentMessage.delete().catch(console.error), deleteTimeout); |  | ||||||
|     }); |  | ||||||
|   }, |   }, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										98
									
								
								commands/ip.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								commands/ip.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | |||||||
|  | let vpnRangesCache = null; | ||||||
|  | const { sendCommandResponse } = require('../utils/messageUtils'); | ||||||
|  |  | ||||||
|  | function ipToInt(ip) { | ||||||
|  |     return ip.split('.').reduce((acc, oct) => (acc << 8) + parseInt(oct, 10), 0) >>> 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function cidrContains(cidr, ip) { | ||||||
|  |     const [range, bitsStr] = cidr.split('/'); | ||||||
|  |     const bits = parseInt(bitsStr, 10); | ||||||
|  |     const ipInt = ipToInt(ip); | ||||||
|  |     const rangeInt = ipToInt(range); | ||||||
|  |     const mask = ~(2 ** (32 - bits) - 1) >>> 0; | ||||||
|  |     return (ipInt & mask) === (rangeInt & mask); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function isVpnIp(ip) { | ||||||
|  |     if (!vpnRangesCache) return false; | ||||||
|  |     for (const cidr of vpnRangesCache) { | ||||||
|  |         if (cidrContains(cidr, ip)) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function isValidIp(ip) { | ||||||
|  |     const ipRegex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; | ||||||
|  |     return ipRegex.test(ip); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module.exports = { | ||||||
|  |     name: 'ip', | ||||||
|  |     description: 'Fetches IP info and checks if the IP is a VPN. Usage: .ip [ip_address]', | ||||||
|  |     async execute(message, args, deleteTimeout) { | ||||||
|  |         const { default: fetch } = await import('node-fetch'); | ||||||
|  |         try { | ||||||
|  |             let targetIp; | ||||||
|  |              | ||||||
|  |             if (args.length > 0) { | ||||||
|  |                 targetIp = args[0]; | ||||||
|  |                 if (!isValidIp(targetIp)) { | ||||||
|  |                     await sendCommandResponse(message, "Invalid IP address format. Please use format: x.x.x.x", deleteTimeout, true); | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 const ipRes = await fetch('http://ip-api.com/json/'); | ||||||
|  |                 const data = await ipRes.json(); | ||||||
|  |                 targetIp = data.query; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (!vpnRangesCache) { | ||||||
|  |                 const vpnRes = await fetch('https://raw.githubusercontent.com/X4BNet/lists_vpn/main/ipv4.txt'); | ||||||
|  |                 const vpnText = await vpnRes.text(); | ||||||
|  |                 vpnRangesCache = vpnText.split('\n').map(line => line.trim()).filter(line => line); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             const ipRes = await fetch(`http://ip-api.com/json/${targetIp}`); | ||||||
|  |             const data = await ipRes.json(); | ||||||
|  |  | ||||||
|  |             if (data.status === 'fail') { | ||||||
|  |                 await sendCommandResponse(message, `Error: ${data.message}`, deleteTimeout, true); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             const ip = data.query || "Unknown"; | ||||||
|  |             const vpnCheck = isVpnIp(ip); | ||||||
|  |  | ||||||
|  |             const hostname = data.hostname || "Unknown"; | ||||||
|  |             const city = data.city || "Unknown"; | ||||||
|  |             const region = data.regionName || "Unknown"; | ||||||
|  |             const country = data.country || "Unknown"; | ||||||
|  |             const timezone = data.timezone || "Unknown"; | ||||||
|  |             const zip = data.zip || "Unknown"; | ||||||
|  |             const isp = data.isp || "Unknown"; | ||||||
|  |             const org = data.org || "Unknown"; | ||||||
|  |             const as = data.as || "Unknown"; | ||||||
|  |  | ||||||
|  |             const output = | ||||||
|  |                 `IP: ${ip} | ||||||
|  | Hostname: ${hostname} | ||||||
|  | City: ${city} | ||||||
|  | Region: ${region} | ||||||
|  | Country: ${country} | ||||||
|  | Time Zone: ${timezone} | ||||||
|  | ZIP: ${zip} | ||||||
|  | ISP: ${isp} | ||||||
|  | Organization: ${org} | ||||||
|  | AS: ${as} | ||||||
|  | VPN: ${vpnCheck ? "True" : "False"}`; | ||||||
|  |  | ||||||
|  |             await sendCommandResponse(message, `\`\`\`\n${output}\n\`\`\``, 30000, true); | ||||||
|  |         } catch (error) { | ||||||
|  |             console.error("Error fetching IP info:", error); | ||||||
|  |             await sendCommandResponse(message, "Error fetching IP info.", deleteTimeout, true); | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  | }; | ||||||
| @@ -1,163 +1,268 @@ | |||||||
| let targetUserId = null; | const { extractUserId } = require('../utils/userUtils'); | ||||||
| let isKickActive = false; | const { sendCommandResponse } = require('../utils/messageUtils'); | ||||||
| let voiceStateHandler = null; |  | ||||||
| let lastKickTime = 0; |  | ||||||
| let consecutiveKicks = 0; |  | ||||||
| let cooldownTime = 0; |  | ||||||
| let checkInterval = null; |  | ||||||
|  |  | ||||||
| const getRandomDelay = () => { | let activeKicks = new Map(); | ||||||
|     return Math.floor(Math.random() * 250) + 100; | let cooldowns = new Map(); | ||||||
|  | let voiceStateUpdateHandlers = new Map(); | ||||||
|  | let checkIntervals = new Map(); | ||||||
|  |  | ||||||
|  | const getKickDelay = () => { | ||||||
|  |     const baseDelay = Math.floor(Math.random() * 400) + 600; | ||||||
|  |     const jitter = Math.floor(Math.random() * 200) - 100; | ||||||
|  |     return Math.max(400, baseDelay + jitter); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| const getRandomCheckDelay = () => { | const calculateCooldown = (kickCount) => { | ||||||
|     return Math.floor(Math.random() * 250) + 200; |     if (kickCount <= 2) return 0; | ||||||
|  |     if (kickCount <= 5) return Math.min((kickCount - 2) * 300, 900); | ||||||
|  |     if (kickCount <= 10) return Math.min(900 + (kickCount - 5) * 400, 2900); | ||||||
|  |     return Math.min(2900 + (kickCount - 10) * 500, 5000); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| const getCooldown = (kicks) => { | const getSafetyPause = () => { | ||||||
|     if (kicks <= 3) return 200; |     if (Math.random() < 0.25) { | ||||||
|     if (kicks <= 5) return 500; |         return Math.floor(Math.random() * 4000) + 3000; | ||||||
|     if (kicks <= 10) return 1000; |     } | ||||||
|     return 2000; |     return 0; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const performUserKick = async (userId, guild, voiceChannel, kickData) => { | ||||||
|  |     if (!activeKicks.has(userId)) return false; | ||||||
|  |      | ||||||
|  |     try { | ||||||
|  |         const member = guild.members.cache.get(userId); | ||||||
|  |         if (!member || !member.voice.channelId) return false; | ||||||
|  |          | ||||||
|  |         console.log(`[KICKVC] Found user ${userId} in VC: ${voiceChannel.name}`); | ||||||
|  |          | ||||||
|  |         const currentTime = Date.now(); | ||||||
|  |         const lastKickTime = kickData.lastKick; | ||||||
|  |         const timeSinceLastKick = currentTime - lastKickTime; | ||||||
|  |          | ||||||
|  |         let cooldownTime = cooldowns.get(userId) || 0; | ||||||
|  |          | ||||||
|  |         if (timeSinceLastKick < 3000) { | ||||||
|  |             cooldownTime = calculateCooldown(kickData.count); | ||||||
|  |             cooldowns.set(userId, cooldownTime); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         if (cooldownTime > 0) { | ||||||
|  |             console.log(`[KICKVC] Cooldown active for ${userId}: ${cooldownTime}ms`); | ||||||
|  |             await new Promise(resolve => setTimeout(resolve, cooldownTime)); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         const safetyPause = getSafetyPause(); | ||||||
|  |         if (safetyPause > 0) { | ||||||
|  |             console.log(`[KICKVC] Adding safety pause of ${safetyPause}ms before kicking ${userId}`); | ||||||
|  |             await new Promise(resolve => setTimeout(resolve, safetyPause)); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         const delay = getKickDelay(); | ||||||
|  |         console.log(`[KICKVC] Will kick ${userId} after ${delay}ms delay`); | ||||||
|  |          | ||||||
|  |         await new Promise(resolve => setTimeout(resolve, delay)); | ||||||
|  |          | ||||||
|  |         if (!activeKicks.has(userId)) { | ||||||
|  |             console.log(`[KICKVC] Kick for ${userId} was stopped during delay`); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         if (member && member.voice.channelId) { | ||||||
|  |             await member.voice.disconnect(); | ||||||
|  |              | ||||||
|  |             kickData.count++; | ||||||
|  |             kickData.lastKick = Date.now(); | ||||||
|  |             activeKicks.set(userId, kickData); | ||||||
|  |              | ||||||
|  |             console.log(`[KICKVC] Successfully kicked ${userId} (${kickData.count} kicks so far)`); | ||||||
|  |              | ||||||
|  |             if (kickData.count % 5 === 0) { | ||||||
|  |                 cooldowns.set(userId, calculateCooldown(kickData.count) + 2000); | ||||||
|  |                 console.log(`[KICKVC] Increased cooldown after ${kickData.count} kicks`); | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         return false; | ||||||
|  |     } catch (error) { | ||||||
|  |         console.log(`[KICKVC] Failed to kick ${userId}:`, error); | ||||||
|  |          | ||||||
|  |         if (Math.random() < 0.3 && kickData.count > 0) { | ||||||
|  |             setTimeout(() => { | ||||||
|  |                 try { | ||||||
|  |                     const member = guild.members.cache.get(userId); | ||||||
|  |                     if (member && member.voice.channelId) { | ||||||
|  |                         member.voice.disconnect().catch(e =>  | ||||||
|  |                             console.log(`[KICKVC] Retry failed for ${userId}:`, e) | ||||||
|  |                         ); | ||||||
|  |                     } | ||||||
|  |                 } catch (retryError) { | ||||||
|  |                     console.log(`[KICKVC] Retry setup failed for ${userId}:`, retryError); | ||||||
|  |                 } | ||||||
|  |             }, 2000 + Math.random() * 1000); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|     name: 'kickvc', |     name: 'kickvc', | ||||||
|     description: 'Automatically kicks a specified user from voice channels.', |     description: 'Automatically kicks specified users from voice channels.', | ||||||
|     async execute(message, args, deleteTimeout) { |     async execute(message, args, deleteTimeout) { | ||||||
|         if (args[0]?.toLowerCase() === 'stop') { |         if (args.length === 0) { | ||||||
|             if (voiceStateHandler) { |             await sendCommandResponse(message, 'Please provide a command: `start <userId(s)>` or `stop <userId or "all">`', deleteTimeout, true); | ||||||
|                 message.client.removeListener('voiceStateUpdate', voiceStateHandler); |  | ||||||
|                 voiceStateHandler = null; |  | ||||||
|             } |  | ||||||
|             if (checkInterval) { |  | ||||||
|                 clearInterval(checkInterval); |  | ||||||
|                 checkInterval = null; |  | ||||||
|             } |  | ||||||
|             isKickActive = false; |  | ||||||
|             targetUserId = null; |  | ||||||
|             lastKickTime = 0; |  | ||||||
|             consecutiveKicks = 0; |  | ||||||
|             cooldownTime = 0; |  | ||||||
|              |  | ||||||
|             console.log('[KICKVC] System deactivated - all variables reset'); |  | ||||||
|             message.channel.send('Voice kick has been deactivated.') |  | ||||||
|                 .then(msg => setTimeout(() => msg.delete().catch(console.error), deleteTimeout)); |  | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         const userId = args[0]; |         const command = args[0].toLowerCase(); | ||||||
|         if (!userId || !/^\d{17,19}$/.test(userId)) { |  | ||||||
|             message.channel.send('Please provide a valid user ID.') |  | ||||||
|                 .then(msg => setTimeout(() => msg.delete().catch(console.error), deleteTimeout)); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         targetUserId = userId; |         if (command === 'stop') { | ||||||
|         isKickActive = true; |             if (args.length < 2) { | ||||||
|         console.log(`[KICKVC] System activated - Targeting user ID: ${userId}`); |                 await sendCommandResponse(message, 'Please specify a user ID or "all" to stop kicking.', deleteTimeout, true); | ||||||
|  |  | ||||||
|         if (voiceStateHandler) { |  | ||||||
|             message.client.removeListener('voiceStateUpdate', voiceStateHandler); |  | ||||||
|         } |  | ||||||
|         if (checkInterval) { |  | ||||||
|             clearInterval(checkInterval); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         const kickUser = async (member, guild, fromEvent = false) => { |  | ||||||
|             if (!isKickActive) return; |  | ||||||
|  |  | ||||||
|             const currentTime = Date.now(); |  | ||||||
|             const timeSinceLastKick = currentTime - lastKickTime; |  | ||||||
|  |  | ||||||
|             if (timeSinceLastKick < cooldownTime) { |  | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             try { |             const target = args[1].toLowerCase(); | ||||||
|                 const delay = fromEvent ? getRandomDelay() : getRandomCheckDelay(); |              | ||||||
|                 await new Promise(resolve => setTimeout(resolve, delay)); |             if (target === 'all') { | ||||||
|  |                 for (const [userId, handler] of voiceStateUpdateHandlers.entries()) { | ||||||
|                 if (!member.voice.channel) return; |                     message.client.off('voiceStateUpdate', handler); | ||||||
|  |                     activeKicks.delete(userId); | ||||||
|                 console.log(`[KICKVC] Target in voice: ${member.user.tag} | ${guild.name} | ${member.voice.channel.name}`); |                     cooldowns.delete(userId); | ||||||
|  |                     clearInterval(checkIntervals.get(userId)); | ||||||
|  |                     checkIntervals.delete(userId); | ||||||
|  |                     console.log(`[KICKVC] Stopped kicking user: ${userId}`); | ||||||
|  |                 } | ||||||
|  |                 voiceStateUpdateHandlers.clear(); | ||||||
|                  |                  | ||||||
|                 await member.voice.disconnect(); |                 await sendCommandResponse(message, 'Stopped all active VC kicks.', deleteTimeout, true); | ||||||
|                 lastKickTime = currentTime; |                 return; | ||||||
|                 consecutiveKicks++; |             } else { | ||||||
|  |                 const userId = extractUserId(target); | ||||||
|                  |                  | ||||||
|                 cooldownTime = getCooldown(consecutiveKicks); |                 if (!userId) { | ||||||
|  |                     await sendCommandResponse(message, 'Invalid user ID.', deleteTimeout, true); | ||||||
|                 setTimeout(() => { |                     return; | ||||||
|                     if (consecutiveKicks > 0) { |  | ||||||
|                         consecutiveKicks--; |  | ||||||
|                         cooldownTime = getCooldown(consecutiveKicks); |  | ||||||
|                     } |  | ||||||
|                 }, 15000); |  | ||||||
|  |  | ||||||
|             } catch { |  | ||||||
|                 try { |  | ||||||
|                     await member.voice.setChannel(null); |  | ||||||
|                 } catch { |  | ||||||
|                     try { |  | ||||||
|                         await member.voice.channel.permissionOverwrites.create(member, { |  | ||||||
|                             Connect: false, |  | ||||||
|                             Speak: false |  | ||||||
|                         }); |  | ||||||
|                         await member.voice.disconnect(); |  | ||||||
|                     } catch {} |  | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  |                 if (voiceStateUpdateHandlers.has(userId)) { | ||||||
|  |                     message.client.off('voiceStateUpdate', voiceStateUpdateHandlers.get(userId)); | ||||||
|  |                     activeKicks.delete(userId); | ||||||
|  |                     cooldowns.delete(userId); | ||||||
|  |                     clearInterval(checkIntervals.get(userId)); | ||||||
|  |                     checkIntervals.delete(userId); | ||||||
|  |                     console.log(`[KICKVC] Stopped kicking user: ${userId}`); | ||||||
|  |                      | ||||||
|  |                     await sendCommandResponse(message, `Stopped kicking user: ${userId}`, deleteTimeout, true); | ||||||
|  |                 } else { | ||||||
|  |                     await sendCommandResponse(message, `No active kick for user: ${userId}`, deleteTimeout, true); | ||||||
|  |                 } | ||||||
|  |                 return; | ||||||
|             } |             } | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         voiceStateHandler = async (oldState, newState) => { |  | ||||||
|             if (!isKickActive || !targetUserId) return; |  | ||||||
|  |  | ||||||
|             const isTargetUser = newState?.member?.id === targetUserId || oldState?.member?.id === targetUserId; |  | ||||||
|             if (!isTargetUser) return; |  | ||||||
|  |  | ||||||
|             const voiceState = newState?.channelId ? newState : oldState; |  | ||||||
|             if (!voiceState?.channel) return; |  | ||||||
|  |  | ||||||
|             try { |  | ||||||
|                 const guild = voiceState.guild; |  | ||||||
|                 const member = await guild.members.fetch(targetUserId).catch(() => null); |  | ||||||
|                 if (member?.voice?.channel) { |  | ||||||
|                     await kickUser(member, guild, true); |  | ||||||
|                 } |  | ||||||
|             } catch {} |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         const intervalTime = Math.floor(Math.random() * 500) + 1000; |  | ||||||
|         checkInterval = setInterval(async () => { |  | ||||||
|             if (!isKickActive) return; |  | ||||||
|  |  | ||||||
|             for (const guild of message.client.guilds.cache.values()) { |  | ||||||
|                 try { |  | ||||||
|                     const member = await guild.members.fetch(targetUserId).catch(() => null); |  | ||||||
|                     if (member?.voice?.channel) { |  | ||||||
|                         await kickUser(member, guild, false); |  | ||||||
|                     } |  | ||||||
|                 } catch {} |  | ||||||
|             } |  | ||||||
|         }, intervalTime); |  | ||||||
|  |  | ||||||
|         message.client.on('voiceStateUpdate', voiceStateHandler); |  | ||||||
|  |  | ||||||
|         try { |  | ||||||
|             const user = await message.client.users.fetch(userId); |  | ||||||
|             message.channel.send(`Now automatically kicking ${user.tag} (${userId}) from voice channels.`) |  | ||||||
|                 .then(msg => setTimeout(() => msg.delete().catch(console.error), deleteTimeout)); |  | ||||||
|  |  | ||||||
|             message.client.guilds.cache.forEach(async (guild) => { |  | ||||||
|                 const member = await guild.members.fetch(userId).catch(() => null); |  | ||||||
|                 if (member?.voice?.channel) { |  | ||||||
|                     await kickUser(member, guild, true); |  | ||||||
|                 } |  | ||||||
|             }); |  | ||||||
|         } catch { |  | ||||||
|             message.channel.send(`Now automatically kicking user ID ${userId} from voice channels.`) |  | ||||||
|                 .then(msg => setTimeout(() => msg.delete().catch(console.error), deleteTimeout)); |  | ||||||
|         } |         } | ||||||
|     }, |  | ||||||
|  |         if (command === 'start') { | ||||||
|  |             if (args.length < 2) { | ||||||
|  |                 await sendCommandResponse(message, 'Please provide at least one user ID to kick.', deleteTimeout, true); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             const userIds = args.slice(1) | ||||||
|  |                 .map(arg => extractUserId(arg)) | ||||||
|  |                 .filter(id => id !== null); | ||||||
|  |  | ||||||
|  |             if (userIds.length === 0) { | ||||||
|  |                 await sendCommandResponse(message, 'No valid user IDs provided.', deleteTimeout, true); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             const startedKicking = []; | ||||||
|  |             const alreadyKicking = []; | ||||||
|  |  | ||||||
|  |             for (const userId of userIds) { | ||||||
|  |                 if (activeKicks.has(userId)) { | ||||||
|  |                     alreadyKicking.push(userId); | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 activeKicks.set(userId, { count: 0, lastKick: 0 }); | ||||||
|  |                 cooldowns.set(userId, 0); | ||||||
|  |  | ||||||
|  |                 for (const guild of message.client.guilds.cache.values()) { | ||||||
|  |                     try { | ||||||
|  |                         const member = await guild.members.fetch(userId).catch(() => null); | ||||||
|  |                         if (member && member.voice.channelId) { | ||||||
|  |                             const kickData = activeKicks.get(userId); | ||||||
|  |                             console.log(`[KICKVC] Found target ${userId} already in voice in ${guild.name}`); | ||||||
|  |                             performUserKick(userId, guild, member.voice.channel, kickData); | ||||||
|  |                             break; | ||||||
|  |                         } | ||||||
|  |                     } catch (error) { | ||||||
|  |                         console.log(`[KICKVC] Error checking guild ${guild.name} for user ${userId}:`, error); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 const checkInterval = setInterval(async () => { | ||||||
|  |                     if (!activeKicks.has(userId)) { | ||||||
|  |                         clearInterval(checkInterval); | ||||||
|  |                         return; | ||||||
|  |                     } | ||||||
|  |                      | ||||||
|  |                     const kickData = activeKicks.get(userId); | ||||||
|  |                      | ||||||
|  |                     for (const guild of message.client.guilds.cache.values()) { | ||||||
|  |                         try { | ||||||
|  |                             const member = await guild.members.fetch(userId).catch(() => null); | ||||||
|  |                             if (member && member.voice.channelId) { | ||||||
|  |                                 performUserKick(userId, guild, member.voice.channel, kickData); | ||||||
|  |                                 return; | ||||||
|  |                             } | ||||||
|  |                         } catch (error) {} | ||||||
|  |                     } | ||||||
|  |                 }, 4000 + Math.floor(Math.random() * 2000)); | ||||||
|  |                  | ||||||
|  |                 checkIntervals.set(userId, checkInterval); | ||||||
|  |  | ||||||
|  |                 const handleVoiceStateUpdate = async (oldState, newState) => { | ||||||
|  |                     if (!activeKicks.has(userId)) return; | ||||||
|  |                      | ||||||
|  |                     const member = newState.member || oldState.member; | ||||||
|  |                     if (!member || member.user.id !== userId) return; | ||||||
|  |                      | ||||||
|  |                     const kickData = activeKicks.get(userId); | ||||||
|  |                      | ||||||
|  |                     if ((!oldState.channelId && newState.channelId) ||  | ||||||
|  |                         (oldState.channelId !== newState.channelId && newState.channelId)) { | ||||||
|  |                          | ||||||
|  |                         const guild = newState.guild; | ||||||
|  |                         const voiceChannel = newState.channel; | ||||||
|  |                          | ||||||
|  |                         console.log(`[KICKVC] Target user ${userId} joined/moved to VC: ${voiceChannel.name}`); | ||||||
|  |                         performUserKick(userId, guild, voiceChannel, kickData); | ||||||
|  |                     } | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 voiceStateUpdateHandlers.set(userId, handleVoiceStateUpdate); | ||||||
|  |                 message.client.on('voiceStateUpdate', handleVoiceStateUpdate); | ||||||
|  |                 startedKicking.push(userId); | ||||||
|  |                 console.log(`[KICKVC] Started kicking user: ${userId}`); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (startedKicking.length > 0) { | ||||||
|  |                 await sendCommandResponse( | ||||||
|  |                     message, | ||||||
|  |                     `Started kicking: ${startedKicking.join(', ')}${alreadyKicking.length > 0 ? `\nAlready kicking: ${alreadyKicking.join(', ')}` : ''}`, | ||||||
|  |                     deleteTimeout, | ||||||
|  |                     true | ||||||
|  |                 ); | ||||||
|  |             } else if (alreadyKicking.length > 0) { | ||||||
|  |                 await sendCommandResponse(message, `Already kicking: ${alreadyKicking.join(', ')}`, deleteTimeout, true); | ||||||
|  |             } | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         await sendCommandResponse(message, 'Unknown command. Use `start <userId(s)>` or `stop <userId or "all">`.', deleteTimeout, true); | ||||||
|  |     } | ||||||
| }; | }; | ||||||
| @@ -1,88 +0,0 @@ | |||||||
| const { DiscordStreamClient } = require('discord-stream-client'); |  | ||||||
|  |  | ||||||
| module.exports = { |  | ||||||
|   name: 'livestream', |  | ||||||
|   description: 'Starts or stops a live stream in a voice channel with a provided video link.', |  | ||||||
|   async execute(message, args, deleteTimeout) { |  | ||||||
|     if (args[0] === 'stop') { |  | ||||||
|       if (message.client.voiceConnection) { |  | ||||||
|         message.client.voiceConnection.disconnect(); |  | ||||||
|         message.client.voiceConnection = null; |  | ||||||
|  |  | ||||||
|         if (message.client.currentPlayer) { |  | ||||||
|           message.client.currentPlayer.stop(); |  | ||||||
|           message.client.currentPlayer.removeAllListeners('end'); |  | ||||||
|           message.client.currentPlayer = null; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return message.channel.send('Livestream stopped.').then(msg => setTimeout(() => msg.delete().catch(console.error), deleteTimeout)); |  | ||||||
|       } else { |  | ||||||
|         return message.channel.send('No active livestream to stop.').then(msg => setTimeout(() => msg.delete().catch(console.error), deleteTimeout)); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (args.length < 2) { |  | ||||||
|       return message.channel.send('Usage: .livestream <channelId> <videoLink> | .livestream stop') |  | ||||||
|         .then(msg => setTimeout(() => msg.delete().catch(console.error), deleteTimeout)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const channelId = args[0]; |  | ||||||
|     const videoLink = args[1]; |  | ||||||
|     const channel = message.client.channels.cache.get(channelId); |  | ||||||
|      |  | ||||||
|     if (!channel) { |  | ||||||
|       return message.channel.send('Channel not found.') |  | ||||||
|         .then(msg => setTimeout(() => msg.delete().catch(console.error), deleteTimeout)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const voiceState = message.guild.members.me.voice; |  | ||||||
|     if (voiceState.channel) { |  | ||||||
|     	console.log('Already in a voice channel, leaving...'); |  | ||||||
|   	await voiceState.disconnect(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     try { |  | ||||||
|       if (message.client.currentPlayer) { |  | ||||||
|         message.client.currentPlayer.stop(); |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       const connection = await message.client.streamClient.joinVoiceChannel(channel, { |  | ||||||
|         selfDeaf: true, |  | ||||||
|         selfMute: true, |  | ||||||
|         selfVideo: false, |  | ||||||
|       }); |  | ||||||
|  |  | ||||||
|       const stream = await connection.createStream(); |  | ||||||
|       const player = message.client.streamClient.createPlayer(videoLink, stream.udp); |  | ||||||
|       message.client.currentPlayer = player; |  | ||||||
|  |  | ||||||
|       player.on('error', err => console.error(err)); |  | ||||||
|  |  | ||||||
|       const playStream = () => { |  | ||||||
|         player.play(videoLink, { |  | ||||||
|           kbpsVideo: 7000, |  | ||||||
|           fps: 60, |  | ||||||
|           hwaccel: true, |  | ||||||
|           kbpsAudio: 128, |  | ||||||
|           volume: 1, |  | ||||||
|         }); |  | ||||||
|       }; |  | ||||||
|  |  | ||||||
|       player.on('finish', () => { |  | ||||||
|         console.log('Media ended, replaying...'); |  | ||||||
|         playStream(); |  | ||||||
|       }); |  | ||||||
|  |  | ||||||
|       playStream();  |  | ||||||
|  |  | ||||||
|       message.channel.send('Livestream started with the provided video link.') |  | ||||||
|         .then(msg => setTimeout(() => msg.delete().catch(console.error), deleteTimeout)); |  | ||||||
|  |  | ||||||
|     } catch (error) { |  | ||||||
|       console.error(error); |  | ||||||
|       message.channel.send('Failed to start the livestream.') |  | ||||||
|         .then(msg => setTimeout(() => msg.delete().catch(console.error), deleteTimeout)); |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
							
								
								
									
										147
									
								
								commands/react.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										147
									
								
								commands/react.js
									
									
									
									
										vendored
									
									
								
							| @@ -1,22 +1,23 @@ | |||||||
|  | const { sendCommandResponse } = require('../utils/messageUtils'); | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|   name: 'react', |   name: 'react', | ||||||
|   description: `Automatically react with specified emojis to multiple users’ messages, or stop reacting.\n |   description: `Automatically react with specified emojis to multiple users' messages, or stop reacting. Usage: .react [user1,user2,...] [emoji1] [emoji2] ...`, | ||||||
|   Usage: |  | ||||||
|   .react <userID1,userID2,...> <emoji1> <emoji2> ... - React to messages from multiple users with specified emojis.  |  | ||||||
|   Example: \`.react 12345,67890 :smile: :thumbsup:\` |  | ||||||
|   .react stop - Stop reacting to users' messages.`, |  | ||||||
|   async execute(message, args, deleteTimeout) { |   async execute(message, args, deleteTimeout) { | ||||||
|  |     const { processUserInput } = require('../utils/userUtils'); | ||||||
|  |      | ||||||
|     if (args.length === 0) { |     if (args.length === 0) { | ||||||
|       if (message.client.targetReactUserIds && message.client.reactEmojis) { |       if (message.client.targetReactUserIds && message.client.reactEmojis) { | ||||||
|         const statusMsg = await message.channel.send( |         await sendCommandResponse( | ||||||
|  |           message, | ||||||
|           `Currently reacting to messages from the following users: ${message.client.targetReactUserIds |           `Currently reacting to messages from the following users: ${message.client.targetReactUserIds | ||||||
|             .map(id => `<@${id}>`) |             .map(id => `User ID: ${id}`) | ||||||
|             .join(', ')} with the following emojis: ${message.client.reactEmojis.join(' ')}.` |             .join(', ')} with the following emojis: ${message.client.reactEmojis.join(' ')}.`, | ||||||
|  |           deleteTimeout, | ||||||
|  |           false | ||||||
|         ); |         ); | ||||||
|         setTimeout(() => statusMsg.delete().catch(console.error), deleteTimeout); |  | ||||||
|       } else { |       } else { | ||||||
|         const noTargetMsg = await message.channel.send('No active reaction target.'); |         await sendCommandResponse(message, 'No active reaction target.', deleteTimeout, false); | ||||||
|         setTimeout(() => noTargetMsg.delete().catch(console.error), deleteTimeout); |  | ||||||
|       } |       } | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| @@ -28,50 +29,126 @@ module.exports = { | |||||||
|         message.client.targetReactUserIds = null; |         message.client.targetReactUserIds = null; | ||||||
|         message.client.reactEmojis = null; |         message.client.reactEmojis = null; | ||||||
|  |  | ||||||
|         const stopMsg = await message.channel.send('Stopped reacting to messages.'); |         await sendCommandResponse(message, 'Stopped reacting to messages.', deleteTimeout, false); | ||||||
|         setTimeout(() => stopMsg.delete().catch(console.error), deleteTimeout); |  | ||||||
|       } else { |       } else { | ||||||
|         const noActiveReactMsg = await message.channel.send('No active reactions to stop.'); |         await sendCommandResponse(message, 'No active reactions to stop.', deleteTimeout, false); | ||||||
|         setTimeout(() => noActiveReactMsg.delete().catch(console.error), deleteTimeout); |  | ||||||
|       } |       } | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const targetIds = args[0].split(',').map(id => id.trim()); |     // Find where the emojis start | ||||||
|     const emojis = args.slice(1); |     let emojiStartIndex = -1; | ||||||
|  |     for (let i = 0; i < args.length; i++) { | ||||||
|  |       // Check if this argument looks like an emoji (contains : or is a single character) | ||||||
|  |       if (args[i].includes(':') || args[i].length <= 2) { | ||||||
|  |         emojiStartIndex = i; | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (targetIds.length === 0 || emojis.length === 0) { |     if (emojiStartIndex === -1) { | ||||||
|       const errorMsg = await message.channel.send('Please provide valid user IDs and at least one emoji.'); |       await sendCommandResponse(message, 'Please provide at least one emoji to react with.', deleteTimeout, false); | ||||||
|       setTimeout(() => errorMsg.delete().catch(console.error), deleteTimeout); |  | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     message.client.targetReactUserIds = targetIds; |     // All arguments before emojiStartIndex are user IDs | ||||||
|     message.client.reactEmojis = emojis; |     const userInput = args.slice(0, emojiStartIndex).join(' '); | ||||||
|  |     const emojis = args.slice(emojiStartIndex); | ||||||
|  |  | ||||||
|     const confirmationMsg = await message.channel.send( |     console.log(`[REACT] Processing user input: "${userInput}"`); | ||||||
|       `I will now react to messages from the following users: ${targetIds |     const targetIds = processUserInput(userInput); | ||||||
|         .map(id => `<@${id}>`) |     console.log(`[REACT] Extracted user IDs: ${targetIds.join(', ')}`); | ||||||
|         .join(', ')} with the following emojis: ${emojis.join(' ')}.` |      | ||||||
|  |     if (targetIds.length === 0) { | ||||||
|  |       await sendCommandResponse(message, 'Please provide valid user IDs or @mentions. You can use multiple users separated by spaces or commas.', deleteTimeout, false); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Process emojis to handle custom emojis | ||||||
|  |     const processedEmojis = emojis.map(emoji => { | ||||||
|  |       // Check if it's a custom emoji (format: :name:) | ||||||
|  |       const customEmojiMatch = emoji.match(/^:([a-zA-Z0-9_]+):$/); | ||||||
|  |       if (customEmojiMatch) { | ||||||
|  |         // For custom emojis, we need to find the emoji ID from the guild | ||||||
|  |         const emojiName = customEmojiMatch[1]; | ||||||
|  |         const customEmoji = message.guild?.emojis.cache.find(e => e.name === emojiName); | ||||||
|  |         if (customEmoji) { | ||||||
|  |           return customEmoji.id; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       // For standard emojis, just return as is | ||||||
|  |       return emoji; | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     message.client.targetReactUserIds = targetIds; | ||||||
|  |     message.client.reactEmojis = processedEmojis; | ||||||
|  |  | ||||||
|  |     // Create a more detailed confirmation message with a different format | ||||||
|  |     let userListText = ''; | ||||||
|  |     if (targetIds.length === 1) { | ||||||
|  |       userListText = `User ID: ${targetIds[0]}`; | ||||||
|  |     } else { | ||||||
|  |       userListText = targetIds.map((id, index) => `User ID ${index + 1}: ${id}`).join('\n'); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     const confirmationMessage = `I will now react to messages from:\n${userListText}\n\nWith the following emojis: ${emojis.join(' ')}`; | ||||||
|  |      | ||||||
|  |     console.log(`[REACT] Confirmation message: ${confirmationMessage}`); | ||||||
|  |      | ||||||
|  |     await sendCommandResponse( | ||||||
|  |       message, | ||||||
|  |       confirmationMessage, | ||||||
|  |       deleteTimeout, | ||||||
|  |       false | ||||||
|     ); |     ); | ||||||
|     setTimeout(() => confirmationMsg.delete().catch(console.error), deleteTimeout); |  | ||||||
|  |  | ||||||
|     if (message.client.reactListener) { |     if (message.client.reactListener) { | ||||||
|       message.client.off('messageCreate', message.client.reactListener); |       message.client.off('messageCreate', message.client.reactListener); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const getRandomDelay = () => Math.floor(Math.random() * (5000 - 2000 + 1)) + 2000; |     const getHumanizedDelay = () => { | ||||||
|  |       const baseDelay = Math.floor(Math.random() * (3000 - 1000 + 1)) + 1000; | ||||||
|  |       const jitter = Math.floor(Math.random() * 1000) - 500;  | ||||||
|  |       return Math.max(800, baseDelay + jitter); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     message.client.reactListener = async (msg) => { |     message.client.reactListener = async (msg) => { | ||||||
|       if (message.client.targetReactUserIds && message.client.targetReactUserIds.includes(msg.author.id)) { |       if (message.client.targetReactUserIds && message.client.targetReactUserIds.includes(msg.author.id)) { | ||||||
|         for (const emoji of emojis) { |         try { | ||||||
|           try { |           const shouldReact = Math.random() < 0.95;  | ||||||
|             const delay = getRandomDelay(); |            | ||||||
|             await new Promise((resolve) => setTimeout(resolve, delay)); |           if (!shouldReact) { | ||||||
|             await msg.react(emoji); |             console.log(`[REACT] Randomly skipping reaction to message ${msg.id}`); | ||||||
|           } catch (error) { |             return; | ||||||
|             console.error('Failed to react:', error); |  | ||||||
|           } |           } | ||||||
|  |            | ||||||
|  |           const initialDelay = getHumanizedDelay(); | ||||||
|  |           await new Promise(resolve => setTimeout(resolve, initialDelay)); | ||||||
|  |            | ||||||
|  |           for (const emoji of processedEmojis) { | ||||||
|  |             if (Math.random() < 0.05) { | ||||||
|  |               console.log(`[REACT] Skipping emoji ${emoji} for more human-like behavior`); | ||||||
|  |               continue; | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             try { | ||||||
|  |               const reactDelay = getHumanizedDelay(); | ||||||
|  |                | ||||||
|  |               if (Math.random() < 0.08) { | ||||||
|  |                 const extraDelay = Math.floor(Math.random() * 4000) + 1000; | ||||||
|  |                 console.log(`[REACT] Adding ${extraDelay}ms extra delay before reacting with ${emoji}`); | ||||||
|  |                 await new Promise(resolve => setTimeout(resolve, extraDelay)); | ||||||
|  |               } | ||||||
|  |                | ||||||
|  |               await new Promise(resolve => setTimeout(resolve, reactDelay)); | ||||||
|  |               await msg.react(emoji); | ||||||
|  |                | ||||||
|  |             } catch (error) { | ||||||
|  |               console.error(`[REACT] Failed to react with ${emoji}:`, error); | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } catch (error) { | ||||||
|  |           console.error('[REACT] Error in reaction handler:', error); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     }; |     }; | ||||||
|   | |||||||
| @@ -1,22 +1,23 @@ | |||||||
|  | const { sendCommandResponse } = require('../utils/messageUtils'); | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|     name: 'reply', |     name: 'reply', | ||||||
|     description: `Automatically reply with a specified message to multiple users’ messages, or stop replying.\n |     description: `Automatically reply with a specified message to multiple users' messages, or stop replying. Usage: .reply [user1,user2,...] [message]`, | ||||||
|     Usage: |  | ||||||
|     .reply <userID1,userID2,...> <message> - Automatically reply to messages from multiple users with the specified message. |  | ||||||
|     Example: \`.reply 12345,67890 Hello there!\` |  | ||||||
|     .reply stop - Stop replying to users' messages.`, |  | ||||||
|     async execute(message, args, deleteTimeout) { |     async execute(message, args, deleteTimeout) { | ||||||
|  |       const { processUserInput } = require('../utils/userUtils'); | ||||||
|  |        | ||||||
|       if (args.length === 0) { |       if (args.length === 0) { | ||||||
|         if (message.client.targetReplyUserIds && message.client.replyMessage) { |         if (message.client.targetReplyUserIds && message.client.replyMessage) { | ||||||
|           const statusMsg = await message.channel.send( |           await sendCommandResponse( | ||||||
|  |             message, | ||||||
|             `Currently replying to messages from the following users: ${message.client.targetReplyUserIds |             `Currently replying to messages from the following users: ${message.client.targetReplyUserIds | ||||||
|               .map(id => `<@${id}>`) |               .map(id => `User ID: ${id}`) | ||||||
|               .join(', ')} with the message: "${message.client.replyMessage}".` |               .join(', ')} with the message: "${message.client.replyMessage}".`, | ||||||
|  |             deleteTimeout, | ||||||
|  |             false | ||||||
|           ); |           ); | ||||||
|           setTimeout(() => statusMsg.delete().catch(console.error), deleteTimeout); |  | ||||||
|         } else { |         } else { | ||||||
|           const noTargetMsg = await message.channel.send('No active reply target.'); |           await sendCommandResponse(message, 'No active reply target.', deleteTimeout, false); | ||||||
|           setTimeout(() => noTargetMsg.delete().catch(console.error), deleteTimeout); |  | ||||||
|         } |         } | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
| @@ -28,33 +29,62 @@ module.exports = { | |||||||
|           message.client.targetReplyUserIds = null; |           message.client.targetReplyUserIds = null; | ||||||
|           message.client.replyMessage = null; |           message.client.replyMessage = null; | ||||||
|    |    | ||||||
|           const stopMsg = await message.channel.send('Stopped replying to messages.'); |           await sendCommandResponse(message, 'Stopped replying to messages.', deleteTimeout, false); | ||||||
|           setTimeout(() => stopMsg.delete().catch(console.error), deleteTimeout); |  | ||||||
|         } else { |         } else { | ||||||
|           const noActiveReplyMsg = await message.channel.send('No active replies to stop.'); |           await sendCommandResponse(message, 'No active replies to stop.', deleteTimeout, false); | ||||||
|           setTimeout(() => noActiveReplyMsg.delete().catch(console.error), deleteTimeout); |  | ||||||
|         } |         } | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|    |    | ||||||
|       const targetIds = args[0].split(',').map(id => id.trim()); |       // Find where the message starts (after all user IDs) | ||||||
|       const replyMessage = args.slice(1).join(' '); |       let messageStartIndex = -1; | ||||||
|  |       for (let i = 0; i < args.length; i++) { | ||||||
|  |         // If this argument looks like a message (contains spaces or is longer than a user ID) | ||||||
|  |         if (args[i].includes(' ') || args[i].length > 20) { | ||||||
|  |           messageStartIndex = i; | ||||||
|  |           break; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |        | ||||||
|  |       if (messageStartIndex === -1) { | ||||||
|  |         await sendCommandResponse(message, 'Please provide a message to reply with.', deleteTimeout, false); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|    |    | ||||||
|       if (targetIds.length === 0 || !replyMessage) { |       // All arguments before messageStartIndex are user IDs | ||||||
|         const errorMsg = await message.channel.send('Please provide valid user IDs and a message to reply with.'); |       const userInput = args.slice(0, messageStartIndex).join(' '); | ||||||
|         setTimeout(() => errorMsg.delete().catch(console.error), deleteTimeout); |       const replyMessage = args.slice(messageStartIndex).join(' '); | ||||||
|  |    | ||||||
|  |       console.log(`[REPLY] Processing user input: "${userInput}"`); | ||||||
|  |       const targetIds = processUserInput(userInput); | ||||||
|  |       console.log(`[REPLY] Extracted user IDs: ${targetIds.join(', ')}`); | ||||||
|  |        | ||||||
|  |       if (targetIds.length === 0) { | ||||||
|  |         await sendCommandResponse(message, 'Please provide valid user IDs or @mentions. You can use multiple users separated by spaces or commas.', deleteTimeout, false); | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|    |    | ||||||
|       message.client.targetReplyUserIds = targetIds; |       message.client.targetReplyUserIds = targetIds; | ||||||
|       message.client.replyMessage = replyMessage; |       message.client.replyMessage = replyMessage; | ||||||
|    |    | ||||||
|       const confirmationMsg = await message.channel.send( |       // Create a more detailed confirmation message with a different format | ||||||
|         `I will now reply to messages from the following users: ${targetIds |       let userListText = ''; | ||||||
|           .map(id => `<@${id}>`) |       if (targetIds.length === 1) { | ||||||
|           .join(', ')} with the message: "${replyMessage}".` |         userListText = `User ID: ${targetIds[0]}`; | ||||||
|  |       } else { | ||||||
|  |         userListText = targetIds.map((id, index) => `User ID ${index + 1}: ${id}`).join('\n'); | ||||||
|  |       } | ||||||
|  |        | ||||||
|  |       const confirmationMessage = `I will now reply to messages from:\n${userListText}\n\nWith the message: "${replyMessage}"`; | ||||||
|  |        | ||||||
|  |       console.log(`[REPLY] Confirmation message: ${confirmationMessage}`); | ||||||
|  |        | ||||||
|  |       await sendCommandResponse( | ||||||
|  |         message, | ||||||
|  |         confirmationMessage, | ||||||
|  |         deleteTimeout, | ||||||
|  |         false | ||||||
|       ); |       ); | ||||||
|       setTimeout(() => confirmationMsg.delete().catch(console.error), deleteTimeout); |  | ||||||
|    |    | ||||||
|       if (message.client.replyListener) { |       if (message.client.replyListener) { | ||||||
|         message.client.off('messageCreate', message.client.replyListener); |         message.client.off('messageCreate', message.client.replyListener); | ||||||
|   | |||||||
							
								
								
									
										58
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								index.js
									
									
									
									
									
								
							| @@ -1,10 +1,8 @@ | |||||||
| require('dotenv').config(); | require('dotenv').config(); | ||||||
| const { Client } = require('discord.js-selfbot-v13'); | const { Client } = require('discord.js-selfbot-v13'); | ||||||
| const { DiscordStreamClient } = require('discord-stream-client'); |  | ||||||
| const client = new Client(); | const client = new Client(); | ||||||
| const fs = require('fs'); | const fs = require('fs'); | ||||||
|  | const readline = require('readline'); | ||||||
| client.streamClient = new DiscordStreamClient(client); |  | ||||||
|  |  | ||||||
| const PREFIX = process.env.PREFIX || '.'; | const PREFIX = process.env.PREFIX || '.'; | ||||||
| const MESSAGE_DELETE_TIMEOUT = 10000 | const MESSAGE_DELETE_TIMEOUT = 10000 | ||||||
| @@ -18,7 +16,57 @@ for (const file of commandFiles) { | |||||||
| } | } | ||||||
|  |  | ||||||
| client.on('ready', () => { | client.on('ready', () => { | ||||||
|   console.log(`Logged in as ${client.user.tag}!`); |   console.log(`Logged in as ${client.user.tag}! (DZ Loves you 2k25).`); | ||||||
|  |    | ||||||
|  |   const rl = readline.createInterface({ | ||||||
|  |     input: process.stdin, | ||||||
|  |     output: process.stdout, | ||||||
|  |     prompt: `Console > ` | ||||||
|  |   }); | ||||||
|  |    | ||||||
|  |   console.log('Type commands without the prefix to execute them in console mode.'); | ||||||
|  |   console.log('--------------------------------------------------------'); | ||||||
|  |   rl.prompt(); | ||||||
|  |  | ||||||
|  |   rl.on('line', async (line) => { | ||||||
|  |     const input = line.trim(); | ||||||
|  |     if (!input) { | ||||||
|  |       rl.prompt(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const args = input.split(/ +/); | ||||||
|  |     const commandName = args.shift().toLowerCase(); | ||||||
|  |  | ||||||
|  |     if (!client.commands.has(commandName)) { | ||||||
|  |       console.log(`Command not found: ${commandName}`); | ||||||
|  |       rl.prompt(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     try { | ||||||
|  |       const mockMessage = { | ||||||
|  |         author: { id: client.user.id }, | ||||||
|  |         client: client, | ||||||
|  |         channel: { | ||||||
|  |           id: 'console', | ||||||
|  |           send: (content) => { | ||||||
|  |             console.log('\nCommand output:'); | ||||||
|  |             console.log(content); | ||||||
|  |             return Promise.resolve({ delete: () => Promise.resolve() }); | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         delete: () => Promise.resolve() | ||||||
|  |       }; | ||||||
|  |  | ||||||
|  |       console.log(`Executing command: ${commandName}`); | ||||||
|  |       await client.commands.get(commandName).execute(mockMessage, args, MESSAGE_DELETE_TIMEOUT); | ||||||
|  |     } catch (error) { | ||||||
|  |       console.error('Error executing command:', error); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     rl.prompt(); | ||||||
|  |   }); | ||||||
| }); | }); | ||||||
|  |  | ||||||
| client.on('messageCreate', async message => { | client.on('messageCreate', async message => { | ||||||
| @@ -46,4 +94,4 @@ client.on('messageCreate', async message => { | |||||||
|   } |   } | ||||||
| }); | }); | ||||||
|  |  | ||||||
| client.login(process.env.DISCORD_TOKEN); | client.login(process.env.DISCORD_TOKEN); | ||||||
							
								
								
									
										1081
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										1081
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,9 +1,11 @@ | |||||||
| { | { | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "discord-stream-client": "^1.4.8", |     "csv-parse": "^5.5.6", | ||||||
|     "discord.js-selfbot-v13": "^3.1.4", |     "discord.js-selfbot-v13": "^3.6.1", | ||||||
|     "dotenv": "^16.4.1", |     "dotenv": "^16.4.1", | ||||||
|     "libsodium-wrappers": "^0.7.13", |     "libsodium-wrappers": "^0.7.13", | ||||||
|     "opusscript": "^0.0.8" |     "node-fetch": "^3.3.2", | ||||||
|  |     "opusscript": "^0.0.8", | ||||||
|  |     "ssh2": "^1.16.0" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										19
									
								
								tokengrab.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								tokengrab.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | window.webpackChunkdiscord_app.push([ | ||||||
|  |   [Math.random()], | ||||||
|  |   {}, | ||||||
|  |   req => { | ||||||
|  |     if (!req.c) return; | ||||||
|  |     for (const m of Object.keys(req.c) | ||||||
|  |       .map(x => req.c[x].exports) | ||||||
|  |       .filter(x => x)) { | ||||||
|  |       if (m.default && m.default.getToken !== undefined) { | ||||||
|  |         return copy(m.default.getToken()); | ||||||
|  |       } | ||||||
|  |       if (m.getToken !== undefined) { | ||||||
|  |         return copy(m.getToken()); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  | ]); | ||||||
|  | console.log('%cWorked!', 'font-size: 50px'); | ||||||
|  | console.log(`%cYou now have your token in the clipboard!`, 'font-size: 16px'); | ||||||
							
								
								
									
										53
									
								
								utils/messageUtils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								utils/messageUtils.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | |||||||
|  | const getHumanizedDeleteDelay = (baseDelay = 5000) => { | ||||||
|  |     const jitter = Math.floor(Math.random() * 2000) - 1000; | ||||||
|  |     return Math.max(1500, baseDelay + jitter); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const sendTempMessage = async (channel, content, baseDeleteDelay = 5000) => { | ||||||
|  |     if (channel.id === 'console') { | ||||||
|  |         return channel.send(content); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     try { | ||||||
|  |         const deleteDelay = getHumanizedDeleteDelay(baseDeleteDelay); | ||||||
|  |         const sentMessage = await channel.send(content); | ||||||
|  |          | ||||||
|  |         sentMessage.scheduledForDeletion = true; | ||||||
|  |          | ||||||
|  |         console.log(`[MESSAGE] Sending temp message in ${channel.id}, will delete in ${deleteDelay}ms`); | ||||||
|  |          | ||||||
|  |         setTimeout(() => { | ||||||
|  |             if (Math.random() < 0.1) { | ||||||
|  |                 const extraDelay = Math.floor(Math.random() * 3000) + 1000; | ||||||
|  |                 console.log(`[MESSAGE] Adding ${extraDelay}ms extra delay before deletion`); | ||||||
|  |                 setTimeout(() => sentMessage.delete().catch(err => console.error('[MESSAGE] Delete error:', err)), extraDelay); | ||||||
|  |             } else { | ||||||
|  |                 sentMessage.delete().catch(err => console.error('[MESSAGE] Delete error:', err)); | ||||||
|  |             } | ||||||
|  |         }, deleteDelay); | ||||||
|  |          | ||||||
|  |         return sentMessage; | ||||||
|  |     } catch (error) { | ||||||
|  |         console.error('[MESSAGE] Error sending temporary message:', error); | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const sendCommandResponse = async (message, content, baseDeleteDelay = 5000, deleteOriginal = true) => { | ||||||
|  |     if (deleteOriginal) { | ||||||
|  |         try { | ||||||
|  |             const cmdDeleteDelay = Math.floor(Math.random() * 1000) + 500; | ||||||
|  |             setTimeout(() => message.delete().catch(() => {}), cmdDeleteDelay); | ||||||
|  |         } catch (error) { | ||||||
|  |             console.error('[MESSAGE] Error deleting original command:', error); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     return await sendTempMessage(message.channel, content, baseDeleteDelay); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | module.exports = { | ||||||
|  |     getHumanizedDeleteDelay, | ||||||
|  |     sendTempMessage, | ||||||
|  |     sendCommandResponse | ||||||
|  | };  | ||||||
							
								
								
									
										33
									
								
								utils/userUtils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								utils/userUtils.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | function extractUserId(input) { | ||||||
|  |     if (/^\d{17,19}$/.test(input)) { | ||||||
|  |         return input; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const mentionRegex = /<@!?(\d{17,19})>/; | ||||||
|  |     const match = input.match(mentionRegex); | ||||||
|  |  | ||||||
|  |     if (match && match[1]) { | ||||||
|  |         return match[1]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return null; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function processUserInput(input) { | ||||||
|  |     // First try to split by commas | ||||||
|  |     let parts = input.split(',').map(part => part.trim()).filter(part => part !== ''); | ||||||
|  |      | ||||||
|  |     // If we only have one part, try splitting by spaces | ||||||
|  |     if (parts.length === 1) { | ||||||
|  |         parts = input.split(/\s+/).filter(part => part !== ''); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     return parts | ||||||
|  |         .map(part => extractUserId(part)) | ||||||
|  |         .filter(id => id !== null); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module.exports = { | ||||||
|  |     extractUserId, | ||||||
|  |     processUserInput | ||||||
|  | };  | ||||||
		Reference in New Issue
	
	Block a user