DiscordのWebhookでURLボタンを使う方法

この記事は約8分で読めます。

こういうのをウェブフックから(Discordアプリ/Botを常時稼働させずに)出したい。


このボタンを押すとXmisskeyへの投稿画面が開く。
真上のを押したときと同様の効果。

Pythonの初歩がわかってる人向け記事。IFTTTやZapierでもdata内の構造を真似すれば同様のことが可能だが、最初のウェブフック取得段階で自作アプリを稼働させる必要があり、若干ハードルが高い。

サンプルコード

import json
from urllib.request import Request, urlopen


webhook_url = 'https://discord.com/api/webhooks/xxxxx'

data = {
	"content": "これは送信テストです\nhttps://la-is.me/p/38",
	"components": [
		{
			"type": 1,
			"components": [
				{
					"type": 2,
					"style": 5,
					"label": "𝕏",
					"url": "https://twitter.com/intent/post?text=Discord%E3%81%AE%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%ABBot%E3%81%A8%E3%81%AF&url=https%3A%2F%2Fla-is.me%2Fp%2F38"
				},  # 以下同様に、横に5つまでコピペで増やせる
				{
					"type": 2,
					"style": 5,
					"label": "misskey",
					"url": "https://misskeyshare.link/share.html?text=Discord%E3%81%AE%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%ABBot%E3%81%A8%E3%81%AF+&url=https://la-is.me/p/38",
                    "emoji": {
                        "id": "1238053804503597066",
                        "name": "",
                        "animated": False
                    }  # サバ絵文字の追加も可能
                }
			]
		},
		{  # こうすると縦に5つまで増やせる
			"type": 1,
			"components": [
				{
					"type": 2,
					"style": 5,
					"label": "2段目",
					"url": "https://google.com",
                    "emoji": {
                            "name": "👀",
                    }  # Unicode絵文字だったら "name": "😀"だけの形式
                }
			]
		}
	]
}

def post_discord(webhook_url, data):
    headers = {
        "Content-Type": "application/json",
        "User-Agent": "_Python-urllib/3.12",
    }

    request = Request(
        webhook_url,
        data=json.dumps(data).encode(),
        headers=headers,
    )

    with urlopen(request) as response:
        response_body = response.read().decode("utf-8")
        print(response_body)

if __name__ == "__main__":
    post_discord(webhook_url, data)

最終的にPOSTがしたいだけなので、やり方が分かるならhttpx等でも良い。

解説

主なハマりポイント

・UAが空欄だと400エラー
・UAが”Python-urllib”(urllibデフォルト値)だと403エラー
・URLが人間由来だとボタンが無視される

ウェブフックURLを取得

人間のアカウントからチャンネル設定画面で取得したURLだとボタンが使用できないので、アプリアカウントを作ってウェブフックを作成する。「Discord Bot 作り方」とかでググって序盤のトークン取得のところまでやればOK。

今回はdiscord.pyライブラリを使う。

py -3 -m pip install -U discord.py

なりの良い感じのコマンドでインストールして、トークンと、作りたいチャンネルのIDを入力して、目的のチャンネルがあるサーバーにアプリを導入し、アプリに”ウェブフックの管理”権限を与え、下記コードを実行する。

import discord
from discord.ext import commands

intents = discord.Intents.default()
bot = commands.AutoShardedBot(command_prefix="", intents=intents, help_command=None)
TOKEN = ""
TARGET_CHANNEL_ID = 1234

@bot.event
async def on_ready():
    ch = bot.get_channel(TARGET_CHANNEL_ID)
    wh = await ch.create_webhook(name="test")
    print(wh.url)

bot.run(TOKEN)

https://discord.com/api/webhooks/xxxxx形式のURLが取得できたはずなので、最初のサンプルコード冒頭に入力する。

content

"content": "これは送信テストです\nhttps://la-is.me/p/38",
アプリ発言の本文。\nで改行。絵文字やメンションも所定の書式に則っていれば使える。ここでは扱わないがEmbedを追加することも可能。

ボタン作成

"components": []
ボタンとかモーダルとかのオプション要素を入れる場所。
ウェブフックではURLリンクボタンのみ使用できる。

行作成

{
    "type": 1,
    "components": [{<ボタン>}, {<ボタン>}]
}

このまとまりを増やすと行(縦列)が増える。最大5行。
type1はボタンの行を意味する。

列/ボタン作成

{
    "type": 2,
    "style": 5,
    "label": "𝕏",
    "url": "https://twitter.com/intent/post?text=xxxx"
}

行のcomponentsの中に入れていくと横に増える。1行あたり最大5列。

type2はボタンを意味し、style5はURLリンクを意味する。これ以外は使えない。
labelはボタンの表示名、urlはクリック/タップされた時に開くURL。URL形式じゃないと403エラーになる。

絵文字つきボタン

ボタンに絵文字を入れることも出来る。ラベルの左に任意の絵文字を表示可能。
labelやurlに並んでemoji項を付け足すだけ。

"emoji": {
    "name": "👀"
}

Unicode絵文字(直接Discordに発言するとTwimojiに変換されるやつ)を使う場合は単純に元の絵文字をnameにいれるだけ。

"emoji": {
    "id": "1238053804503597066",
    "name": "",
    "animated": False
}

サバ絵文字を使うことも出来る。
アニメ絵文字ならanimatedをTrue、静止絵文字ならFalse

idは、そのサバ絵文字をDiscordクライアントで発言しようとして、直前に\を付け足して発言すると取得できる。

上が入力画面、下が発言した後の様子。
nameは本来絵文字名を入れるが、何でも通るので空白で良い。

Discordに登録されている絵文字なら何でも良く、ウェブフックを送信するサバ以外の絵文字でも、ウェブフックを作成したBotが参加していないサバのものでも使える。絵文字が消去されると(たしか)事後的に表示されなくなり、新規送信時に400エラーが出るようになるので、自分しか参加してないサバで登録した絵文字を使うことを推奨。

POST

ここまで作ったjsonを添えて指定のURLにPOSTする。
冒頭にも書いたように、UAが空欄か、urllibのデフォルト値だと通らない。

コメント

タイトルとURLをコピーしました