This commit is contained in:
ShuriZma 2024-03-30 15:27:45 +01:00
commit e4e20af282
Signed by: ShuriZma
GPG Key ID: 8D289758EE9B8074
12 changed files with 468 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules
.idea

4
index.ts Normal file
View File

@ -0,0 +1,4 @@
import { Bot } from "./src/bot";
const bot = Bot.getInstance();
bot.init();

21
package.json Normal file
View File

@ -0,0 +1,21 @@
{
"name": "nickskeeeebot",
"version": "1.0.0",
"description": "",
"main": "index.ts",
"scripts": {
"bot": "ts-node index.ts"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"discord.js": "^14.14.1",
"sqlite3": "^5.1.7",
"ts-node": "^10.9.2"
},
"devDependencies": {
"@types/node": "^20.11.30",
"typescript": "^5.4.3"
}
}

254
src/bot.ts Normal file
View File

@ -0,0 +1,254 @@
import {
ChatInputCommandInteraction,
Client,
Collection,
EmbedBuilder,
Events,
GatewayIntentBits,
Message, PermissionsBitField, REST,
Routes,
User
} from 'discord.js';
import * as sqlite3 from 'sqlite3';
import config from "./config";
import SetChannel from "./commands/setChannel";
import Library from "./commands/library";
import Reset from "./commands/reset";
import SetModRole from "./commands/setModRole";
import SetIgnorePrefix from "./commands/setIgnorePrefix";
import SetAutoEmbedMessages from "./commands/setAutoEmbedMessages";
export class Bot {
private db: sqlite3.Database;
private channel: string;
private static instance: Bot;
private counter = 0;
private lastUser: string;
private modRole: string;
private ignorePrefix: string = '+';
private autoEmbedMessages: number = 10;
public init() {
const client = new Client({intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent]});
this.connectDatabase()
this.registerCommands();
const commands: Collection<any, any> = new Collection();
commands.set(SetChannel.data.name, SetChannel);
commands.set(Library.data.name, Library);
commands.set(Reset.data.name, Reset);
commands.set(SetModRole.data.name, SetModRole);
commands.set(SetIgnorePrefix.data.name, SetIgnorePrefix);
commands.set(SetAutoEmbedMessages.data.name, SetAutoEmbedMessages);
client.once(Events.ClientReady, readyClient => {
console.log(`Ready! Logged in as ${readyClient.user.tag}`);
});
client.on(Events.Error, (err) => {
console.error(err);
});
client.on(Events.InteractionCreate, async interaction => {
if (!interaction.isChatInputCommand()) return;
const command = commands.get(interaction.commandName);
if (!command) {
console.error(`No command matching ${interaction.commandName} was found.`);
return;
}
try {
await command.execute(interaction);
} catch (error) {
console.error(error);
if (interaction.replied || interaction.deferred) {
await interaction.followUp({ content: 'There was an error while executing this command!', ephemeral: true });
} else {
await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true });
}
}
});
client.on(Events.MessageCreate, async (msg) => {
if (
this.channel
&& msg.channel.id === this.channel
&& !msg.content.startsWith(this.ignorePrefix)
&& !msg.author.bot
) {
if (
this.lastUser === msg.author.id
&& this.modRole ? msg.member.roles.highest.comparePositionTo(this.modRole) < 0 : !msg.member.permissions.has(PermissionsBitField.Flags.Administrator)
) {
await msg.delete();
return;
}
this.counter++;
msg.content = msg.content.charAt(0).toUpperCase() + msg.content.slice(1);
this.db.run(
'INSERT OR REPLACE INTO library (word, amount) VALUES (?, COALESCE((SELECT amount FROM library WHERE word = ?), 0) + 1)',
[
msg.content,
msg.content,
]
);
}
if (this.counter === this.autoEmbedMessages) {
this.counter = 0;
this.sendEmbed(msg);
}
});
client.login(config.token);
}
private registerCommands() {
const commands = [];
commands.push(
SetChannel.data.toJSON(),
Library.data.toJSON(),
Reset.data.toJSON(),
SetModRole.data.toJSON(),
SetIgnorePrefix.data.toJSON(),
SetAutoEmbedMessages.data.toJSON(),
);
const rest = new REST().setToken(config.token);
(async () => {
try {
console.log(`Started refreshing ${commands.length} application (/) commands.`);
const data = await rest.put(
Routes.applicationGuildCommands(config.clientId, config.guildId),
{body: commands},
);
console.log(`Successfully reloaded ${data['length']} application (/) commands.`);
} catch (error) {
// And of course, make sure you catch and log any errors!
console.error(error);
}
})();
}
public sendEmbed(msg: Message<boolean>|ChatInputCommandInteraction) {
this.db.all(
'SELECT * FROM library ORDER BY amount DESC LIMIT 9',
async (err, rows) => {
if (rows) {
const icons = [
':first_place: • ',
':second_place: • ',
':third_place: • ',
':four: • ',
':five: • ',
':six: • ',
':seven: • ',
':eight: • ',
':nine: • ',
];
const fields = [];
for (let index in rows) {
fields.push({
name: icons[index] + rows[index]['word'],
value: rows[index]['amount'] + ' uses',
inline: true,
});
}
fields.push({
name: '⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤',
value: '\u200B',
});
const embed = new EmbedBuilder()
.setTitle('Top 10 most used words.')
.setDescription('This is the Library with the most used words and their amount.\u200B⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤')
.setColor(0xffe600)
.setFields(fields);
await msg.reply({embeds: [embed]});
}
}
);
}
private connectDatabase() {
this.db = new sqlite3.Database(config.database)
this.db.run('CREATE TABLE IF NOT EXISTS config (configKey VARCHAR PRIMARY KEY, value VARCHAR NOT NULL)');
this.db.run('CREATE TABLE IF NOT EXISTS library (word VARCHAR PRIMARY KEY UNIQUE, amount INT NOT NULL DEFAULT 0)');
this.db.get('SELECT value FROM config WHERE configKey = "channelId"', (err, row) => {
if (row) {
this.channel = row['value'];
}
});
this.db.get('SELECT value FROM config WHERE configKey = "modRoleId"', (err, row) => {
if (row) {
this.modRole = row['value'];
}
});
this.db.get('SELECT value FROM config WHERE configKey = "ignorePrefix"', (err, row) => {
if (row) {
this.ignorePrefix = row['value'];
}
});
this.db.get('SELECT value FROM config WHERE configKey = "autoEmbedMessages"', (err, row) => {
if (row) {
this.autoEmbedMessages = row['value'];
}
});
}
public getDB() {
return this.db;
}
public setChannel(channelId: string): Bot {
this.channel = channelId;
return this;
}
public setCounter(counter: number): Bot {
this.counter = counter;
return this;
}
public setLastUser(lastUserId: string): Bot {
this.lastUser = lastUserId;
return this;
}
public setModRole(roleId: string): Bot {
this.modRole = roleId;
return this;
}
public setIgnorePrefix(prefix: string): Bot {
this.ignorePrefix = prefix;
return this;
}
public setAutoEmbedMessages(counter: number): Bot {
this.autoEmbedMessages = counter;
return this;
}
public static getInstance(): Bot {
if (!Bot.instance) {
Bot.instance = new Bot();
}
return Bot.instance;
}
}

18
src/commands/library.ts Normal file
View File

@ -0,0 +1,18 @@
import {
ChatInputCommandInteraction,
EmbedBuilder,
SlashCommandBuilder,
} from 'discord.js';
import { Bot } from "../bot";
export default {
data: new SlashCommandBuilder()
.setName('library')
.setDescription('Get an embed of the most used words!'),
async execute(interaction: ChatInputCommandInteraction) {
const bot = Bot.getInstance();
bot.setCounter(0);
return bot.sendEmbed(interaction);
},
};

29
src/commands/reset.ts Normal file
View File

@ -0,0 +1,29 @@
import {
ChatInputCommandInteraction,
PermissionsBitField,
SlashCommandBuilder,
SlashCommandStringOption,
} from 'discord.js';
import { Bot } from "../bot";
const option = new SlashCommandStringOption()
.setName('word')
.setDescription('Only delete this word.');
export default {
data: new SlashCommandBuilder()
.setName('reset')
.setDescription('Reset the entire library or remove a single word.')
.setDefaultMemberPermissions(PermissionsBitField.Flags.Administrator)
.addStringOption(option),
async execute(interaction: ChatInputCommandInteraction) {
const bot = Bot.getInstance();
if (interaction.options.data.at(0)) {
bot.getDB().run('DELETE FROM library WHERE word = ?', [interaction.options.data.at(0).value]);
}
bot.getDB().run('DELETE FROM library WHERE TRUE');
bot.setCounter(0);
return await interaction.reply('Done!');
},
};

View File

@ -0,0 +1,33 @@
import {
ChatInputCommandInteraction,
PermissionsBitField,
SlashCommandBuilder,
SlashCommandIntegerOption,
} from 'discord.js';
import { Bot } from "../bot";
const option = (new SlashCommandIntegerOption())
.setName('amount')
.setDescription('Amount of messages needed.')
.setRequired(true);
export default {
data: new SlashCommandBuilder()
.setName('setautoembedmessages')
.setDescription('Set the amount of messages required to automatically send the embed.')
.setDefaultMemberPermissions(PermissionsBitField.Flags.Administrator)
.addIntegerOption(option),
async execute(interaction: ChatInputCommandInteraction) {
const bot = Bot.getInstance();
bot.getDB().run(
'INSERT OR REPLACE INTO config (configKey, value) VALUES (?, ?)',
[
'autoEmbedMessages',
interaction.options.data.at(0).value,
]
);
bot.setAutoEmbedMessages(parseInt(interaction.options.data.at(0).value.toString()));
return await interaction.reply('Done!');
},
};

View File

@ -0,0 +1,35 @@
import {
ChatInputCommandInteraction,
PermissionsBitField,
SlashCommandBuilder,
SlashCommandChannelOption,
} from 'discord.js';
import { ChannelType } from 'discord-api-types/v10';
import { Bot } from "../bot";
const channelOption = (new SlashCommandChannelOption())
.setName('channel')
.setDescription('The channel you want the bot to listen to.')
.setRequired(true)
.addChannelTypes(ChannelType.GuildText);
export default {
data: new SlashCommandBuilder()
.setName('setchannel')
.setDescription('Set the channel the bot should listen to.')
.setDefaultMemberPermissions(PermissionsBitField.Flags.Administrator)
.addChannelOption(channelOption),
async execute(interaction: ChatInputCommandInteraction) {
const bot = Bot.getInstance();
bot.getDB().run(
'INSERT OR REPLACE INTO config (configKey, value) VALUES (?, ?)',
[
'channelId',
interaction.options.data.at(0).value,
]
);
bot.setChannel(interaction.options.data.at(0).value.toString());
return await interaction.reply('Done!');
},
};

View File

@ -0,0 +1,33 @@
import {
ChatInputCommandInteraction,
PermissionsBitField,
SlashCommandBuilder,
SlashCommandStringOption,
} from 'discord.js';
import { Bot } from "../bot";
const option = (new SlashCommandStringOption())
.setName('prefix')
.setDescription('The prefix.')
.setRequired(true);
export default {
data: new SlashCommandBuilder()
.setName('setignoreprefix')
.setDescription('Set the prefix that causes the bot to ignore a message.')
.setDefaultMemberPermissions(PermissionsBitField.Flags.Administrator)
.addStringOption(option),
async execute(interaction: ChatInputCommandInteraction) {
const bot = Bot.getInstance();
bot.getDB().run(
'INSERT OR REPLACE INTO config (configKey, value) VALUES (?, ?)',
[
'ignorePrefix',
interaction.options.data.at(0).value,
]
);
bot.setIgnorePrefix(interaction.options.data.at(0).value.toString());
return await interaction.reply('Done!');
},
};

View File

@ -0,0 +1,33 @@
import {
ChatInputCommandInteraction,
PermissionsBitField,
SlashCommandBuilder,
SlashCommandRoleOption,
} from 'discord.js';
import { Bot } from "../bot";
const option = (new SlashCommandRoleOption())
.setName('role')
.setDescription('The moderator role.')
.setRequired(true);
export default {
data: new SlashCommandBuilder()
.setName('setmodrole')
.setDescription('Set the moderator role.')
.setDefaultMemberPermissions(PermissionsBitField.Flags.Administrator)
.addRoleOption(option),
async execute(interaction: ChatInputCommandInteraction) {
const bot = Bot.getInstance();
bot.getDB().run(
'INSERT OR REPLACE INTO config (configKey, value) VALUES (?, ?)',
[
'modRoleId',
interaction.options.data.at(0).value,
]
);
bot.setModRole(interaction.options.data.at(0).value.toString());
return await interaction.reply('Done!');
},
};

6
src/config.ts Normal file
View File

@ -0,0 +1,6 @@
export default {
database: 'nickskeeeeBot',
token: 'NTQxNjA5MTE4MjMwNzczNzYw.Gb2Sod.5gmcsr0d79AuKN79Huh94U4zTXfmyGL3ViKHqA',
guildId: '848666630200360962',
clientId: '541609118230773760',
};

0
tsconfig.json Normal file
View File