PythonでDiscordボットの作成
テンプレートリポジトリ
cogs ディレクトリ下のファイルを動的に読み込む構成になっており、コマンドの追加が容易。
ボットに読み込ませたいファイルに以下のコードを書いておけば良さそう。
Template
のところは読み込ませるファイル内に実装したクラスに適宜変更する。
async def setup(bot):
await bot.add_cog(Template(bot))
テンプレートリポジトリで使用しているライブラリ (discord.py) のドキュメント
スラッシュコマンドの注意
スラッシュコマンドを使えるようにするには bot.tree.sync()
を実行する必要がある。
デフォルトだとグローバルコマンドとして登録されてしまうため、テンプレートリポジトリでは有効とする設定としている場合のみ実行するようになっている。
(bot.py
の on_ready
関数内に上記コードが書かれている。)
ギルドコマンド(特定のサーバでのみ有効なコマンド)とするには、コマンドに @discord.app_commands.guilds(<GUILD ID>)
デコレータをつける。
グローバルコマンドは反映に時間がかかるが、ギルドコマンドは即時反映される。
自身の特定のサーバでのみ使用するコマンドはギルドコマンドとして登録すればよさそう。
テンプレートリポジトリのREADMEにも上記デコレータに関して書かれているが、手元の環境での動作確認ではデコレータをつけるだけでは即時反映されなかった。
さらにbot.tree.sync(discord.Object(<GUILD ID>))
とすることで即時反映されることを確認できた。
コマンドに@discord.app_command.describe(msg="投稿したいメッセージ")
というようなデコレータをつけることで、引数に説明文を追加できるとライブラリのドキュメントにかかれていた。
手元の環境にて、docstringに引数の説明を書くことでデコレータと同様の説明を追加できることを確認した。
@bot.hybrid_command()
async def test(ctx, msg: str):
"""
テストコマンド
Parameters
---------------
msg : str
投稿したいメッセージ
"""
await ctx.send(f"{msg}")
コマンド引数に型ヒントをつけることで値を変換してくれる。
@bot.hybrid_command()
async def test(ctx, number: int):
# 関数内でint型として`number`を扱える (int型に変換できる値の場合)
await ctx.send(f"{number}")
独自クラスを作ることで、より高度な変換も可能。
Cogで定義したコマンドの定期実行
from discord.ext import commands, tasks
class ExampleCog(commands.Cog):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
@tasks.loop(seconds=5.0)
def example_task(self) -> None:
print("example task")
@commands.Cog.listener()
async def on_ready(self) -> None:
self.example_task.start()
以下のように__init__
でstart
する方法も見受けられたが、自分の環境では動作しなかった。
from discord.ext import commands, tasks
class ExampleCog(commands.Cog):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
self.example_task.start()
@tasks.loop(seconds=5.0)
def example_task(self) -> None:
print("example task")
@tasks.loop(time=datetime.time(hour=8))
とすることで、毎日指定時刻に実行することができる。
タイムゾーンを指定しない場合はUTCとして扱われる。
上記例の場合、毎日UTCの8時に実行される。
任意のチャンネルの取得
bot.get_channel(<channel id>)
でチャンネルを取得できない現象に遭遇した。
正しいチャンネルのIDであってもNone
が返ってくる。
この現象について調べたところ、下記のブログを見つけた。
【pycord】チャンネルが取得できない対処法【Python3.10】 - nekoy3`s room
上記ブログの通り、bot.get_partial_messageable(<channel id>)
としたところ、チャンネルを取得できた。
このスクラップの内容をブログにまとめた。