Discord Bot作成を完全に理解する
1. はじめに
Discord Bot は SDK を使用することで簡単に作成することが可能です。
テキストでのメッセージの送信はもちろん、埋め込み、音声メッセージなど Discord Bot で表現できることの幅は広くなっています。
今回は新たに Discord Bot を作成する上で Discord Bot で表現できること、および運用する上での注意点を紹介します。
本記事の内容はGo(v1.20)とdiscordgo(v0.27.1)
を使用し作成しています。
また記事内の内容は章ごとに独立しているので、必要に応じて目次から参照してください。
対象読者
- Discord Bot で何ができるかよくわからない人
- Discord Bot を作成したい人
- Discord Bot の運用について知りたい人
2. Discord Bot で表現できるメッセージの種類
2.1. テキストメッセージ
- 基本的なメッセージ形式です。
- 2000 文字までのテキストを送信できます。
実装例
dg, err := discordgo.New("Bot " + TOKEN)
...
_, err = dg.ChannelMessageSend(channelID, "Hello, Test Channel!")
2.2. ファイル
画像や動画、ドキュメントなどのファイルを送信・共有することができます。
基本的な形式はサポートされており、一例ですが以下のようなものが添付できます。
画像: .jpg, .jpeg, .png, .gif, .webp
動画: .mp4, .mov
オーディオ: .mp3, .wav
テキスト: .txt, .md, .log
ドキュメント: .pdf, .doc, .docx, .ppt, .pptx, .xls, .xlsx
圧縮ファイル: .zip, .rar, .tar.gz
実装例
dg, err := discordgo.New("Bot " + TOKEN)
...
resp, err := http.Get("")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
// ファイルをメッセージとして送信
message := &discordgo.MessageSend{
Content: "画像:",
Files: []*discordgo.File{
{
Name: "sugar.png",
Reader: resp.Body,
},
},
}
_, err = dg.ChannelMessageSendComplex(channelID, message)
2.3. リアクション
-
メッセージに絵文字での反応を追加できます。
-
リアクションとしてつけられる絵文字は 2 種類あります。
-
Unicode絵文字
カスタム絵文字
実装例
// Unicode絵文字
err = dg.MessageReactionAdd(channelID, message.ID, "😀")
// カスタム絵文字 name:id形式でエンコードする必要があります。
err = dg.MessageReactionAdd(channelID, message.ID, "emoji_name:emoji_id")
- emoji_id はスタンプのリンクから得られる
XXX
の部分です。https://cdn.discordapp.com/emojis/?XXX.webp
2.4. リプライ
- 特定のメッセージに返信することができます。
実装例
dg, err := discordgo.New("Bot " + TOKEN)
...
m, _ := dg.ChannelMessageSend(channelID, "Hello, Test Channel!")
message := &discordgo.MessageSend{
Content: "This is a reply!",
// 該当のメッセージIDを指定し、Contentの内容を送信する
Reference: &discordgo.MessageReference{MessageID: m.ID},
}
_, err = dg.ChannelMessageSendComplex(channelID, message)
2.5. スレッド
-
トピックごとに分けられたメッセージのスレッドを作成できます。
-
スレッド名は 1~100 文字
-
スレッドの非表示までの時間が調整できます
実装例
thread, err := s.MessageThreadStartComplex(m.ChannelID, m.ID, &discordgo.ThreadStart{
// see: https://discord.com/developers/docs/resources/channel#start-thread-from-message
Name: "Pong game with " + m.Author.Username,
AutoArchiveDuration: 60,
Invitable: false,
RateLimitPerUser: 10,
})
if err != nil {
log.Println("Error starting thread:", err)
return
}
_, err = s.ChannelMessageSend(thread.ID, "pong")
2.6. コンテキストメニュー
メッセージに関連する追加アクションを提供するメニューです。
実装例
func registerContextMenu(s *discordgo.Session, guildID string) {
// Define the context menu
// see: https://discord.com/developers/docs/interactions/application-commands#create-global-application-command
cmd := &discordgo.ApplicationCommand{
Name: "share-with-me",
Type: discordgo.MessageApplicationCommand,
}
_, err := s.ApplicationCommandCreate(s.State.User.ID, guildID, cmd)
if err != nil {
log.Println("Failed to create context menu:", err)
}
}
2.7. Embed メッセージ
リッチなメッセージ形式です。
実装例
dg, err := discordgo.New("Bot " + TOKEN)
...
embed := &discordgo.MessageEmbed{
Title: "Embed Title",
Description: "This is an embed message",
Color: 0x00ff00, // Green
}
_, err = dg.ChannelMessageSendEmbed(channelID, embed)
- 埋め込み対象はカスタマイズできます。
2.8. TTS (Text-to-Speech) メッセージ
テキストを音声に変換して読み上げるメッセージ形式です。
※音量注意
- ユーザーが TTS を無効にしている場合、メッセージは通常のテキストとして表示されます。
- TTS の音声のピッチや速度などの細かい設定をカスタマイズすることはできません。
- TTS メッセージはテキストチャンネルでのみ再生されます。
実装例
dg, err := discordgo.New("Bot " + TOKEN)
...
_, err = dg.ChannelMessageSendTTS(channelID, "Hello in Text-to-Speech!")
2.9. コンポーネント (Button や Select Menu)
メッセージ内で使用できる UI コンポーネントです。
1.ButtonComponent
- メッセージ内で表示されるインタラクティブなボタンコンポーネントです。
- ユーザーがクリックするとアプリにインタラクションを送信できます。
- アクション行の中で送信の必要があります。
- アクション行は最大 5 つのボタンを含むことができ、セレクトメニューコンポーネントと同時に含むことはできません。
ボタンの種類は下記を参照して下さい。
実装例
&discordgo.MessageComponent{
Type: discordgo.ButtonComponent,
Label: "Click Me!",
Style: discordgo.PrimaryButton, // 例: プライマリーボタン
CustomID: "button_click",
}
2.SelectMenuComponent
- メッセージ内のドロップダウンリストからユーザーがオプションを選択するインタラクティブなコンポーネントです。
- シングルセレクトとマルチセレクトをサポートしています。
- アクション行内で送信する必要があり、1 つのアクション行には 1 つのセレクトメニューのみ含めることができます。セレクトメニューとボタンを同時に含むことはできません。
実装例
&discordgo.MessageComponent{
&discordgo.SelectMenu{
CustomID: "select_option",
Options: []discordgo.SelectMenuOption{
{
Label: "Option 1",
Value: "opt1",
},
{
Label: "Option 2",
Value: "opt2",
},
},
},
}
3.TextInputComponent
- テキスト入力はモーダルで表示されるインタラクティブなコンポーネントです。
- 短いフォームまたは長いフォームのテキストの収集に適しています。
※このコンポーネントは Interaction のみで利用可能です。
実装例
discordgo.TextInput{
CustomID: "text_input",
Placeholder: "Enter some text here",
Style: discordgo.TextInputParagraph,
}
- ボタン、セレクトメニュー、スラッシュコマンドなどのコンポーネントを活用してユーザのアクションに応答することができる機能です。
Interaction の種類:
-
スラッシュコマンド (Slash Commands):
-
/
を使用してコマンドを起動する機能。 - カスタムコマンドを作成して、特定のアクションや応答をトリガーすることができる。
- グローバルまたは特定のサーバーでのみ使用するために登録できる。
-
-
メッセージコンポーネント (Message Components):
- 前述したコンポーネント(TextInput など)を埋め込むことができる。
-
コンテキストメニュー (Context Menus):
- ユーザやメッセージに対してカスタムアクションを追加するための右クリックメニュー。
- スラッシュコマンドと同様の登録と処理フローを持つ。
重い処理を行う場合は、時間制限を考慮し非同期で処理を行う必要があります。
下記の記事では、リクエストを受け付けるエンドポイントを用意し、PubSub キューにリダイレクトするような構成にすることで、Discord Bot への応答を返しつつ、非同期での処理を実現しています。
2.10. スケジュール
特定の時間や日付にメッセージを送信するスケジューリング機能です。
- イベントは最大 100 件登録できます。
実装例
dg, err := discordgo.New("Bot " + TOKEN)
...
params := &discordgo.GuildScheduledEventParams{
Name: "イベント名",
Description: "イベントの説明",
ScheduledStartTime: &startTime,
ScheduledEndTime: &endTime,
PrivacyLevel: discordgo.GuildScheduledEventPrivacyLevelGuildOnly,
EntityType: discordgo.GuildScheduledEventEntityTypeExternal,
EntityMetadata: &discordgo.GuildScheduledEventEntityMetadata{Location: "場所の情報"},
}
// スケジュールイベントを作成
_, err = dg.GuildScheduledEventCreate(guildID, params)
2.11. ボイスチャンネルでの音声メッセージ
ユーザーとの音声コミュニケーションを実現できます。
※音量注意
機能 | 実装例 | 説明 |
---|---|---|
ボイスチャンネルへの参加・退出 |
dg.ChannelVoiceJoin(...) / v.Disconnect()
|
Bot がボイスチャンネルに参加・退出するための基本的なメソッド |
音声の受信 | v.OpusRecv |
Bot が他のユーザーからの音声を受け取るためのメソッド。具体的には PCM データを取得することが可能 |
音声の送信 | v.OpusSend |
Bot が他のユーザーからの音声を受け取るためのメソッド。具体的には Opus 形式の音声データを受け取る |
ユーザーのミュート制御 | dg.GuildMemberMute(...) |
特定のユーザーをミュートにする、またはミュートを解除するためのメソッド |
ユーザーの音量調整 | - (Discord API に直接的なメソッドは存在しない) | ユーザーの音量を調整するための機能。具体的な実装は、音声データを操作して実現することが必要 |
オーディオファイルの再生 | カスタム実装が必要 | オーディオファイルを読み込んで、Opus 形式に変換し、v.OpusSend を利用してボイスチャンネルに送信する |
ユーザーとのインタラクティブなコマンド処理 | カスタム実装が必要 | テキストチャンネルでユーザーからのコマンドを受け取り、それに応じて Voice Bot の動作を変更するなどのインタラクティブな処理を実現 |
実装例
dg, err := discordgo.New("Bot " + TOKEN)
...
// ボットが参加するギルドとチャンネルの ID、ミュートやスピーカーのステータスなどのオプションを引数として受け取る。
v, err := dg.ChannelVoiceJoin(guildID, channelID, true, false)
- ボイスチャンネルで効果音を送信する
-
dca
フォーマットのオーディオファイルを読み込む
-
func playSound(s *discordgo.Session, guildID, channelID string) (err error) {
vc, err := s.ChannelVoiceJoin(guildID, channelID, false, true)
if err != nil {
return err
}
defer vc.Disconnect()
time.Sleep(250 * time.Millisecond)
vc.Speaking(true)
for _, buff := range buffer {
vc.OpusSend <- buff
}
vc.Speaking(false)
time.Sleep(250 * time.Millisecond)
return nil
}
- 録音
- 効果音
3. Discord Bot の運用
3.1. 開発言語
Bot を開発する際の主要な言語、それぞれの SDK の特性は以下の通りです。
Discord Bot を開発するための言語は多岐にわたります。以下は主要な言語と、それぞれの SDK の特性、情報源をまとめたものです。
言語 | SDK の特性 | OSS |
---|---|---|
Python | 豊富なライブラリと組み合わせることで、高度な機能を持つ Bot の開発が可能。主に非同期処理に対応している | discord.py, hikari |
JavaScript | Node.js 上で動作する Bot 向けのライブラリ。非同期処理をサポートし、効率的な Bot 開発が可能 | discord.js, Eris |
Java | 型安全性を活かした Bot 開発が可能。大規模な Bot の開発・運用が可能 | JDA, Discord4J |
C# | .NET フレームワークをベースにした Bot 開発が行える。非同期処理やイベント駆動をサポート | Discord.Net, DSharpPlus |
Go | Go 言語の特性を活かした、高性能・並行処理が得意な Bot の開発が可能 | discordgo |
Clojure | JVM 上で動作する関数型言語での Bot 開発が可能 | discljord |
C++ | 性能を追求した Bot 開発が可能 | D++ |
Lua | 軽量なスクリプト言語での Bot 開発が行える | Discordia |
PHP | Web アプリケーションとの連携を重視した Bot 開発が可能 | DiscordPHP |
Rust | 高性能かつ安全性を重視した Bot の開発が可能 | Serenity |
Ruby | オブジェクト指向の特性を活かした Bot 開発が可能 | discordrb |
3.2. Interactions
Interactions をサポートするためのライブラリやツールは多数あります。
Webhook 経由で Interactions を受信する場合に必須となるセキュリティと認証チェックのヘルパーやデータモデルの型を提供しています。
以下はその代表的なものを一部紹介します。
言語 | 特性 | 情報源 |
---|---|---|
C# | Interactions via outgoing webhook のサポート | Discord.Net.Rest |
Dart | Slash commands サポート、Commands framework を含み、クロスプラットフォームで動作、全ての送信 HTTP リクエストや WebSocket メッセージのコントロールが可能。 | nyxx |
Go | Minimal caching を持つ高速な API ラッパー | Tempest |
Javascript | Interactions webhook を実装する際に役立つタイプとヘルパー関数を提供 | discord-interactions-js |
Python | Python 向けの Interactions サポートライブラリ | discord-interactions-python |
PHP | Interactions webhook を実装する際に役立つタイプとヘルパー関数を提供 | discord-interactions-php |
3.3. API Types
Discord API 用のシンプルな型定義です。
名前 | 言語 |
---|---|
dasgo | Go |
discord-api-types | JavaScript |
3.4. Discord Bot の開発を支えるツール
Game SDK Tools
Discord Game SDK と他のゲームプラットフォーム(例: Valve の Steamworks SDK)のネットワーク層は類似しています。
以下の OSS を使用することで、共有機能のための統一されたインターフェースを開発者に提供し、複数のプラットフォームでの開発を簡略化することができます。
ツール名 | 詳細 | 対応プラットフォーム |
---|---|---|
HouraiNetworking | Unity3D 向けのライブラリ | Unity3D |
Dispatch Tools
Discord の Dispatch ツールを使用してゲームを Discord で公開する際に使用するツールです。
ツール名 | 詳細 |
---|---|
JohnyTheCarrot's Dispatch CLI | ゲームのアップデートを Push するときの Webhook サポート |
Permission Calculators
Discord の権限は複雑ですが、以下のツールを使えば簡単に計算できます。
ツール名 | 詳細 |
---|---|
FiniteReality's Permissions Calculator | 権限計算ツール |
abalabahaha's Permissions Calculator | 権限計算ツール |
Intent Calculators
インテントの計算に使用できます。(インテントは、特定のイベント群を Bot にサブスクライブさせるためのものです。)
ツール名 | 詳細 |
---|---|
ziad87's Intent Calculator | Intent 計算ツール |
Larko's Intent Calculator | Intent 計算ツール |
Embed Visualizers
Embeds の視覚化に役立つツールです。
ツール名 | 詳細 |
---|---|
Autocode Embed Builder | Embed のビジュアライザ |
JohnyTheCarrot's Embed Previewer | Discord 内での Embed 表示をテストするブラウザ拡張 |
3.5. (無料枠での)ホスティング先
Bot のホスティング先には様々な選択肢があります。
無料枠で常時起動可能なマネージドなサービスで代表的なものは以下のとおりです。
サービス名 | コスト (月) | RAM | CPU | ストレージ | ネットワーク転送量 | 備考 |
---|---|---|---|---|---|---|
Render | $0 (制限あり) | 512 MB | 0.1 vCPU | - | - | 制限詳細 |
fly.io | 無料プランあり | 256 MB (3 VMs まで) | 共有 CPU (3 VMs まで) | 3 GB (合計) | 160 GB | 3 VMs (V2 apps, V1 apps, Machines 合計) |
replit | 無料プランあり | 0.5 GiB | 0.5 vCPUs | 10 GiB | 10 GiB (開発用) | Unlimited Public Repls |
Railway | 初回 $5 まで無料 | $10/GB/月 | $20/vCPU/月 | $0.25/GB/月 (オプション) | $0.10/GB | 2023 年 8 月 1 日からの転送料金 |
上記以外にも、Interaction 経由のみの動作、またはユーザーの入力を受け付けない...など、Bot の機能によってホスティング先の選択肢は異なります。
常駐の必要がなく HTTP Interaction のみの利用で十分な場合は、Lambda や Cloudflare Workers などの Faas によるホスティングも可能なため検討してください。
3.6. 一般に公開する場合
Discord Bot を一般に公開する際は、セキュリティや利用者の利便性、API の制限などさまざまな面での注意が必要です。
基本情報
- Bot は一般に公開する場合、Discord Developer Portal での公開設定が必要です。
- Bot の公開設定は、Discord Developer Portal の「OAuth2」タブから設定できます。
- 100 サーバー以上に Bot を導入する場合は別途申請が必要です。(75 サーバ以上に導入されると Dev Portal 上で本人確認が行われます)
権限と機能の制限
不正利用を防ぐため、ボットには必要最低限の権限のみを与えるのが基本です。
ボットの権限管理は、ホワイトリスト形式の許可制を採用しています。(ボットに明示的に権限が付与されない限りアクションは実行できません)
またサーバー側でコマンド権限を設定することで、ユーザーごとにコマンド(/hoge
) Interaction の実行を制限することができます。
API リミットについて
Discord API は一定の制限があります。これを超えると Bot が一時的に動作を停止する可能性があります。
1. レートリミットの種類と詳細
タイプ | 説明 | 上限値 |
---|---|---|
Per-route | 個別のエンドポイントごとの制限。HTTP メソッドやエンドポイントの種類による。ヘッダーX-RateLimit-Bucket を参照。 |
ヘッダーX-RateLimit-Limit に示される値 |
Global | ボットやユーザーが全体として行うリクエストの制限。 | 1 秒あたり 50 リクエスト |
Emoji-specific | 絵文字に関するエンドポイントは通常の制限とは異なる。 | 具体的な上限値は提示されていない |
Invalid Request | 無効な HTTP リクエストの制限。主に 401、403、429 ステータスに関連。 | 10 分間に 10,000 リクエスト |
2. 主なレートリミット関連ヘッダー
ヘッダー名 | 説明 |
---|---|
X-RateLimit-Limit |
そのエンドポイントのリクエスト上限値 |
X-RateLimit-Remaining |
残りのリクエスト回数 |
X-RateLimit-Reset |
レートリミットがリセットされるエポックタイム(1970 年 1 月 1 日 00:00:00 UTC からの秒数) |
X-RateLimit-Reset-After |
レートリミットがリセットされるまでの時間(秒) |
X-RateLimit-Bucket |
レートリミットの一意な識別子 |
X-RateLimit-Global |
429 レスポンス時にのみ返され、グローバルレートリミットにヒットしたことを示すフラグ |
X-RateLimit-Scope |
429 レスポンス時にのみ返され、ユーザー、グローバル、またはリソースのレートリミットの種類を示す |
API からの応答は HTTP 429 として返される。応答にはRetry-After
ヘッダーまたはretry_after
フィールドが含まれ、再試行するまでの待機時間が示されます。
注意点: アプリケーションはレートリミットにヒットするのを避けるため、応答ヘッダーを適切に解析し、制限に従って動作する必要があります。特に、401 や 403 などのエラーレスポンスを適切に処理することで、無効なリクエスト制限にヒットするリスクを減らすことができます。
4. 一般公開されている Bot の紹介
- 公開されている Discord Bot の一覧がランキング形式で閲覧できます。
- VOICEVOX 読み上げ Bot
- (著者が作成した)Vtuber グループ の配信を通知する Bot
Tweet
5. 参考文献
Discussion