From 3572b97661a3f7c6c29e958b63c20d9f2ef936ac Mon Sep 17 00:00:00 2001 From: Amygdala Peanut-Almond Date: Wed, 22 Apr 2026 22:49:01 +0200 Subject: initialise repository Signed-off-by: Amygdala Peanut-Almond --- commands/eval.js | 42 ++++++++++++++++++++++++++++ commands/exec.js | 43 ++++++++++++++++++++++++++++ commands/haze.js | 28 +++++++++++++++++++ commands/help.js | 18 ++++++++++++ commands/ping.js | 12 ++++++++ commands/reload.js | 35 +++++++++++++++++++++++ commands/sql.js | 65 +++++++++++++++++++++++++++++++++++++++++++ config.json | 7 +++++ events/00ready.js | 13 +++++++++ events/cat.js | 9 ++++++ events/dphoque.js | 11 ++++++++ events/messageCommands.js | 71 +++++++++++++++++++++++++++++++++++++++++++++++ events/messageDelete.js | 35 +++++++++++++++++++++++ events/spambot-fucker.js | 10 +++++++ index.js | 52 ++++++++++++++++++++++++++++++++++ libs/datajob.js | 27 ++++++++++++++++++ libs/webhook.js | 11 ++++++++ package.json | 11 ++++++++ utils/initdb.js | 7 +++++ 19 files changed, 507 insertions(+) create mode 100644 commands/eval.js create mode 100644 commands/exec.js create mode 100644 commands/haze.js create mode 100644 commands/help.js create mode 100644 commands/ping.js create mode 100644 commands/reload.js create mode 100644 commands/sql.js create mode 100644 config.json create mode 100644 events/00ready.js create mode 100644 events/cat.js create mode 100644 events/dphoque.js create mode 100644 events/messageCommands.js create mode 100644 events/messageDelete.js create mode 100644 events/spambot-fucker.js create mode 100644 index.js create mode 100644 libs/datajob.js create mode 100644 libs/webhook.js create mode 100644 package.json create mode 100644 utils/initdb.js diff --git a/commands/eval.js b/commands/eval.js new file mode 100644 index 0000000..e73c9bc --- /dev/null +++ b/commands/eval.js @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2024 Emilia Luminé + * This file is a part of the Shamestech bot. + * + * The Shamestech bot is free software: you can redistribute it and/or modify it + * under the terms of the European Union Public License as published by + * by the European Union, only the version 1.2 of the License. + * + * The Shamestech bot is distributed in the hope that it will be useful + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * European Union Public License for more details. + * + * You should have received a copy of the European Union Public License, If not + * see +*/ + +const util = require('node:util'); + +module.exports = { + name: 'eval', + hidden: true, + async execute(message, args) { + const prompt = args.join(' '); + let out = ''; + + if (message.author.id !== "1425229394703683614") { + return; + } + + try { + out = util.inspect(await eval(prompt)); + } catch (e) { + out = `${e}`; + } + + return await message.reply({ + content: `${out.length === 0 ? 'empty' : out}` + }); + } +} + diff --git a/commands/exec.js b/commands/exec.js new file mode 100644 index 0000000..c92b32a --- /dev/null +++ b/commands/exec.js @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 Emilia Luminé + * This file is a part of the Shamestech bot. + * + * The Shamestech bot is free software: you can redistribute it and/or modify it + * under the terms of the European Union Public License as published by + * by the European Union, only the version 1.2 of the License. + * + * The Shamestech bot is distributed in the hope that it will be useful + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * European Union Public License for more details. + * + * You should have received a copy of the European Union Public License, If not + * see +*/ + +const childprocess = require("node:child_process"); +const util = require('node:util'); + +module.exports = { + name: 'exec', + hidden: true, + async execute(message, args) { + const prompt = args.join(' '); + let out = ''; + + if (message.author.id !== "1425229394703683614") { + return; + } + + try { + out = util.format(childprocess.execSync(prompt).toString()); + } catch (e) { + out = `${e}`; + } + + return await message.reply({ + content: `\`\`\`\n${out.length === 0 ? 'empty' : out}\n\`\`\`` + }); + } +} + diff --git a/commands/haze.js b/commands/haze.js new file mode 100644 index 0000000..3533be2 --- /dev/null +++ b/commands/haze.js @@ -0,0 +1,28 @@ +const { saveUserData } = require("../libs/datajob.js"); + +module.exports = { + name: 'haze', + hidden: true, + async execute(message, args) { + let fetchable = []; + let i = 0; + + const connection = await database.connect(); + + message.guild.members.cache.forEach((fetchie) => { + fetchable.push(fetchie.id); + }); + + for (let i = 0; i < fetchable.length; i++) { + const member = fetchable[i]; + console.log(member); + await saveUserData(connection, member); + i++; + }; + + connection.release(); + + return await message.reply({ content: `${i}` }); + } +} + diff --git a/commands/help.js b/commands/help.js new file mode 100644 index 0000000..e65e9ad --- /dev/null +++ b/commands/help.js @@ -0,0 +1,18 @@ +module.exports = { + name: 'help', + description: "shows the available commands", + hidden: false, + async execute(message, args) { + let out = ''; + + globalThis.commands.forEach((cmd) => { + if (cmd.hidden) return; + out = `${out}${cmd.name} - ${cmd.description}\n` + }); + + return await message.reply({ + content: `available commands:\n${out}` + }); + } +} + diff --git a/commands/ping.js b/commands/ping.js new file mode 100644 index 0000000..e30781d --- /dev/null +++ b/commands/ping.js @@ -0,0 +1,12 @@ +module.exports = { + name: 'ping', + description: "🏓 pong!", + async execute(message, args) { + const a = Date.now(); + const mesgA = await message.reply(`🏓 pong!\ngateway: ${client.ws.ping}ms`); + const b = Date.now(); + + await mesgA.edit(`${mesgA.content}\napi: ${b-a}ms`); + } +} + diff --git a/commands/reload.js b/commands/reload.js new file mode 100644 index 0000000..c1624ab --- /dev/null +++ b/commands/reload.js @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2024 Emilia Luminé + * This file is a part of the Shamestech bot. + * + * The Shamestech bot is free software: you can redistribute it and/or modify it + * under the terms of the European Union Public License as published by + * by the European Union, only the version 1.2 of the License. + * + * The Shamestech bot is distributed in the hope that it will be useful + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * European Union Public License for more details. + * + * You should have received a copy of the European Union Public License, If not + * see +*/ + +const util = require('node:util'); + +module.exports = { + name: 'reload', + hidden: true, + async execute(message, args) { + if (message.author.id !== "1425229394703683614") { + return; + } + + globalThis.commandsReload(); + globalThis.reloadEvents(); + return await message.reply({ + content: `meow` + }); + } +} + diff --git a/commands/sql.js b/commands/sql.js new file mode 100644 index 0000000..78aeb02 --- /dev/null +++ b/commands/sql.js @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2024 Emilia Luminé + * This file is a part of the Shamestech bot. + * + * The Shamestech bot is free software: you can redistribute it and/or modify it + * under the terms of the European Union Public License as published by + * by the European Union, only the version 1.2 of the License. + * + * The Shamestech bot is distributed in the hope that it will be useful + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * European Union Public License for more details. + * + * You should have received a copy of the European Union Public License, If not + * see +*/ + +const util = require('node:util'); + +function _plushie(object) { + let loopie = Object.keys(object); + let out = ""; + + for (let i = 0; i < loopie.length; i++) { + out = `${out}${loopie[i]}: ${object[loopie[i]]}; ` + } + out = `${out}` + + return out; +} + +function plushie(arrie) { + let out = ''; + + for (let i = 0; i < arrie.length; i++) { + out = `${out}\n${_plushie(arrie[i])}`; + } + + return out; +} + +module.exports = { + name: 'sql', + hidden: true, + async execute(message, args) { + const prompt = args.join(' '); + let out = ''; + + if (message.author.id !== "1425229394703683614") { + return; + } + + try { + const query = await database.query(prompt); + out = `${plushie(query)}`; + } catch (e) { + out = `${e}`; + } + + return await message.reply({ + content: `${out}` + }); + } +} + diff --git a/config.json b/config.json new file mode 100644 index 0000000..2379ceb --- /dev/null +++ b/config.json @@ -0,0 +1,7 @@ +{ + "directories": { + "eventsDir": "./events", + "commandsDir": "./commands" + }, + "prefixes": ["amy!", "!", "?", "z"] +} diff --git a/events/00ready.js b/events/00ready.js new file mode 100644 index 0000000..0a45a16 --- /dev/null +++ b/events/00ready.js @@ -0,0 +1,13 @@ +const Discord = require("discord.js"); +const postgresql = require("pg"); + +global.database = new postgresql.Pool(); + +module.exports = { + name: 'clientReady', + async execute() { + globalThis.client.user.setActivity("a ball of yarn!! >w<", { type: Discord.ActivityType.Playing }); + console.log("clientReady"); + } +} + diff --git a/events/cat.js b/events/cat.js new file mode 100644 index 0000000..1e1f561 --- /dev/null +++ b/events/cat.js @@ -0,0 +1,9 @@ +module.exports = { + name: 'messageCreate', + async execute(message) { + if (message.content.includes('cat') || message.content.includes("meow")) { + await message.react("🐈"); + } + } +} + diff --git a/events/dphoque.js b/events/dphoque.js new file mode 100644 index 0000000..15a3f84 --- /dev/null +++ b/events/dphoque.js @@ -0,0 +1,11 @@ +module.exports = { + name: 'messageCreate', + async execute(message) { + if (message.content.includes('d\'phoque') || message.content.includes('dphoque')) { + return await message.channel.send({ + content: `shut your bitch ass up <@!${message.author.id}> 💜 I PURPLE YOU 🫰` + }); + } + } +} + diff --git a/events/messageCommands.js b/events/messageCommands.js new file mode 100644 index 0000000..25f1260 --- /dev/null +++ b/events/messageCommands.js @@ -0,0 +1,71 @@ +const path = require('node:path'); +const util = require('node:util'); +const fs = require('node:fs'); + +const { Collection } = require('discord.js'); + +globalThis.commands = new Collection(); + +globalThis.commandsReload = () => { + globalThis.commands = new Collection(); + + console.error('commands:'); + + const commandsDir = fs.readdirSync(config.directories.commandsDir).filter((fileName) => fileName.endsWith('.js')); + + for (let i = 0; i < commandsDir.length; i += 1) { + const commandModulePath = path.join(process.cwd(), config.directories.commandsDir, commandsDir[i]); + delete require.cache[require.resolve(commandModulePath)]; + + const commandModule = require(commandModulePath); + + if (typeof commandModule.name !== 'string' || typeof commandModule.execute !== 'function') { + console.error(`${commandModulePath} is not a valid command module`); + continue; + } + + commands.set(commandModule.name, commandModule); + + console.log(`\t${commandsDir[i]} -> ${commandModule.name}`); + } +} + +globalThis.commandsReload(); + +module.exports = { + name: 'messageCreate', + async execute(message) { + if (message.author.bot) return; + + let prefix = false; + for (let i = 0; i < config.prefixes.length; i += 1) { + const configuredPrefix = config.prefixes[i]; + + if (message.content.startsWith(configuredPrefix)) { + prefix = configuredPrefix; + break; + } + } + + if (!prefix) { + return; + } + + const args = message.content.slice(prefix.length).trim().split(/ +/gmi); + const command = globalThis.commands.get(args[0]); + + if (!command) { + return; + } + + try { + await command.execute(message, args.slice(1), globalThis.client); + } catch (e) { + console.error(e); + return await message.reply({ + content: `an error occurred\n${e}\nplease contact the bot developer` + }); + } + } +} + diff --git a/events/messageDelete.js b/events/messageDelete.js new file mode 100644 index 0000000..cfba446 --- /dev/null +++ b/events/messageDelete.js @@ -0,0 +1,35 @@ +const { getWebhook } = require("../libs/webhook.js"); + +module.exports = { + name: "messageDelete", + async execute(msg) { + if (msg.webhookId !== null) return; + + console.log("a"); + const wh = await getWebhook(msg.guild.id); + if (wh === null) return; + console.log("b"); + + await wh.send({ + content: `Message deleted in <#${msg.channel.id}>`, + embeds: [ + { + title: "Deleted message", + author: { + name: `${msg.author.globalName} (${msg.author.username}; ${msg.author.id})` + }, + fields: [ + { + name: "Content", + value: msg.content + } + ], + timestamp: msg.createdAt + } + ] + }); + delete wh; + console.log("d"); + } +} + diff --git a/events/spambot-fucker.js b/events/spambot-fucker.js new file mode 100644 index 0000000..c343865 --- /dev/null +++ b/events/spambot-fucker.js @@ -0,0 +1,10 @@ +module.exports = { + name: 'messageCreate', + async execute(msg) { + if (msg.channel.id === "1491056218498793552") { + await msg.member.timeout(2_419_200_000); + } + } +} + + diff --git a/index.js b/index.js new file mode 100644 index 0000000..57c1091 --- /dev/null +++ b/index.js @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2024 Emilia Luminé + * This file is a part of the Amygdala bot. +*/ + +const path = require('node:path'); +const fs = require('node:fs'); + +const dotenv = require('dotenv'); +const { Client, GatewayIntentBits, Partials } = require('discord.js'); + +globalThis.config = require('./config.json'); +dotenv.config({ quiet: true }); + +const client = new Client({ + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.GuildMembers, + GatewayIntentBits.MessageContent + ] +}); +globalThis.client = client; + +globalThis.reloadEvents = () => { + client.removeAllListeners(); + + const eventsDir = fs.readdirSync(config.directories.eventsDir).filter((fileName) => fileName.endsWith('.js')); + + for (let i = 0; i < eventsDir.length; i += 1) { + const eventModulePath = path.join(process.cwd(), config.directories.eventsDir, eventsDir[i]); + + const eventModule = require(eventModulePath); + + if (typeof eventModule.name !== 'string' || typeof eventModule.execute !== 'function') { + console.error(`${eventModulePath} is not a valid event module`); + break; + } + + console.log(`${eventModule.name}`); + client.on(eventModule.name, eventModule.execute); + } +} + +process.on('unhandledRejection', async (a) => { + console.error(a); +}); + +globalThis.reloadEvents(); + +client.login(process.env.DISCORD_BOT_TOKEN); + diff --git a/libs/datajob.js b/libs/datajob.js new file mode 100644 index 0000000..3453bcd --- /dev/null +++ b/libs/datajob.js @@ -0,0 +1,27 @@ +function queryAw(connection, id, key, value) { + connection.query("INSERT INTO amygdala_profile(timestamp, userID, key, value) VALUES ($1, $2, $3, $4);", [Date.now(), id, key, value]); +} + +module.exports = { + async saveUserData(connection, userId) { + let userData = client.users.cache.get(userId); + if (userData === undefined) { + userData = await client.users.fetch(userId); + } + + await connection.query("BEGIN;"); + + try { + if (userData.globalName !== null) await queryAw(connection, userId, "discord_globalName", userData.globalName); + if (userData.avatar !== null) await queryAw(connection, userId, "discord_avatar", userData.avatar); + await queryAw(connection, userId, "discord_username", userData.username); + await queryAw(connection, userId, "discord_discriminator", userData.discriminator); + } catch (e) { + await connection.query("ROLLBACK;"); + throw e; + } + + await connection.query("COMMIT;"); + } +} + diff --git a/libs/webhook.js b/libs/webhook.js new file mode 100644 index 0000000..5c89f12 --- /dev/null +++ b/libs/webhook.js @@ -0,0 +1,11 @@ +const Discord = require("discord.js"); + +module.exports = { + async getWebhook(guildId) { + const result = await database.query("SELECT * FROM amygdala_webhook WHERE guildId = $1;", [guildId]); + if (result.rows.length !== 1) return null; + + return new Discord.WebhookClient({ url: result.rows[0].webhookurl }); + } +} + diff --git a/package.json b/package.json new file mode 100644 index 0000000..e54b8ac --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "amygdala", + "version": "1.0.0", + "main": "index.js", + "dependencies": { + "better-sqlite3": "^12.8.0", + "discord.js": "14", + "dotenv": "^17.3.1", + "pg": "^8.20.0" + } +} diff --git a/utils/initdb.js b/utils/initdb.js new file mode 100644 index 0000000..471837e --- /dev/null +++ b/utils/initdb.js @@ -0,0 +1,7 @@ +const SQLite = require("better-sqlite3"); +const database = SQLite("./database.db"); + +database.prepare("CREATE TABLE amygdala_webhook(guildId TEXT PRIMARY KEY, webhookUrl TEXT);").run(); +database.prepare("CREATE TABLE amygdala_profile(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, timestamp INTEGER, userID TEXT, key TEXT, value TEXT);").run(); +database.close(); + -- cgit 1.4.1