API discord предоставляет инструмент для создания и использования ботов. Рассмотрим пример создания базового музыкального бота и добавления его на сервер. Бот сможет проигрывать, пропускать и останавливать музыку, а также будет поддерживать функцию очереди воспроизведения.
Установка discord-бота
Создаем новое приложение на портале разработки discord.
Переходим на портал и нажимаем на “new application”.
Затем вводим название приложения и нажимаем на кнопку “create”.
Затем переходим на вкладку бот и нажимаем на “add bot”.
Бот создан! Теперь можно перейти к добавлению его на сервер.
Добавление бота на сервер
Добавляем созданный бот с помощью генератора OAuth2 URL.
Для этого переходим на страницу OAuth2 и выбираем бота в панели scope.
Затем выбираем необходимые разрешения для проигрывания музыки и чтения сообщений.
Теперь копируем сгенерированный URL и вставляем его в браузер.
Затем выбираем сервер, на который хотим добавить URL и нажимаем на кнопку “authorize”.
Создание проекта
Переходим к созданию проекта с использованием терминала.
Для начала создаем директорию и переходим в нее, используя две следующие команды:
mkdir musicbot && cd musicbot
Затем создаем модули проекта с помощью команды npm init. После введения команды будут заданы несколько вопросов. Ответьте на них и продолжайте.
Создаем два файла, в которых мы будем работать.
touch index.js && touch config.json
Теперь откройте проект в текстовом редакторе. Я использую VS Code и открываю его с помощью следующей команды:
code.
Основы Discord js
Прежде чем начать, нужно установить несколько зависимостей.
npm install discord.js ffmpeg-binaries opusscript ytdl-core --save
После завершения установки продолжаем написание файла config.json. Сохраните для бота токен и префикс, который он должен слушать.
{
"prefix": "!",
"token": "your-toke"
}
Для получения токена снова зайдите на портал разработки discord и скопируйте его из раздела bot.
Это все, что нужно выполнить в файле config.json. Приступим к написанию кода javascript.
Сначала импортируем все зависимости.
const Discord = require('discord.js');
const {
prefix,
token,
} = require('./config.json');
const ytdl = require('ytdl-core');
Затем с помощью токена создаем клиента и логин.
const client = new Discord.Client();
client.login(token);
Добавляем несколько базовых listeners, выполняющих метод console.log при запуске.
client.once('ready', () => {
console.log('Ready!');
});
client.once('reconnecting', () => {
console.log('Reconnecting!');
});
client.once('disconnect', () => {
console.log('Disconnect!');
});
Теперь можно начать работу с ботом с помощью команды node. Бот должен быть online в discord и в консоль выведется“Ready!”
node index.js
Чтение сообщений
Бот находится на сервере и может выходить online. Теперь можно начать читать сообщения в чате и отвечать на них.
Для чтения сообщений нужно написать лишь одну простую функцию.
client.on('message', async message => {
}
Создаем listener для события message, получаем сообщение и сохраняем его в объект message.
Проверяем: если сообщение пришло от бота, то игнорируем его.
if (message.author.bot) return;
В этой строке проверяется, является ли автором сообщения бот. Сообщение возвращается, если это так.
Затем проверяем, начинается ли сообщение с ранее определенного префикса. Сообщение возвращается, если нет.
if (!message.content.startsWith(prefix)) return;
После этого проверяем, какую команду нужно запустить. Это можно выполнить с помощью простых операторов if.
const serverQueue = queue.get(message.guild.id);
if (message.content.startsWith(`${prefix}play`)) {
execute(message, serverQueue);
return;
} else if (message.content.startsWith(`${prefix}skip`)) {
skip(message, serverQueue);
return;
} else if (message.content.startsWith(`${prefix}stop`)) {
stop(message, serverQueue);
return;
} else {
message.channel.send('You need to enter a valid command!')
}
В этом блоке кода проверяется, какую команду нужно запустить, а также осуществляется вызов команды. Если полученная команда недопустима, то вводим сообщение об ошибке в чат с использованием функции send().
Узнав, какие команды нужно запустить, можно перейти к их реализации.
Добавление песен
Начнем с добавления команды play. Для этого понадобится песня и гильдия (гильдия представляет собой изолированную коллекцию пользователей и каналов и часто упоминается в качестве сервера). Также понадобится ранее установленная библиотека ytdl.
Для начала создаем map с названием очереди, в котором будут сохранены все песни, введенные в чат.
const queue = new Map();
Затем создаем функцию async под названием execute и проверяем, находится ли пользователь в голосовом чате, и есть ли у бота соответствующее разрешение. Если нет, то пишем сообщение об ошибке и возвращаем.
async function execute(message, serverQueue) {
const args = message.content.split(' ');
const voiceChannel = message.member.voiceChannel;
if (!voiceChannel) return message.channel.send('You need to be in a voice channel to play music!');
const permissions = voiceChannel.permissionsFor(message.client.user);
if (!permissions.has('CONNECT') || !permissions.has('SPEAK')) {
return message.channel.send('I need the permissions to join and speak in your voice channel!');
}
}
Переходим к получению информации о песне и сохранении ее в объект song. Для этого используем библиотеку ytdl, которая получает информацию о песне по ссылке на youtube.
const songInfo = await ytdl.getInfo(args[1]);
const song = {
title: songInfo.title,
url: songInfo.video_url,
};
Необходимая информация сохраняется в объект song.
После сохранения информации нужно создать контракт для добавления в очередь. Для этого проверяем, определен ли serverQueue, что означает, что музыка уже играет. Если да, то добавляем песню в существующий serverQueue и отправляем сообщение об успешном выполнении. Если нет, то создаем его, подключаемся к голосовому каналу и начинаем проигрывать музыку.
if (!serverQueue) {
}else {
serverQueue.songs.push(song);
console.log(serverQueue.songs);
return message.channel.send(`${song.title} has been added to the queue!`);
}
В этом фрагменте мы проверяем, является ли serverQueue пустым. Если нет добавляем туда песню.
Если serverQueue имеет значение null, создаем контракт.
// Creating the contract for our queue
const queueContruct = {
textChannel: message.channel,
voiceChannel: voiceChannel,
connection: null,
songs: [],
volume: 5,
playing: true,
};
// Setting the queue using our contract
queue.set(message.guild.id, queueContruct);
// Pushing the song to our songs array
queueContruct.songs.push(song);
try {
// Here we try to join the voicechat and save our connection into our object.
var connection = await voiceChannel.join();
queueContruct.connection = connection;
// Calling the play function to start a song
play(message.guild, queueContruct.songs[0]);
} catch (err) {
// Printing the error message if the bot fails to join the voicechat
console.log(err);
queue.delete(message.guild.id);
return message.channel.send(err);
}
В этом блоке кода создается контракт, а песня добавляется в массив songs.
Затем присоединяемся к голосовому чату пользователя и вызываем функцию play(), которую затем реализуем.
Проигрывание песен
Поскольку теперь можно добавлять песни в очередь и создавать контракт при его отсутствии, можно приступить к реализации функцию проигрывания.
Сначала создаем функцию play, которая обладает двумя параметрами (гильдия и песня, которую нужно проиграть) и проверяет, является ли объект song пустым. Если да, то покидаем голосовой канал и удаляем очередь.
function play(guild, song) {
const serverQueue = queue.get(guild.id);
if (!song) {
serverQueue.voiceChannel.leave();
queue.delete(guild.id);
return;
}
}
Затем начинаем проигрывать песню с помощью функции playStream() и URL-адреса песни.
const dispatcher = serverQueue.connection.playStream(ytdl(song.url))
.on('end', () => {
console.log('Music ended!');
// Deletes the finished song from the queue
serverQueue.songs.shift();
// Calls the play function again with the next song
play(guild, serverQueue.songs[0]);
})
.on('error', error => {
console.error(error);
});
dispatcher.setVolumeLogarithmic(serverQueue.volume / 5);
В этом фрагменте мы создаем stream и передаем его URL-адресу песни. Также добавляем два listeners, которые обрабатывают события end и error.
Примечание: это рекурсивная функция, которая повторяет вызов самой себя. Рекурсия используется для проигрывания следующей песни, когда другая заканчивается.
Теперь можно проиграть песню, введя !play URL в чат.
Пропуск песен
Переходим к реализации функции пропуска. Для этого нужно выполнить завершения диспетчера, созданного в функции play() для начала проигрывания следующей песни.
function skip(message, serverQueue) {
if (!message.member.voiceChannel) return message.channel.send('You have to be in a voice channel to stop the music!');
if (!serverQueue) return message.channel.send('There is no song that I could skip!');
serverQueue.connection.dispatcher.end();
}
В этом фрагменте мы проверяем, находится ли пользователь, который ввел команду, в голосовом канале, а также есть ли песни для пропуска.
Остановка песен
Функция stop() похожа на skip(), за исключением того, что массив songs очищается, из-за чего бот удаляет очередь и покидает голосовой чат.
function stop(message, serverQueue) {
if (!message.member.voiceChannel) return message.channel.send('You have to be in a voice channel to stop the music!');
serverQueue.songs = [];
serverQueue.connection.dispatcher.end();
}
Исходный код для index.js:
Полный исходный код для музыкального бота:
const Discord = require('discord.js');
const {
prefix,
token,
} = require('./config.json');
const ytdl = require('ytdl-core');
const client = new Discord.Client();
const queue = new Map();
client.once('ready', () => {
console.log('Ready!');
});
client.once('reconnecting', () => {
console.log('Reconnecting!');
});
client.once('disconnect', () => {
console.log('Disconnect!');
});
client.on('message', async message => {
if (message.author.bot) return;
if (!message.content.startsWith(prefix)) return;
const serverQueue = queue.get(message.guild.id);
if (message.content.startsWith(`${prefix}play`)) {
execute(message, serverQueue);
return;
} else if (message.content.startsWith(`${prefix}skip`)) {
skip(message, serverQueue);
return;
} else if (message.content.startsWith(`${prefix}stop`)) {
stop(message, serverQueue);
return;
} else {
message.channel.send('You need to enter a valid command!')
}
});
async function execute(message, serverQueue) {
const args = message.content.split(' ');
const voiceChannel = message.member.voiceChannel;
if (!voiceChannel) return message.channel.send('You need to be in a voice channel to play music!');
const permissions = voiceChannel.permissionsFor(message.client.user);
if (!permissions.has('CONNECT') || !permissions.has('SPEAK')) {
return message.channel.send('I need the permissions to join and speak in your voice channel!');
}
const songInfo = await ytdl.getInfo(args[1]);
const song = {
title: songInfo.title,
url: songInfo.video_url,
};
if (!serverQueue) {
const queueContruct = {
textChannel: message.channel,
voiceChannel: voiceChannel,
connection: null,
songs: [],
volume: 5,
playing: true,
};
queue.set(message.guild.id, queueContruct);
queueContruct.songs.push(song);
try {
var connection = await voiceChannel.join();
queueContruct.connection = connection;
play(message.guild, queueContruct.songs[0]);
} catch (err) {
console.log(err);
queue.delete(message.guild.id);
return message.channel.send(err);
}
} else {
serverQueue.songs.push(song);
console.log(serverQueue.songs);
return message.channel.send(`${song.title} has been added to the queue!`);
}
}
function skip(message, serverQueue) {
if (!message.member.voiceChannel) return message.channel.send('You have to be in a voice channel to stop the music!');
if (!serverQueue) return message.channel.send('There is no song that I could skip!');
serverQueue.connection.dispatcher.end();
}
function stop(message, serverQueue) {
if (!message.member.voiceChannel) return message.channel.send('You have to be in a voice channel to stop the music!');
serverQueue.songs = [];
serverQueue.connection.dispatcher.end();
}
function play(guild, song) {
const serverQueue = queue.get(guild.id);
if (!song) {
serverQueue.voiceChannel.leave();
queue.delete(guild.id);
return;
}
const dispatcher = serverQueue.connection.playStream(ytdl(song.url))
.on('end', () => {
console.log('Music ended!');
serverQueue.songs.shift();
play(guild, serverQueue.songs[0]);
})
.on('error', error => {
console.error(error);
});
dispatcher.setVolumeLogarithmic(serverQueue.volume / 5);
}
client.login(token);
Заключение
У вас все получилось! Надеюсь, эта статья помогла вам разобраться в API Discord и создании с его помощью простого бота.
Читайте также:
Перевод статьи Gabriel Tanner: How to create a music bot using Discord.js