summary refs log tree commit diff
diff options
context:
space:
mode:
authorAmygdala Peanut-Almond <amygdala@almond.desloratadyna.net>2026-04-22 22:49:01 +0200
committerAmygdala Peanut-Almond <amygdala@almond.desloratadyna.net>2026-04-22 22:49:01 +0200
commit3572b97661a3f7c6c29e958b63c20d9f2ef936ac (patch)
treeb3ee056039cf792edd467e5172feee25a07dd56c
initialise repository
Signed-off-by: Amygdala Peanut-Almond <amygdala@almond.desloratadyna.net>
-rw-r--r--commands/eval.js42
-rw-r--r--commands/exec.js43
-rw-r--r--commands/haze.js28
-rw-r--r--commands/help.js18
-rw-r--r--commands/ping.js12
-rw-r--r--commands/reload.js35
-rw-r--r--commands/sql.js65
-rw-r--r--config.json7
-rw-r--r--events/00ready.js13
-rw-r--r--events/cat.js9
-rw-r--r--events/dphoque.js11
-rw-r--r--events/messageCommands.js71
-rw-r--r--events/messageDelete.js35
-rw-r--r--events/spambot-fucker.js10
-rw-r--r--index.js52
-rw-r--r--libs/datajob.js27
-rw-r--r--libs/webhook.js11
-rw-r--r--package.json11
-rw-r--r--utils/initdb.js7
19 files changed, 507 insertions, 0 deletions
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é <eqilia@national.shitposting.agency>
+ * 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 <https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12>
+*/
+
+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é <eqilia@national.shitposting.agency>
+ * 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 <https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12>
+*/
+
+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é <eqilia@national.shitposting.agency>
+ * 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 <https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12>
+*/
+
+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é <eqilia@national.shitposting.agency>
+ * 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 <https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12>
+*/
+
+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é <eqilia@national.shitposting.agency>
+ * 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();
+