Como criar um bot do discord com javascript
Se você é familiar com o Discord você provavelmente conhece algum bot usado na palataforma, seja a Loritta, o MEE6 ou algum outro. De fato, usar eles no seu servidor é uma parte crucial da experiência do Discord hoje em dia. Pensando nisso, vamos hoje ver como podemos criar nosso próprio bot!
Preparando o Ambiente de Desenvolvimento
Primeiro de tudo, precisamos instalar o Node.js e uma IDE ou editor de texto, eu gosto do Visual Studio Code.
Agora crie uma nova pasta com o nome que desejar, seu projeto ficará dentro dessa pasta, entre na sua pasta criada com o seu editor de código de preferência e use o comando npm init -y
, isso vai criar um projeto em javascript para você.
Como pode ver, esse comando criou o arquivo package.json, esse arquivo guarda as informações do seu projeto, como o foco desse artigo não é ensinar javascript, não irei me aprofundar na funcionalidade de cada campo, o importante é saber que esse arquivo é essencial para o funcionamento correto do seu projeto.
Criando uma nova aplicação
Antes de fazer qualquer outra coisa no nosso projeto, precisamos registrar uma nova aplicação no Portal de Desenvolvedores do Discord
Essa é a página de aplicações do Discord, aqui todos as suas aplicações podem ser vistas e editadas, "aplicações" é o termo que o Discord usa para se referir a bots, caso você nunca tenha criado um anteriormente, essa página estará vazia, vamos clicar em "Nova Aplicação" no canto superior direito.
O Discord agora vai te pedir um nome para seu bot, não se preocupe, ele pode ser editado mais tarde!
Depois disso, a página de informações gerais vai aparecer, ela é assim:
Essa página contém informações como o nome, descrição, foto, tags, número de servidores do seu bot entre outras, sinta-se livre para deixar o bot com a sua cara, pela simplicidade, eu deixarei tudo como está.
O próximo passo é criar um link de convite do seu bot, assim podemos adicionar ele em qualquer servidor que desejarmos, para isso precisamos selecionar o botão OAuth2 no menu lateral, quando o menu abrir embaixo desse botão escolha o gerador de URL.
Em "Scopes", vamos selecionar "bot" e "applications.commands", isso vai dizer para o Discord que queremos adicionar um Bot que tem permissão para registrar comandos.
Assim que você clicar em "bot", uma nova seção de permissões do bot vai aparecer, isso serve para o Discord criar automaticamente um cargo para o seu bot quando ele entrar em um servidor, assim você garante que seu bot terá certas permissões que podem ser essenciais para seu funcionamento (se quem adicionar o bot permitir), nesse tutorial não precisamos selecionar nenhuma, pois nosso bot só mandará mensagens, coisa que o cargo "everyone" já pode fazer.
Desça até o final da página e copie o link que o Discord gerou, esse é o link que será usado para adicionar seu bot nos servidores, adicione seu bot em algum servidor seu que sirva para fazer testes (recomendo criar um novo servidor para isso).
Acesse novamente o menu lateral e agora clique na página "Bot".
Nessa página temos uma parte muito importante, o "Build-A-Bot", ela controla como os usuários veem seu bot, a sua foto, seu username e ela também guarda o seu token.
O token é o que diz para o Discord qual é o seu bot, não compartilhe ele, quem tiver acesso ao seu token tem acesso ao seu bot, vá em frente e clique para resetar o token, não se esqueça de anotá-lo pois o Discord só mostra ele uma vez!
(não perca seu tempo tentando controlar meu bot, ele já foi resetado)
Se você chegou até aqui, parabéns! Você registrou um novo bot no Discord com sucesso, agora vamos ver como programá-lo.
Dando vida ao Bot
Anteriormente criamos um novo projeto javascript, vamos acessá-lo novamente.
Usaremos aqui uma biblioteca chamada discord.js, ela é uma das bibliotecas mais usadas para a criação de bots e vai ser nossa principal ferramenta.
Podemos instalar ela rodando o comando npm i discord.js
, note que uma pasta chamada node_modules foi criada no seu projeto, ela guarda todos as bibliotecas que você instalar, não mexa nela a não ser que saiba o que está fazendo!
Agora vamos criar um novo arquivo chamado .env, ele será responsável por guardar o token do nosso bot de uma maneira segura, crie ele da seguinte maneira, coloque "TOKEN=" e em seguida o seu token, assim criamos uma variável de ambiente chamada TOKEN.
Para conseguirmos usar essa variável no projeto, precisamos baixar uma biblioteca chamada dotenv, npm i dotenv
.
Ademais, precisamos criar um arquivo index.js ele vai ser o arquivo principal do nosso bot, responsável por deixá-lo online, registrar comandos, etc.
Inicialmente o conteúdo do nosso arquivo index será o seguinte:
// Importamos as dependências necessárias
const { Client, GatewayIntentBits } = require("discord.js")
require("dotenv").config()
// Criamos uma instância do client
const client = new Client({ intents: [GatewayIntentBits.Guilds] })
// Quando o client (bot) estiver pronto, escrevemos no console
client.once("ready", () => {
console.log("Olá mundo!")
})
// Logamos o bot
client.login(process.env.TOKEN)
Esse é um código bem direto ao ponto, importamos o dotenv e as classes necessárias do discord.js, criamos um novo "client" que é o cliente do nosso bot, esses GatewayIntentBits são eventos (intents) que você declara que deseja receber no nosso caso estamos interessados em eventos relacionados a servidores (guilds), para mais informações consulte a Documentação do Discord.
Depois disso declaramos então a função client.once("ready")
, quando o bot estiver logado, todo o código dentro dela será executado uma única vez, note a diferença entre client.on
e client.once
, o primeiro executa o código toda vez que aquele evento aconteça, enquanto o segundo executa somente da primeira vez que esse evento acontecer.
Por fim invocamos client.login
passando o token que colocamos no .env, se tudo estiver correto, quando você usar node .
no terminal, o bot deve te responder e ficar online no discord.
Comandos de barra
Criaremos uma pasta chamada src e dentro dela uma pasta commands, assim, cada comando será seu próprio arquivo, vamos começar com um comando chamado user.js.
Um comando de barra nada mais é que um objeto com as propriedades "data" e "execute" (claro que se pode adicionar mais propriedades, mas essas são as essenciais), a "data" se refere as informações do seu comando, como nome, descrição, argumentos, etc. Como o nome do arquivo sugere, vamos fazer um comando que mostra algumas informações sobre um usuário, começamos assim:
const { SlashCommandBuilder, EmbedBuilder, time } = require("discord.js")
module.exports = {
data: new SlashCommandBuilder()
.setName("user")
.setDescription("See some information about a user")
.setDMPermission(false)
.addUserOption((option) =>
option
.setName("user")
.setNameLocalization("pt-BR", "usuário")
.setDescription("The user to get information")
.setDescriptionLocalization("pt-BR", "O usuário para pegar as informações")
.setRequired(true)
),
Calma, é muita informação nova de uma vez, não se apresse e leia tudo, a maioria dos métodos são triviais e se explicam pelo nome.
Aqui estamos declarando um comando usando o SlashCommandBuilder
, usamos .setDMPermission(false)
para indicar que não queremos que esse comando possa ser usado em DM, adicionalmente, declaramos um argumento que o usuário precisará fornecer na hora de usar o comando, do tipo usuário.
Agora vamos escrever a propriedade execute abaixo do código que já temos:
execute: async ({ interaction }) => {
// eu sempre gosto de fazer isso para ter mais tempo para responder, fica aquela mensagem que o bot está pensando
await interaction.deferReply().catch(() => {})
// pegamos o usuário que foi passado como argumento
const member = interaction.options.getMember("user")
// pegamos informações do usuário e colocamos numa embed
const embed = new EmbedBuilder()
.setTitle(member.displayName)
.setColor(member.displayColor)
.setThumbnail(member.displayAvatarURL())
.addFields(
{
name: "Membro do Discord desde",
value: time(member.user.createdAt),
inline: true,
},
{
name: "Membro desse servidor desde",
value: time(member.joinedAt),
inline: true,
}
)
.setFooter({ text: member.user.tag, iconURL: member.displayAvatarURL() })
// temos que editar a resposta e não só responder porque deferReply() foi usado anteriormente
interaction.editReply({ embeds: [embed] })
},
}
Como o nome implica, esse é o pedaço de código que será executado toda vez que um usuário usar esse comando, em resumo, criamos aqui uma embed com algumas informações do usuário, como imagem, nome, quando criou a conta do discord, etc.
Se você é como eu, talvez ao terminar esse comando já tenha reiniciado o bot e tentando usar o comando, caso tenha feito isso, você percebeu que ele não aparece, porque?
Lidando com comandos e eventos
Nosso comando ainda não aparece porque comandos de barra são diferentes dos comandos de prefixo, isso porque temos que registrá-los na API do Discord, vamos aprender como fazer isso.
Dentro da pasta src mas fora da pasta commands, vamos criar um novo arquivo functions.js
Dentro desse arquivo, iremos declarar a função loadFiles:
const fs = require("fs")
const { promisify } = require("util")
const readdir = promisify(fs.readdir)
async function loadFiles(dirName) {
const basePath = `${process.cwd().replace(/\\/g, "/")}/src/${dirName}`
const files = []
const items = await readdir(basePath)
for (const item of items) {
const itemPath = `${basePath}/${item}`
if (itemPath.endsWith(".js")) {
files.push(itemPath)
delete require.cache[require.resolve(itemPath)]
}
}
return files
}
Talvez esse código pareça alienígena, mas ele serve para carregar todos os arquivos de uma pasta dentro do diretório src.
Em sequência, vamos escrever a função loadCommands, que como o nome sugere serve para carregarmos todos os comandos e registrarmos eles:
async function loadCommands(client) {
await client.commands.clear()
const commandsArray = []
const Files = await loadFiles("commands")
Files.forEach((file) => {
const command = require(file)
client.commands.set(command.data.name, command)
commandsArray.push(command.data.toJSON())
console.log(`Comando: ${command.data.name} ✅`)
})
client.application.commands.set(commandsArray)
}
Analogamente, vamos declarar a loadEvents, assim podemos declarar eventos como declaramos comandos, um por arquivo dentro de sua própria pasta:
async function loadEvents(client) {
await client.events.clear()
const Files = await loadFiles("events")
Files.forEach((file) => {
const event = require(file)
const execute = (...args) => event.execute(...args, client)
client.events.set(event.name, execute)
if (event.once) {
client.once(event.name, execute)
} else {
client.on(event.name, execute)
}
console.log(`Evento: ${event.name} ✅`)
})
}
module.exports = {
loadFiles,
loadEvents,
loadCommands,
}
Perceba que caso na declaração do evento exista a propriedade once: true
, declaramos ele como client.once
e do contrário como client.on
, diferença que discutimos anteriormente. Por fim, exportamos as 3 funções.
Talvez agora você se encontre meio confuso, acabei de te mostrar 3 funções e entrei em pouco detalhe sobre elas, peço paciência, logo logo a importância delas ficará clara.
Agora que temos essas funções, vamos voltar ao index.js e mudar o código:
// Importamos as dependências necessárias
const { Client, GatewayIntentBits, Collection } = require("discord.js")
require("dotenv").config()
// Importamos as funções que criamos
const { loadEvents, loadCommands } = require("./src/functions")
// Criamos uma instância do client
const client = new Client({
intents: [GatewayIntentBits.Guilds],
})
// Quando o client (bot) estiver pronto, escrevemos no console
client.once("ready", () => {
console.log("Olá mundo!")
})
// Logamos o bot
client.login(process.env.TOKEN)
Leitores atentos perceberam que importamos as funções que acabamos de criar, leitores mais atentos perceberam que adicionamos Collection as classes que importamos do discord, uma Collection é uma estrutura de dados criada pelo discord.js, que é basicamente um Map com métodos extras, usaremos ela dentro do evento "ready" da seguinte maneira:
// Quando o client (bot) estiver pronto, escrevemos no console
client.once("ready", () => {
console.log("Olá mundo!")
client.commands = new Collection()
client.events = new Collection()
loadEvents(client)
loadCommands(client)
})
Os comandos e eventos serão armazenados dentro client usando as Collections, usamos a loadEvents e loadCommands para carregá-los.
Talvez, você esteja pensando porque eu criei uma função chamada loadEvents e a chamei dentro do arquivo principal, sendo que não temos nenhum evento, para controlar os comandos de barra, precisamos de um evento, o interactionCreate.
Criemos então a pasta events dentro da pasta src e dentro dela o arquivo interactions.js
Dentro desse arquivo, vamos declarar o evento interactionCreate:
module.exports = {
name: "interactionCreate",
execute: async (interaction, client) => {
// se a interação for um comando de chat, continuamos
if (interaction.isChatInputCommand()) {
// pegamos o comando pelo nome
const command = client.commands.get(interaction.commandName)
// invocamos a função execute do comando, passando algumas informações úteis
command.execute({
interaction,
client,
member: interaction.member,
guild: interaction.guild,
user: interaction.user,
channel: interaction.channel,
})
}
},
}
Essa é a estrutura de um evento, name se refere ao tipo de evento, nesse caso interactionCreate e novamente temos o execute como o código que será executado toda vez que esse evento for invocado.
Usamos o interaction.IsChatInputCommand()
para garantir que se trata de um comando que é invocado pelo chat, pois temos outros tipos de comandos que são tratados dentro desse mesmo evento, após isso verificamos qual comando é e invocamos o seu execute passando algumas propriedades úteis.
Ufa! Agora sim, quando rodarmos o projeto novamente com node .
, veremos o bot no terminal nos dizendo que o comando user e o evento interactionCreate foram carregados com sucesso.
Agora, se formos para o Discord e digitar /user, veremos o comando! (lembre-se que se seu Discord está em português o comando aparecerá como "/usuário", de qualquer modo digitar /user vai mostrar o comando desejado)
Escolha um usuário e veja a mágica acontecer!
Parabéns! Você criou seu primeiro bot do Discord!
Essa é a estrutura básica de um bot, existem ainda muitos conceitos mais avançados, cooldowns, sub comandos, testes... mas com essa estrutura você já pode começar sua jornada nesse universo!
Dicas
Deixarei aqui algumas dicas soltas para você que quer seguir desenvolvendo nessa área:
- Crie um segundo bot, deixe seu primeiro bot como um ambiente de "produção" e faça seus testes no segundo bot, assim você pode desenvolver sem afetar seus usuários (podemos alternar entre os dois só mudando o token)
- O site top.gg contém milhares de bots diferentes e é possível filtrar por categorias, é um bom lugar para pesquisar outros bots parecidos com o seu e também é possível colocar o seu bot lá para mais exposição
- Pense em criar um site para o seu bot, caso você deseje verificar seu bot, você tem que preencher alguns requisitos, dois deles é fornecer o link para sua Política de Privacidade e Termos de Serviço, uma boa forma de fazer isso é com um site, que também é um bom veículo para promover seu bot
- Meu jeito de criar bots não é o supremo! A biblioteca discord.js é bem não-opinativa e existem infinitos modos de se declarar um bot (é possível até criar bots com Typescript com a mesma biblioteca), use o Github! Pesquise!
Aprenda mais
Se quer aprender mais e levar seu bot ao próximo nível, aqui estão alguns materiais úteis:
- Guia discord.js esse é um guia muito completo e bem escrito que cobre tudo que eu cobri aqui e MUITO mais! O único detalhe é que ele é escrito em inglês.
- Documentação da biblioteca discord.js a documentação é um ótimo site para você deixar salvo e conferir sempre que precisar, é muito simples de achar o que você quer dentro dela e ver todos os métodos e propriedades daquela classe
- Um pouco de marketing da minha parte, mas que também pode ser útil como referência são os repositórios do meu bot principal, minha própria biblioteca de minigames pro discord e meu template de discord bots que é um pouco mais completo que o que desenvolvemos juntos aqui
- O código desenvolvido nesse artigo também estará disponível no meu github
Conclusão
Se você chegou até aqui, muito obrigado! Esse é uma versão um pouco mais enxuta do meu primeiro artigo publicado no dev.to, se quiser ler o orginal este é o link: https://dev.to/falcao_g/como-criar-um-bot-do-discord-com-javascript-19im