Skip to content

Written in TypeScript using custom classes with advanced Features

License

Notifications You must be signed in to change notification settings

CuteNikki/discord-bot

Repository files navigation

- A WORK IN PROGRESS -

DiscordJS V14 Bot written in TypeScript

This discord bot was built with custom classes, i18next for translations, Pino as logger and MongoDB as database.

pino mongodb i18next discord.js
Repository Stars Repository Issues Repository Forks License

Made with 💖 by Nikki

Run it locally

All it takes is just 6-7 simple steps.

  1. Clone the repository.
git clone https://github.com/CuteNikki/discord-bot.git
  1. Navigate into the project directory.
cd discord-bot
  1. Install all the dependencies.
bun install
  1. Set up your config file.
# copy example.config.json and rename to config.json
# or use this command if you are on Linux
cp example.config.json config.json
# fill in all values (more details in the config file)
  1. Deploy the slash commands.
bun run deploy
# you may also use the /register-commands slash command on discord
# once the commands have been registered using the above command.
  1. Run the bot using a script.
# run in development
bun run dev
# or compile and run
bun run build
bun run start
You may also use --debug for more detailed logs!
  1. (optional) Configure more settings using the developer command.

How to create new commands, events, buttons, etc.

1. Creating a slash command using the custom command class and i18next.

This displays the use of all command properties including autocomplete.

import {
  Colors, // all discord colors
  EmbedBuilder,
  PermissionFlagsBits,
  SlashCommandBuilder,
  type ColorResolvable
} from 'discord.js';
import { t } from 'i18next';

import { Command, ModuleType } from 'classes/command';

import { logger } from 'utils/logger';

export default new Command({
  module: ModuleType.General,
  // the module this command belongs to
  // it categorizes commands in the commands list
  cooldown: 1_000,
  // 1 second cooldown between command uses
  isDeveloperOnly: false,
  // only developers can use this command
  botPermissions: ['SendMessages'],
  // the bot needs to have this permission to be able to use this command
  data: new SlashCommandBuilder()
    .setName('preview-color')
    // command name
    .setDescription('Sends an embed with a color to preview')
    // command description
    .setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages)
    // only users with the manage messages permission can see and use this command
    .addStringOption(
      (option) =>
        option
          .setName('color')
          // option name
          .setDescription('The color to preview')
          // option description
          .setRequired(true)
          // makes the option required
          .setAutocomplete(true)
      // enables autocompletion
    ),
  async autocomplete({ interaction, client }) {
    const input = interaction.options.getFocused();
    // This gets us whatever the user has typed in the autocomplete
    const colors = [
      { name: 'white', value: Colors.White.toString(16) },
      { name: 'aqua', value: Colors.Aqua.toString(16) },
      { name: 'green', value: Colors.Green.toString(16) },
      { name: 'blue', value: Colors.Blue.toString(16) },
      { name: 'yellow', value: Colors.Yellow.toString(16) },
      { name: 'purple', value: Colors.Purple.toString(16) },
      { name: 'luminous-vivid-pink', value: Colors.LuminousVividPink.toString(16) },
      { name: 'fuchsia', value: Colors.Fuchsia.toString(16) },
      { name: 'gold', value: Colors.Gold.toString(16) },
      { name: 'orange', value: Colors.Orange.toString(16) },
      { name: 'red', value: Colors.Red.toString(16) },
      { name: 'grey', value: Colors.Grey.toString(16) },
      { name: 'navy', value: Colors.Navy.toString(16) },
      { name: 'dark-aqua', value: Colors.DarkAqua.toString(16) },
      { name: 'dark-green', value: Colors.DarkGreen.toString(16) },
      { name: 'dark-blue', value: Colors.DarkBlue.toString(16) },
      { name: 'dark-purple', value: Colors.DarkPurple.toString(16) },
      { name: 'dark-vivid-pink', value: Colors.DarkVividPink.toString(16) },
      { name: 'dark-gold', value: Colors.DarkGold.toString(16) },
      { name: 'dark-orange', value: Colors.DarkOrange.toString(16) },
      { name: 'dark-red', value: Colors.DarkRed.toString(16) },
      { name: 'dark-grey', value: Colors.DarkGrey.toString(16) },
      { name: 'darker-grey', value: Colors.DarkerGrey.toString(16) },
      { name: 'light-grey', value: Colors.LightGrey.toString(16) },
      { name: 'dark-navy', value: Colors.DarkNavy.toString(16) },
      { name: 'blurple', value: Colors.Blurple.toString(16) },
      { name: 'greyple', value: Colors.Greyple.toString(16) },
      { name: 'dark-but-not-black', value: Colors.DarkButNotBlack.toString(16) },
      { name: 'not-quite-black', value: Colors.NotQuiteBlack.toString(16) }
    ];
    if (!input.length) return await interaction.respond(colors.slice(0, 25));
    await interaction.respond(
      colors
        .filter(
          (color) => color.name.toLowerCase().includes(input.toLowerCase())
          // Check if the input includes the color name
        )
        .slice(0, 25)
    );
    // Making sure we only ever return max of 25 results
  },
  async execute({ interaction, client, lng }) {
    // the order of interaction, client and lng does not matter

    // get a guilds language
    // import { getGuildLanguage } from 'db/guild';
    // const guildLng = await getGuildLanguage(guildId);

    // get a different users language
    // import { getUserLanguage } from 'db/user';
    // const otherLng = await getUserLanguage(userId);

    const color = interaction.options.getString('color', true);

    // Autocomplete allows you to give the user a list to choose from
    // but they will still be able to type in whatever they want!
    // it's a must to check if they actually provided a valid color.

    try {
      await interaction.reply({
        embeds: [
          new EmbedBuilder()
            .setColor(color as ColorResolvable)
            // casting the color to a color resolvable
            .setDescription(t('preview-color.preview', { lng, color }))
        ]
      });
    } catch (err) {
      logger.debug({ err }, 'Error while previewing color');
      if (!interaction.replied) {
        await interaction.reply({ content: t('preview-color.invalid', { lng }), ephemeral: true });
      } else {
        await interaction.editReply({ content: t('preview-color.invalid', { lng }) });
      }
    }
  }
});
Translating messages

src/structure/locales/{lng}-messages.json

{
  "preview-color": {
    "preview": "Heres a preview of the color {{color}}!",
    "invalid": "The color you provided is invalid!"
  }
}
Translating commands

src/structure/locales/{lng}-commands.json

{
  "preview-color": {
    "name": "preview-color",
    "description": "Sends an embed with a color to preview",
    "options": [
      {
        "name": "color",
        "description": "The color to preview"
      }
    ]
  }
}

2. Creating an event using the custom event class.

import { Events } from 'discord.js';

import { Event } from 'classes/event';

import { logger } from 'utils/logger';

export default new Event({
  name: Events.ClientReady,
  // the name of the event
  once: true,
  // only run this once, won't run again even if another ready event is emitted
  execute(client, readyClient) {
    // it is important to always have client first
    // and other events properties after that

    logger.info(`Logged in as ${readyClient.user.username}#${readyClient.user.discriminator}`);
  }
});

3. Creating a button using the custom button class.

import { Button } from 'classes/button';

export default new Button({
  customId: 'ping',
  // the custom id of the button
  isAuthorOnly: true,
  // if the button was received by a command, only the command sender can use this button
  isCustomIdIncluded: false,
  // if true then a button with the custom id of "ping-two" would still
  // trigger this button because the custom id includes "ping"
  permissions: ['SendMessages'],
  // the permissions required to use this button
  botPermissions: ['SendMessages'],
  // permissions the bot needs to execute this function
  async execute({ interaction, client, lng }) {
    await interaction.channel?.send({ content: 'pong!' });
  }
});

Contributing

Contributions, issues and feature requests are welcome. Feel free to check issues page if you want to contribute.

Show your support

Please ⭐️ this repository if this project helped you!

License

Copyright © 2024 CuteNikki. This project is MIT licensed.

TO-DO

  • miscellaneous
    • fully translated all messages sent by the bot
    • added locales to all registered slash commands
    • replace any null/undefined, true/false and so on with proper translations
    • fix translation props (sometimes the id is displayed because toString() was not used)
  • moderation module
    • infractions command
      • slash and user context menu commands
    • purge command
      • filter by specific user, channel and before/after a message
    • ban command
      • temporary bans
        • automatically unbans users once the ban expires
    • unban command
    • kick command
    • timeout command
    • warn command
  • general module
    • language command
      • editable user language
      • editable server language (mainly used for the ticket system and the server log)
    • bot information
      • botinfo command
      • clusters/shards command
      • ping command
      • uptime command
    • list of commands (/commands)
    • support command
    • invite command
  • level module
    • automatically resets weekly level
    • rank command (with weekly option)
    • leaderboard command (with weekly option)
    • modify users level/xp with config command
  • utility module (not checked because I'd like to add more)
    • avatar/banner slash and user context menu commands
    • userinfo slash and user context menu commands
    • serverinfo command
    • weather command
    • reminder command (weatherapi.com)
  • developer module (more features might be added)
    • evaluate code (/eval)
      • edit button
    • execute console command (/exec)
    • register commands command (/register-commands)
  • fun module
    • phone command
      • if no message sent within 4 minutes, automatically end the call
      • button to enter the queue again or end the call
    • game command
      • Rock-Paper-Scissors
      • Tic-Tac-Toe
      • Connect-4
      • Trivia
      • Hangman
      • Memory
      • Snake
      • Fast-Type
      • Remember-Emoji
      • Tetris
      • Sokoban
      • 2048 (maybe?)
      • Lights Out (maybe?)
  • config commands
    • custom voice channels
      • fully customizable for users
    • reaction roles
      • choose between reactions and buttons (Buttons provide more user feedback)
      • fully customizable message
    • counting game
      • reset on wrong number is optional
    • word chain game (next word needs to start with the last letter of the previous word)
    • giveaway
      • create giveaway (time, prize, winnercount, channel)
      • edit giveaway (time, prize, winnercount)
      • delete giveaway (giveaway id)
      • reroll giveaway (giveaway id)
      • list active giveaways
      • join/leave giveaway (updates participants count on giveaway)
      • announce winners and delete giveaway on end
    • economy
      • needs todo
    • confession
      • needs todo
    • suggestions
      • needs todo
    • starboard
      • enable/disable module
      • starboard messages can be deleted or edited by the author
      • users can only star a message once and can also remove their star
    • moderation config
      • enable/disable module
      • staff role (maybe? not sure yet)
      • adjustable option to make reasons required (optional by default)
    • level config
      • refactor
      • disable/enable module
      • modify users level/xp
      • levelup announcement
        • can send to current/other channel or dms
        • fully customizable message
      • ignored roles and channels
      • enabled channels
    • welcome config
      • disable/enable module
      • fully customizable welcome messages
      • add roles on join
    • farewell config
      • disable/enable module
      • fully customizable farewell messages
    • ticket config
      • disable/enable module
      • fully customizable ticket options (color of buttons)
    • developer config
      • update support settings
        • invite url
        • support server
      • globally ban users
      • custom badges
        • add/remove badges from users
        • implement badges:
          • developer
          • staff member
          • translator
          • expert bughunter
          • bughunter
          • supporter
            • automatically added on support server boost
    • server log config
      • refactor
      • enable/disable
      • implement events:
        • autoModerationActionExecution
        • applicationCommandPermissionUpdate
        • autoModerationRuleCreate
        • autoModerationRuleDelete
        • autoModerationRuleUpdate
        • channelCreate
        • channelDelete
        • channelUpdate
        • emojiCreate
        • emojiDelete
        • emojiUpdate
        • guildBanAdd
        • guildBanRemove
        • guildMemberAdd
          • warns about potentially dangerous users and gives option to ban/kick them
        • guildMemberRemove
        • guildMemberUpdate
        • guildScheduledEventCreate
        • guildScheduledEventDelete
        • guildScheduledEventUpdate
        • guildScheduledEventUserAdd
        • guildScheduledEventUserRemove
        • guildUpdate
        • inviteCreate
        • inviteDelete
        • messageUpdate
        • messageDelete
        • messageBulkDelete
        • messageReactionRemoveAll
        • roleCreate
        • roleDelete
        • roleUpdate
        • stickerCreate
        • stickerDelete
        • stickerUpdate
        • threadCreate
        • threadDelete
        • threadUpdate
        • voiceStateUpdate

About

Written in TypeScript using custom classes with advanced Features

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published