Créer un robot Discord avec les Slash Commands

Créer un robot Discord avec les Slash Commands

INFORMATION : Ce tutoriel sert à créer un robot Discord avec des Slashs Commands.

En savoir plus sur l'utilisation des Slash Commands →

📚 PrĂ©-requis avant de se lancer

Avant de commencer ce tutoriel, suivez les consignes suivantes. Vous devez installer plusieurs outils afin que le robot fonctionne, et crĂ©ez un dossier avec n'importe quel nom, de prĂ©fĂ©rence court et sans espace. Ça sera votre dossier contenant vos fichiers du robot.

Liste des outils et des choses Ă  savoir :

  • Connaitre les bases du JavaScript
  • Installer la derniĂšre version stable de Node.js
  • Avoir accĂšs au terminal
  • Avoir une bonne connexion Internet
  • Un Ă©diteur de texte ou IDE (Notepad++, Atom, WebStorm, VSCode 
)
  • Savoir lire un minimum l'anglais pour les documentations

Nous allons dans un premier temps si tout a bien Ă©tĂ© installĂ©, ouvrez votre invitĂ© de commande et non celle d'installĂ© par Node.js (si vous ĂȘtes sous Windows), et tapez :

bash
node --version

Il est censĂ© vous relever la version que vous avez installĂ©e. Laissez cette fenĂȘtre ouverte pour la suite de l'installation.

✹ Ce que nous allons rĂ©aliser pour ce tutoriel

Avant de continuer Ă  lire la suite, vous devez comprendre que vous devez un minimum modifier certaines valeurs, comme les IDs et les noms de commandes.
Nous allons réaliser un simple robot Discord avec les Slash Commands, et avec quoi on ajoutera un module permettant de synchroniser trÚs facilement la liste de nos commandes.
Et pour finir, une commande exemple : /ping.

La commande ping en Slash Command

Image Ă  titre exemplaire concernant le corps de la commande /ping

Il faut aussi noter que les packages vous sont proposés dans cet exemple de package.json avec une version fixe, n'hésitez donc pas à vérifier s'il y a une mise à jour pour chacun d'entre-eux.

đŸ•șđŸŒ Installation du projet et des paquets

AprÚs avoir correctement installé la derniÚre version de Node.js, vous devez vous rendre dans le dossier de votre robot.
Pour se déplacer dans l'invité de commande :

bash
cd /nomDuDossier

Pour plus de simplicitĂ©, allez dans votre dossier en naviguant avec l'interface graphique et non avec l'invitĂ© de commande et copiez l'URL en haut. Ensuite, collez-la dans l’invitĂ© de commande en ajoutant cd avant votre texte copiĂ©.
Si vous n'ĂȘtes pas dans le dossier de votre robot avec l'invitĂ© de commande, veuillez revoir les lignes en haut. Nous allons installer le paquet pour que le robot marche. Ce paquet se nomme Discord.js, c'est une librairie pour faciliter Ă  interagir avec l'API de Discord et dĂ©veloppĂ© sous JavaScript.

Les différents paquets

Nous aurons besoin de différents Node package (npm) pour que le robot fonctionne.

bash
npm install discord.js discord-api-types fs

Exemple de package.json

Vous pouvez en soi avoir le mĂȘme package.json :

package.jsonjson
{
  "name": "example_discord_bot_slash_commands",
  "version": "1.0.0",
  "main": "app.js",
  "scripts": {
    "start": "node app.js"
  },
  "keywords": [
    "discordapp",
    "bot",
    "discordjs"
  ],
  "author": "Thomas Bnt <contact+git@thomasbnt.fr>",
  "license": "GPL-3.0-only",
  "dependencies": {
    "discord-api-types": "^0.37.31",
    "discord.js": "^14.7.1"
  }
}

Comme vous le pouvez le lire, nous avons indiquĂ© dans le script un fichier, app.js est le fichier oĂč l'on va exĂ©cuter le robot.

Nous allons donc installer tous les packages :

bash
npm install

đŸ€– CrĂ©ation du robot sur la plateforme

Désormais, il faut créer le robot sur la plateforme de Discord et l'ajouter sur votre serveur. Pour cela, nous allons le faire en deux étapes.
Suivez ce processus, vous devez ĂȘtre connectĂ© Ă  votre compte Discord afin de pouvoir accĂ©der Ă  cette page.

Création du robot Discord

  • Allez dans l'onglet Bot
  • Cliquez sur "Add Bot", puis cliquez sur "Yes, do it!"

Activer le 'mode' robot

Il reste plus qu'à l'ajouter sur votre propre serveur. Pour cela, il suffit juste d'aller sur l'onglet OAuth2, donnez-lui les permissions nécessaires pour le bon fonctionnement du robot, et générez votre lien.

Générer une URL Oauth2 sur Discord

Copiez-le et ouvrez-le dans un nouvel onglet, on vous demande de sélectionner un serveur. Sélectionnez le vÎtre et cliquez sur Autoriser. Vous avez dorénavant votre robot qui est sur votre serveur, mais il est hors ligne. C'est tout à fait normal ! Suivez la suite afin de l'allumer.

🚀 CrĂ©er la premiĂšre commande

Nous y sommes ! C'est le moment oĂč nous allons crĂ©er notre premiĂšre commande.

Le fichier principal : app.js

AprÚs avoir correctement tout installé, vous devez créer le fichier app.js.
Il vous sert tout simplement de 'root' de votre projet, j'aime bien l'appeler son cƓur 💜. Car c'est Ă  partir de lui que tout dĂ©marre.

Voici donc un exemple de fichier nommé app.js :

app.jsjs
/**
 @document   : app.js
 @author     : Thomas Bnt
 @version    : 3.0.0
 @copyright  : 2023, Thomas Bnt
 @license    : GNU General Public License v3.0
 @repository : https://github.com/thomasbnt/Bord-Pi
 @description: Un robot Discord gérant et aidant les utilisateurs pour un serveur.
 */

const fs = require('fs')
const {Client, Collection, GatewayIntentBits, Options} = require('discord.js')

const client = new Client({
  // Les intents dépendra de ce que vous voulez faire avec le robot, 
  // mais n'oubliez pas de les activer dans votre dashboard discord.dev
  // Ă  l'adresse https://discord.com/developers/applications/{ID}/bot, 
  // section "Privileged Gateway Intents"
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages
  ],
})

// Nous créons une collection pour les commandes
client.commands = new Collection()
const commandFiles = fs
  .readdirSync('./commands')
  .filter((file) => file.endsWith('.js'))

for (const file of commandFiles) {
  const command = require(`./commands/${file}`)
  client.commands.set(command.data.name, command)
}

// Les events comme par exemple ready.js (quand le robot s'allume), 
// ou encore messageCreate.js (quand un utilisateur/robot envoie un message)
const eventFiles = fs
  .readdirSync('./events')
  .filter((file) => file.endsWith('.js'))

for (const file of eventFiles) {
  const event = require(`./events/${file}`)
  if (event.once) {
    client.once(event.name, (...args) => event.execute(...args, client))
  } else {
    client.on(event.name, (...args) => event.execute(...args, client))
  }
}

// L'event interactionCreate directement ici, car c'est en soit le coeur du robot.
client.on('interactionCreate', async (interaction) => {
  if (!interaction.isCommand()) return
  const command = client.commands.get(interaction.commandName)
  if (!command) return

  // On log quand un utilisateur fait une commande
  try {
    await console.log(
      `/${interaction.commandName} — Par ${interaction.user.username}`
    )
    await command.execute(interaction, client)
    // Mais s'il y a une erreur, 
    // alors on log ça et on renvoi un message d'erreur seulement à la personne (ephemeral: true)
  } catch (error) {
    console.error(error)
    return interaction.reply({
      content: "Une erreur s'est produite lors de l'exécution de cette commande !",
      ephemeral: true,
      fetchReply: true
    })
  }
})

// Le token de votre robot à insérer
client.login("JOLI TOKEN A NE JAMAIS DIVULGER")

Synchronisation des Slash Commands

Ce fichier sera mis dans le dossier modules/, et appelé dÚs que le robot se lance avec l'évent
Ready (events/ready.js). Je l'ai repris de ce dépÎt GitHub réalisé par Androz.
Il vous permet de facilement synchroniser et mettre Ă  jour votre liste de commandes.

Voici donc le fichier de synchronisation des Slash Commands (/modules/sync_commands.js):

/modules/sync_commands.jsjs
const Discord = require('discord.js')
module.exports = async (client, commands, options = {debug: false, guildId: null}) => {
  const log = (message) => options.debug && console.log(message)

  const ready = client.readyAt
    ? await Promise.resolve()
    : new Promise((resolve) => client.once('ready', resolve))
  await ready
  const currentCommands = await client.application.commands.fetch(
    options.guildId && {guildId: options.guildId}
  )

  log(`Synchronizing commands...`)
  log(`Currently ${currentCommands.size} commands.`)

  const newCommands = commands.filter(
    (command) => !currentCommands.some((c) => c.name === command.name)
  )
  for (const newCommand of newCommands) {
    await client.application.commands.create(newCommand, options.guildId)
  }

  log(`Created ${newCommands.length} commands!`)

  const deletedCommands = currentCommands
    .filter((command) => !commands.some((c) => c.name === command.name))
    .toJSON()
  for (const deletedCommand of deletedCommands) {
    await deletedCommand.delete()
  }

  log(`Deleted ${deletedCommands.length} commands!`)

  const updatedCommands = commands.filter((command) =>
    currentCommands.some((c) => c.name === command.name)
  )
  let updatedCommandCount = 0
  for (const updatedCommand of updatedCommands) {
    const newCommand = updatedCommand
    const previousCommand = currentCommands.find(
      (c) => c.name === updatedCommand.name
    )
    let modified = false
    if (previousCommand.description !== newCommand.description) modified = true
    if (
      !Discord.ApplicationCommand.optionsEqual(
        previousCommand.options ?? [],
        newCommand.options ?? []
      )
    )
      modified = true
    if (modified) {
      await previousCommand.edit(newCommand)
      updatedCommandCount++
    }
  }

  log(`Updated ${updatedCommandCount} commands!`)

  log(`Commands synchronized!`)

  return {
    currentCommandCount: currentCommands.size,
    newCommandCount: newCommands.length,
    deletedCommandCount: deletedCommands.length,
    updatedCommandCount
  }
}

Beaaucoup de choses, mais retenez juste qu'il limite les requĂȘtes API de Discord, et qu'il synchronise vos commandes sans difficultĂ©. C'est un module, donc on va devoir l'appeler dans un event qui est le Ready !

Le fichier de l'event Ready

Quand vous allumerez votre robot, à chaque fois cet event s'exécutera. Donc, nous pouvons faire en sorte de placer une fonction ou tout autre de code qui devrait s'exécuter dÚs le début.

/events/ready.jsjs
const synchronizeSlashCommands = require('../modules/sync_commands')
const {ActivityType} = require('discord.js')
module.exports = {
  name: 'ready',
  async execute(client) {
    console.log(`Connecté en tant que ${client.user.username}`)
    client.user.setActivity(`/bord`, {type: ActivityType.Watching})

    // C'est Ă  ce moment-lĂ  que la synchronisation des Slash Commands se lance
    await synchronizeSlashCommands(client,
      client.commands.map((c) => c.data),
      {
        // Les paramĂštres Ă  modifier pour la synchronisation
        debug: true,
        // Si vous définissez un ID de serveur, alors ça ne sera QUE pour le serveur ciblé.
        // Si dans le cas contraire vous ne mettez pas guildID, ça sera en GLOBAL,
        // Donc sur tout les serveurs.
        guildId: "TonIDDeServeurOuSupprimeCetteLigne"
      }
    )
  }
}

La commande /ping comme exemple

Alors, elle est basique comme commande, mais elle peut aussi ĂȘtre utilisĂ©e pour dĂ©tecter des anomalies sur la connexion. Donc pas si inutile que ça.

/commands/ping.jsjs
const {EmbedBuilder} = require('discord.js')
module.exports = {
  // "data" est le corps de la commande,
  // c'est ce qu'on va retrouver quand on va taper /ping
  data: {
    name: 'ping',
    description: 'Obtenir le ping du robot',
    options: []
  },
  // et tout ça, c'est la logique de la commande
  async execute(interaction, client) {
    // Par exemple là on créée un embed avec EmbedBuilder de discord.js
    // On lui ajoute un name et iconURL, et on va par la suite le modifier avec les valeurs.
    const PingBeforeEmbed = new EmbedBuilder().setAuthor({
      name: `L'oiseau va revenir avec le ping du robot...`,
      iconURL: client.user.avatarURL()
    })
    const sent = await interaction.reply({
      embeds: [PingBeforeEmbed],
      fetchReply: true,
      ephemeral: true
    })
    const TotalPing = sent.createdTimestamp - interaction.createdTimestamp
    const PingEmbed = new EmbedBuilder()
      .setAuthor({
        name: `Le ping de ${client.user.username}`,
        iconURL: client.user.avatarURL()
      })
      .addFields(
        {
          name: 'Total du ping',
          value: `${TotalPing}ms`,
          inline: true
        },
        {
          name: 'Websocket',
          value: `${client.ws.ping} ms`,
          inline: true
        }
      )
    await interaction.editReply({
      embeds: [PingEmbed],
      ephemeral: true
    })
  }
}

Ce que je devrais avoir dans mon projet

  • CrĂ©er le fichier app.js
  • CrĂ©er le dossier events/ et le fichier events/ready.js
  • CrĂ©er le dossier modules/ et le fichier modules/sync_commands.js
  • CrĂ©er le dossier commands/ et le fichier commands/ping.js
bash
.
├── app.js
├── commands
│   └── ping.js
├── events
│   └── ready.js
├── modules
│   └── sync_commands.js
└── package.json

S'il vous manque quelque chose, c'est que vous n'avez pas tout lu. đŸ˜±

đŸ„ł DĂ©marrage du robot !

Vous devez copier le token de votre robot qui se trouve sur la page Discord pour les développeurs.

Exemple de token Ă  recopier

Et l'insérer avec ce bout de code à la fin de votre app.js

/app.jsjs
client.login("VOTRE TOKEN ICI SANS ESPACE")

Sauvegardez votre fichier et faites cette commande dans l'invité de commande :

bash
node app.js

Et voilĂ  ! Votre robot est allumĂ© ! 🎉


đŸŽ„ Streamer ?

Obtenez le script pour votre propre robot Discord afin d'avertir vos membres quand vous passez en live sur Twitch.

Shop Buy Me a Coffee

Si vous ĂȘtes un streamer, vous pouvez obtenir ce script pour avertir vos membres que vous passez en live sur Twitch.
Faites savoir à votre communauté que vous passez en live sur Twitch ! Ce script est conçu pour ça, il alerte dans un salon choisi quand vous passez en live et quand vous le finissez. Il vous change aussi l'icÎne de votre serveur en ce que vous voulez.


Soutenez-moi
Si vous aimez mon contenu, vous pouvez me soutenir en faisant un don récurant ou spontanément sur Buy Me a Coffee.