简体中文 English 繁體中文 日本語 Русский
本文为静态镜像,内容以交互版为准 在交互式文档中心打开 →

Discord 平台特性文件

DiscordAdapter 是基於 Discord Gateway (WebSocket) 和 REST API v10 協議建構的適配器,整合了 Discord Bot 的核心功能,提供統一的事件處理和訊息操作介面。


文件資訊

基本資訊

配置說明

DiscordAdapter 支援多帳戶設定,每個帳戶對應一個獨立的 Discord Bot。

# config.toml

# 帳戶1
[DiscordAdapter.accounts.default]
token = "YOUR_BOT_TOKEN"       # Discord Bot Token(必填)
intents = 33281                 # Gateway Intents(可選,預設 33281)
enabled = true                  # 是否啟用(可選,預設 true)

# 帳戶2
[DiscordAdapter.accounts.bot2]
token = "ANOTHER_BOT_TOKEN"
intents = 33281
enabled = true

設定項目說明(每個帳戶):

Gateway Intents

Intents 使用位遮罩,計算方式為各 Intent 值按位或(|):

Intent 位 值 說明 Privileged
GUILDS 1 << 0 1 伺服器建立/刪除/更新、頻道、角色變更 否
GUILD_MEMBERS 1 << 1 2 成員加入/離開/更新 是
GUILD_MESSAGES 1 << 9 512 伺服器訊息收發 否
MESSAGE_CONTENT 1 << 15 32768 訊息內容(無此 Intent 時 content 為空) 是

預設值 33281 = GUILDS(1) | GUILD_MESSAGES(512) | MESSAGE_CONTENT(32768)。

注意:Privileged Intents 需在 Discord Developer Portal → Bot → Privileged Gateway Intents 中開啟。如果 Bot 在超過 100 個伺服器中,還需透過 Discord 審核。

API 環境:

v5 範式更新(4.2.0)

本適配器已完成 v5 範式對齊(增量升級,API 兼容):

標準 Api 動作

from ErisPulse import sdk
discord = sdk.adapter.get("discord")

result = await discord.Api.get_self_info()                # GET /users/@me
result = await discord.Api.get_user_info(user_id)         # GET /users/{id}
result = await discord.Api.get_guild_info(guild_id)       # GET /guilds/{id}
result = await discord.Api.get_guild_list()               # GET /users/@me/guilds
result = await discord.Api.get_channel_list(guild_id)     # GET /guilds/{id}/channels
result = await discord.Api.get_guild_member_info(gid, uid)
await discord.Api.delete_message(message_id)              # 登記表自動補全 channel_id
await discord.Api.leave_guild(guild_id)
result = await discord.Api.Using("main").get_self_info()

按鈕(keyboard / components)

rows = [[{"label": "點擊", "type": "callback", "data": "btn:1"},
         {"label": "官網",  "type": "link",     "data": "https://example.com"}]]
await discord.Send.To("channel", channel_id).Keyboard(rows).Text("請選擇")
# 自動轉換為 components: callback → custom_id / link → url

支援的消息發送類型

所有發送方法均透過串接語法實作,例如:

from ErisPulse.Core import adapter
discord = adapter.get("discord")

await discord.Send.To("group", channel_id).Text("Hello World!")

支援的發送類型包括:

串接修飾方法(可組合使用)

串接修飾方法回傳 self,支援串接呼叫,必須在最終發送方法前呼叫:

串接呼叫範例

# 基礎發送
await discord.Send.To("group", channel_id).Text("Hello")

# 回覆訊息
await discord.Send.To("group", channel_id).Reply(msg_id).Text("回覆訊息")

# 便捷回覆(一步到位)
await discord.Send.To("group", channel_id).Reply("回覆內容", msg_id)

# @使用者
await discord.Send.To("group", channel_id).At("user_id").Text("你好")

# @多個使用者
await discord.Send.To("group", channel_id).At("user1").At("user2").Text("多使用者@")

# @全體
await discord.Send.To("group", channel_id).AtAll().Text("公告")

# 組合使用
await discord.Send.To("group", channel_id).Reply(msg_id).At("user_id").Text("複合訊息")

# 嵌入訊息
embed = {
    "title": "通知",
    "description": "這是一條嵌入訊息",
    "color": 5814783,
    "fields": [{"name": "欄位", "value": "值", "inline": True}],
}
await discord.Send.To("group", channel_id).Embed(embed)

# 發送圖片
await discord.Send.To("group", channel_id).Image("https://example.com/image.png")

私訊發送

私訊發送時,適配器會自動建立 DM 頻道:

# 發送私訊
await discord.Send.To("user", user_id).Text("私訊內容")
await discord.Send.To("user", user_id).Embed(embed)

訊息操作

# 撤回訊息
await discord.Send.To("group", channel_id).Recall(msg_id)

# OneBot12 格式
ob12_msg = [
    {"type": "text", "data": {"text": "Hello "}},
    {"type": "mention", "data": {"user_id": "user_id"}},
]
await discord.Send.To("group", channel_id).Raw_ob12(ob12_msg)

發送方法返回值

所有發送方法均返回一個 Task 對象,可以直接 await 獲取發送結果。返回結果遵循 ErisPulse 适配器标准化返回规范:

{
    "status": "ok",           // 執行狀態: "ok" 或 "failed"
    "retcode": 0,             // 返回碼(0 為成功)
    "data": {...},            // Discord API 原始響應
    "message_id": "xxx",      // 消息ID(發送消息時)
    "message": "",            // 錯誤信息
    "discord_raw": {...}      // 原始響應數據
}

錯誤碼說明

retcode 說明
0 成功
33001 網路錯誤(連接失敗、超時等)
34000 Discord API 返回錯誤(權限不足、參數錯誤等)

特有事件類型

需要 platform == "discord" 檢測再使用本平台特性。

核心差異點

  1. 伺服器/頻道系統:Discord 使用伺服器(Guild)和頻道(Channel)兩層結構,頻道是訊息的基本發送目標
  2. Gateway 事件:所有事件透過 WebSocket Gateway 接收,使用 Opcode + Dispatch 機制
  3. Intents 訂閱:透過位遮罩訂閱事件類型,MESSAGE_CONTENT 需 Privileged 權限
  4. 訊息段類型:支援文字、圖片、檔案、影片、音訊、Embed、Sticker 等訊息段
  5. Mention 格式:Discord 使用 <@user_id> 格式表示使用者提及

擴展欄位

所有特有欄位均以 discord_ 前綴標識:

detail_type 映射

Discord 場景 detail_type 說明
頻道訊息 channel ErisPulse 擴展類型
私訊(DM) private OneBot12 標準類型

事件類型映射

Discord 事件 OneBot12 type detail_type 說明
MESSAGE_CREATE message channel/private 訊息建立
MESSAGE_UPDATE message channel/private 訊息編輯
MESSAGE_DELETE notice group_message_delete / private_message_delete 訊息刪除
GUILD_MEMBER_ADD notice group_member_increase 成員加入
GUILD_MEMBER_REMOVE notice group_member_decrease 成員離開
GUILD_MEMBER_UPDATE notice group_member_update 成員資訊更新
GUILD_ROLE_CREATE notice group_role_create 角色建立
GUILD_ROLE_DELETE notice group_role_delete 角色刪除
CHANNEL_CREATE notice channel_create 頻道建立
CHANNEL_DELETE notice channel_delete 頻道刪除
INTERACTION_CREATE request interaction 互動(按鈕、命令等)

特殊欄位範例

# 頻道文字訊息
{
  "type": "message",
  "detail_type": "channel",
  "user_id": "發送者ID",
  "user_nickname": "使用者名稱",
  "group_id": "頻道ID",
  "message_id": "訊息ID",
  "discord_raw": {...},
  "discord_raw_type": "MESSAGE_CREATE",
  "discord_guild_id": "伺服器ID",
  "discord_channel_id": "頻道ID",
  "message": [
    {"type": "text", "data": {"text": "Hello"}}
  ],
  "alt_message": "Hello"
}

# 私訊訊息
{
  "type": "message",
  "detail_type": "private",
  "user_id": "發送者ID",
  "user_nickname": "使用者名稱",
  "message_id": "訊息ID",
  "discord_raw": {...},
  "discord_raw_type": "MESSAGE_CREATE",
  "discord_channel_id": "DM頻道ID",
  "message": [
    {"type": "text", "data": {"text": "私訊內容"}}
  ],
  "alt_message": "私訊內容"
}

# 帶 Embed 的訊息
{
  "type": "message",
  "detail_type": "channel",
  "message": [
    {"type": "discord_embed", "data": {"embed": {...}}}
  ],
  "alt_message": "[嵌入訊息]"
}

# 帶附件的訊息
{
  "type": "message",
  "detail_type": "channel",
  "message": [
    {"type": "text", "data": {"text": "看這張圖"}},
    {"type": "image", "data": {"file": "圖片URL", "url": "圖片URL", "file_name": "image.png"}}
  ],
  "alt_message": "看這張圖[圖片]"
}

訊息段類型

Discord 訊息內容根據 content、attachments、embeds 欄位自動轉換為對應訊息段:

來源 轉換類型 說明
content 文本 text 純文字內容
content <@id> mention 使用者提及
content <@&id> discord_role_mention 角色提及
content <#id> discord_channel_mention 頻道提及
attachments (image/*) image 圖片附件
attachments (video/*) video 影片附件
attachments (audio/*) audio 音訊附件
attachments (其他) file 檔案附件
embeds discord_embed 嵌入訊息
sticker_items discord_sticker 貼紙

discord_embed 訊息段

{
  "type": "discord_embed",
  "data": {
    "embed": {
      "title": "標題",
      "description": "描述",
      "color": 12345,
      "fields": [...],
      "image": {"url": "..."},
      "thumbnail": {"url": "..."},
      "footer": {"text": "..."}
    }
  }
}

網關連接

連接流程

  1. 呼叫 GET /gateway/bot 以獲取 WebSocket 網關 URL
  2. 連接到 wss://gateway.discord.gg/?v=10&encoding=json
  3. 收到 opcode 10 HELLO:包含 heartbeat_interval
  4. 發送 opcode 2 IDENTIFY:攜帶 token、intents、properties
  5. 開始心跳循環:依照 heartbeat_interval 定期發送 opcode 1 Heartbeat
  6. 收到 opcode 0 Dispatch:事件分發(t=事件名, s=序號, d=資料)
  7. 收到 opcode 11 Heartbeat ACK:心跳確認

Opcode 說明

Opcode 名稱 方向 說明
0 Dispatch 接收 事件分發(含 t、s、d 欄位)
1 Heartbeat 發送/接收 心跳(攜帶最後 seq)
2 Identify 發送 身份驗證
6 Resume 发送 恢復會話
7 Reconnect 接收 伺服器要求重連
9 Invalid Session 接收 無效會話
10 Hello 接收 連接握手(含 heartbeat_interval)
11 Heartbeat ACK 接收 心跳確認

斷線重連與 RESUME

心跳機制

使用範例

處理頻道訊息

from ErisPulse.Core.Event import message
from ErisPulse import sdk

discord = sdk.adapter.get("discord")

@message.on_message()
async def handle_group_msg(event):
    if event.get("platform") != "discord":
        return

    text = event.get_text()
    channel_id = event.get("group_id")

    if text == "hello":
        await discord.Send.To("group", channel_id).Text("Hello!")

處理私訊

@message.on_message()
async def handle_private_msg(event):
    if event.get("platform") != "discord":
        return
    if not event.is_dm():
        return

    text = event.get_text()
    user_id = event.get("user_id")

    await discord.Send.To("user", user_id).Text(f"你說了: {text}")

發送 Embed 訊息

embed = {
    "title": "伺服器公告",
    "description": "歡迎使用 ErisPulse Discord 适配器",
    "color": 3447003,
    "fields": [
        {"name": "版本", "value": "4.0.0", "inline": True},
        {"name": "框架", "value": "ErisPulse", "inline": True},
    ],
    "footer": {"text": "Powered by ErisPulse"},
    "timestamp": "2025-01-01T00:00:00.000Z",
}
await discord.Send.To("group", channel_id).Embed(embed)

使用 Discord 特有方法

@message.on_message()
async def handle(event):
    if event.get("platform") != "discord":
        return

    channel_id = event.get_channel_id()
    guild_id = event.get_guild_id()
    is_dm = event.is_dm()
    embeds = event.get_embeds()
    attachments = event.get_attachments()

    if embeds:
        await discord.Send.To("group", channel_id).Text(
            f"收到 {len(embeds)} 個 Embed"
        )

處理互動事件

from ErisPulse.Core.Event import request

@request.on_request()
async def handle_interaction(event):
    if event.get("platform") != "discord":
        return

    interaction = event.get_interaction_data()
    if interaction.get("type") == 3:  # MESSAGE_COMPONENT
        await event.reply("按鈕已點擊!")