从零开始构建一个现代化的 Discord 机器人。学习基础知识。
Discord 机器人可以帮助您与服务器成员互动,并管理服务器。Discord 机器人可以在服务器上发送消息、直接向用户发送私信 (DM)、封禁用户、提升和降级用户等等。
作为服务器所有者,您不可能一直都在监控服务器,但机器人可以,而且速度更快。
您可能不是服务器所有者,但您想为自己所属的服务器创建一个机器人,或者创建一个公共机器人(供其他服务器使用),本文将帮助您实现这一目标。
在深入代码之前,让我们先来看看 Discord 机器人是如何工作的。
本文
主要面向不了解 Discord 机器人工作原理及构建方法的初学者。如果您已经熟悉 Discord 机器人的构建,本文内容可能不会对您有所帮助。
虽然这是面向初学者的教程,但我希望你对NodeJS和npm有一定的了解。
Discord机器人的工作原理
如果你所在的服务器里有机器人,你可能已经注意到这些机器人与用户帐户非常相似。
他们通常使用类似机器人的头像,似乎总是在线,回复消息速度也很快。这些都很酷,但这一切是怎么实现的呢?
有一种专门用于自动化操作的用户类型,称为机器人账户。它们看起来与普通用户账户非常相似。
机器人帐户使用令牌(而不是用户名、密码)进行身份验证,该令牌使这些帐户能够完全访问所有 Discord API 路由。
所以基本上,
- 我们在 Discord 开发者网站上创建了一个机器人(更多详情即将公布)。
- 为机器人分配角色,即授予机器人权限。
- 为机器人创建 OAuth 范围(简单来说,就是一个用于身份验证的链接)
- 将机器人添加到我们的某个服务器
- 砰!机器人开始施展魔法,比如回复消息。
很简单。不过我必须提醒一下,在机器人开始运行之前,你需要连接到 Discord API 并登录机器人。以下是创建这个机器人的方法。
- 在 Discord 中创建机器人
- 为我们的机器人创建权限
- 生成 OAuth 链接并使用它来连接到我们的 Discord 服务器
- 然后,我们将在电脑上创建一个用于存放机器人的文件夹,并打开 VSCode。
- 安装一些依赖项,编写一些代码来连接到 Discord API
- 至此,我们的机器人已上线。
现在不明白也不用担心,后面会详细解释。
你可以用 Discord 机器人构建什么?
Discord 机器人种类繁多,从适合老公使用的简单机器人到功能强大的机器人,应有尽有。你可以用 Discord 机器人构建任何东西。以下是一些示例。
- YouTube视频抓取器
- 有趣的推文抓取器
- 来自Reddit的表情包抓取器
- 一场游戏
- 带有日历的日程安排器
- 音乐播放器和歌曲搜索器
- 服务器管理器
- 测验机器人
还有更多。这里还有一些Discord 机器人创意。
关于机器人
本文将介绍的机器人将非常基础,但它几乎包含了构建你自己的超级机器人所需的一切。
有了这个机器人,我们将能够回复消息(命令)、查看消息历史记录、发送私信。
所以请尽量跟上进度。我会在我的 Discord 服务器上进行这个项目。
如果你没有自己拥有或管理的服务器,你应该创建一个。
让我们创建第一个机器人
提醒一下,这是对本文的配套练习。所以,阅读时尽量跟着我做。
创建机器人
首先,我们需要在Discord开发者页面上创建机器人。要创建机器人,首先需要创建一个应用程序。
- 所以请前往https://discord.com/developers/applications,点击右上角的“创建新应用程序” 。
- 输入应用名称。你可以随意命名,但为了方便本教程,我将其命名为“Buddy”。
太棒了!你刚刚创建了你的第一个Discord应用程序。现在让我们来创建机器人。
- 点击左侧导航栏中的“机器人” 。
- 现在点击“添加机器人”
- 将会弹出一个对话框,只需点击蓝色按钮即可继续。
雅虎!一个野生机器人出现了!准备好赋予它生命了吗?
机器人权限和 OAuth
现在我们需要为这个机器人定义一些权限,但为此我们首先需要创建一个 OAuth 作用域。这很简单。
点击左侧导航栏中的OAuth2 。
这里你会看到一些复选框,其子标题为“范围”。
在中间一栏找到“bot”,勾选它。
定义权限
(仅当您在第一组复选框中勾选后)将显示名为“机器人权限”的子标题下的另一组复选框。
现在选择您希望机器人拥有的权限,为了本教程的演示,我们再次选择。
- 查看频道(这是必填项)。
- 发送消息。
- 嵌入链接。
- 管理消息。
- 查看消息历史记录。
这就是这个机器人所需的所有权限。
完成后,滚动回到第一组复选框(“范围”),复制下面的链接。
在浏览器中打开一个新标签页,粘贴该链接,接下来选择你想让机器人运行的服务器。然后点击“继续”。
接下来,您将看到我们选择的权限列表,您可以直接点击“授权”继续,验证您是真人,这样就完成了。
如果你查看你邀请这个机器人加入的 Discord 服务器,你会发现机器人已经加入,但处于离线状态。现在是时候让它活跃起来了。
正在连接到 Discord API
我相信你的本地计算机上已经创建了一个文件夹。如果没有,请立即创建。
本教程将使用NodeJS。您也可以使用其他语言,例如Python,来构建Discord机器人。
建立我们的环境
文件夹已准备就绪,打开终端并运行npm init -y。
要运行此程序,您的本地计算机需要安装 NodeJS 和 NPM(特别是 NodeJS 16.6.0 或更高版本)。
安装依赖项
我们只需要两个依赖项:- Discord.js:npm install discord.js- Nodemon(开发依赖项):npm install -D nodemon
运行以上命令安装依赖项。
Discord.js 允许我们在 NodeJS 中与 Discord API 进行交互。
Nodemon会在每次进行并保存新更改时重启应用程序。
继续
创建一个名为app.js的文件。你可以把它命名为任何名称,比如 bot.js 或 index.js。
打开package.json文件,并将main更改为你刚刚创建的文件名。
接下来,将这些 JSON 脚本复制到package.json文件中的 scripts 属性中。
"scripts": {
"app": "nodemon app",
"start": "node app"
},
继续
创建一个名为config 的文件夹和一个名为default.js 的文件;我们将把我们的密钥存储在这里。
将以下内容复制到config/default.js 文件中
const config = {
DISCORD_TOKEN: 'YOUR TOKEN HERE',
};
module.exports = config;
请将“YOUR TOKEN HERE”替换为您的 Discord 令牌。
您可以在 Discord 开发者页面找到您的 Discord 令牌。点击您的应用,点击左侧导航栏中的“机器人” ,然后点击“复制”(靠近机器人头像)。
继续
在 config 文件夹中创建一个名为config.js 的文件。这样你就有了config/config.js 文件。在这个文件中,我们将包含所有的配置信息。
这些配置包括命令、前缀和意图。
-
命令就是机器人会响应的指令。因此,每当用户在 Discord 服务器中输入命令时,机器人都会做出相应的响应。
-
前缀(或多个前缀,可能有所不同)是命令前缀。对于这个机器人,我们只会使用一个前缀。前缀用于命令之前,例如 !get-meme。! 是前缀,而 get-meme 是命令。
你也可以直接调用 !get-meme 命令。
- 意图是新增的功能,它用于指定你希望机器人根据其行为接收的事件。如果没有指定这些意图,Discord API 将抛出错误。
那么,我们开始吧。
构建一个 Discord 机器人
我们先让机器人上线。
转到config/config.js并导入 Intents。
const { Intents } = require('discord.js');
请复制并粘贴以下代码。
const {
DIRECT_MESSAGES,
GUILD_MESSAGES,
GUILDS,
} = Intents.FLAGS;
这些是我们希望机器人拥有的权限,因此我们只是从“discord.js”提供的 Intents.FLAGS 中解构它。
创建一个名为“botIntents”的数组,并将上面的变量复制粘贴到其中,这样你就得到了类似这样的结果:
const botIntents = [
DIRECT_MESSAGES,
GUILD_MESSAGES,
GUILDS,
];
现在导出 botIntents
module.exports = { botIntents };
在app.js中导入以下内容
const { Client } = require('discord.js');
const { botIntents } = require('./config/config');
const config = require('./config/default');
然后粘贴这段文字
const client = new Client({
intents: botIntents,
partials: ['CHANNEL', 'MESSAGE'],
});
在这里,我们通过 'discord.js' 中的类创建一个新客户端Client,并传入一些属性。
第一个属性是 intents,也就是我们的 botIntents;最后一个属性是 partials,它是一个数组,用于让我们的机器人能够发送私信。如果您不需要此功能,可以移除该属性。
继续
现在我们有了 Discord API 的访问权限,我们可以监听事件了。
我们要监听的第一个事件是 onready。换句话说,就是机器人准备好上线的时候。
client.on('ready', () => {
console.log('Logged in as ' + client.user.tag);
});
当机器人准备上线时,我们只需将机器人的名称记录到控制台即可。
我们快完成了。在机器人上线之前,我们需要使用 Discord 令牌登录。
在app.js 文件底部复制粘贴以下内容
client.login(config.DISCORD_TOKEN);
请注意,配置文件是一个保存我们 Discord 令牌的对象。
现在运行该应用程序,进入你的 Discord 服务器,你就会看到机器人在线。
虽然机器人已上线,但它无法发送或回复任何消息。所以我们接下来就来解决这个问题。
设置命令
我通常使用正则表达式来设置命令,并使用 switch 和 case 语句来检查使用了哪个命令。这就是机器人监听不同命令的方式。
但这个机器人很简单,所以我们也会尽量简化操作。
在config/config.js 文件中,我们来注册一些命令。创建一个名为 `<command>` 的对象commands,并将以下内容粘贴到其中,例如:
const commands = {
getName: 'get-name',
tellJoke: 'tell-a-joke',
sad: 'sad',
lastMsgs: 'last-messages',
};
所以,这些就是我们的机器人将要监听的命令。
在导出之前,创建一个变量并将其命名为prefix`$`,然后将其赋值为 `!`。您也可以使用任何其他前缀,例如 `$`。这样我们就有了 `$`。const prefix = '!';
分别将命令和前缀导出为命令和前缀。
在app.js中,从config/config.js导入命令和前缀。只需将其添加commands, prefix到花括号周围即可botIntents。
继续
将以下内容复制粘贴到app.js 文件中
client.on('messageCreate', (msg) => {
if (msg.author.bot) return;
if (!msg.content.startsWith(prefix)) return; // do nothing if command is not preceded with prefix
const userCmd = msg.content.slice(prefix.length);
if (userCmd === commands.getName) {
msg.reply(msg.author.username);
} else {
msg.reply('I do not understand your command');
}
});
哇,这里发生的事情太多了。我们来逐一分析一下吧?
- 我们监听了一个名为 的事件
messageCreate,还有其他类似messageDelete、messageReactionAdd等的事件。请查看文档了解所有事件。 - 该
messageCreate事件返回一个包含消息信息的 msg 参数。 - 接下来,我们检查消息是否来自机器人
msg.author.bot。在这里,我们要确保忽略来自机器人的消息。 - 此外,我们会忽略不包含我们声明的前缀(“!”)的消息。
- 下一步是获取不带前缀的实际消息,这就是我们去掉前缀的原因。然后我们将其分配给 userCmd(即用户命令)。
- 最后,我们检查了消息内容(现在去掉前缀)是否与我们的第一个命令(即 getName)相同。如果相同,则
- 我们使用 (msg.author.username) 向用户回复了用户名。更多关于消息的信息,请参阅文档。如果回复内容不一致,请继续阅读。
- 我们回复了另一条消息:“我不理解您的命令”。
保存更改。前往你的 Discord 服务器,输入任意一条带有前缀的消息,查看回复。现在输入“!get-name”,也查看回复。
你可以用一些技巧让消息更友好一些Your discord username is ${msg.author.username}。这在实际的聊天机器人中并不实用,因为它会返回用户的用户名。但至少它展示了哪些功能是可行的。
接下来,
要添加其余命令,我们只需else if在初始的 if 语句链中添加更多内容即可。像这样。
if (userCmd === commands.getName) {
msg.reply(msg.author.username);
} else if (userCmd === commands.tellJoke) {
msg.reply('HTML is a programming language'); // bad joke i guess, unless i don't have any jokes
} else if (userCmd === commands.sad) {
msg.reply("Don't be sad! This is not the end of the road");
} else if (userCmd === commands.lastMsgs) {
const reply = await getLastMsgs(msg);
msg.reply(reply);
} else {
msg.reply('I do not understand your command');
}
为了获取最后一条消息,我们将在app.js中创建一个名为 `get_last_messages` 的函数getLastMsgs,并传入一个参数。
传统上,如果你的机器人监听的每个命令都有数量不明确的操作,为了便于阅读,通常建议将这些任务拆分成函数。
另外,你可以把这些函数放在同一个文件夹下的一个单独文件中,你可以把这个文件夹命名为“操作”之类的名称。
我不是说你现在就应该这么做,我只是说如果机器人有很多任务要做,这样做会更好。但这个机器人任务并不多。
这里有一个例子。虽然这个机器人项目被取消了,但它应该能让你了解拥有大量任务的机器人是如何构建的。
接下来,将
这段代码复制粘贴到getLastMsgs函数中(如果没有异步函数,可以创建一个),就像这样。
const getLastMsgs = async (msg) => {
// fetching the last 10 messages
const res = await msg.channel.messages.fetch({ limit: 10 });
return 'Last ten messages';
};
从技术上讲,我们传递的是收到的onmessageCreate事件消息的msg参数。因此,在当前接收命令的频道(可能是私信或服务器)中,将会获取最近的十条消息。
fetch 方法由Discord API提供,阅读本文后您应该了解一下。
结果是一个包含十条消息的数组,它不像传统数组那样可以通过索引访问每个元素。例如,如果要获取数组中的第一条消息,则必须使用相应的方法.first()。
因此,可以这样访问第一条消息的内容:
res.first().content; // don't add this to the function, just a showcase
另一个好处是,我们可以遍历数组中的每个元素。因此,return在getLastMsgs函数中的语句之前,添加以下内容:
const lastTenMsgs = messages.map((message) => {
return message.content;
});
forEach我们可以使用`or`循环遍历map,我们还可以访问filter`method` 方法。
现在将return语句更改为 lastTenMsgs。换句话说,你的函数应该如下所示:
const getLastMsgs = async (msg) => {
// fetching the last 10 messages
const res = await msg.channel.messages.fetch({ limit: 10 });
const lastTenMsgs = res.map((message) => {
return message.content;
});
return lastTenMsgs;
};
async保存之前,记得在事件函数中传递该参数messageCreate。例如:
client.on('messageCreate', async (msg) => {});
现在保存应用,并测试新命令。“!last-messages”命令会抛出一个数组,我们很快会修复这个问题。但现在,让我们先给机器人加点料吧。
首先要说明的是,并非所有消息都会被回复,而是机器人会创建一条新消息。我们用“!tell-a-joke”命令来实现这一点。
不要使用 msg.reply,而是这样做
msg.channel.send('HTML bla bla bla');
当你仔细研读文档时,你会了解更多相关内容,文档写得很好。
另外,我们说过机器人应该能够发送私信。那么,让我们用“!last-messages”命令来实现这个功能。
不要使用 msg.reply,而是这样做
msg.author.send(reply);
这并不能完全解决问题。我们现在就来解决这个问题。
最后,你肯定已经注意到 Discord 中的一些机器人发送/回复消息时,会在旁边添加颜色、粗体字,并像博客文章一样添加页眉和页脚。
其实这并不难做到。但在那之前,我应该先告诉你,你也可以用传统的方式将单词或文本加粗。
它几乎就像 Markdown 一样,但并非所有已知的 Markdown 语法都能使用。让我们把“!tell-a-joke”文本加粗。
msg.channel.send("**HTML** bla bla bla.\nI really don't have a joke");
如果你测试一下这个命令,你会发现 HTML 现在变成了粗体,并且“我真的没有笑话”显示在新的一行上。
那么,我们就继续往下看吧。
为了使我们的消息看起来像一篇带有漂亮颜色的博客文章,让我们使用“!last-messages”命令来实现这一点。
在app.js中,首先MessageEmbed从 'discord.js' 导入。这样你就有了
const { Client, MessageEmbed } = require('discord.js');
在getLastMsgs函数中,添加以下内容
const embeds = [];
lastTenMsgs.forEach((msg, index) => {
const embed = new MessageEmbed()
.setColor('ORANGE') // can be hex like #3caf50
.setTitle(`Message ${index + 1}`)
.setDescription(`${msg}`)
.setFooter('Buddy says Hi');
embeds.push(embed);
});
return embeds;
我们只是创建了一个新的消息嵌入,并对其应用了一些方法。对于每条消息(共十条消息),我们都会创建一个嵌入,并将其添加到嵌入数组中,稍后我们会返回该数组。
这些方法setColor、等等都描述得相当清楚。点击此处setTitle了解更多关于嵌入的信息。
现在,我们对“!last-messages”命令的回复将更改为
msg.author.send({ embeds: reply });
我们需要让 Discord 知道这是一个嵌入式应用,这样它才能正常工作。
如果只有一个嵌入内容,你也应该确保将其包装在一个数组中,例如:
msg.author.send({ embed: [onlyEmbed] });
现在保存更改并测试您的命令。错误消失了。现在一切都运行正常了。让我们发布机器人,让它永久在线吧!
我会使用 Heroku 的免费套餐。但问题是,我们的Heroku dyno在 30 分钟不活动后就会进入休眠状态。
解决这个问题的方法是使用 Uptime Robot。Uptime Robot 可以保证你的应用始终在线。不过,这样做也会带来一些副作用,所以通常来说,Heroku 的最佳替代方案是 Replit。
但无论如何,你仍然需要 Uptime 机器人来维持服务器运行,而且你需要一个服务器(而不是 Discord 服务器)。
所以,无论你使用 Replit 还是 Heroku,都需要先搭建一个服务器,然后将你的机器人连接到该服务器。那么,让我们在本地机器上创建一个服务器吧。
由于这是 NodeJS 项目,我们使用 'express'。使用以下命令安装 express npm i express:.
在根目录下创建一个名为server.js 的文件。在package.json文件中,将 main 函数改为 "server.js",并将 scripts 指向 "server.js" 而不是 "app.js"。
在server.js 文件中粘贴以下内容;
const express = require('express');
const app = express();
const PORT = process.env.PORT || 5000;
app.get('/', (req, res) => {
res.send('Buddy bot is running');
});
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
这里没什么大事发生,我们只是用 Express 创建了一个服务器。
我们只创建了一条路由,并附带一条简单的回复消息。如果您之前从未使用过 Express 或 NodeJS 服务器,相信我,您在这里真的无需担心太多。
直接复制粘贴就可以了。
如果保存,重新运行程序npm run app,您将看到日志消息“服务器正在端口 5000 上运行”。
如果你打开网页浏览器,打开一个新标签页,然后输入“ http://localhost:5000 ”,你就会收到“Buddy bot 正在运行”的消息。
服务器现在运行正常,但机器人似乎无法与之配合工作。我们来解决这个问题。
在app.js中,我们有 `<script>` 标签client.login,创建一个名为 `<script>` 的函数startBot并将其包装在 `<script>` 标签内client.login。这样你就有了 `<script>` 标签。
const startBot = () => {
client.login(config.DISCORD_TOKEN);
};
// export startBot as default
module.exports = startBot;
在server.jsstartBot中,从 './app.js'导入。
现在,在第一个路由之前调用该函数,即
startBot();
// before app.get()
虽然你可以在任何地方调用这个函数,只要它在 listen 方法之前即可。但我更喜欢在路由之前调用它。
推送之前,别忘了创建一个.gitignore文件来忽略 node*modules。还要注意推送到哪里。如果要推送到 GitHub,请将/config/default.js添加到 _gitignore* 中。
现在把它推送到 Heroku 或 Replit。我已经写过一篇关于使用 Uptime Robot 的文章,可以去看看。
结论
我相信这已经足够清晰明了,可以帮助你开始为数十个服务器或单个服务器创建机器人。如果你遇到任何问题,请在评论区留言。
该项目的源代码已上传至 GitHub,请给它点个赞,如果您喜欢这个项目,也请关注我。
最后,在我离开之前,我想说我真的每天都会在推特(@elijahtrillionz)上发布一些关于网页开发技巧和资源的推文。欢迎关注我,开启通知,让我们保持联系。
感谢阅读。下次再见,我和我的机器人也会再见。
文章来源:https://dev.to/elijahtrillionz/build-a-modern-discord-bot-from-scratch-learn-the-basics-973