🦕

Discordeno を使って Deno で Discord BOT を動かす

2022/12/10に公開約7,000字

Discordeno

Deno で Discord の BOT を扱うことができるライブラリです。

https://github.com/discordeno/discordeno
https://discordeno.mod.land/

ドキュメントはまだあまり充実していないのですが、比較的頻繁に更新されており、結構イイ感じのライブラリです。
JS の Discord API ライブラリといえば Discord.js がありますが、それとは操作感がかなり異なるので少し注意が必要です。

Deno で Discord BOT を動かす利点として大きいのが無料で使える Deno Deploy の存在で、Heroku が有料となった今、無料で常に BOT を動かせるのはかなり嬉しいです。

サンプルコード

今回作成した BOT のコードは以下のレポで公開しています。
解説が意味不明なときはこっちを丸写しすれば動くと思います。

https://github.com/p1atdev/discordeno_sample

必要なもの

Node.jsやPythonなど、他の言語で Discord BOT を動かしたことがあることが望ましいです。Denoの知識も多少あるとよいです。

  • Deno 1.28

また、この記事では VSCode 上で進めることを想定しています

BOT の準備

注意点だけ書いておきます。

Discord の BOT の設定画面に Privileged Gateway Intents という項目がありますが、少なくともこの下2つのチェックは入れておくとよいです。

プロジェクト作成

新しく Deno プロジェクトを作成します。VSCode 上で Deno の拡張機能を有効にし、Deno: Initialize Workspace Configuration を選んでエンターキーを三回連打します。

以下のファイルを作成します

deno.jsonc
{
    "tasks": {
        "dev": "deno run -A --watch ./main.ts",
        "start": "deno run -A --watch ./main.ts"
    }
}

main.tsdeps.ts も作成しておきます。

deps.ts

以下のようにします

deps.ts
// discordeno
export * from "https://deno.land/x/discordeno@17.1.0/mod.ts"

// dotenv
export * as dotenv from "https://deno.land/std@0.167.0/dotenv/mod.ts"

discordenoはバージョンによって破壊的な変更が多いので注意が必要です。
dotenvはトークンの読み込みに使います。

BOT のコードを書いていく

機密情報

BOT のトークンを .env.local に書きます。

.env.local
DISCORD_TOKEN=hogehoge

トークンを読み取るのはBOT本体とは別の場所にしたいので、 secret.ts を作成して、以下のようにします。

secret
import { dotenv } from "./deps.ts"

dotenv.configSync({
    export: true,
    path: "./.env.local",
})

export const Secret = {
    DISCORD_TOKEN: Deno.env.get("DISCORD_TOKEN")!,
}

configSyncexporttrue にしないと、Deno.env.get で取得できないので注意です。

BOT のコードを書く

main.ts に BOT のコードを書いていきます。

main.ts
import { createBot, Intents, startBot } from "./deps.ts"
import { Secret } from "./secret.ts"

const bot = createBot({
    token: Secret.DISCORD_TOKEN,
    intents: Intents.Guilds | Intents.GuildMessages | Intents.MessageContent,
    events: {
        ready: (_bot, payload) => {
            console.log(`${payload.user.username} is ready!`)
        },
    },
})

bot.events.messageCreate = (b, message) => {
    if (message.content === "!neko") {
        b.helpers.sendMessage(message.channelId, {
            content: "にゃーん",
        })
    }
}

await startBot(bot)

ここまで書いて、以下を実行すると BOT が起動します

deno task dev

--watch フラグがついているので、コードを保存すると自動で再実行されます。便利です。

うまく動いていれば、BOT のいるサーバーで !neko と発言すると にゃーん と返ってきます。

Discord.js を触ったことがある人は違和感があるかもしれませんが、送られたメッセージのあるチャンネルにメッセージを返すには、 Bot に用意されている helpers.sendMessage() を利用する形になります。

スラッシュコマンドを使う

スラッシュコマンドを作成してみます。
今回は、反映が早いので自分のサーバーに対してコマンドを作成します。

自分のサーバー ID を GUILD_ID として .env.localsecret.ts に保存します。

.env.local
DISCORD_TOKEN=hogehoge
GUILD_ID=1234
secret.ts
import { dotenv } from "./deps.ts"

dotenv.configSync({
    export: true,
    path: "./.env.local",
})

export const Secret = {
    DISCORD_TOKEN: Deno.env.get("DISCORD_TOKEN")!,
    GUILD_ID: Deno.env.get("GUILD_ID")!,
}

main.ts を以下のようにします

main.ts
- import { createBot, Intents, startBot } from "./deps.ts"
+ import { createBot, Intents, startBot, CreateSlashApplicationCommand, InteractionResponseTypes } from "./deps.ts"
import { Secret } from "./secret.ts"

const bot = createBot({
    token: Secret.DISCORD_TOKEN,
    intents: Intents.Guilds | Intents.GuildMessages | Intents.MessageContent,
    events: {
        ready: (_bot, payload) => {
            console.log(`${payload.user.username} is ready!`)
        },
    },
})

+ const nekoCommand: CreateSlashApplicationCommand = {
+     name: "neko",
+     description: "にゃーんと返します",
+ }

+ await bot.helpers.createGuildApplicationCommand(nekoCommand, Secret.GUILD_ID)
+ await bot.helpers.upsertGuildApplicationCommands(Secret.GUILD_ID, [nekoCommand])

bot.events.messageCreate = (b, message) => {
    if (message.content === "!neko") {
        b.helpers.sendMessage(message.channelId, {
            content: "にゃーん",
        })
    }
}

+ bot.events.interactionCreate = (b, interaction) => {
+     console.log(interaction.data?.name)
+ }

await startBot(bot)

これらを追加すると、BOT のいるサーバーで neko のスラッシュコマンドが追加されたと思います。

このまま実行しても何も反応はありませんが、deno の方で neko と出力されます。

bot.events.interactionCreate を次のように書き換えてみます。

main.ts
// 略

bot.events.interactionCreate = (b, interaction) => {
    switch (interaction.data?.name) {
        case "neko": {
            b.helpers.sendInteractionResponse(interaction.id, interaction.token, {
                type: InteractionResponseTypes.ChannelMessageWithSource,
                data: {
                    content: "にゃーん!!",
                },
            })
            break
        }
        default: {
            break
        }
    }
}

すると、/neko を実行すると にゃーん!! が返ってくるようになります。

Deno Deploy にデプロイする

.gitignore を作成

.gitignore を作成します。
gitignore.io にアクセスして以下の用な条件で生成し、.gitignore として保存します。

git を設定

git init
git add .
git commit -m "initial commit"

します。
お好みで

git branch -m main

します。

GitHub に上げる

適当に GitHub のレポを作成して上げます。

git remote add origin レポのURL
git push -u origin master

Deploy

Secret の修正

Deno Deploy ではREAD権限がないため、dotenv の configSync でクラッシュします。
なので、簡易的な対策として try catch で囲みます。多分このやり方はあんまり良くないので、ちゃんとしたプロジェクトでやるなら、開発環境と本番環境を区別するコードを書いたほうがいいです。

secret.ts
// 略

try {
    dotenv.configSync({
        export: true,
        path: "./.env.local",
    })
} catch {}

// 略

Deno Deploy にアクセスし、アカウントがない場合は作り、サインインします。

https://deno.com/deploy

New Project を選択し、

Deploy from GitHub repository で作成したレポと main.ts を選択し、イイ感じの名前を付けます。

Link を押すと紐付けられ、デプロイが開始されます。10秒程度でデプロイが終わります。爆速です。

環境変数の設定

Discordのトークンなどを設定します。
Settings > Environment Variables から Add Variable します。

環境変数が更新されると自動で再実行されるはずですので、これで動くようになったと思います。

(もし動かない場合は、Deno Deploy で与えられた URL に一度アクセスすると起きるはずです。)


おわり

なぜか Discordeno の記事が全然なかったので、とりあえず簡単な BOT の解説記事を書きました。Discordeno の仕様は他の Discord ライブラリとは少し異なるのでそのまま移行するのは難しいかもしれませんが、 Deno も Deno Deploy も非常に便利なので一つの選択肢として覚えておくとよいかと思います。
Discordeno はドキュメントが充実していないのですが、コードにコメントが付いてるのと、いくつかのテンプレート があるので、そちらを参考にするとよいです。ドキュメントのコード例は古くてそのままだと全然動かないことがあるので気をつけてください。

今回作成したサンプルコードのレポ
https://github.com/p1atdev/discordeno_sample

GitHubで編集を提案

Discussion

ログインするとコメントできます