LoginSignup
21
21

More than 1 year has passed since last update.

【最新版】discord.pyでbotに一定時間ごとに発言させる

Last updated at Posted at 2019-12-12

注意

既にアナウンスされている通り、discord.pyは2021年8月下旬ころ、以降のサポートを停止する旨発表されております。
もし本記事を参考にして不具合が生じた場合、ライブラリのサポート終了による影響である可能性もあります。
詳しくは the_future_of_dpy.md をご覧ください。

概要

チャットツールDiscordにおいてbotを簡潔に記述できる、PythonのDiscordAPIラッパーであるdiscord.pyを利用して、botに定期的な処理を行わせる手法を解説する。

注意

コード例が実際には動作しないものになっておりました。2020年4月10日にコード例を修正しております。

前提

  • discord.py 1.3.0a
  • Python 3.6

バージョンに関する注意

discord.pyは長らく ver0.16.12(いわゆるasync版)が提供されてきましたが、2019年4月にv1.0.0(いわゆるrewrite版)がリリースされ、v0系はもはや使用は推奨されていません。
実際、v0系はPython3.7以上には対応しておらず今後のアップデート・メンテナンスは見込めません。
可能な限り、最新版への対応をお勧めします。
v0系での定期的な処理については、以下の記事を参考にしてください。

discord.pyでbotに一定時間ごとに発言させる【async版】

手法

'discord.py'の拡張であるtasksを使用します。
これはbot開発でよく用いられる繰り返し実行に主眼を置いたライブラリで、
繰り返し処理を非常に簡潔に記載することができます。
公式のドキュメント

基本的には定期実行を行いたいメソッドの1行上に
@tasks.loop([実行間隔])を付け加えた上で、定期実行を開始したいタイミングでstart()するというものです。

次の節で具体的な例を見てみましょう。

具体例

以下は、予め指定したIDを持つチャンネルにbot起動直後から定期実行を10秒ごとに行う例となります。

from discord.ext import tasks
import discord

client = discord.Client()

channel_sent = None
"""
10秒ごとに発言するメソッドを定義している部分。
async def の1行上が定期実行を示すもので、()内で間隔を指定します。
例えば5分ごとなら(minutes=5)です。
"""
@tasks.loop(seconds=10)
async def send_message_every_10sec():
    await channel_sent.send("10秒経ったよ")

"""
今回はbotの起動直後に定期実行を開始したいので、
botの準備ができた段階で定期実行をstart()します
"""
@client.event
async def on_ready():
    global channel_sent 
    channel_sent = client.get_channel(any_channel_id)
    send_message_every_10sec.start() #定期実行するメソッドの後ろに.start()をつける


client.run("hogehogetoken")

これで、指定したチャンネルに10秒ごとに「10秒経ったよ」と発言させることができます。

応用すれば、指定したコマンドを受け取ったら、そのタイミングから実行することもできます。
start()のタイミングを変更するだけですね。

終わりに

discord.pyでbotに一定時間ごとに発言させる【async版】
この記事の閲覧数が未だに増え続けていて申し訳なくなったので、ひとまず最新版への動線を作成。必ずアップデートします……。

質問があればコメントください。discord.pyはある程度使いこなせてきました。

コード例の補足

上記のコード例は、いくつかの不具合の報告を受け数回の修正を行ったコードです。もともと記載していたコード例からかけ離れたものにならないよう修正をしているため、少し不自然な部分もあります。
特にglobalを用いて外側の変数の値を書き換えるのは、必要性がなければ避けるべきです(可読性が落ち、意図せず変数の値を書き換えてしまうこともありえます)。

例えば以下の記事を参考に、ループする関数自体が送信先チャンネルを引数に取るようにすれば、globalで書き換えずともstart()の引数として渡すだけで済みます。
https://qiita.com/rareshana/items/b84bec58acd48cb14118

あるいは、Cogというコマンドやイベント、タスクをひとまとめにする機能を使えば、インスタンス変数にチャンネルを格納することができるため、やはりglobal変数を使う必要はなくなります。状況に応じて適切に書き換えてください。

21
21
7

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
21