From bc39fe3f7a26ef2e4b40c56e84c9b4c2d44318af Mon Sep 17 00:00:00 2001 From: Ryahn Date: Mon, 12 May 2025 15:08:23 -0500 Subject: [PATCH] Updated gaydar and refactor --- assets/gaydar.jpg | Bin 0 -> 17489 bytes commands/gaydar.js | 109 +++++++++++++++++++++++++++-------- events/messageCreate.js | 2 - handlers/command.js | 54 ++++++++++++++--- handlers/database.js | 27 ++++++--- handlers/event.js | 50 +++++++++++++--- handlers/function.js | 43 +++++++++++--- index.js | 125 +++++++++++++++++++++++++++------------- package-lock.json | 10 ++-- package.json | 2 +- 10 files changed, 318 insertions(+), 104 deletions(-) create mode 100644 assets/gaydar.jpg diff --git a/assets/gaydar.jpg b/assets/gaydar.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d7a000049e2e86d1a2b4f0841da6140301d7f4c8 GIT binary patch literal 17489 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 { - function randomInteger(min, max) { - min = Math.ceil(min); - max = Math.floor(max); - return Math.floor(Math.random() * (max - min + 1)) + min; + try { + + function randomInteger(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + let targetUser; + + // Check if there's a mentioned user + if (message.mentionIds && message.mentionIds.length > 0) { + try { + const server = await client.servers.fetch(message.server.id); + const member = await server.fetchMember(message.mentionIds[0]); + + if (!member || !member.id || !member.id.user) { + throw new Error("Invalid member structure"); + } + + // Fetch the user using the user ID from the member object + targetUser = await client.users.fetch(member.id.user); + + if (!targetUser || !targetUser.username) { + throw new Error("Could not fetch user information"); + } + + } catch (fetchError) { + console.error("Fetch error details:", fetchError.message); + return message.reply({ + embeds: [new Embed() + .setDescription("Could not find the mentioned user.") + .setColor(`#FF0000`)] + }, false); + } + } else { + // Use the command author if no user is mentioned + targetUser = message.author; + } + + if (!targetUser) { + return message.reply({ + embeds: [new Embed() + .setDescription("Could not determine the target user.") + .setColor(`#FF0000`)] + }, false); + } + + const amount = randomInteger(1, 100); + const imagePath = path.join(__dirname, "../assets/gaydar.jpg"); + + // Check if file exists + if (!fs.existsSync(imagePath)) { + return message.reply({ + embeds: [new Embed() + .setDescription("Error: Required image file not found.") + .setColor(`#FF0000`)] + }, false); + } + + // Upload the image as an attachment + const attachment = await client.Uploader.uploadFile(imagePath, "gaydar.jpg"); + + // Send the message with the attachment + await message.channel.sendMessage({ + content: `#### ${targetUser.username} is ${amount}% gay.`, + attachments: [attachment] + }); + + } catch (error) { + console.log(`${Date(Date.now().toString()).slice(0, 25)}`); + console.log("User: " + message.author.username + ` [${message.authorId}] ` + " | Command: gaydar | Args: " + (args?.join(" ") || "NONE")); + console.log(error.message); + + return message.reply({ + embeds: [new Embed() + .setDescription("An error occurred while processing the command.") + .setColor(`#FF0000`)] + }, false); } - - const member = await (client.servers.get(message.server.id) || await client.servers.fetch(message.server.id))?.fetchMember(message.mentionIds[0]).then((user) => { - return console.log(); - }); - // const target = member.user.username; - // return console.log(member) - // let amount = randomInteger(1, 100); - - // const embed = { - // description: `#### ${target} is ${amount}% gay.`, - // colour: "#ff8080", - // image: 'https://overlord.lordainz.xyz/f/gaydar.jpg' - // } - - // await message.channel.sendMessage({ content: "", embeds: [embed] }).catch(err => { - // console.log(`${Date(Date.now().toString()).slice(0, 25)}`); - // console.log("User: " + message.author.username + ` [${message.authorId}] ` + " | Command: gardar | Args: " + (args?.join(" ") || "NONE")) - // console.log(err.message); - // return; - // }); }, }; \ No newline at end of file diff --git a/events/messageCreate.js b/events/messageCreate.js index 49a1fc0..ded25b9 100644 --- a/events/messageCreate.js +++ b/events/messageCreate.js @@ -3,8 +3,6 @@ const Collector = require("../functions/messageCollector"); const EditCollector = require("../functions/messageEdit"); const CommandDB = require('../models/commands'); const { isJson } = require('../functions/randomStr'); -const logger = require('../functions/logger'); -const audit = require('../functions/audit'); module.exports = async (client, message) => { // Early return checks diff --git a/handlers/command.js b/handlers/command.js index ce381b4..9e42424 100644 --- a/handlers/command.js +++ b/handlers/command.js @@ -1,12 +1,50 @@ const { readdirSync } = require("fs") +const { join } = require("path") const color = require("../functions/colorCodes") -module.exports = (client) => { - const commands = readdirSync(`./commands/`).filter(d => d.endsWith('.js')); - for (let file of commands) { - let pull = require(`../commands/${file}`); - client.commands.set(pull.config.name, pull); - if (pull.config.aliases) pull.config.aliases.forEach(a => client.aliases.set(a, pull.config.name)); - }; - console.log(color("%", `%b[Command_Handler]%7 :: Loaded %e${client.commands.size} %7commands`)); +/** + * Loads and registers all command files from the commands directory + * @param {Object} client - The Discord client instance + * @returns {Promise} + */ +module.exports = async (client) => { + try { + const commandsPath = join(__dirname, "..", "commands") + const commandFiles = readdirSync(commandsPath).filter(file => file.endsWith(".js")) + + let loadedCommands = 0 + let failedCommands = 0 + + for (const file of commandFiles) { + try { + const command = require(join(commandsPath, file)) + + // Validate command structure + if (!command.config?.name) { + console.error(color("%", `%r[Command_Handler]%7 :: Command in ${file} is missing required config.name property`)) + failedCommands++ + continue + } + + // Register command and aliases + client.commands.set(command.config.name, command) + if (command.config.aliases?.length) { + command.config.aliases.forEach(alias => client.aliases.set(alias, command.config.name)) + } + + loadedCommands++ + } catch (error) { + console.error(color("%", `%r[Command_Handler]%7 :: Failed to load command ${file}: ${error.message}`)) + failedCommands++ + } + } + + console.log(color("%", `%b[Command_Handler]%7 :: Successfully loaded %e${loadedCommands}%7 commands`)) + if (failedCommands > 0) { + console.warn(color("%", `%y[Command_Handler]%7 :: Failed to load %r${failedCommands}%7 commands`)) + } + } catch (error) { + console.error(color("%", `%r[Command_Handler]%7 :: Critical error: ${error.message}`)) + throw error // Re-throw to handle at higher level + } } \ No newline at end of file diff --git a/handlers/database.js b/handlers/database.js index 338615d..226b439 100644 --- a/handlers/database.js +++ b/handlers/database.js @@ -1,11 +1,24 @@ const { connect } = require("mongoose").set('strictQuery', true); const color = require("../functions/colorCodes") +const fs = require('fs'); +const path = require('path'); module.exports = class DatabaseHandler { constructor(connectionString) { this.cache = new Map(); - this.guildModel = require('../models/guilds'); this.connectionString = connectionString; + this.models = {}; + this.initializeModels(); + } + + initializeModels() { + const modelsPath = path.join(__dirname, '../models'); + const modelFiles = fs.readdirSync(modelsPath).filter(file => file.endsWith('.js')); + + for (const file of modelFiles) { + const modelName = path.parse(file).name; + this.models[modelName] = require(path.join(modelsPath, file)); + } } cacheSweeper(client) { @@ -46,17 +59,17 @@ module.exports = class DatabaseHandler { } async fetchGuild(guildId, createIfNotFound = false) { - const fetched = await this.guildModel.findOne({ id: guildId }); + const fetched = await this.models.guilds.findOne({ id: guildId }); if (fetched) return fetched; if (!fetched && createIfNotFound) { - await this.guildModel.create({ + await this.models.guilds.create({ id: guildId, language: 'en_EN', botJoined: Date.now() / 1000 | 0, }); - return this.guildModel.findOne({ id: guildId }); + return this.models.guilds.findOne({ id: guildId }); } return null; } @@ -78,7 +91,7 @@ module.exports = class DatabaseHandler { async deleteGuild(guildId, onlyCache = false) { if (this.cache.has(guildId)) this.cache.delete(guildId); - return !onlyCache ? this.guildModel.deleteMany({ id: guildId }) : true; + return !onlyCache ? this.models.guilds.deleteMany({ id: guildId }) : true; } async updateGuild(guildId, data = {}, createIfNotFound = false) { @@ -91,13 +104,13 @@ module.exports = class DatabaseHandler { this.cache.set(guildId, data); - return this.guildModel.updateOne({ + return this.models.guilds.updateOne({ id: guildId, }, data); } return null; } async getAll() { - return this.guildModel.find(); + return this.models.guilds.find(); } }; \ No newline at end of file diff --git a/handlers/event.js b/handlers/event.js index 55c74dd..6a967f8 100644 --- a/handlers/event.js +++ b/handlers/event.js @@ -1,12 +1,44 @@ const { readdirSync } = require("fs") +const path = require("path") const color = require("../functions/colorCodes") -module.exports = (client) => { - const events = readdirSync(`./events/`).filter(d => d.endsWith('.js')); - for (let file of events) { - let evt = require(`../events/${file}`); - client.event.set(file.split(".")[0], evt.bind(null, client)); - client.on(file.split('.')[0], evt.bind(null, client)); - }; - console.log(color("%", `%b[Event_Handler]%7 :: Loaded %e${client.event.size} %7events`)); -}; \ No newline at end of file +/** + * Loads and registers all event handlers for the client + * @param {Object} client - The Discord client instance + * @returns {Promise} + */ +module.exports = async (client) => { + try { + const eventsPath = path.join(__dirname, "..", "events") + const eventFiles = readdirSync(eventsPath) + .filter(file => file.endsWith(".js")) + + const loadedEvents = await Promise.all( + eventFiles.map(async (file) => { + try { + const eventName = path.parse(file).name + const event = require(path.join(eventsPath, file)) + + // Register the event + client.event.set(eventName, event.bind(null, client)) + client.on(eventName, event.bind(null, client)) + + return eventName + } catch (error) { + console.error(color("%", `%r[Event_Handler]%7 :: Failed to load event %e${file}%7: ${error.message}`)) + return null + } + }) + ) + + const successfulEvents = loadedEvents.filter(Boolean) + console.log(color("%", `%b[Event_Handler]%7 :: Successfully loaded %e${successfulEvents.length}%7 events`)) + + if (successfulEvents.length < eventFiles.length) { + console.warn(color("%", `%y[Event_Handler]%7 :: %r${eventFiles.length - successfulEvents.length}%7 events failed to load`)) + } + } catch (error) { + console.error(color("%", `%r[Event_Handler]%7 :: Critical error: ${error.message}`)) + throw error // Re-throw to handle it in the main application + } +} \ No newline at end of file diff --git a/handlers/function.js b/handlers/function.js index be5637c..c77ebdd 100644 --- a/handlers/function.js +++ b/handlers/function.js @@ -1,11 +1,40 @@ const { readdirSync } = require("fs") +const { join } = require("path") const logger = require("../functions/logger") -module.exports = (client) => { - const functions = readdirSync(`./functions`).filter(d => d.endsWith('.js')); - for (let file of functions) { - let evt = require(`../functions/${file}`); - client.functions.set(file.split(".")[0], evt); - }; - logger.event('Function_Handler', `Loaded ${client.functions.size} functions`); +/** + * Loads and registers all function modules from the functions directory + * @param {Object} client - The client instance + * @returns {Promise} + */ +module.exports = async (client) => { + try { + if (!client || !client.functions) { + throw new Error('Invalid client object or missing functions collection'); + } + + const functionsDir = join(__dirname, '..', 'functions'); + const functions = readdirSync(functionsDir) + .filter(file => file.endsWith('.js') && file !== 'logger.js'); + + const loadedFunctions = await Promise.all( + functions.map(async (file) => { + try { + const functionName = file.split('.')[0]; + const functionModule = require(join(functionsDir, file)); + client.functions.set(functionName, functionModule); + return functionName; + } catch (error) { + logger.error('Function_Handler', `Failed to load function ${file}: ${error.message}`); + return null; + } + }) + ); + + const successfulLoads = loadedFunctions.filter(Boolean).length; + logger.event('Function_Handler', `Successfully loaded ${successfulLoads}/${functions.length} functions`); + } catch (error) { + logger.error('Function_Handler', `Failed to initialize function handler: ${error.message}`); + throw error; + } }; \ No newline at end of file diff --git a/index.js b/index.js index bb29e1e..6930b7c 100644 --- a/index.js +++ b/index.js @@ -2,57 +2,102 @@ const { Client } = require("revolt.js"); const { Collection } = require('@discordjs/collection'); const { token, mongoDB, api } = require("./botconfig.json"); const logger = require('./functions/logger'); -const checkPolls = require('./functions/checkPolls') - +const checkPolls = require('./functions/checkPolls'); const color = require("./functions/colorCodes"); - -const client = new Client({ baseURL: api }); const Uploader = require("revolt-uploader"); -const fetch = require("wumpfetch"); const TranslationHandler = require('./handlers/translation'); const DatabaseHandler = require('./handlers/database'); -client.Uploader = new Uploader(client); -client.config = require("./config"); -client.translate = new TranslationHandler(); -client.logger = require('./functions/logger'); -client.botConfig = require("./botconfig.json"); +class Bot { + constructor(config) { + this.config = config; + this.client = new Client({ baseURL: config.api }); + this.initializeCore(); + this.initializeCollections(); + this.setupErrorHandling(); + } -client.database = new DatabaseHandler(mongoDB); -client.database.connectToDatabase(); -client.database.cacheSweeper(client); -client.database.guildSweeper(client); + initializeCore() { + this.client.Uploader = new Uploader(this.client); + this.client.config = require("./config"); + this.client.translate = new TranslationHandler(); + this.client.logger = logger; + this.client.botConfig = this.config; + } -["reactions", "paginate", "timeout", "polls", "used", "messageCollector", "messageEdit"].forEach(x => client[x] = new Map()); -["aliases", "commands", "event", "functions"].forEach(x => client[x] = new Collection()); -["command", "event", "function"].forEach(x => require(`./handlers/${x}`)(client)); + initializeCollections() { + const collections = ["aliases", "commands", "event", "functions"]; + const maps = ["reactions", "paginate", "timeout", "polls", "used", "messageCollector", "messageEdit"]; -client.once("ready", async () => { - logger.success('Bot Ready', `${client.user.username} is ready`); + collections.forEach(x => this.client[x] = new Collection()); + maps.forEach(x => this.client[x] = new Map()); + } -//client.database.connectToDatabase(); -//client.database.cacheSweeper(client); -//client.database.guildSweeper(client); + async initializeDatabase() { + try { + const db = new DatabaseHandler(this.config.mongoDB); + await db.connectToDatabase(); + + this.client.database = db; + this.client.models = db.models; + + db.cacheSweeper(this.client); + db.guildSweeper(this.client); + + logger.success('Database', 'Successfully connected to database'); + } catch (error) { + logger.error('Database Error', error); + throw error; + } + } - await checkPolls(client); + setupErrorHandling() { + const errorTypes = { + "unhandledRejection": "Unhandled Rejection/Catch", + "uncaughtException": "Uncaught Exception/Catch", + "uncaughtExceptionMonitor": "Uncaught Exception/Catch (MONITOR)" + }; -}); + Object.entries(errorTypes).forEach(([event, message]) => { + process.on(event, (error, origin) => { + logger.error('Error Handling', `${message}: ${error.message}`); + console.log(color("%", `%4[Error_Handling] :: ${message}%c`)); + console.log(error); + if (origin) console.log(origin); + }); + }); + } + async initializeHandlers() { + try { + ["command", "event", "function"].forEach(x => require(`./handlers/${x}`)(this.client)); + logger.success('Handlers', 'Successfully initialized all handlers'); + } catch (error) { + logger.error('Handler Error', error); + throw error; + } + } -process.on("unhandledRejection", (reason, p) => { - console.log(color("%", "%4[Error_Handling] :: Unhandled Rejection/Catch%c")); - console.log(reason); - console.log(p) -}); -process.on("uncaughtException", (err, origin) => { - console.log(color("%", "%4[Error_Handling] :: Uncaught Exception/Catch%c")); - console.log(err); - console.log(origin) -}); -process.on("uncaughtExceptionMonitor", (err, origin) => { - console.log(color("%", "%4[Error_Handling] :: Uncaught Exception/Catch (MONITOR)%c")); - console.log(err); - console.log(origin) -}); + setupEventListeners() { + this.client.once("ready", async () => { + logger.success('Bot Ready', `${this.client.user.username} is ready`); + await checkPolls(this.client); + }); + } -client.loginBot(token); + async start() { + try { + await this.initializeDatabase(); + await this.initializeHandlers(); + this.setupEventListeners(); + await this.client.loginBot(this.config.token); + } catch (error) { + logger.error('Startup Error', error); + process.exit(1); + } + } +} + +// Start the bot +const bot = new Bot({ token, mongoDB, api }); +bot.start(); diff --git a/package-lock.json b/package-lock.json index 37a1cc1..3a079c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "mongoose": "^7.2.0", "nanoid": "3.3.4", "node-fetch-commonjs": "^3.3.2", - "revolt-uploader": "^1.1.1", + "revolt-uploader": "^1.1.5", "revolt.js": "npm:revolt.js-update@^7.0.0-beta.9", "screen": "^0.2.10", "wumpfetch": "^0.3.1" @@ -1227,10 +1227,10 @@ } }, "node_modules/revolt-uploader": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/revolt-uploader/-/revolt-uploader-1.1.4.tgz", - "integrity": "sha512-hnUCc1grg6Yq1J2q0HcsbfbWCvHIR6hPHzk3/75EjWEjP7bPYwAAVsHOwwtfdMtwMUPN9EAmBj3NvU4t+o1JJw==", - "license": "ISC", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/revolt-uploader/-/revolt-uploader-1.1.6.tgz", + "integrity": "sha512-teMUhz/QJDqx/sXJFFReur8kR/KUSl2A5dYy9hLY/KLLgpaZw+el4bV+TgFb0vPtpM4hg7mLn44gLiuBR7kD7g==", + "license": "MIT", "dependencies": { "form-data": "^4.0.0", "node-fetch": "^2.6.7" diff --git a/package.json b/package.json index a1e4348..bf2fa4b 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "mongoose": "^7.2.0", "nanoid": "3.3.4", "node-fetch-commonjs": "^3.3.2", - "revolt-uploader": "^1.1.1", + "revolt-uploader": "^1.1.5", "revolt.js": "npm:revolt.js-update@^7.0.0-beta.9", "screen": "^0.2.10", "wumpfetch": "^0.3.1"