Executando verificação de segurança...
20
falcao
13 min de leitura ·

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ê.

Conteúdo do arquivo package.json

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.

Página Inicial do Portal de Desenvolvedores do Discord

O Discord agora vai te pedir um nome para seu bot, não se preocupe, ele pode ser editado mais tarde!

Nome da Aplicação

Depois disso, a página de informações gerais vai aparecer, ela é assim:

Informações gerais sobre o bot

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.

Botão OAuth2

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.

Escopos do Bot

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).

Link de convite

Acesse novamente o menu lateral e agora clique na página "Bot".

Botão 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!

Seção Build-A-Bot
(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.

Conteúdo do arquivo .env

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.

Estrutura do projeto, com o arquivo user.js dentro de uma pasta commands dentro de uma pasta src

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

Estrutura do projeto com o arquivo functions.js fora da pasta commands e dentro da pasta src

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

Estrutura do projeto com o arquivo interactions.js dentro da pasta events dentro da pasta src

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.

Terminal com as mensagens de 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)

Comando aparecendo no chat do discord

Escolha um usuário e veja a mágica acontecer!

Comando funcionando no chat do discord, mostrando uma embed com algumas informações do usuário escolhido

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

Carregando publicação patrocinada...
1
0
1

Ótimo texto! Eu sou um entusiasta com bots, já mexi com integrações com whatsapp, libs oficiais e não oficiais, e atualmente to no meu segundo bot do discord. O primeiro fiz de brincadeira, pra um servidor pessoal, agora o segundo estou tentando fazer pra comercializar.

No primeiro projeto usei PHP com uma lib chamada discordPHP, nesse segundo já parti pra TS, to usando uma lib chamada Necord

0
1

Que chique!
Me dá uma consultoria sobre isso?
Depois vou seguir seu tutorial com calma, mas já quero saber se tu me dá uma consultoria no precinho, quero por em prática algumas ideias.

0

opa, podemos combinar isso sim, imagino que você tenha discord, me manda uma mensagem por lá. meu @ lá é falcao_g