Créer un bot musical Discord en 2026 : le guide complet
Apprenez à créer votre propre bot musical Discord avec Discord.js et discord-player. Tutoriel pas à pas depuis zéro jusqu'au déploiement.
Marie Chen
Développeuse Discord
Depuis l’arrêt de Groovy et Rythm en 2021, de nombreux serveurs Discord cherchent des alternatives pour écouter de la musique ensemble. La bonne nouvelle ? Vous pouvez créer votre propre bot musical personnalisé et le garder privé pour votre serveur.
Dans ce tutoriel complet, nous allons créer un bot musical fonctionnel avec Discord.js v14 et discord-player.
Prérequis
Avant de commencer, assurez-vous d’avoir :
- Node.js 18+ installé sur votre machine
- Un compte Discord
- Des connaissances de base en JavaScript
- Un éditeur de code (VS Code recommandé)
Étape 1 : Créer l’application Discord
1.1 Accéder au portail développeur
- Rendez-vous sur Discord Developer Portal
- Connectez-vous avec votre compte Discord
- Cliquez sur New Application
- Donnez un nom à votre bot (ex: “MusicBot”)
1.2 Configurer le bot
- Dans le menu latéral, cliquez sur Bot
- Cliquez sur Add Bot puis confirmez
- Sous Privileged Gateway Intents, activez :
- Message Content Intent
- Server Members Intent
- Cliquez sur Reset Token et copiez le token (gardez-le secret !)
1.3 Générer le lien d’invitation
- Allez dans OAuth2 > URL Generator
- Dans Scopes, cochez :
botetapplications.commands - Dans Bot Permissions, cochez :
- Connect
- Speak
- Use Voice Activity
- Send Messages
- Embed Links
- Read Message History
- Copiez l’URL générée et ouvrez-la pour inviter le bot sur votre serveur
Étape 2 : Initialiser le projet
Créez un nouveau dossier et initialisez le projet :
mkdir discord-music-bot
cd discord-music-bot
npm init -y
Installez les dépendances nécessaires :
npm install discord.js @discordjs/voice discord-player @discord-player/extractor
npm install dotenv
:::tip
discord-player gère toute la complexité de la lecture audio. C’est la bibliothèque la plus maintenue pour les bots musicaux en 2026.
:::
Étape 3 : Structure du projet
Créez la structure suivante :
discord-music-bot/
├── src/
│ ├── commands/
│ │ ├── play.js
│ │ ├── skip.js
│ │ ├── stop.js
│ │ ├── queue.js
│ │ └── nowplaying.js
│ ├── events/
│ │ └── ready.js
│ └── index.js
├── .env
├── .gitignore
└── package.json
Étape 4 : Configuration
4.1 Fichier .env
Créez le fichier .env à la racine :
DISCORD_TOKEN=votre_token_ici
CLIENT_ID=id_de_votre_application
4.2 Fichier .gitignore
node_modules/
.env
4.3 Mettre à jour package.json
Ajoutez le type module et le script de démarrage :
{
"name": "discord-music-bot",
"version": "1.0.0",
"type": "module",
"main": "src/index.js",
"scripts": {
"start": "node src/index.js",
"dev": "node --watch src/index.js"
}
}
Étape 5 : Fichier principal
Créez src/index.js :
import { Client, GatewayIntentBits, Collection, REST, Routes } from 'discord.js';
import { Player } from 'discord-player';
import { DefaultExtractors } from '@discord-player/extractor';
import { config } from 'dotenv';
import { readdirSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
config();
const __dirname = dirname(fileURLToPath(import.meta.url));
// Créer le client Discord
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildVoiceStates,
GatewayIntentBits.MessageContent,
],
});
// Initialiser le player
const player = new Player(client, {
ytdlOptions: {
quality: 'highestaudio',
highWaterMark: 1 << 25,
},
});
// Charger les extracteurs (YouTube, Spotify, SoundCloud, etc.)
await player.extractors.loadMulti(DefaultExtractors);
// Collection pour les commandes
client.commands = new Collection();
// Charger les commandes
const commandsPath = join(__dirname, 'commands');
const commandFiles = readdirSync(commandsPath).filter(file => file.endsWith('.js'));
const commands = [];
for (const file of commandFiles) {
const filePath = join(commandsPath, file);
const command = await import(`file://${filePath}`);
if ('data' in command && 'execute' in command) {
client.commands.set(command.data.name, command);
commands.push(command.data.toJSON());
}
}
// Enregistrer les slash commands
const rest = new REST().setToken(process.env.DISCORD_TOKEN);
try {
console.log('Enregistrement des commandes slash...');
await rest.put(
Routes.applicationCommands(process.env.CLIENT_ID),
{ body: commands }
);
console.log('Commandes enregistrées avec succès !');
} catch (error) {
console.error('Erreur lors de l\'enregistrement des commandes:', error);
}
// Gérer les interactions
client.on('interactionCreate', async interaction => {
if (!interaction.isChatInputCommand()) return;
const command = client.commands.get(interaction.commandName);
if (!command) return;
try {
await command.execute(interaction, player);
} catch (error) {
console.error(error);
const content = { content: 'Une erreur est survenue !', ephemeral: true };
if (interaction.replied || interaction.deferred) {
await interaction.followUp(content);
} else {
await interaction.reply(content);
}
}
});
// Événements du player
player.events.on('playerStart', (queue, track) => {
queue.metadata.channel.send({
embeds: [{
color: 0x1DB954,
title: '🎵 Lecture en cours',
description: `**[${track.title}](${track.url})**`,
thumbnail: { url: track.thumbnail },
fields: [
{ name: 'Durée', value: track.duration, inline: true },
{ name: 'Demandé par', value: track.requestedBy.toString(), inline: true },
],
}],
});
});
player.events.on('emptyQueue', queue => {
queue.metadata.channel.send('✅ File d\'attente terminée, je quitte le salon vocal.');
});
player.events.on('error', (queue, error) => {
console.error('Erreur player:', error);
});
// Quand le bot est prêt
client.once('ready', () => {
console.log(`✅ Connecté en tant que ${client.user.tag}`);
client.user.setActivity('de la musique 🎵', { type: 2 }); // "Écoute"
});
// Connexion
client.login(process.env.DISCORD_TOKEN);
Étape 6 : Les commandes
6.1 Commande Play
Créez src/commands/play.js :
import { SlashCommandBuilder, EmbedBuilder } from 'discord.js';
import { useMainPlayer } from 'discord-player';
export const data = new SlashCommandBuilder()
.setName('play')
.setDescription('Joue une musique depuis YouTube, Spotify ou SoundCloud')
.addStringOption(option =>
option
.setName('query')
.setDescription('Nom de la musique ou URL')
.setRequired(true)
);
export async function execute(interaction, player) {
const query = interaction.options.getString('query');
const voiceChannel = interaction.member.voice.channel;
if (!voiceChannel) {
return interaction.reply({
content: '❌ Vous devez être dans un salon vocal !',
ephemeral: true,
});
}
await interaction.deferReply();
try {
const { track } = await player.play(voiceChannel, query, {
nodeOptions: {
metadata: {
channel: interaction.channel,
requestedBy: interaction.user,
},
leaveOnEmpty: true,
leaveOnEmptyCooldown: 60000,
leaveOnEnd: true,
leaveOnEndCooldown: 60000,
},
requestedBy: interaction.user,
});
const embed = new EmbedBuilder()
.setColor(0x1DB954)
.setTitle('🎵 Ajouté à la file d\'attente')
.setDescription(`**[${track.title}](${track.url})**`)
.setThumbnail(track.thumbnail)
.addFields(
{ name: 'Durée', value: track.duration, inline: true },
{ name: 'Artiste', value: track.author || 'Inconnu', inline: true }
);
await interaction.editReply({ embeds: [embed] });
} catch (error) {
console.error(error);
await interaction.editReply({
content: '❌ Impossible de jouer cette musique. Vérifiez le lien ou réessayez.',
});
}
}
6.2 Commande Skip
Créez src/commands/skip.js :
import { SlashCommandBuilder } from 'discord.js';
import { useQueue } from 'discord-player';
export const data = new SlashCommandBuilder()
.setName('skip')
.setDescription('Passe à la musique suivante');
export async function execute(interaction) {
const queue = useQueue(interaction.guildId);
if (!queue || !queue.isPlaying()) {
return interaction.reply({
content: '❌ Aucune musique en cours de lecture.',
ephemeral: true,
});
}
const currentTrack = queue.currentTrack;
queue.node.skip();
await interaction.reply({
content: `⏭️ **${currentTrack.title}** a été passée.`,
});
}
6.3 Commande Stop
Créez src/commands/stop.js :
import { SlashCommandBuilder } from 'discord.js';
import { useQueue } from 'discord-player';
export const data = new SlashCommandBuilder()
.setName('stop')
.setDescription('Arrête la musique et vide la file d\'attente');
export async function execute(interaction) {
const queue = useQueue(interaction.guildId);
if (!queue) {
return interaction.reply({
content: '❌ Aucune musique en cours de lecture.',
ephemeral: true,
});
}
queue.delete();
await interaction.reply({
content: '⏹️ Musique arrêtée et file d\'attente vidée.',
});
}
6.4 Commande Queue
Créez src/commands/queue.js :
import { SlashCommandBuilder, EmbedBuilder } from 'discord.js';
import { useQueue } from 'discord-player';
export const data = new SlashCommandBuilder()
.setName('queue')
.setDescription('Affiche la file d\'attente');
export async function execute(interaction) {
const queue = useQueue(interaction.guildId);
if (!queue || !queue.isPlaying()) {
return interaction.reply({
content: '❌ Aucune musique en cours de lecture.',
ephemeral: true,
});
}
const currentTrack = queue.currentTrack;
const tracks = queue.tracks.toArray();
const embed = new EmbedBuilder()
.setColor(0x1DB954)
.setTitle('📜 File d\'attente')
.setDescription(
`**En cours :**\n🎵 [${currentTrack.title}](${currentTrack.url}) - ${currentTrack.duration}`
);
if (tracks.length > 0) {
const trackList = tracks
.slice(0, 10)
.map((track, i) => `${i + 1}. [${track.title}](${track.url}) - ${track.duration}`)
.join('\n');
embed.addFields({
name: `À suivre (${tracks.length} titre${tracks.length > 1 ? 's' : ''})`,
value: trackList,
});
if (tracks.length > 10) {
embed.setFooter({ text: `Et ${tracks.length - 10} autres titres...` });
}
}
await interaction.reply({ embeds: [embed] });
}
6.5 Commande Now Playing
Créez src/commands/nowplaying.js :
import { SlashCommandBuilder, EmbedBuilder } from 'discord.js';
import { useQueue } from 'discord-player';
export const data = new SlashCommandBuilder()
.setName('nowplaying')
.setDescription('Affiche la musique en cours');
export async function execute(interaction) {
const queue = useQueue(interaction.guildId);
if (!queue || !queue.isPlaying()) {
return interaction.reply({
content: '❌ Aucune musique en cours de lecture.',
ephemeral: true,
});
}
const track = queue.currentTrack;
const progress = queue.node.createProgressBar();
const embed = new EmbedBuilder()
.setColor(0x1DB954)
.setTitle('🎵 En cours de lecture')
.setDescription(`**[${track.title}](${track.url})**`)
.setThumbnail(track.thumbnail)
.addFields(
{ name: 'Artiste', value: track.author || 'Inconnu', inline: true },
{ name: 'Durée', value: track.duration, inline: true },
{ name: 'Demandé par', value: track.requestedBy.toString(), inline: true },
{ name: 'Progression', value: progress || 'N/A' }
);
await interaction.reply({ embeds: [embed] });
}
Étape 7 : Lancer le bot
Démarrez votre bot :
npm start
Si tout fonctionne, vous devriez voir :
Enregistrement des commandes slash...
Commandes enregistrées avec succès !
✅ Connecté en tant que MusicBot#1234
Étape 8 : Tester
- Rejoignez un salon vocal sur votre serveur
- Tapez
/playsuivi du nom d’une musique ou d’une URL YouTube - Le bot devrait rejoindre et jouer la musique !
Commandes supplémentaires
Voici quelques idées pour enrichir votre bot :
| Commande | Description |
|---|---|
/pause | Met en pause la lecture |
/resume | Reprend la lecture |
/volume | Ajuste le volume (0-100) |
/shuffle | Mélange la file d’attente |
/loop | Active/désactive la répétition |
/lyrics | Affiche les paroles |
Sources audio supportées
Avec @discord-player/extractor, votre bot peut lire :
- YouTube (vidéos et playlists)
- YouTube Music
- Spotify (nécessite conversion)
- SoundCloud
- Apple Music
- Vimeo
- Et bien d’autres…
:::warning Important : YouTube peut bloquer les bots qui font trop de requêtes. Pour un usage intensif, envisagez d’utiliser des proxies ou de vous conformer aux conditions d’utilisation de YouTube. :::
Dépannage
Le bot ne joue pas de son
- Vérifiez que FFmpeg est installé sur votre système
- Installez-le si nécessaire :
npm install ffmpeg-static - Vérifiez que le bot a les permissions “Connect” et “Speak”
Erreur “Cannot find module”
Assurez-vous d’avoir "type": "module" dans votre package.json pour utiliser les imports ES6.
Le bot se déconnecte tout seul
C’est normal ! Par défaut, le bot quitte après 60 secondes d’inactivité. Vous pouvez modifier leaveOnEmptyCooldown et leaveOnEndCooldown dans les options.
Conclusion
Vous avez maintenant un bot musical Discord fonctionnel ! Ce bot est privé et vous appartient entièrement, contrairement aux bots publics qui peuvent être supprimés à tout moment.
Pour aller plus loin :
- Ajoutez une base de données pour sauvegarder les playlists
- Créez un système de DJ avec rôles
- Intégrez un dashboard web pour la configuration
Dans un prochain article, nous verrons comment héberger ce bot pour qu’il reste en ligne 24h/24.
Articles similaires
Héberger son bot Discord 24/7 : toutes les solutions expliquées
Découvrez toutes les options pour héberger votre bot Discord en permanence : VPS, hébergement spécialisé, solutions gratuites et payantes comparées.