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

Kookプラットフォームの機能ドキュメント

KookAdapter は、Kook(開黒啦)Bot WebSocket プロトコルに基づいて構築されたアダプタであり、Kook のすべての機能モジュールを統合し、一貫したイベント処理とメッセージ操作インターフェースを提供します。


ドキュメント情報

基本情報

設定の説明

KookAdapter は、複数のアカウントをサポートしており、各アカウントは独立した Kook ロボットに対応します。

# config.toml
# アカウント1
[KookAdapter.accounts.default]
token = "YOUR_BOT_TOKEN"     # Kook Bot Token(必須、形式: Bot xxx/xxx)
bot_id = ""                   # Bot ユーザーID(任意、空欄の場合は token から解析)
compress = true               # WebSocket 圧縮を有効にするか(任意、デフォルトは true)
enabled = true                # 有効にするか(任意、デフォルトはtrue)

# アカウント2
[KookAdapter.accounts.bot2]
token = "ANOTHER_BOT_TOKEN"
bot_id = ""
enabled = true

旧設定の互換性:[KookAdapter] に token を含む旧の単一アカウント設定が検出された場合、accounts.default に自動的に移行されます。

各アカウントの設定項目の説明:

API 環境:

v5 フレームワークの更新(4.1.0)

このアダプタは v5 フレームワークに準拠した更新を完了しました(段階的なアップグレード、API は互換性を保つ)。

標準的な API アクション

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

result = await kook.Api.get_self_info()              # GET /users/@me
result = await kook.Api.get_user_info(user_id)       # POST /user/view
result = await kook.Api.get_guild_info(guild_id)     # POST /guild/view
result = await kook.Api.get_guild_list()             # POST /guild/list
result = await kook.Api.get_channel_info(channel_id) # POST /channel/view
result = await kook.Api.get_channel_list(guild_id)   # POST /channel/list
await kook.Api.delete_message(msg_id)                # POST /message/delete
result = await kook.Api.Using("main").get_self_info()

ボタン(keyboard)

rows = [[{"label": "オプションA", "type": "callback", "data": "vote:A"},
         {"label": "公式サイト",  "type": "link",     "data": "https://example.com"}]]
await kook.Send.To("channel", channel_id).Keyboard(rows).Text("選択してください")
# テキストとボタンは自動的に Kook カードメッセージ(section + action-group)に組み合わされます。

# ボタンのクリックコールバック(標準的なフィールド)
from ErisPulse.Core.Event import notice

@notice.on_notice()
async def handle_button(event):
    if event.get("platform") == "kook" and event.get("button_data"):
        data = event["button_data"]

支援されるメッセージ送信タイプ

すべての送信メソッドは、メソッドチェーン構文で実装されています。たとえば、次のように使用します:

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

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

サポートされている送信タイプは以下の通りです:

チェイン修飾メソッド(複数組み合わせて使用可能)

チェイン修飾メソッドは self を返し、メソッドチェーンで呼び出すことができます。最終的な送信メソッドの前に呼び出す必要があります:

チェイン呼び出しの例

# 基本的な送信
await kook.Send.To("group", channel_id).Text("Hello")

# メッセージの返信
await kook.Send.To("group", channel_id).Reply(msg_id).Text("返信メッセージ")

# ユーザーを@する
await kook.Send.To("group", channel_id).At("user_id").Text("こんにちは")

# 複数のユーザーを@する
await kook.Send.To("group", channel_id).At("user1").At("user2").Text("複数ユーザー@")

# 全員を@する
await kook.Send.To("group", channel_id).AtAll().Text("お知らせ")

# 修飾メソッドを組み合わせる
await kook.Send.To("group", channel_id).Reply(msg_id).At("user_id").Text("複合メッセージ")

OneBot12メッセージのサポート

アダプタは、OneBot12形式のメッセージを送信する機能をサポートしており、プラットフォーム間のメッセージ互換性を確保します。

# OneBot12形式のメッセージを送信する
ob12_msg = [{"type": "text", "data": {"text": "Hello"}}]
await kook.Send.To("group", channel_id).Raw_ob12(ob12_msg)

# 修飾メソッドと組み合わせる
ob12_msg = [{"type": "text", "data": {"text": "返信メッセージ"}}]
await kook.Send.To("group", channel_id).Reply(msg_id).Raw_ob12(ob12_msg)

# Raw_ob12でmentionとreplyメッセージセグメントを使用する
ob12_msg = [
    {"type": "text", "data": {"text": "Hello "}},
    {"type": "mention", "data": {"user_id": "user_id"}},
    {"type": "reply", "data": {"message_id": "msg_id"}}
]
await kook.Send.To("group", channel_id).Raw_ob12(ob12_msg)

追加操作メソッド

メッセージ送信以外にも、Kookアダプタは以下の操作をサポートしています:

# メッセージの編集(KMarkdown type=9 と CardMessage type=10 にのみ対応)
await kook.Send.To("group", channel_id).Edit(msg_id, "**更新後の内容**")

# メッセージの撤回
await kook.Send.To("group", channel_id).Recall(msg_id)

# ファイルのアップロード(ファイルURLの取得)
result = await kook.Send.Upload("C:/path/to/file.jpg")
file_url = result["data"]["url"]

送信メソッドの戻り値

すべての送信メソッドは Task オブジェクトを返します。これを直接 await することで送信結果を取得できます。返り値は ErisPulse アダプタの標準化された返り値規格に従います:

{
    "status": "ok",           // 実行ステータス: "ok" または "failed"
    "retcode": 0,             // 戻りコード(Kook API の code)
    "data": {...},            // 応答データ
    "message_id": "xxx",      // メッセージID
    "message": "",            // エラーメッセージ
    "kook_raw": {...}         // 元の応答データ
}

エラーコードの説明

retcode 説明
0 成功
40100 Token が無効または提供されていない
40101 Token が期限切れ
40102 Token が Bot と一致しない
40103 権限が不足している
40000 パラメータエラー
40400 対象が存在しない
40300 操作権限がありません
50000 サーバ内部エラー
-1 アダプタ内部エラー

特有イベントタイプ

このプラットフォームの機能を使用するには、platform=="kook" の検証が必要です。

核心的な違い

  1. チャンネルシステム:Kook はサーバー(Guild)とチャンネル(Channel)の2層構造を使用し、チャンネルがメッセージの基本的な送信先となります。
  2. メッセージタイプ:Kook はテキスト(1)、画像(2)、動画(3)、ファイル(4)、音声(8)、KMarkdown(9)、カードメッセージ(10)など、多様なメッセージタイプをサポートしています。
  3. プライベートメッセージシステム:Kook はチャンネルメッセージとプライベートメッセージを区別し、異なる API エンドポイントを使用します。
  4. メッセージの順序番号:Kook の WebSocket は sn 番号を使用してメッセージの順序性を保証し、メッセージの一時保存や順序の乱れを再配置することをサポートします。
  5. メッセージの編集と撤回:既に送信されたメッセージ(KMarkdown および CardMessage に限る)を編集し、メッセージを撤回することができます。

拡張フィールド

特殊フィールドの例

# チャンネルのテキストメッセージ
{
  "type": "message",
  "detail_type": "group",
  "user_id": "ユーザーID",
  "group_id": "チャンネルID",
  "channel_id": "チャンネルID",
  "message_id": "メッセージID",
  "kook_raw": {...},
  "kook_raw_type": "1",
  "message": [
    {"type": "text", "data": {"text": "Hello"}}
  ],
  "alt_message": "Hello"
}

# 画像付きのメッセージ
{
  "type": "message",
  "detail_type": "group",
  "user_id": "ユーザーID",
  "group_id": "チャンネルID",
  "channel_id": "チャンネルID",
  "message_id": "メッセージID",
  "kook_raw": {...},
  "kook_raw_type": "2",
  "message": [
    {"type": "image", "data": {"file": "画像URL", "url": "画像URL"}}
  ],
  "alt_message": "画像の内容"
}

# KMarkdownメッセージ
{
  "type": "message",
  "detail_type": "group",
  "user_id": "ユーザーID",
  "group_id": "チャンネルID",
  "message_id": "メッセージID",
  "kook_raw": {...},
  "kook_raw_type": "9",
  "message": [
    {"type": "text", "data": {"text": "解析後の純粋なテキスト"}}
  ]
}

# カードメッセージ
{
  "type": "message",
  "detail_type": "group",
  "user_id": "ユーザーID",
  "group_id": "チャンネルID",
  "message_id": "メッセージID",
  "kook_raw": {...},
  "kook_raw_type": "10",
  "message": [
    {"type": "json", "data": {"data": "カードのJSON内容"}}
  ]
}

# プライベートチャットメッセージ
{
  "type": "message",
  "detail_type": "private",
  "user_id": "ユーザーID",
  "message_id": "メッセージID",
  "kook_raw": {...},
  "kook_raw_type": "1",
  "message": [
    {"type": "text", "data": {"text": "プライベートチャットの内容"}}
  ]
}

メッセージセグメントタイプ

Kook のメッセージタイプは type フィールドに基づいて対応するメッセージセグメントに自動的に変換されます:

Kook type 変換タイプ 説明
1 text テキストメッセージ
2 image 画像メッセージ
3 video 動画メッセージ
4 file ファイルメッセージ
8 record 音声メッセージ
9 text KMarkdownメッセージ(純粋なテキスト内容を抽出)
10 json カードメッセージ(元のJSON)

メッセージセグメントの構造例:

{
  "type": "image",
  "data": {
    "file": "画像URL",
    "url": "画像URL"
  }
}

Mentionメッセージセグメント

メッセージに @ 情報が含まれる場合、メッセージセグメントの前に mention メッセージセグメントが挿入されます:

{
  "type": "mention",
  "data": {
    "user_id": "メンションされたユーザーID"
  }
}

mention_allメッセージセグメント

メッセージが @全員 の場合、mention_all メッセージセグメントが挿入されます:

{
  "type": "mention_all",
  "data": {}
}

WebSocket接続

接続フロー

  1. Bot Tokenを使用して POST /gateway/index を呼び出すことでWebSocketゲートウェイのアドレスを取得します。
  2. WebSocketゲートウェイに接続します。
  3. HELLO(s=1)シグナルを受信し、接続状態を確認します。
  4. ハートビートループを開始します(PING、s=2、30秒ごとに1回)。
  5. メッセージイベント(s=0)を受信し、sn番号を使用して順序を保証します。
  6. ハートビート応答PONG(s=3)を受信します。

シグナルタイプ

シグナル s値 説明
HELLO 1 サーバーからの歓迎シグナル、接続成功後に受信します。
PING 2 クライアントのハートビート、30秒ごとに現在のsnを含めて送信します。
PONG 3 ハートビート応答
RESUME 4 接続の復元シグナル、snを含んでセッションを復元します。
RECONNECT 5 サーバーからの再接続要求、ゲートウェイを再取得する必要があります。
RESUME_ACK 6 RESUMEの成功応答

断線再接続

メッセージ番号メカニズム

Kook WebSocketはsn(増加する番号)を使用してメッセージの順序を保証します:

使用例

チャンネルメッセージの処理

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

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

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

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

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

プライベートメッセージの処理

@message.on_message()
async def handle_private_msg(event):
    if event.get("platform") != "kook":
        return
    if event.get("detail_type") != "private":
        return

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

    await kook.Send.To("user", user_id).Text(f"あなたが言った: {text}")

通知イベントの処理(絵文字反応など)

from ErisPulse.Core.Event import notice

@notice.on_notice()
async def handle_notice(event):
    if event.get("platform") != "kook":
        return

    sub_type = event.get("sub_type")

    if sub_type == "added_reaction":
        emoji = event.get("emoji", {})
        user_id = event.get("user_id")
        msg_id = event.get("message_id")
        print(f"ユーザー {user_id} がメッセージ {msg_id} に絵文字反応を追加しました")

    elif sub_type == "deleted_reaction":
        emoji = event.get("emoji", {})
        user_id = event.get("user_id")
        msg_id = event.get("message_id")
        print(f"ユーザー {user_id} がメッセージ {msg_id} の絵文字反応を削除しました")

メディアメッセージの送信

# 画像の送信(URL)
await kook.Send.To("group", channel_id).Image("https://example.com/image.png")

# 画像の送信(バイナリ)
with open("image.png", "rb") as f:
    image_bytes = f.read()
await kook.Send.To("group", channel_id).Image(image_bytes)

# ビデオの送信
await kook.Send.To("group", channel_id).Video("https://example.com/video.mp4")

# ファイルの送信
await kook.Send.To("group", channel_id).File("https://example.com/file.pdf", filename="document.pdf")

# 音声の送信
await kook.Send.To("group", channel_id).Voice("https://example.com/voice.mp3")

KMarkdown とカードメッセージの送信

# KMarkdown
await kook.Send.To("group", channel_id).Markdown("**太字** *斜体* [リンク](https://example.com)")

# カードメッセージ
card = {
    "type": "card",
    "theme": "primary",
    "size": "lg",
    "modules": [
        {"type": "header", "text": {"type": "plain-text", "content": "タイトル"}},
        {"type": "section", "text": {"type": "kmarkdown", "content": "内容"}}
    ]
}
await kook.Send.To("group", channel_id).Card(card)

メッセージの編集と撤回

# メッセージの送信
result = await kook.Send.To("group", channel_id).Markdown("**元の内容**")
msg_id = result["data"]["msg_id"]

# メッセージの編集(KMarkdown と CardMessage にのみ対応)
await kook.Send.To("group", channel_id).Edit(msg_id, "**更新後の内容**")

# メッセージの撤回
await kook.Send.To("group", channel_id).Recall(msg_id)

プライベートメッセージの編集と削除通知の処理

@notice.on_notice()
async def handle_private_notice(event):
    if event.get("platform") != "kook":
        return

    sub_type = event.get("sub_type")

    if sub_type == "updated_private_message":
        msg_id = event.get("message_id")
        content = event.get("content")
        print(f"プライベートメッセージが更新されました: {msg_id}, 新しい内容: {content}")

    elif sub_type == "deleted_private_message":
        msg_id = event.get("message_id")
        print(f"プライベートメッセージが削除されました: {msg_id}")