commit 8379d0905878573b852ac155b350727a9b140eb6 Author: Nick Date: Sat Aug 10 02:53:40 2024 -0500 feat: init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..941d536 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.env +node_modules +package-lock.json \ No newline at end of file diff --git a/commands/baboon.js b/commands/baboon.js new file mode 100644 index 0000000..840e4dc --- /dev/null +++ b/commands/baboon.js @@ -0,0 +1,65 @@ +const fs = require('fs'); +const path = require('path'); + +module.exports = { + name: 'baboon', + description: 'Strip all roles from a user and assign the role with ID 1160622954082738347.', + async execute(message) { + const authorizedRoles = ['827303828884946944', '827332588803850270']; + const userRoles = message.member.roles.cache.map(role => role.id); + + console.log('User roles:', userRoles); // Debugging line + console.log('Authorized roles:', authorizedRoles); // Debugging line + + if (!userRoles.some(role => authorizedRoles.includes(role))) { + return message.reply('You do not have permission to use this command.'); + } + + let target; + if (message.mentions.members.first()) { + target = message.mentions.members.first(); + } else if (message.reference) { + target = await message.channel.messages.fetch(message.reference.messageId).then(msg => msg.member); + } else { + return message.reply('You have not targeted a user to baboon.'); + } + + console.log('Target user identified:', target.user.tag); // Debugging line + + const roleID = '1160622954082738347'; + const role = message.guild.roles.cache.get(roleID); + if (!role) { + return message.reply('Role not found.'); + } + + const previousRoles = target.roles.cache.filter(r => r.name !== '@everyone'); + const rolesArray = previousRoles.map(role => role.id); + + const filePath = path.join(__dirname, '../roles_backup.json'); + let rolesBackup = {}; + + if (fs.existsSync(filePath)) { + rolesBackup = JSON.parse(fs.readFileSync(filePath, 'utf8')); + } + + rolesBackup[target.id] = rolesArray; + fs.writeFileSync(filePath, JSON.stringify(rolesBackup, null, 2), 'utf8'); + + try { + await target.roles.remove(rolesArray); + await target.roles.add(role); + + const logChannelID = '1028786996505759794'; // Replace with your actual channel ID + const logChannel = message.guild.channels.cache.get(logChannelID); + + if (logChannel) { + message.channel.send(`${target.displayName} has become a ${role.name}! Check them out in ${logChannel.toString()}`); + } else { + console.error('Log channel not found'); + } + } catch (error) { + console.error(error); + message.channel.send('Sorry, I am having trouble with my baboon gun.'); + } + }, +}; diff --git a/commands/coma.js b/commands/coma.js new file mode 100644 index 0000000..4a51ea2 --- /dev/null +++ b/commands/coma.js @@ -0,0 +1,92 @@ +module.exports = { + name: 'coma', + description: 'Temporarily delete all messages and reactions of a user for 24 hours.', + async execute(message, args, comaUsers) { + try { + // Define role IDs + const authorizedRoles = ['969767633278869515', '827303828884946944', '827332588803850270']; + const targetRoleID = '1160622954082738347'; + + // Check if the command user has the authorized role + const userRoles = message.member.roles.cache.map(role => role.id); + console.log('User roles:', userRoles); // Debugging line + console.log('Authorized roles:', authorizedRoles); // Debugging line + + if (!userRoles.some(role => authorizedRoles.includes(role))) { + return message.reply('You do not have permission to use this command.'); + } + + // Identify the target user + let target; + if (message.mentions.members.first()) { + target = message.mentions.members.first(); + } else if (message.reference) { + target = await message.channel.messages.fetch(message.reference.messageId).then(msg => msg.member); + } else { + return message.reply('Please mention a user or reply to their message to use this command.'); + } + + // Check if the target user has the specific role + if (!target.roles.cache.has(targetRoleID)) { + return message.reply('The target user does not have the required role.'); + } + + // Define the time period to delete messages + const timePeriod = 24 * 60 * 60 * 1000; // 24 hours in milliseconds + const now = Date.now(); + + // Fetch the target user's recent messages and delete them + const fetchOptions = { + limit: 100, // Fetch up to 100 messages per channel + }; + + // Function to delete messages in a channel + const deleteMessages = async (channel, userID) => { + const messages = await channel.messages.fetch(fetchOptions); + const userMessages = messages.filter(m => m.author.id === userID && (now - m.createdTimestamp) <= timePeriod); + + for (const msg of userMessages.values()) { + await msg.delete(); + } + }; + + // Function to remove reactions from messages in a channel + const removeReactions = async (channel, userID) => { + const messages = await channel.messages.fetch(fetchOptions); + const userMessages = messages.filter(m => m.author.id === userID && (now - m.createdTimestamp) <= timePeriod); + + for (const msg of userMessages.values()) { + for (const reaction of msg.reactions.cache.values()) { + await reaction.users.remove(userID); + } + } + }; + + // Iterate through all channels and delete the target user's messages and reactions + for (const channel of message.guild.channels.cache.values()) { + if (channel.type === 'GUILD_TEXT') { + await deleteMessages(channel, target.id); + await removeReactions(channel, target.id); + } + } + + // Add the user to the comaUsers set + comaUsers.add(target.id); + console.log(`Added ${target.id} to comaUsers`); // Debugging line + console.log(`Current comaUsers: ${Array.from(comaUsers)}`); // Debugging line + + // Schedule removal from the comaUsers set after 24 hours + setTimeout(() => { + comaUsers.delete(target.id); + message.channel.send(`${target.displayName} is no longer comatose.`); + }, timePeriod); + + // Send a confirmation message + message.channel.send(`${target.displayName} has received an overdose of tranquilizers and will be in a coma for 24 hours.`); + + } catch (error) { + console.error('An error occurred:', error); + message.channel.send('There was an error trying to execute the command.'); + } + }, +}; diff --git a/commands/stim.js b/commands/stim.js new file mode 100644 index 0000000..8609076 --- /dev/null +++ b/commands/stim.js @@ -0,0 +1,60 @@ +module.exports = { + name: 'stim', + description: 'Cancel the tranquilization or coma effect of a user.', + async execute(message, args, tranqUsers, comaUsers) { + try { + // Define role IDs for authorized users + const authorizedRoles = ['969767633278869515', '827303828884946944', '827332588803850270']; + + // Check if the command user has the authorized role + const userRoles = message.member.roles.cache.map(role => role.id); + console.log('User roles:', userRoles); // Debugging line + console.log('Authorized roles:', authorizedRoles); // Debugging line + + if (!userRoles.some(role => authorizedRoles.includes(role))) { + return message.reply('You do not have permission to use this command.'); + } + + // Identify the target user + let target; + if (message.mentions.members.first()) { + target = message.mentions.members.first(); + } else if (message.reference) { + target = await message.channel.messages.fetch(message.reference.messageId).then(msg => msg.member); + } else { + return message.reply('Please mention a user or reply to their message to use this command.'); + } + + // Ensure comaUsers and tranqUsers are initialized + if (!tranqUsers || !comaUsers) { + return message.reply('The user sets are not properly initialized.'); + } + + // Initialize confirmation message + let confirmationMessage = ''; + + // Debugging lines to check user status + console.log(`Checking status of user ${target.id}`); + console.log(`Is user in comaUsers: ${comaUsers.has(target.id)}`); + console.log(`Is user in tranqUsers: ${tranqUsers.has(target.id)}`); + + // Remove user from both sets + const wasComatose = comaUsers.delete(target.id); + const wasTranquilized = tranqUsers.delete(target.id); + + if (wasComatose || wasTranquilized) { + confirmationMessage = `${target.displayName} has been stimmed and is no longer tranquilized or in a coma.`; + console.log(`Removed ${target.id} from comaUsers or tranqUsers`); // Debugging line + } else { + return message.reply('The user is not currently tranquilized or in a coma.'); + } + + // Send the appropriate confirmation message + message.channel.send(confirmationMessage); + + } catch (error) { + console.error('An error occurred:', error); + message.channel.send('There was an error trying to execute the command.'); + } + }, +}; diff --git a/commands/tranq.js b/commands/tranq.js new file mode 100644 index 0000000..7e11eaf --- /dev/null +++ b/commands/tranq.js @@ -0,0 +1,90 @@ +module.exports = { + name: 'tranq', + description: 'Temporarily delete all messages and reactions of a user for 10 minutes.', + async execute(message, args, tranqUsers) { + try { + // Define role IDs + const authorizedRoles = ['969767633278869515', '827303828884946944', '827332588803850270']; + const targetRoleID = '1160622954082738347'; + + // Check if the command user has the authorized role + const userRoles = message.member.roles.cache.map(role => role.id); + console.log('User roles:', userRoles); // Debugging line + console.log('Authorized roles:', authorizedRoles); // Debugging line + + if (!userRoles.some(role => authorizedRoles.includes(role))) { + return message.reply('You do not have permission to use this command.'); + } + + // Identify the target user + let target; + if (message.mentions.members.first()) { + target = message.mentions.members.first(); + } else if (message.reference) { + target = await message.channel.messages.fetch(message.reference.messageId).then(msg => msg.member); + } else { + return message.reply('Please mention a user or reply to their message to use this command.'); + } + + // Check if the target user has the specific role + if (!target.roles.cache.has(targetRoleID)) { + return message.reply('The target user does not have the required role.'); + } + + // Define the time period to delete messages + const timePeriod = 10 * 60 * 1000; // 10 minutes in milliseconds + const now = Date.now(); + + // Fetch the target user's recent messages and delete them + const fetchOptions = { + limit: 100, // Fetch up to 100 messages per channel + }; + + // Function to delete messages in a channel + const deleteMessages = async (channel, userID) => { + const messages = await channel.messages.fetch(fetchOptions); + const userMessages = messages.filter(m => m.author.id === userID && (now - m.createdTimestamp) <= timePeriod); + + for (const msg of userMessages.values()) { + await msg.delete(); + } + }; + + // Function to remove reactions from messages in a channel + const removeReactions = async (channel, userID) => { + const messages = await channel.messages.fetch(fetchOptions); + const userMessages = messages.filter(m => m.author.id === userID && (now - m.createdTimestamp) <= timePeriod); + + for (const msg of userMessages.values()) { + for (const reaction of msg.reactions.cache.values()) { + await reaction.users.remove(userID); + } + } + }; + + // Iterate through all channels and delete the target user's messages and reactions + for (const channel of message.guild.channels.cache.values()) { + if (channel.type === 'GUILD_TEXT') { + await deleteMessages(channel, target.id); + await removeReactions(channel, target.id); + } + } + + // Add the user to the tranqUsers set + tranqUsers.add(target.id); + + // Schedule removal from the tranqUsers set after 10 minutes + setTimeout(() => { + tranqUsers.delete(target.id); + message.channel.send(`${target.displayName} is no longer tranquilized.`); + }, timePeriod); + + // Send a confirmation message + message.channel.send(`${target.displayName} was becoming unruly and has been tranquilized for 10 minutes.`); + + } catch (error) { + console.error('An error occurred:', error); + message.channel.send('There was an error trying to execute the command.'); + } + }, +}; diff --git a/commands/unbaboon.js b/commands/unbaboon.js new file mode 100644 index 0000000..3d17348 --- /dev/null +++ b/commands/unbaboon.js @@ -0,0 +1,75 @@ +const fs = require('fs'); +const path = require('path'); + +module.exports = { + name: 'unbaboon', + description: 'Restore the roles of a user that were previously removed by the baboon command and remove the role with ID 1160622954082738347. If no cached roles are found, assign a default role.', + async execute(message) { + const authorizedRoles = ['827303828884946944', '827332588803850270']; + const userRoles = message.member.roles.cache.map(role => role.id); + + console.log('User roles:', userRoles); // Debugging line + console.log('Authorized roles:', authorizedRoles); // Debugging line + + if (!userRoles.some(role => authorizedRoles.includes(role))) { + return message.reply('You are not alpha enough to unbaboon other users.'); + } + + try { + // Identify the target user + let target; + if (message.mentions.members.first()) { + target = message.mentions.members.first(); + } else if (message.reference) { + target = await message.channel.messages.fetch(message.reference.messageId).then(msg => msg.member); + } else { + return message.reply('Please tag the baboon you wish to rewild.'); + } + + console.log('Target user identified:', target.user.tag); + + // Retrieve the bot's own member object + const botMember = await message.guild.members.fetch(message.client.user.id); + + // Check if the bot has MANAGE_ROLES permission + if (!botMember.permissions.has('MANAGE_ROLES')) { + return message.reply('My kung fu is not strong enough.'); + } + + const roleID = '1160622954082738347'; + const defaultRoleID = '964354344948494416'; + const role = message.guild.roles.cache.get(roleID); + const defaultRole = message.guild.roles.cache.get(defaultRoleID); + + if (!role) { + return message.reply('Role not found.'); + } + if (!defaultRole) { + return message.reply('Default role not found.'); + } + + const filePath = path.join(__dirname, '../roles_backup.json'); + if (!fs.existsSync(filePath)) { + return message.reply('No role backup file found.'); + } + + const rolesBackup = JSON.parse(fs.readFileSync(filePath, 'utf8')); + const rolesArray = rolesBackup[target.id]; + + await target.roles.remove(role); + if (rolesArray && rolesArray.length > 0) { + await target.roles.add(rolesArray); + message.channel.send(`${target.displayName} has been rewilded.`); + } else { + await target.roles.add(defaultRole); + message.channel.send(`${target.displayName} has returned to civilization.`); + } + + delete rolesBackup[target.id]; + fs.writeFileSync(filePath, JSON.stringify(rolesBackup, null, 2), 'utf8'); + } catch (error) { + console.error('An error occurred:', error); + message.channel.send('There was an error trying to restore the roles.'); + } + }, +}; diff --git a/index.js b/index.js new file mode 100644 index 0000000..2b773fb --- /dev/null +++ b/index.js @@ -0,0 +1,116 @@ +const { Client, GatewayIntentBits, Collection } = require('discord.js'); +require('dotenv').config(); +const fs = require('fs'); +const path = require('path'); + +const client = new Client({ + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.MessageContent, + GatewayIntentBits.GuildMembers, + GatewayIntentBits.GuildVoiceStates + ] +}); + +client.commands = new Collection(); +const commandsPath = path.join(__dirname, 'commands'); + +try { + const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js')); + for (const file of commandFiles) { + const filePath = path.join(commandsPath, file); + const command = require(filePath); + client.commands.set(command.name, command); + } +} catch (error) { + console.error('Error loading commands:', error); +} + +client.once('ready', () => { + console.log('Bot is online!'); +}); + +// Sets to keep track of "tranq" and "coma" users +const tranqUsers = new Set(); +const comaUsers = new Set(); + +// Path to the JSON file to store baboon users +const baboonUsersPath = path.join(__dirname, 'baboon_users.json'); + +// Load baboon users from the JSON file +let baboonUsers = {}; +if (fs.existsSync(baboonUsersPath)) { + baboonUsers = JSON.parse(fs.readFileSync(baboonUsersPath, 'utf8')); +} + +client.on('messageCreate', async message => { + if (tranqUsers.has(message.author.id) || comaUsers.has(message.author.id)) { + await message.delete(); + return; + } + + if (!message.content.startsWith('~') || message.author.bot) return; + + const args = message.content.slice(1).split(/ +/); + const commandName = args.shift().toLowerCase(); + + if (!client.commands.has(commandName)) return; + + const command = client.commands.get(commandName); + + try { + console.log(`Passing comaUsers and tranqUsers sets to ${commandName} command with sizes: comaUsers=${comaUsers.size}, tranqUsers=${tranqUsers.size}`); + await command.execute(message, args, tranqUsers, comaUsers); + } catch (error) { + console.error(error); + message.reply('There was an error trying to execute that command!'); + } +}); + +client.on('guildMemberRemove', async member => { + const channelId = '826225570219687956'; // Channel ID to send the message + const roleId = '1160622954082738347'; // Baboon role ID + + if (member.roles.cache.has(roleId)) { + const channel = member.guild.channels.cache.get(channelId); + if (channel) { + channel.send('The baboon has made an escape!'); + } else { + console.error(`Channel with ID ${channelId} not found`); + } + + // Store the user ID in the baboon users list + baboonUsers[member.id] = true; + fs.writeFileSync(baboonUsersPath, JSON.stringify(baboonUsers, null, 2), 'utf8'); + } +}); + +client.on('guildMemberAdd', async member => { + const channelId = '826225570219687956'; // Channel ID to send the message + const roleId = '1160622954082738347'; // Baboon role ID + + // Check if the user is in the baboon users list + if (baboonUsers[member.id]) { + const role = member.guild.roles.cache.get(roleId); + if (role) { + try { + await member.roles.add(role); + console.log(`Reapplied baboon role to ${member.user.tag}`); + + const channel = member.guild.channels.cache.get(channelId); + if (channel) { + channel.send(`A loose baboon has been recaptured!`); + } else { + console.error(`Channel with ID ${channelId} not found`); + } + } catch (error) { + console.error(`Failed to reapply baboon role to ${member.user.tag}`, error); + } + } else { + console.error('Baboon role not found'); + } + } +}); + +client.login(process.env.DISCORD_TOKEN); diff --git a/package.json b/package.json new file mode 100644 index 0000000..07c0fb8 --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "discord-bot", + "version": "1.0.0", + "description": "A simple Discord bot", + "main": "index.js", + "scripts": { + "start": "node index.js" + }, + "dependencies": { + "discord.js": "^14.0.0", + "dotenv": "^16.4.5" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/roles_backup.json b/roles_backup.json new file mode 100644 index 0000000..ff42e7e --- /dev/null +++ b/roles_backup.json @@ -0,0 +1,37 @@ +{ + "167477492838432768": [ + "964354344948494416" + ], + "572126749597630464": [ + "963208841741340743", + "1160622954082738347", + "963557331327672372", + "969767633278869515", + "971984383164711002", + "963206030924333096", + "975061440794861638", + "963985624329756682", + "963462828872859668" + ], + "452942530065989642": [ + "1160622954082738347" + ], + "1013430816304541766": [ + "964354344948494416" + ], + "1233111163882176594": [ + "964354344948494416" + ], + "1226168443426967632": [ + "964354344948494416" + ], + "1050959386371166288": [ + "964354344948494416" + ], + "1230771811147321344": [ + "964354344948494416" + ], + "994895147621949511": [ + "964354344948494416" + ] +} \ No newline at end of file diff --git a/scripts/bot.log b/scripts/bot.log new file mode 100644 index 0000000..e69de29 diff --git a/scripts/start-bot.sh b/scripts/start-bot.sh new file mode 100755 index 0000000..5d7529a --- /dev/null +++ b/scripts/start-bot.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +# Absolute path to your bot's main JavaScript file +BOT_JS_PATH="/home/nick/discord-bots/zookeeper/index.js" + +# Log file for the bot +LOG_FILE="/home/nick/discord-bots/zookeeper/scripts/bot.log" + +# Function to start the bot using forever +start_bot() { + echo "$(date): Starting bot..." | tee -a $LOG_FILE + forever start --spinSleepTime 5000 -c "node" $BOT_JS_PATH >> $LOG_FILE 2>&1 +} + +# Function to stop the bot +stop_bot() { + echo "$(date): Stopping bot..." | tee -a $LOG_FILE + forever stop $BOT_JS_PATH >> $LOG_FILE 2>&1 +} + +# Check if the bot is already running +if forever list | grep -q $BOT_JS_PATH; then + echo "$(date): Bot is already running. Restarting bot..." | tee -a $LOG_FILE + stop_bot +fi + +# Start the bot +start_bot + +# Keep the script running to monitor the bot +while true; do + sleep 1 + if ! forever list | grep -q $BOT_JS_PATH; then + echo "$(date): Bot has crashed. Restarting bot..." | tee -a $LOG_FILE + start_bot + fi +done