概要
Discordの予約投稿をしようと従来のBOTを使おうとすると、画像類の添付ができなかったり、表記が難しいといったところがありました。
そこでGUIだけで直感的に操作できるようなシステムが構築できるようにしてみました。
Discordの指定チャンネルに、テキスト・画像・動画・ZIPファイルを指定日時に自動送信できるWebシステムです。PHPとMySQLが使えるレンタルサーバーにインストールして使用します。
一度設置が終われば、あとはブラウザ(Windows、スマホなど)からURLを指定してアクセスして使用してください。
主な機能
・テキスト・画像(JPG/PNG/WebP)・動画(MP4/MOV)・ZIPファイルの予約投稿(本文または添付ファイルのいずれかがあれば登録可能)
・複数のDiscord Webhookを管理・切り替え
・Webhookごとに予約投稿の初期表示時刻を設定可能
・よく使う時刻を「時刻プリセット」として登録し、ワンタップで反映
・送信先チャンネル選択時、空いている日時を自動で提案(重複があれば自動で翌日以降にずらす)
・25MB超のファイルは自動分割送信
・添付ファイルのサムネイルをクリックすると拡大プレビュー表示(画像・動画とも対応)
・送信済み投稿の本文をDiscord上でリアルタイム編集
・ロールメンション対応(<@&ロールID> 形式)
・複数ユーザー管理(管理者・一般ユーザー)
・送信完了・失敗時のメール通知(編集URL・ダッシュボードURL付き)
・操作ログ・ログイン試行ログ
動作環境
・PHP 8.0以上(8.3推奨)
・MySQL 5.7以上(utf8mb4対応)
・Cronが使えるレンタルサーバー(毎分実行推奨)
・エックスサーバー スタンダードプラン以上での動作確認済み
配布について
このシステムはPHP・MySQL・CRONが使えるレンタルサーバーにインストールして使用します。
構築には多少の技術的知識が必要ですが、詳しい手順(フォルダ作成・データベース設定・ファイルアップロード・Cron設定・トラブルシューティングなど)はソース一式に同梱の構築手順書(banana_post_manual.txt)にまとめてあります。手順書はエックスサーバ(スタンダードプラン以上)を前提としています。
ご興味のある方はダウンロードしてご確認ください。
所要時間の目安は1〜2時間程度です。
システムの仕様
対応ファイル形式
このシステムで添付できるファイル形式は以下の通りです。
・画像:JPG / JPEG / PNG / WebP
・動画:MP4 / MOV
・その他:ZIP
動画ファイル(MP4・MOV)はDiscordに埋め込み形式で送信されます。受信者はDiscord上でそのまま再生できます。動画も画像・ZIPと同様に25MBの制限が適用されます。
Discord上でその場再生(埋め込み再生)を確実に行うには、動画のエンコード形式を H.264 にすることを推奨します。H.265(HEVC)でエンコードされた動画はDiscordで再生できない場合があります。スマートフォンで撮影した動画は H.265 でエンコードされていることが多いため、アップロード前にエンコード形式をご確認ください。
添付ファイルのプレビュー表示
新規投稿・編集画面ともに、添付ファイル一覧のサムネイルをクリックすると画面中央に拡大表示されます。画像はそのまま拡大表示され、動画は再生コントロール付きで自動再生されます。表示を閉じるには、右上の「×」ボタンを押すか、画面の暗い部分をクリックするか、Escキーを押してください。
投稿内容のルール
投稿テキスト(本文)と添付ファイルは、どちらか一方が入力されていれば投稿を登録できます。両方とも空の場合はエラーになります。画像や動画のみを送りたい場合、本文を空欄のまま登録して問題ありません。
ファイル添付の制限
Discord Webhookでは、1ファイルあたりの上限・1メッセージあたりの合計上限ともに最大25MBです。これはDiscordのプラン(無料・Nitro等)に関わらず共通の制限です。そのため、このシステムのWebhook登録画面でも上限は最大25MBまでしか設定できません。
この制限はDiscordがWebhook送信に課しているものであり、受信者側のプランには関係ありません。例えばNitroユーザーは通常50MBのファイルを扱えますが、Webhook経由での送信は25MB以下に制限されます。
1ファイルあたりのサイズ上限の目安:
・Discord無料:10MB
・Nitro Basic・Nitro:Webhook経由では最大25MB
Webhook登録時はご自身の利用状況に合わせて上限を設定してください。上限を超えるファイルは投稿フォームで警告が表示され、登録できません。
なお合計が25MBを超える場合は自動的に複数メッセージに分割して送信されます。分割される場合は投稿フォームに「〇件のメッセージに分割して送信されます」という案内が表示されます。例えばNitroユーザーが1ファイル20MBのファイルを2個添付した場合、合計40MBとなるため自動的に2件のメッセージに分割されます。
1ファイル自体が25MBを超える場合は分割できないため送信に失敗します。Webhook登録時のファイルサイズ上限は必ず25MB以下に設定してください。
分割送信された場合、Discordでは複数のメッセージとして連続投稿される形になります。画像の表示位置がメッセージ内で自動的に上部に移動するなど、意図した順番と異なる表示になる場合があります。
ロールメンションについて
Discord上でテキストを直接入力する場合、@ロール名 と入力するとメンションとして機能します。しかしWebhook API経由で送信する場合、@ロール名 はただの文字列として扱われ、メンションとして機能しません。
Webhook経由でメンションを機能させるには以下の形式が必要です。
<@&ロールID>
例:<@&123456789012345678> と送信すると、Discord上では @チョコバナナ会員 としてメンションが機能します。
ロールIDはDiscordのサーバー設定→「ロール」→該当ロールを右クリック→「IDをコピー」で取得できます。
このシステムでは投稿テキストをそのままDiscordに送信するため、投稿フォームに <@&ロールID> 形式で入力することでメンションが機能します。定型文を生成するツールをお持ちの場合は、そちらで @ロール名 を <@&ロールID> に変換してからペーストすることをお勧めします。
送信済み投稿の本文編集
送信済みの投稿はダッシュボードの「送信済み」タブから本文のみ編集できます。「本文編集」ボタンをクリックすると編集画面が開き、Discordの投稿内容をリアルタイムで更新できます。
ただし以下の制約があります。
・テキスト本文のみ変更可能です。添付ファイルの変更はできません。
・分割送信された場合は最初のメッセージのみ編集できます。
・このシステムで送信した投稿のみ対象です。以前に送信済みでメッセージIDが保存されていない投稿は編集できません。
・Webhookが削除されている場合は編集できません。
万が一メッセージIDが保存されていない投稿がある場合は、Discordのメッセージを右クリック→「IDをコピー」で取得したIDを「ID登録」ボタンから手動登録することで本文編集が可能になります。
Webhookの並び替えと初期選択
Webhook管理画面では登録済みのWebhookをドラッグ&ドロップで並び替えできます。一番上に配置したWebhookが新規投稿フォームの初期選択になります。よく使うチャンネルを一番上に置いておくと便利です。
並び替え後は「この順番で保存する」ボタンを押すまで保存されません。ボタンを押し忘れないよう注意してください。
登録済みのWebhookは「編集」ボタンから表示名・Webhook URL・ファイルサイズ上限を変更できます。URLを間違えて登録した場合などに利用してください。
Webhookごとの初期表示時刻
Webhookの新規登録・編集画面で「予約投稿の初期表示時刻」を設定できます。ここで設定した時刻は、新規投稿フォームでそのWebhookを選んだときの送信時刻の初期値として使われます。「このチャンネルはいつも夜9時に投稿する」といった運用の場合に設定しておくと便利です。
未設定のままにした場合は、現在時刻から30分単位で切り上げた時刻が自動的に使われます(例:14:12なら14:30、14:45なら15:00)。
時刻プリセット
新規投稿フォームの送信日時欄には、よく使う時刻をボタンとして登録しておける「時刻プリセット」機能があります。プリセットボタンをクリックすると、その時刻(時・分)だけが即座に反映されます(日付は変わりません)。
プリセットの登録・削除は「✎ プリセット編集」ボタンから行います。
・「+ 追加」:新しい時刻をプリセットとして登録します(最大10個まで)
・プリセットボタンをクリック:その場で時刻を編集できます(インライン編集)
・「×」:そのプリセットを削除します
・「✓ 完了」:編集モードを終了します
プリセットはユーザーごとに管理されており、他のユーザーが登録したプリセットが表示されることはありません。
送信先チャンネル選択時の日時自動調整
新規投稿フォームで送信先チャンネル(Webhook)を選択すると、送信日時が自動的に以下のルールで提案されます。
1. 選択したWebhookの「初期表示時刻」(未設定の場合は現在時刻から30分単位で切り上げた時刻)を基準にする
2. その日時が既に過去、または同じWebhook宛に同じ日時の予約が既にある場合は、1日ずつ先へずらして空いている日時を探す
3. 見つかった日時が自動的に入力される
そのため「チャンネルを選び間違えていた」という場合でも、選び直すだけで送信日時も適切な空き日時に調整されます。この自動調整はチャンネルを選択・変更したタイミングでのみ動作し、プリセットボタンをクリックしたときには動作しません(プリセットは時刻のみを反映します)。
予約投稿の編集画面でチャンネルを変更した場合も同様に日時が自動調整されますが、編集中の投稿自身は重複判定の対象から除外されます。
他環境での使用
今回はエックスサーバーでの利用を想定して作りましたが、PHPとMySQLが使え、定期実行の仕組み(Cronまたはその代替)が用意できるレンタルサーバーであれば、他の環境でも動作すると思います。ただし細かい設定(フォルダのパスやパーミッション、コマンドのパスなど)は環境によって異なりますので、その点は各自で読み替えていただければと思います。
なお、Cronが使えないサーバーの場合でも、外部のスケジューラーサービスなどを使って定期的にスクリプトを呼び出す形にすれば代用できる可能性があります。この点は今回検証していないため、確実に動くとは言い切れませんが、参考情報として記載しておきます。
AWS
AWSで動かす場合は、レンタルサーバーとは構成の考え方が変わります。
PHPの実行環境としてLightsailやEC2にPHPとMySQLを構築する方法のほか、RDSをデータベースとして使う形も考えられます。
定期実行の部分は、サーバー内のCronの代わりに、EventBridgeのスケジュール機能からLambdaやスクリプトを呼び出す構成が一般的です。
ファイルの保存先も、サーバー内のディレクトリではなくS3に置き換える方が構成としては自然ですが、その場合はファイルの保存・読み込み部分のコードを書き換える必要があります。
AWSでの構築は、レンタルサーバーに比べて自由度が高い分、初期設定の手間や知識が必要になる点にご注意ください。
Railway
RailwayのようなPaaS系のサービスを使う場合は、また違ったアプローチになります。
PHPを動かすコンテナと、MySQLのデータベースサービスをそれぞれ用意し、両者を接続する形が基本になります。
定期実行の部分は、サービス側で提供されているスケジュール実行の仕組みを使うか、それが難しい場合は常駐プロセスとして一定間隔で処理を繰り返すスクリプトを動かす方法も考えられます。
ファイルの保存先は、コンテナ内のディスクは再デプロイのたびに消える可能性があるため、外部のストレージサービスと組み合わせる方が安全です。PaaS系のサービスは環境構築の手間が少ない一方、無料枠の範囲や制限がサービスごとに異なるため、事前に利用規約や料金体系をご確認ください。
おわりに
このシステムは個人で使う分には十分な作りにしていますが、無料・無保証での公開となります。
導入や利用によって生じたトラブル・データの損失・その他不利益について、責任は負いかねますので、あらかじめご了承ください。
動作環境や仕様は今後変更される可能性もあります。
不具合の報告や改善のご提案などがあれば、コメントや各種連絡先等でお知らせいただけると助かります。

コメント