init
This commit is contained in:
commit
eb242e85bb
|
@ -0,0 +1,2 @@
|
||||||
|
node_modules
|
||||||
|
.idea
|
|
@ -0,0 +1,11 @@
|
||||||
|
## How to install & run this bot.
|
||||||
|
Prerequisites:
|
||||||
|
* [NodeJS/NPM](https://nodejs.org/en/download)
|
||||||
|
* Potentially [Git](https://git-scm.com/downloads)
|
||||||
|
|
||||||
|
1. Download the repo files.
|
||||||
|
1. `git clone https://git.shuri.gg/ShuriZma/WordCounterBot.git`
|
||||||
|
2. or just click the 3 dots at the top right and download the ZIP
|
||||||
|
2. Open a console inside the downloaded repo folder.
|
||||||
|
3. Run `npm i`
|
||||||
|
4. Run `npm run bot`
|
|
@ -0,0 +1,4 @@
|
||||||
|
import { Bot } from "./src/bot";
|
||||||
|
|
||||||
|
const bot = Bot.getInstance();
|
||||||
|
bot.init();
|
|
@ -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"
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
},
|
||||||
|
};
|
|
@ -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!');
|
||||||
|
},
|
||||||
|
};
|
|
@ -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!');
|
||||||
|
},
|
||||||
|
};
|
|
@ -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!');
|
||||||
|
},
|
||||||
|
};
|
|
@ -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!');
|
||||||
|
},
|
||||||
|
};
|
|
@ -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!');
|
||||||
|
},
|
||||||
|
};
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
database: 'name of the database file',
|
||||||
|
token: 'bot token',
|
||||||
|
guildId: 'server id',
|
||||||
|
clientId: 'client id of your bot instance',
|
||||||
|
};
|
Loading…
Reference in New Issue