Discordにwebhook経由でPOST(cURL)

## はじめに

[Under MIT license](https://opensource.org/license/mit)[^license_mit]
[^license_mit]: https://opensource.org/license/mit
<details><summary>Copyright (c) 2025 n138-kz</summary>

「MITライセンスの全文」の意訳
> 下記の条件を受け入れていただけるのであれば、誰でも自由に無料で、このソフトウェアをつかっていただくことができます。
このソフトウェアをコピーしてつかったり、配布したり、変更を加えたり、変更を加えたものを配布したり、商用利用したり、有料で販売したり、なんにでも自由につかってください。
> このソフトウェアの著作権表示（「Copyright (c) 年 作者名」）と、このライセンスの全文（英語の文章）を、ソースコードのなかや、ソースコードに同梱したライセンス表示用の別ファイルなどに掲載してください。
> このソフトウェアにはなんの保証もついていません。たとえ、このソフトウェアを利用したことでなにか問題が起こったとしても、作者はなんの責任も負いません。
</details>

書いてある内容はあっているとは限りません。
あくまで参考程度に、ほとんどが自分用のメモです。

検証にあたりdocker([almainux:8](https://hub.docker.com/_/almalinux/tags?name=8))環境で実行していますが、
通常のホスト環境においても動作するはずです。

文中に記載の変数っぽい表記は下記のとおりです。

| 変数名 | 主な用途 |
|:-:|:-|
| `${discord_webhook_url}` | &lt;URL&gt;<br>Webhook Endpoint URL |
| `${discord_avatar_url}` | &lt;URL&gt;<br>Webhook Icon<br> `https://hangstuck.com/wp-content/uploads/2020/08/bash-official-icon-512x512-1.png`を設定している |
| `${discord_username}` | &lt;Text&gt;<br>`${HOSTNAME%%.*}`を設定している<br>`${HOSTNAME}`=ホスト名（FQDN[^FQDN]） |
[^FQDN]: [FQDN: Fully Qualified Domain Name（完全修飾ドメイン名）](https://www.nic.ad.jp/ja/basics/terms/fqdn.html)

<details><summary>変数設定</summary>

```sh
discord_webhook_url=''
discord_avatar_url='https://hangstuck.com/wp-content/uploads/2020/08/bash-official-icon-512x512-1.png'
discord_username=${HOSTNAME%%.*}
```
</details>


## 環境

<details><summary>cURL: 7.61.1</summary>

```sh
# curl --version
curl 7.61.1 (x86_64-redhat-linux-gnu) libcurl/7.61.1 OpenSSL/1.1.1k zlib/1.2.11 nghttp2/1.33.0
Release-Date: 2018-09-05
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: AsynchDNS IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy
```

### curl default

```sh
-X GET
-H 'Content-Type:application/x-www-form-urlencoded'
```

</details>

https://ja.wikipedia.org/wiki/CURL

## Discordにコマンドで写真(イラストなど)と文字を投げつける準備

やることリスト

<details><summary>Discordのアカウント作成</summary>

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/731000b6-7ce0-48f9-9d9b-752841d70644.png)](https://discord.com/register)[^discord_register]
[^discord_register]: https://discord.com/register

</details>

https://discord.com/register

<details><summary>自分でサーバ建てるか、どこかのサーバに招待してもらう</summary>

:::note info
他人管理のサーバに招待してもらう場合は、Webhookの権限を付与してもらってください。
チャンネルごとにwebhook権限付与する/しないが設定できます。（詳細はググってみてください）
私はロールごとに設定してますが。
:::

:::note warn
他人管理のサーバで本記事の内容を実施しKICKやBANされても知りません。自己判断で実施してください。
短時間連続POSTは嫌がる人がほとんどです。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/218a9877-56a5-446f-8b10-cd16dddcd217.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/2d573031-57d4-4160-a391-772d5307d15e.png)

</details>

<details><summary>Webhook URL作成</summary>

1. `チャンネルの編集` > `連携サービス` > `ウェブフック`

2. `ウェブフックURLをコピー`をポチってURLもらう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/1469698d-4732-41f3-8e70-965212c9b992.png)

</details>

## Discordにコマンドで投げつける

### これが基本形
[^discord_refs_opcodes-and-status-codes]: https://discord.com/developers/docs/topics/opcodes-and-status-codes#json-json-error-codes

```http
POST https://discordapp.com/api/webhooks/channel_id/webhook_id
```

```sh
curl -X POST ${discord_webhook_url}
```

<details><summary>実際には content がないと弾かれる</summary>

[JSON Error Codes](https://discord.com/developers/docs/topics/opcodes-and-status-codes#json-json-error-codes
)[^discord_refs_opcodes-and-status-codes]

```json:curl -X POST ${discord_webhook_url}
{
  "message": "Cannot send an empty message",
  "code": 50006
}
```
</details>

### content をつけてもう一度

```sh
curl -X POST -d 'content=Hello world.' ${discord_webhook_url}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/5bb171e9-7ca5-47f4-8a51-a09e24da23fd.png)

<details><summary>コマンドが長くなったら \で行末の改行をエスケープ</summary>

**行末の`\`あとには半角スペース含む文字を一切書かないこと**
`\`でエスケープしてるのは EOL文字(`CR`, `LF`, `CRLF`)

```sh
curl \
  -X POST \
  -d 'content=Hello world.' \
  ${discord_webhook_url}
```

`'`～`'`や`"`～`"`みたいな<span style="text-decoration:underline;"><u>引用符の中***以外***</u></span>であれば自由に改行できる
どうしても引用符の中で改行させたい場合は、一旦引用符を閉じる（引用符～引用符の間はスペースは入れない）

```sh
curl \
  -X POST \
  -d 'content=Hello world.'\
'Webhook test' \
  ${discord_webhook_url}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/dced92f5-50f5-47b9-b515-cd4425af0ce5.png)

</details>

<details><summary>HTTP/GETすることも可能</summary>

```json:curl -X GET ${discord_webhook_url}
{
  "application_id": null,
  "avatar": null,
  "channel_id": "(hide)",
  "guild_id": "(hide)",
  "id": "(hide)",
  "name": "Spidey Bot",
  "type": 1,
  "token": "(hide)",
  "url": "(hide)"
}
```

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/aaeefe32-5753-4250-b036-32b734b4d147.png)](https://discord.com/developers/docs/resources/webhook#webhook-object-webhook-types) [^discord_refs_object-webhook-types]
[^discord_refs_object-webhook-types]: https://discord.com/developers/docs/resources/webhook#webhook-object-webhook-types

:::note info
`-X GET`は[デフォルト](#curl-default)なのでつけなくてもOK
:::
</details>

<details><summary>HTTP/DELETEすることも可能</summary>

:::note warn
Webhook URL自体が失効します
:::

```sh:
curl -X DELETE ${discord_webhook_url}
```
```sh:
curl -X GET ${discord_webhook_url}
```
```json:curl -X GET ${discord_webhook_url}
{
  "message": "Unknown Webhook",
  "code": 10015
}
```
</details>


### POSTしたときに出力を受け取りたいとき

POSTしたチャンネルの情報、投稿メッセージIDを見る方法がある。
何度もAPIを叩く(curlコマンドを実行する)必要はなく、URLの末尾に`?wait=true`[^discord_refs/webhook-execute-webhook]もしくは`&wait=true`[^discord_refs/webhook-execute-webhook]を追記するだけ。
デフォルト(`?wait=true`[^discord_refs/webhook-execute-webhook]が無い状態)では、Response-codeが[204 NoContent](https://developer.mozilla.org/ja/docs/Web/HTTP/Status/204)[^HTTP/Status/204]となり何も出力されないが、`?wait=true`[^discord_refs/webhook-execute-webhook]を追記することで[200 OK](https://developer.mozilla.org/ja/docs/Web/HTTP/Status/200)[^HTTP/Status/200]になり、色々見れる。
[^HTTP/Status/429]: https://developer.mozilla.org/ja/docs/Web/HTTP/Status/429
[^HTTP/Status/200]: https://developer.mozilla.org/ja/docs/Web/HTTP/Status/200
[^HTTP/Status/204]: https://developer.mozilla.org/ja/docs/Web/HTTP/Status/204

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/0ef378b6-3e4c-4afa-b041-858fd555a061.png)](https://discord.com/developers/docs/resources/webhook#execute-webhook#:~:text=waits%20for%20server%20confirmation%20of%20message%20send%20before%20response)
[^discord_refs/webhook-execute-webhook]: https://discord.com/developers/docs/resources/webhook#execute-webhook

<details><summary>サンプル</summary>

```sh
curl \
  -X POST \
  -d 'content=Hello world.'\
  ${discord_webhook_url}?wait=true
```
```json
{
  "type": 0,
  "content": "Hello world.",
  "mentions": [],
  "mention_roles": [],
  "attachments": [],
  "embeds": [],
  "timestamp": "2025-02-15T11:56:03.243000+00:00",
  "edited_timestamp": null,
  "flags": 0,
  "components": [],
  "id": "(hide)",
  "channel_id": "(hide)",
  "author": {
    "id": "(hide)",
    "username": "Spidey Bot",
    "avatar": null,
    "discriminator": "0000",
    "public_flags": 0,
    "flags": 0,
    "bot": true,
    "global_name": null,
    "clan": null,
    "primary_guild": null
  },
  "pinned": false,
  "mention_everyone": false,
  "tts": false,
  "webhook_id": "(hide)"
}
```
</details>


### Content Type
把握してる限り、応答(response)はすべて`application/json`
要求(request)は`application/json`, `application/x-www-form-urlencoded`, `multipart/form-data`のどれか

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/bf9ed3a3-1fc2-4902-af77-633cfbc026b4.png)](https://discord.com/developers/docs/reference#content-type)[^discord_refs_content-type]
[^discord_refs_content-type]: https://discord.com/developers/docs/reference#content-type

curlコマンド実行時、リクエスト本体(Request-body(i.e. `content=`, etc))を
`-d`で指定する場合は`application/x-www-form-urlencoded`が、
`-F`で指定する場合は`multipart/form-data`が自動で設定されるらしい。[^QIITA_ContentType]
[^QIITA_ContentType]: https://qiita.com/att55/items/04e8080d1c441837ad42


### Rate Limits

[^discord_refs_rate-limits]: https://discord.com/developers/docs/reference#content-type
[^rfc6585-4]: https://datatracker.ietf.org/doc/html/rfc6585#section-4

連投する場合は [Rate Limits](https://discord.com/developers/docs/topics/rate-limits#rate-limits)[^discord_refs_rate-limits] に注意する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/51b44c4b-8099-481c-b4bd-0e289abd311c.png)
[RFC 6585](https://datatracker.ietf.org/doc/html/rfc6585#section-4)[^rfc6585-4]準拠らしいがよくわからん。([429 Too Many Requests](https://developer.mozilla.org/ja/docs/Web/HTTP/Status/429)[^HTTP/Status/429]返すってことくらいしかわからん)
連投しなければ問題なさそう。

<details><summary>だがとりあえず 5/pps っぽい</summary>


```shell:application/x-www-form-urlencoded
# date +%s;curl -I -X POST ${discord_webhook_url}
1739613504
HTTP/2 400
date: Sat, 15 Feb 2025 09:58:25 GMT
content-type: application/json
content-length: 58
x-ratelimit-bucket: 3d2712a9e4fe17cc9d3fed4a8e672e5f
x-ratelimit-limit: 5
x-ratelimit-remaining: 4
x-ratelimit-reset: 1739613506
x-ratelimit-reset-after: 1
```
`1739613504`= コマンド実行した時間
`Sat, 15 Feb 2025 09:58:25 GMT`(`1739613505`)= 要求受け取った時間(`date`)
`1739613506`= リセットされる時間(`x-ratelimit-reset`)

</details>

### ウェブフックのアイコンカスタマイズ

`content=`と一緒に`avatar_url=`をつけてあげる

```sh:application/x-www-form-urlencoded
curl \
  -X POST \
  -d 'content=Hello world.' \
  -d 'avatar_url='${discord_avatar_url} \
  ${discord_webhook_url}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/4f41d565-17de-4f16-a988-5830531e1bc7.png)

<details><summary>シェル(shell)が引用符内変数展開に対応しているなら</summary>

`""`で囲ってあげればスマート

```sh
curl \
  -X POST \
  -d 'content=Hello world.' \
  -d "avatar_url=${discord_avatar_url}" \
  ${discord_webhook_url}
```
</details>


### アイコンと一緒に名前も

`username=`もつけてあげる

```sh:application/x-www-form-urlencoded
curl \
  -X POST \
  -d 'content=Hello world.' \
  -d 'avatar_url='${discord_avatar_url} \
  -d 'username='${discord_username} \
  ${discord_webhook_url}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/28c627b7-ca48-46d4-a740-49dbddd9e33a.png)


### ファイルといっしょに投げつける

ファイルを投げるときは `Content-Type` を `multipart/form-data` に設定する。
```sh
-H 'Content-Type:multipart/form-data'
```

サーバーのブースト具合にも寄るが、投げれるファイルはデフォルト（ギルドレベル：0）だと `10MiB`（課金すれば最大100MBまでいける）
[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/24fae154-a4ae-4dcd-82f0-0ebb5299e8d1.png)](https://discord.com/developers/docs/reference#uploading-files)
[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/7abfd8cc-971e-4ed0-8f43-9682d765e4d5.png)](https://support.discord.com/hc/ja/articles/360028038352-%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%83%96%E3%83%BC%E3%82%B9%E3%83%88-FAQ#h_01HGX7DJ33W4WY3FYVPRZ2CK02)

投げるだけならそんなに考慮はいらない。（日本語のようなマルチバイト文字でも行ける）
`file=`のあとに続けて`@ファイル名` とすることでファイルを送信できる。
[アップロードアイコン.{png|jpg|svg}](https://icooon-mono.com/15625-%e3%82%a2%e3%83%83%e3%83%97%e3%83%ad%e3%83%bc%e3%83%89%e3%82%a2%e3%82%a4%e3%82%b3%e3%83%b3/)

```sh
curl -X POST \
    -H 'Content-Type:multipart/form-data' \
    -F 'avatar_url='${discord_avatar_url} \
    -F 'username='${discord_username} \
    -F 'file=@アップロードアイコン.png' \
    -F 'content=Attached files.' \
    ${discord_webhook_url} | jq
```

<details><summary>image/pngだと画像として表示される</summary>

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/9e89b3f9-68a4-4114-a200-af0ab3d1fdf2.png)](https://icooon-mono.com/15625-%e3%82%a2%e3%83%83%e3%83%97%e3%83%ad%e3%83%bc%e3%83%89%e3%82%a2%e3%82%a4%e3%82%b3%e3%83%b3/)

</details>
<details><summary>image/svgだとテキスト形式で表示される</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/570c381b-3da9-4e0d-b396-0ca9eef9c39a.png)
</details>


### 複数のファイルを投げる

[Rate Limits](https://discord.com/developers/docs/topics/rate-limits#rate-limits) の件もあり、複数のファイルを短い間隔でポンポン投げるのは、あまり望ましく無い。

`file=` ではなく `files=` にすることで複数のファイルを同時に投げれる様になる。[^discord_refs_uploadingfiles]
[^discord_refs_uploadingfiles]: https://discord.com/developers/docs/reference#uploading-files

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/8c6e101d-c494-4e3f-a9fb-723807c628e3.png)](https://discord.com/developers/docs/reference#uploading-files) [^discord_refs_uploadingfiles]

```sh
curl -X POST \
    -H 'Content-Type:multipart/form-data' \
    -F 'avatar_url='${discord_avatar_url} \
    -F 'username='${discord_username} \
    -F 'files[0]=@アップロードアイコン.png' \
    -F 'files[1]=@アップロードアイコン.svg' \
    -F 'content=Attached files.' \
    ${discord_webhook_url} | jq
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/c602d1a8-4532-4222-baaf-f1ee92c5b70c.png)

html formの場合は`<input type="file" name="files[]" />`にして、受取り側(i.e. PHP)では`$_FILES['files'][]`になる感覚かな...
```html:sample.html
<input type="file" name="files[]" />
```
```php:sample.php
<?php
foreach($_FILES['files'][] as $key => $value){
    if(! is_uploaded_file($value['tmp_name'])){continue;}
    if(! move_uploaded_file($value['tmp_name'],$value['name'])){continue;}
    echo 'Upload succeed.'.PHP_EOL;
}
```

最大42個[^discord_refs_uploadingfiles]のファイルまで受信してくれるっぽいので、そんなに不便はなさそう。


### まとめて何個か投げる

2個とかならまだいい。
4個とか`files[]=`書くの大変だし、辛い( ๑╹⌓╹ )
なら、forでまわすべ

webpファイルをまとめて投げる場合はこれでいける（いけた）
他のやつ送る場合は1行目だけいじればいいはず。
```sh:Send the *.webp
curl_files=''; i=0; for f in *.webp; do curl_files=${curl_files}" -F file[$i]=@${f}";i=$((i+1));done; \
curl -X POST \
    -H 'Content-Type:multipart/form-data' \
    -F 'avatar_url='${discord_avatar_url} \
    -F 'username='${discord_username} \
    ${curl_files} \
    -F 'content=Attached files.' \
    ${discord_webhook_url} | jq
```
ファイルの一覧はcurlのオプション`-F`といっしょに変数`$curl_files`にぶち込んで、curl実行するときにべってやってる。

ワンライナーでできたらって思ったけど、これ以上いい方法あるのカナ...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/f109642a-0354-4967-9345-55e2bc1ac1fd.png)

12個くらいのファイルをまとめて投げようとしたら弾かれたんだけど、42個じゃないのか・・・
```json
{
  "message": "Maximum number of allowed attachments in a message reached (10).",
  "code": 30015
}
```


### 見た目を上げるなら`embeds`にもゴニョゴニョ

配列を標準で実装していて、かつコードもそんなに負担にならないphpとかpythonとかならいいんだろうけども、
shell scriptって 連想配列(associative array)や 配列(indexed array)みたいなやつに対してそんなに充実した機能があるわけじゃない（実際には?）ので、結構大変。

`Array.push()` とかあれば JSONの `[]` を自由に増やせるんだけど。

一応やったのが、↓なんですが
`payload_json` つくるのがメンド

<details><summary>details</summary>

```sh
request_json=''
request_json=${request_json}''
request_json=${request_json}'{'
request_json=${request_json}'"avatar_url":"'${discord_avatar_url}'",'
request_json=${request_json}'"username":"'${discord_username}'",'
request_json=${request_json}'"content":"Attached files.",'
request_json=${request_json}'"embeds":['
for f in *.webp; do
request_json=${request_json}'{'
request_json=${request_json}'"title":"Attached files.",'
request_json=${request_json}'"color":'$((16#ffa500))','
request_json=${request_json}'"image":{'
request_json=${request_json}'"url":"attachment://'${f}'"'
request_json=${request_json}'}'
request_json=${request_json}'},'
done
request_json=${request_json}']'
request_json=${request_json}'}'
request_json=$(echo ${request_json} | sed -e 's/\}},\]}$/}}]}/g')
echo ${request_json} | jq > payload_json.json

curl_files=''; i=0; for f in *.webp; do curl_files=${curl_files}" -F file[$i]=@${f}";i=$((i+1));done; \
curl_exec=$(curl -X POST \
    -H 'Content-Type:multipart/form-data' \
    -H 'Content-Disposition:form-data;name="payload_json"' \
    -F "payload_json=${request_json}" \
    ${curl_files} \
    ${discord_webhook_url}); echo ${curl_exec} | jq
    
curl_exec_id=$(echo ${curl_exec} | jq -r .id); \
echo ${curl_exec} | jq | tee ${curl_exec_id}.json;
```

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/d5ffcde4-0c2a-45db-85ee-54fc9a9479fd.png)](https://bluearchive.jp/)
</details>

[^color_16_to_10]

`enbeds`の中の`fields`には`inline=true|false`の項目があって図のようにすることもできるみたい。（画像を左右に埋め込めないのかな）

<details><summary>details</summary>

```sh
request_json=''
request_json=${request_json}''
request_json=${request_json}'{'
request_json=${request_json}'"avatar_url":"'${discord_avatar_url}'",'
request_json=${request_json}'"username":"'${discord_username}'",'
request_json=${request_json}'"content":"Attached files.",'
request_json=${request_json}'"embeds":['
for f in *.webp; do
request_json=${request_json}'{'
request_json=${request_json}'"fields":[{"inline":true,"name":"fname","value":"'${f}'"},{"inline":true,"name":"username","value":"'${discord_username}'"}],'
request_json=${request_json}'"title":"'${f}'",'
request_json=${request_json}'"color":'$((16#ffa500))','
request_json=${request_json}'"image":{'
request_json=${request_json}'"url":"attachment://'${f}'"'
request_json=${request_json}'}'
request_json=${request_json}'},'
done
request_json=${request_json}']'
request_json=${request_json}'}'
request_json=$(echo ${request_json} | sed -e 's/\}},\]}$/}}]}/g')
echo ${request_json} | jq > payload_json.json

curl_files=''; i=0; for f in *.webp; do curl_files=${curl_files}" -F files[$i]=@${f}";i=$((i+1));done; \
curl_exec=$(curl -X POST \
    -H 'Content-Type:multipart/form-data' \
    -H 'Content-Disposition:form-data;name="payload_json"' \
    -F "payload_json=${request_json}" \
    ${curl_files} \
    ${discord_webhook_url}); echo ${curl_exec} | jq
    
curl_exec_id=$(echo ${curl_exec} | jq -r .id); \
echo ${curl_exec} | jq | tee ${curl_exec_id}.json;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/6b10c13d-c0af-4ceb-b060-e3106daf8ad6.png)

</details>

[^color_16_to_10]: `color=`は10進数の値を入力する。CSSで使用されるような形式からshellで変換するには `$((16#ffa500))` `#ffa500`

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104374/8c6e101d-c494-4e3f-a9fb-723807c628e3.png)](https://discord.com/developers/docs/reference#uploading-files) [^discord_refs_uploadingfiles]

`payload_json`って名前のヤツに入れれば良さそうってことで入れてみた。

[公式マニュアル](https://discord.com/developers/docs/reference#editing-message-attachments-example-request-bodies-multipartformdata)には最低限 content, embeds, files[n] 入れてね的なことが書いてあったので、とりあえずそれだけ。
> This example demonstrates usage of the endpoint with payload_json and all content fields (content, embeds, files[n]) set.

サンプルだと `message_reference`, `attachments` があったけどなくても動くんだよなぁ





<details><summary>公式サンプル</summary>

```
--boundary
Content-Disposition: form-data; name="payload_json"
Content-Type: application/json

{
  "content": "Hello, World!",
  "embeds": [{
    "title": "Hello, Embed!",
    "description": "This is an embedded message.",
    "thumbnail": {
      "url": "attachment://myfilename.png"
    },
    "image": {
      "url": "attachment://mygif.gif"
    }
  }],
  "message_reference": {
    "message_id": "233648473390448641"
  },
  "attachments": [{
      "id": 0,
      "description": "Image of a cute little cat",
      "filename": "myfilename.png"
  }, {
      "id": 1,
      "description": "Rickroll gif",
      "filename": "mygif.gif"
  }]
}
--boundary
Content-Disposition: form-data; name="files[0]"; filename="myfilename.png"
Content-Type: image/png

[image bytes]
--boundary
Content-Disposition: form-data; name="files[1]"; filename="mygif.gif"
Content-Type: image/gif

[image bytes]
--boundary--
```

</details>



## Discordにshell scriptで投げるなら複雑にしないほうが良い

やってみてわかった。
`content=`と`username=`, `avatar_url=`くらいならまだいい。

`embeds=`だけはまじでおすすめしない。
中身が複雑すぎてタイパ悪すぎる...( ๑╹⌓╹ )

`embeds`は更に`fields`って項目があったりして自由にいじれるけど、それやるくらいだったらPythonとかで組んだほうが楽っすね。
CとかC++はできないけど、Pythonなら行け無いことも無いので、必要なときが来たら作ろう（きっとこない）

そういえば、Github Actionの無料枠が上限迎えてしまった。。。

あと13日つら・・・