Un bot Kaamelott pour Discord en Javascript

By Léo Penaguin 25 juillet 2019

Il y a quelques années j’avais fait un petit bot pour Discord qui nous avait bien fait rire. Le concept est très simple, vous écrivez !Kaamelott dans le chat et le bot viens se connecter dans votre salon pour lire une citation de Kaamelott.

Ça sert à rien mais c’est cool et ça permet de s’entrainer au Javascript et d’avoir une petite base pour faire un bot plus complet. 😊

Comment ca marche

D’abord il faut créer une nouvelle application ici : https://discordapp.com/developers/applications

Oui oui oui

Ensuite, dans la configuration de l’application, il y a une section « Bot » …

… et surtout un TOKEN que vous pouvez générer.

Ce « jeton » vous permet simplement de lier votre code avec cette application pour pouvoir l’utiliser sur des serveurs. Maintenant que vous avez ce qu’il faut pout ajouter votre Bot, vous pouvez vous rendre dans la section « OAuth2 » de la page pour utiliser le « OAUTH2 URL GENERATOR ».

J’ai aussi coché la case « Administrateur » dans cette même page, pour ne pas être embêté avec des permissions. C’est évidemment une mauvaise idée de donner tous les droits à votre Bot, il devrait être « confiné » pour pouvoir faire seulement ce qu’il est censé faire et éviter tout risques.

Quoi qu’il en soit, vous avez maintenant généré une URL (la capture précédente) qui vous permet, lorsque vous l’ouvrez avec votre navigateur, d’ajouter le Bot à un serveur.

Quand c’est fait, votre bot se connecte à votre serveur avec les droits que vous lui avait donné ! Évidemment, à ce stade, a par rester là à rien faire, il ne peut pas faire grand-chose.

Commencer à dévelloper

J’ai publié un dépôt GitHub ici : https://github.com/LeoPenaguin/kaamelott-bot, pour ceux qui voudraient directement copier mon code. Je vous conseille évidemment de suivre un peu ce qui suit d’abord, surtout si vous n’avez pas encore les connaissances suffisantes pour le comprendre rapidement.

L’arborescence

On a une arborescence très simple : index.js est le point d’entrée de notre application. Le package.json contient nos dépendances, le dossier sound contient les répliques de Kaamelott. Le fichier command.js, dans le dossier commands, est une classe qui va être héritée par notre commande !kaamelott dans le fichier kaamelott.js puis par toutes les autres commandes que vous voudraient faire plus tard.

index.js

Dans ce fichier on va notamment créer un objet correspondant au Bot et exécuter des actions. Ici on écoute deux événements : Ready et Message.

Ready permet d’exécuter du code lorsque le Bot se connecte. Dans notre cas on va simplement afficher un petit message dans la console, côté serveur, pour donner le nom du Bot. Ensuite on change l’activité du Bot pour afficher le jeu auquel il joue sous son nom dans la liste des connectés à votre serveur. J’ai choisi d’afficher « !Kaamelott » mais vous pouvez afficher un jeu plus fun comme Farming simulator 2014 🤡.

C’est surtout « Message » qui est important puisqu’on va ici exécuter du code lorsque le bot détecte un nouveau message (texte) dans le chat.

require('dotenv').config()

const Discord = require('discord.js');
const client = new Discord.Client();
const Kaamelott = require("./commands/kaamelott");

const playedGame = '!kaamelott';

client.on('ready', () => {
    console.log("🤖 Logged in as " + client.user.tag + "!");
    client.user.setActivity(playedGame).catch(console.error);
});

client.on('message', message => {
    if (!message.author.bot) {
        Kaamelott.parse(message);
    }
});

client.login(process.env.DISCORD_TOKEN);

À la fin on appelle la fonction login de notre bot (client.login()). Le paramètre de cette fonction doit être le token que vous avez généré plus tôt, dans l’onglet bot de votre application.

Maintenant qu’on a une base solide, on s’intéresse au prochain fichier.

command.js

Comme je l’ai dit command est une classe qui va nous servir de classe parente au cas pour nos différentes « commandes ». Au lieu de recréer chaque commande de zéro, on va donc créer une structure et une logique générique qui permet d’appeler le code correspondant à une commande entrée dans le chat. Du coup, l’écriture du code est plus courte et plus propre !

Le fichier Kaamelott.js que nous verrons ensuite utilise donc cette classe.

On a donc une classe « Command » qui contient trois fonctions : parse(), match() et action().

La fonction match() nous permet, dans les classes qui hérite de Command, de définir la chaine de caractère qui active une action.

parse() permet de vérifier que la chaine de caractère attendu par une commande correspond à ce qu’un utilisateur vient de poster. Si c’est le cas on exécute l’action configurée, on affiche un message dans la console, sur le serveur, ensuite avec message delete() on supprime le message pour pas que le chat soit inondé de commandes.

action() n’a pas de logic ici puisque cette classe est seulement destinée à être utilisé plus tard.

module.exports = class Command {

    static parse(message) {
        if (this.match(message)) {
            this.action(message);
            console.log("🤖 " + message.author.tag + " a dit " + message.content);
            message.delete();
            return true;
        }
        return false;
    }

    static match(message) {
        return false;
    }

    static action(message) {}

};

kaamelott.js

On rentre ici dans le coeur du sujet ! On va écrire la logique, l’action exécutée par le Bot. La classe Kaamelott qui est appelée dans index.js étend dans la classe Command. Cela veut dire que l’on n’a pas besoin de réécrire la fonction parse() mais qu’il faut maintenant écrire match() et surtout action().

Match() va retourner un booléen, return message.content.startsWith("!kaamelott"); si le contenu du message correspond a la chaine de caractère écrite ici. La fonction parse() va pouvoir appeler la fonction action().

const Command = require('./command');

const fs = require('fs');
const sounds = './sounds/kaamelott/';

module.exports = class Kaamelott extends Command {

    static match(message) {
        return message.content.startsWith("!kaamelott");
    }

    static action(message) {
        let member = message.member;

        if (typeof member.voiceChannel !== "undefined") {
            let voiceChannel = member.voiceChannel;

            voiceChannel
                .join()
                .then(connection => {
                    fs.readdir(sounds, (err, files) => {
                        var sound = files[Math.floor((Math.random() * files.length) + 1)];
                        console.log("🤖 " + member.user.tag + " played the sound : " + sound);
                        connection.playFile(sounds + sound);
                    });
                })
                .catch((err) => {
                    console.log(err);
                });
        } else {
            message.channel.send('🤖 Tu doit être dans un channel lol.');
        }
    }

};

Voilà ce qu’on fait ici :

1. let member = message.member; : On récupère l’objet correspondant a l’utilisateur qui vient de poster la commande sous forme de message texte dans le chat

2. let voiceChannel = member.voiceChannel; : On récupère le canal audio dans lequel il est pour s’y connecter.

3. fs.readdir(sounds, (err, files) : On récupère la liste des sons avec fs : Cette librairie permet de naviguer dans le système de fichiers. Plus d’informations ici https://www.npmjs.com/package/file-system

4. À ce stade on a une liste de mp3 (la variable files), on en extrait au hasard avec var sound = files[Math.floor((Math.random() * files.length) + 1)];

5. Enfin on joue le son dans le canal où on vient de se connecter avec connection.playFile(sounds + sound);

L’installation

Avant de pouvoir exécuter le programme, vous avez besoin de FFmpeg sur votre système : https://ffmpeg.org/download.html

Vous devez aussi créer un fichier .env a la racine du projet contenant la ligne « DISCORD_TOKEN=VOTRE_TOKEN » vous pouvez aussi ignorer cette étape et coller votre token directement dans le fichier index.js a la place de process.env.DISCORD_TOKEN.

Ensuite vous pouvez éxécuter le code avec Node.js :

Naviguez vers la racine du projet avec votre terminal puis éxécuter npm install et node index.js.

Commentaires 💬

Edmondio

Bonjour, je viens de mettre en place ton bot pour, j'ai réussi à le mettre sur glitch pour qu'il soit toujours en ligne, il fonctionne parfaitement, j'aimerais juste pouvoir rajouter une commande pour qu’une fois qu'il est fini de lire le son il ce déconnecté du chan et je ne trouve pas, je suis tout nouveau sur discord si tu as une piste :)

Léo Penaguin

J'ai ajouté ca au projet sur github :) J'en ai profité pour tout mettre à jour.

Le commit ici https://github.com/LeoPenaguin/kaamelott-bot/commit/08affd788cee4e134f94904c899fe9aafce7addb

Merci pour ton retour

Edmondio

Ah super !! Merci beaucoup !