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