Compare commits
6 Commits
235398d200
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 1d8017e5b5 | |||
| 887ebb0c64 | |||
| 73149b8d6d | |||
| 5f750b0666 | |||
| b15f7097f8 | |||
| 7ca36a4938 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
.env
|
||||
node_modules/*
|
||||
*.json
|
||||
@@ -3,9 +3,60 @@ 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;
|
||||
@@ -173,6 +224,33 @@ const handleNewMessage = (message) => {
|
||||
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)}...`);
|
||||
|
||||
@@ -198,93 +276,288 @@ module.exports = {
|
||||
async execute(message, args, deleteTimeout) {
|
||||
ignoredMessages.add(message.id);
|
||||
|
||||
if (args[0]?.toLowerCase() === 'stop') {
|
||||
isAutoDeleteActive = false;
|
||||
|
||||
for (const [messageId, timer] of messageTimers) {
|
||||
clearTimeout(timer);
|
||||
console.log(`[AUTODELETE] Cleared timer for message: ${messageId}`);
|
||||
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`;
|
||||
}
|
||||
|
||||
messageTimers.clear();
|
||||
deleteQueue = [];
|
||||
isProcessingQueue = false;
|
||||
isFirstDeletion = true;
|
||||
const statusText = isAutoDeleteActive
|
||||
? `Auto-delete is ON - Messages will be deleted after approximately ${Math.round(DELETION_DELAY / 1000 / 60)} minutes.`
|
||||
: 'Auto-delete is OFF.';
|
||||
|
||||
DELETE_INTERVAL_MIN = 8000;
|
||||
DELETE_INTERVAL_MAX = 15000;
|
||||
currentBatchCount = 0;
|
||||
|
||||
console.log('[AUTODELETE] System deactivated - All timers cleared');
|
||||
message.channel.send('Auto-delete has been deactivated.')
|
||||
.then(msg => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout));
|
||||
await sendCommandResponse(
|
||||
message,
|
||||
`${statusText}\nQueue size: ${deleteQueue.length} messages | Tracked messages: ${messageTimers.size}${ignoreStatus}`,
|
||||
deleteTimeout,
|
||||
true
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (args[0]?.toLowerCase() === 'delay' && args[1]) {
|
||||
const newDelay = parseInt(args[1], 10);
|
||||
if (!isNaN(newDelay) && newDelay >= 1) {
|
||||
const oldDelay = Math.round(DELETION_DELAY / 1000 / 60);
|
||||
DELETION_DELAY = newDelay * 1000 * 60;
|
||||
message.channel.send(`Auto-delete delay changed from ${oldDelay} to ${newDelay} minutes.`)
|
||||
.then(msg => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout));
|
||||
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;
|
||||
} else {
|
||||
message.channel.send('Please provide a valid delay in minutes (minimum 1 minute).')
|
||||
.then(msg => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (args[0]?.toLowerCase() === 'speed') {
|
||||
if (args[1]?.toLowerCase() === 'slow') {
|
||||
DELETE_INTERVAL_MIN = 15000;
|
||||
DELETE_INTERVAL_MAX = 30000;
|
||||
PAUSE_CHANCE = 0.25;
|
||||
message.channel.send('Auto-delete speed set to slow mode (very human-like with frequent pauses).')
|
||||
.then(msg => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout));
|
||||
return;
|
||||
} else if (args[1]?.toLowerCase() === 'medium') {
|
||||
DELETE_INTERVAL_MIN = 8000;
|
||||
DELETE_INTERVAL_MAX = 15000;
|
||||
PAUSE_CHANCE = 0.15;
|
||||
message.channel.send('Auto-delete speed set to medium mode (balanced human-like behavior).')
|
||||
.then(msg => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout));
|
||||
return;
|
||||
} else if (args[1]?.toLowerCase() === 'fast') {
|
||||
DELETE_INTERVAL_MIN = 5000;
|
||||
DELETE_INTERVAL_MAX = 10000;
|
||||
PAUSE_CHANCE = 0.05;
|
||||
message.channel.send('Auto-delete speed set to fast mode (less human-like but quicker progress).')
|
||||
.then(msg => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout));
|
||||
return;
|
||||
} else {
|
||||
message.channel.send('Please specify a valid speed: slow, medium, or fast.')
|
||||
.then(msg => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isAutoDeleteActive) {
|
||||
isAutoDeleteActive = true;
|
||||
isFirstDeletion = true;
|
||||
currentBatchCount = 0;
|
||||
console.log('[AUTODELETE] System activated - Now tracking new messages');
|
||||
|
||||
message.client.removeListener('messageCreate', handleNewMessage);
|
||||
message.client.on('messageCreate', handleNewMessage);
|
||||
|
||||
const delayInMinutes = Math.round(DELETION_DELAY / 1000 / 60);
|
||||
message.channel.send(
|
||||
`Auto-delete activated. Messages will be deleted after ~${delayInMinutes} minutes ` +
|
||||
`with human-like timing. Use \`.autodelete speed slow/medium/fast\` to adjust deletion speed.`
|
||||
).then(msg => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout));
|
||||
} else {
|
||||
const delayInMinutes = Math.round(DELETION_DELAY / 1000 / 60);
|
||||
message.channel.send(
|
||||
`Auto-delete is already active. Current delay: ~${delayInMinutes} minutes. ` +
|
||||
`Use \`.autodelete speed slow/medium/fast\` to adjust deletion speed.`
|
||||
).then(msg => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout));
|
||||
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
|
||||
);
|
||||
},
|
||||
};
|
||||
@@ -2,6 +2,7 @@ let isDeleting = 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) {
|
||||
@@ -16,14 +17,12 @@ module.exports = {
|
||||
async execute(message, args, deleteTimeout) {
|
||||
if (args[0] && args[0].toLowerCase() === 'cancel') {
|
||||
cancelDelete = true;
|
||||
const cancelMsg = await message.channel.send('Delete operation canceled.');
|
||||
setTimeout(() => cancelMsg.delete().catch(console.error), deleteTimeout);
|
||||
await sendCommandResponse(message, 'Delete operation canceled.', deleteTimeout, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDeleting) {
|
||||
const inProgressMsg = await message.channel.send('A delete operation is already in progress. Please wait or cancel it with `.delete cancel`.');
|
||||
setTimeout(() => inProgressMsg.delete().catch(console.error), deleteTimeout);
|
||||
await sendCommandResponse(message, 'A delete operation is already in progress. Please wait or cancel it with `.delete cancel`.', deleteTimeout, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -44,8 +43,7 @@ module.exports = {
|
||||
} else if (targetGuildId) {
|
||||
await deleteMessagesFromServer(message, targetGuildId, deleteTimeout, speed);
|
||||
} else {
|
||||
const errorMsg = await message.channel.send('Please specify how many messages to delete or a server ID. You can also set speed: `.delete [slow/medium/fast] [count/server]`');
|
||||
setTimeout(() => errorMsg.delete().catch(console.error), deleteTimeout);
|
||||
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);
|
||||
}
|
||||
|
||||
isDeleting = false;
|
||||
@@ -182,16 +180,13 @@ async function deleteMessagesFromChannel(message, deleteCount, deleteTimeout, sp
|
||||
}
|
||||
|
||||
if (cancelDelete) {
|
||||
const canceledMsg = await message.channel.send(`Delete operation canceled after removing ${deletedCount} messages.`);
|
||||
setTimeout(() => canceledMsg.delete().catch(console.error), deleteTimeout);
|
||||
await sendCommandResponse(message, `Delete operation canceled after removing ${deletedCount} messages.`, deleteTimeout, true);
|
||||
} else {
|
||||
const completedMsg = await message.channel.send(`Finished deleting ${deletedCount} messages.`);
|
||||
setTimeout(() => completedMsg.delete().catch(console.error), deleteTimeout);
|
||||
await sendCommandResponse(message, `Finished deleting ${deletedCount} messages.`, deleteTimeout, true);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[DELETE] Failed to delete messages:', error);
|
||||
const errorMsg = await message.channel.send('There was an error while trying to delete messages.');
|
||||
setTimeout(() => errorMsg.delete().catch(console.error), deleteTimeout);
|
||||
await sendCommandResponse(message, 'There was an error while trying to delete messages.', deleteTimeout, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,8 +194,7 @@ async function deleteMessagesFromServer(message, guildId, deleteTimeout, speed =
|
||||
const guild = message.client.guilds.cache.get(guildId);
|
||||
|
||||
if (!guild) {
|
||||
const errorMsg = await message.channel.send('I am not in the server with the specified ID.');
|
||||
setTimeout(() => errorMsg.delete().catch(console.error), deleteTimeout);
|
||||
await sendCommandResponse(message, `Guild with ID ${guildId} not found.`, deleteTimeout, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -341,15 +335,12 @@ async function deleteMessagesFromServer(message, guildId, deleteTimeout, speed =
|
||||
}
|
||||
|
||||
if (cancelDelete) {
|
||||
const canceledMsg = await message.channel.send(`Server cleanup canceled after removing ${totalDeleted} messages across ${processedChannels} channels.`);
|
||||
setTimeout(() => canceledMsg.delete().catch(console.error), deleteTimeout);
|
||||
await sendCommandResponse(message, `Delete operation canceled after removing ${totalDeleted} messages across ${processedChannels} channels.`, deleteTimeout, true);
|
||||
} else {
|
||||
const completedMsg = await message.channel.send(`Finished cleaning up ${guild.name}: ${totalDeleted} messages deleted across ${processedChannels} channels.`);
|
||||
setTimeout(() => completedMsg.delete().catch(console.error), deleteTimeout);
|
||||
await sendCommandResponse(message, `Finished cleaning up ${guild.name}: ${totalDeleted} messages deleted across ${processedChannels} channels.`, deleteTimeout, true);
|
||||
}
|
||||
} catch (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.');
|
||||
setTimeout(() => errorMsg.delete().catch(console.error), deleteTimeout);
|
||||
await sendCommandResponse(message, 'There was an error while trying to delete messages from the server.', deleteTimeout, true);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ 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;
|
||||
@@ -28,8 +29,7 @@ module.exports = {
|
||||
const { extractUserId } = require('../utils/userUtils');
|
||||
|
||||
if (message.channel.type !== 'GROUP_DM') {
|
||||
message.channel.send('This command only works in group DMs.')
|
||||
.then(msg => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout));
|
||||
await sendCommandResponse(message, 'This command only works in group DMs.', deleteTimeout, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -42,8 +42,7 @@ module.exports = {
|
||||
channelToWatch = null;
|
||||
console.log('[GROUPADD] System deactivated');
|
||||
|
||||
message.channel.send('Group auto-add deactivated.')
|
||||
.then(msg => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout));
|
||||
await sendCommandResponse(message, 'Group auto-add deactivated.', deleteTimeout, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -52,8 +51,7 @@ module.exports = {
|
||||
.filter(id => id !== null);
|
||||
|
||||
if (validIds.length === 0) {
|
||||
message.channel.send('Please provide at least one valid user ID or @mention.')
|
||||
.then(msg => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout));
|
||||
await sendCommandResponse(message, 'Please provide at least one valid user ID or @mention.', deleteTimeout, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -156,7 +154,6 @@ module.exports = {
|
||||
message.client.on('channelRecipientRemove', handleRecipientRemove);
|
||||
|
||||
const targetCount = targetUserIds.size;
|
||||
message.channel.send(`Now watching for ${targetCount} user${targetCount > 1 ? 's' : ''} to leave the group.`)
|
||||
.then(msg => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout));
|
||||
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 = {
|
||||
name: 'help',
|
||||
description: 'List all of my commands or info about a specific command.',
|
||||
execute(message, args, deleteTimeout) {
|
||||
async execute(message, args, deleteTimeout) {
|
||||
let reply = '```';
|
||||
reply += 'Here are the available commands:\n\n';
|
||||
|
||||
@@ -12,9 +14,7 @@ module.exports = {
|
||||
|
||||
reply += '```';
|
||||
|
||||
message.channel.send(reply).then(sentMessage => {
|
||||
setTimeout(() => sentMessage.delete().catch(console.error), deleteTimeout);
|
||||
});
|
||||
await sendCommandResponse(message, reply, deleteTimeout, false);
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
let vpnRangesCache = null;
|
||||
const { sendCommandResponse } = require('../utils/messageUtils');
|
||||
|
||||
function ipToInt(ip) {
|
||||
return ip.split('.').reduce((acc, oct) => (acc << 8) + parseInt(oct, 10), 0) >>> 0;
|
||||
@@ -23,14 +24,30 @@ function isVpnIp(ip) {
|
||||
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.',
|
||||
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');
|
||||
@@ -38,6 +55,14 @@ module.exports = {
|
||||
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);
|
||||
|
||||
@@ -52,7 +77,8 @@ module.exports = {
|
||||
const as = data.as || "Unknown";
|
||||
|
||||
const output =
|
||||
`Hostname: ${hostname}
|
||||
`IP: ${ip}
|
||||
Hostname: ${hostname}
|
||||
City: ${city}
|
||||
Region: ${region}
|
||||
Country: ${country}
|
||||
@@ -63,12 +89,10 @@ Organization: ${org}
|
||||
AS: ${as}
|
||||
VPN: ${vpnCheck ? "True" : "False"}`;
|
||||
|
||||
message.channel.send(`\`\`\`\n${output}\n\`\`\``)
|
||||
.then(sentMsg => setTimeout(() => sentMsg.delete().catch(console.error), 30000));
|
||||
await sendCommandResponse(message, `\`\`\`\n${output}\n\`\`\``, 30000, true);
|
||||
} catch (error) {
|
||||
console.error("Error fetching IP info:", error);
|
||||
message.channel.send("Error fetching IP info.")
|
||||
.then(sentMsg => setTimeout(() => sentMsg.delete().catch(console.error), deleteTimeout));
|
||||
await sendCommandResponse(message, "Error fetching IP info.", deleteTimeout, true);
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
const { extractUserId } = require('../utils/userUtils');
|
||||
const { sendCommandResponse } = require('../utils/messageUtils');
|
||||
|
||||
let activeKicks = new Map();
|
||||
let cooldowns = new Map();
|
||||
@@ -111,8 +112,7 @@ module.exports = {
|
||||
description: 'Automatically kicks specified users from voice channels.',
|
||||
async execute(message, args, deleteTimeout) {
|
||||
if (args.length === 0) {
|
||||
message.channel.send('Please provide a command: `start <userId(s)>` or `stop <userId or "all">`')
|
||||
.then(msg => setTimeout(() => msg.delete().catch(() => {}), deleteTimeout));
|
||||
await sendCommandResponse(message, 'Please provide a command: `start <userId(s)>` or `stop <userId or "all">`', deleteTimeout, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -120,8 +120,7 @@ module.exports = {
|
||||
|
||||
if (command === 'stop') {
|
||||
if (args.length < 2) {
|
||||
message.channel.send('Please specify a user ID or "all" to stop kicking.')
|
||||
.then(msg => setTimeout(() => msg.delete().catch(() => {}), deleteTimeout));
|
||||
await sendCommandResponse(message, 'Please specify a user ID or "all" to stop kicking.', deleteTimeout, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -138,15 +137,13 @@ module.exports = {
|
||||
}
|
||||
voiceStateUpdateHandlers.clear();
|
||||
|
||||
message.channel.send('Stopped all active VC kicks.')
|
||||
.then(msg => setTimeout(() => msg.delete().catch(() => {}), deleteTimeout));
|
||||
await sendCommandResponse(message, 'Stopped all active VC kicks.', deleteTimeout, true);
|
||||
return;
|
||||
} else {
|
||||
const userId = extractUserId(target);
|
||||
|
||||
if (!userId) {
|
||||
message.channel.send('Invalid user ID.')
|
||||
.then(msg => setTimeout(() => msg.delete().catch(() => {}), deleteTimeout));
|
||||
await sendCommandResponse(message, 'Invalid user ID.', deleteTimeout, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -158,11 +155,9 @@ module.exports = {
|
||||
checkIntervals.delete(userId);
|
||||
console.log(`[KICKVC] Stopped kicking user: ${userId}`);
|
||||
|
||||
message.channel.send(`Stopped kicking user: ${userId}`)
|
||||
.then(msg => setTimeout(() => msg.delete().catch(() => {}), deleteTimeout));
|
||||
await sendCommandResponse(message, `Stopped kicking user: ${userId}`, deleteTimeout, true);
|
||||
} else {
|
||||
message.channel.send(`No active kick for user: ${userId}`)
|
||||
.then(msg => setTimeout(() => msg.delete().catch(() => {}), deleteTimeout));
|
||||
await sendCommandResponse(message, `No active kick for user: ${userId}`, deleteTimeout, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -170,8 +165,7 @@ module.exports = {
|
||||
|
||||
if (command === 'start') {
|
||||
if (args.length < 2) {
|
||||
message.channel.send('Please provide at least one user ID to kick.')
|
||||
.then(msg => setTimeout(() => msg.delete().catch(() => {}), deleteTimeout));
|
||||
await sendCommandResponse(message, 'Please provide at least one user ID to kick.', deleteTimeout, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -180,8 +174,7 @@ module.exports = {
|
||||
.filter(id => id !== null);
|
||||
|
||||
if (userIds.length === 0) {
|
||||
message.channel.send('No valid user IDs provided.')
|
||||
.then(msg => setTimeout(() => msg.delete().catch(() => {}), deleteTimeout));
|
||||
await sendCommandResponse(message, 'No valid user IDs provided.', deleteTimeout, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -257,22 +250,19 @@ module.exports = {
|
||||
console.log(`[KICKVC] Started kicking user: ${userId}`);
|
||||
}
|
||||
|
||||
let responseMessage = '';
|
||||
|
||||
if (startedKicking.length > 0) {
|
||||
responseMessage += `Started kicking ${startedKicking.length} user(s): ${startedKicking.join(', ')}\n`;
|
||||
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);
|
||||
}
|
||||
|
||||
if (alreadyKicking.length > 0) {
|
||||
responseMessage += `Already kicking: ${alreadyKicking.join(', ')}`;
|
||||
}
|
||||
|
||||
message.channel.send(responseMessage)
|
||||
.then(msg => setTimeout(() => msg.delete().catch(() => {}), deleteTimeout));
|
||||
return;
|
||||
}
|
||||
|
||||
message.channel.send('Unknown command. Use `start <userId(s)>` or `stop <userId or "all">`')
|
||||
.then(msg => setTimeout(() => msg.delete().catch(() => {}), deleteTimeout));
|
||||
await sendCommandResponse(message, 'Unknown command. Use `start <userId(s)>` or `stop <userId or "all">`.', deleteTimeout, true);
|
||||
}
|
||||
};
|
||||
135
commands/react.js
vendored
135
commands/react.js
vendored
@@ -1,20 +1,23 @@
|
||||
const { sendCommandResponse } = require('../utils/messageUtils');
|
||||
|
||||
module.exports = {
|
||||
name: 'react',
|
||||
description: `Automatically react with specified emojis to multiple users' messages, or stop reacting.`,
|
||||
description: `Automatically react with specified emojis to multiple users' messages, or stop reacting. Usage: .react [user1,user2,...] [emoji1] [emoji2] ...`,
|
||||
async execute(message, args, deleteTimeout) {
|
||||
const { processUserInput } = require('../utils/userUtils');
|
||||
|
||||
if (args.length === 0) {
|
||||
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
|
||||
.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 {
|
||||
const noTargetMsg = await message.channel.send('No active reaction target.');
|
||||
setTimeout(() => noTargetMsg.delete().catch(console.error), deleteTimeout);
|
||||
await sendCommandResponse(message, 'No active reaction target.', deleteTimeout, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -26,50 +29,126 @@ module.exports = {
|
||||
message.client.targetReactUserIds = null;
|
||||
message.client.reactEmojis = null;
|
||||
|
||||
const stopMsg = await message.channel.send('Stopped reacting to messages.');
|
||||
setTimeout(() => stopMsg.delete().catch(console.error), deleteTimeout);
|
||||
await sendCommandResponse(message, 'Stopped reacting to messages.', deleteTimeout, false);
|
||||
} else {
|
||||
const noActiveReactMsg = await message.channel.send('No active reactions to stop.');
|
||||
setTimeout(() => noActiveReactMsg.delete().catch(console.error), deleteTimeout);
|
||||
await sendCommandResponse(message, 'No active reactions to stop.', deleteTimeout, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const targetIds = processUserInput(args[0]);
|
||||
const emojis = args.slice(1);
|
||||
// Find where the emojis start
|
||||
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) {
|
||||
const errorMsg = await message.channel.send('Please provide valid user IDs or @mentions and at least one emoji.');
|
||||
setTimeout(() => errorMsg.delete().catch(console.error), deleteTimeout);
|
||||
if (emojiStartIndex === -1) {
|
||||
await sendCommandResponse(message, 'Please provide at least one emoji to react with.', deleteTimeout, false);
|
||||
return;
|
||||
}
|
||||
|
||||
// All arguments before emojiStartIndex are user IDs
|
||||
const userInput = args.slice(0, emojiStartIndex).join(' ');
|
||||
const emojis = args.slice(emojiStartIndex);
|
||||
|
||||
console.log(`[REACT] Processing user input: "${userInput}"`);
|
||||
const targetIds = processUserInput(userInput);
|
||||
console.log(`[REACT] 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;
|
||||
}
|
||||
|
||||
// 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 = emojis;
|
||||
message.client.reactEmojis = processedEmojis;
|
||||
|
||||
const confirmationMsg = await message.channel.send(
|
||||
`I will now react to messages from the following users: ${targetIds
|
||||
.map(id => `User ID: ${id}`)
|
||||
.join(', ')} with the following emojis: ${emojis.join(' ')}.`
|
||||
// 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) {
|
||||
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) => {
|
||||
if (message.client.targetReactUserIds && message.client.targetReactUserIds.includes(msg.author.id)) {
|
||||
for (const emoji of emojis) {
|
||||
try {
|
||||
const delay = getRandomDelay();
|
||||
await new Promise((resolve) => setTimeout(resolve, delay));
|
||||
await msg.react(emoji);
|
||||
} catch (error) {
|
||||
console.error('Failed to react:', error);
|
||||
const shouldReact = Math.random() < 0.95;
|
||||
|
||||
if (!shouldReact) {
|
||||
console.log(`[REACT] Randomly skipping reaction to message ${msg.id}`);
|
||||
return;
|
||||
}
|
||||
|
||||
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,20 +1,23 @@
|
||||
const { sendCommandResponse } = require('../utils/messageUtils');
|
||||
|
||||
module.exports = {
|
||||
name: 'reply',
|
||||
description: `Automatically reply with a specified message to multiple users' messages, or stop replying.`,
|
||||
description: `Automatically reply with a specified message to multiple users' messages, or stop replying. Usage: .reply [user1,user2,...] [message]`,
|
||||
async execute(message, args, deleteTimeout) {
|
||||
const { processUserInput } = require('../utils/userUtils');
|
||||
|
||||
if (args.length === 0) {
|
||||
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
|
||||
.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 {
|
||||
const noTargetMsg = await message.channel.send('No active reply target.');
|
||||
setTimeout(() => noTargetMsg.delete().catch(console.error), deleteTimeout);
|
||||
await sendCommandResponse(message, 'No active reply target.', deleteTimeout, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -26,33 +29,62 @@ module.exports = {
|
||||
message.client.targetReplyUserIds = null;
|
||||
message.client.replyMessage = null;
|
||||
|
||||
const stopMsg = await message.channel.send('Stopped replying to messages.');
|
||||
setTimeout(() => stopMsg.delete().catch(console.error), deleteTimeout);
|
||||
await sendCommandResponse(message, 'Stopped replying to messages.', deleteTimeout, false);
|
||||
} else {
|
||||
const noActiveReplyMsg = await message.channel.send('No active replies to stop.');
|
||||
setTimeout(() => noActiveReplyMsg.delete().catch(console.error), deleteTimeout);
|
||||
await sendCommandResponse(message, 'No active replies to stop.', deleteTimeout, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const targetIds = processUserInput(args[0]);
|
||||
const replyMessage = args.slice(1).join(' ');
|
||||
// Find where the message starts (after all user IDs)
|
||||
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 (targetIds.length === 0 || !replyMessage) {
|
||||
const errorMsg = await message.channel.send('Please provide valid user IDs or @mentions and a message to reply with.');
|
||||
setTimeout(() => errorMsg.delete().catch(console.error), deleteTimeout);
|
||||
if (messageStartIndex === -1) {
|
||||
await sendCommandResponse(message, 'Please provide a message to reply with.', deleteTimeout, false);
|
||||
return;
|
||||
}
|
||||
|
||||
// All arguments before messageStartIndex are user IDs
|
||||
const userInput = args.slice(0, messageStartIndex).join(' ');
|
||||
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;
|
||||
}
|
||||
|
||||
message.client.targetReplyUserIds = targetIds;
|
||||
message.client.replyMessage = replyMessage;
|
||||
|
||||
const confirmationMsg = await message.channel.send(
|
||||
`I will now reply to messages from the following users: ${targetIds
|
||||
.map(id => `User ID: ${id}`)
|
||||
.join(', ')} with the message: "${replyMessage}".`
|
||||
// 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 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) {
|
||||
message.client.off('messageCreate', message.client.replyListener);
|
||||
|
||||
51
index.js
51
index.js
@@ -2,6 +2,7 @@ require('dotenv').config();
|
||||
const { Client } = require('discord.js-selfbot-v13');
|
||||
const client = new Client();
|
||||
const fs = require('fs');
|
||||
const readline = require('readline');
|
||||
|
||||
const PREFIX = process.env.PREFIX || '.';
|
||||
const MESSAGE_DELETE_TIMEOUT = 10000
|
||||
@@ -16,6 +17,56 @@ for (const file of commandFiles) {
|
||||
|
||||
client.on('ready', () => {
|
||||
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 => {
|
||||
|
||||
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
|
||||
};
|
||||
@@ -14,9 +14,15 @@ function extractUserId(input) {
|
||||
}
|
||||
|
||||
function processUserInput(input) {
|
||||
return input
|
||||
.split(',')
|
||||
.map(part => part.trim())
|
||||
// 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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user