LoginSignup
0
2

More than 1 year has passed since last update.

discord.pyでログオフ機能を実装する(追加でシステム自体も落とす)

Last updated at Posted at 2022-11-12

0.この記事で解説すること

  • discord.pyのAPIリファレンスの読み方が分かる
  • いきなりrun(token)が動かなくなった時の対応方法
  • Botのログオフ機能を実装する

1.今回、解説に至った経緯

  1. デバッグしたいのでbotをログオフさせたい
  2. 解説記事を色々と見たが実装してる方がいなかった
  3. システムの強制終了を頻繁にしているとrun(token)で動かなくなった
  4. 対策ができたので記事を書くことに

※対策の追記内容があります! 対策の追記

3.についてですが、Replitで動かしてると発生するようです(他環境でも起きるかも?)
内容としては以下のエラーログが出ます(一部抜粋)

discord.errors.HTTPException: 429 Too Many Requests (error code: 0):

2.ログオフ機能を実装する

2.1 開発環境

  • 統合開発環境: Replit
  • discord.py: 2.0.1
  • 言語: python3.8

2.2 処理の詳細内容

  1. Discordのユーザー入力を検知
  2. Botをログオフさせる
  3. コード上でログオフを検知してシステム自体を落とす

2.2.1 Discordのユーザー入力検知

on_message(message)で取得できます。
image.png
以下の内容を踏まえて元となるコードを書きます。

.py
import discord
import os, sys, datetime, json

class MyClient(discord.Client):

  #メッセージが書き込まれた時
  async def on_message(self, message):
  #送信者がbot自身の場合はコマンドを無効にする
  if message.author.bot:
    print("bot送信\n")
    return

  if ".logoff" in message.content:
    #ログオフ
    await self.Logoff(message)
    return

def main():
  #環境変数からtokenを取ってくる
  TOKEN = os.getenv("TOKEN")
  #すべての機能を使えるようにする
  intents = discord.Intents.all()
  #intentsは必須パラメータ
  client = MyClient(intents=intents)
  #Discord接続
  client.run(TOKEN)

if __name__ == "__main__":
    main()

on_message(message)で使われる引数はクラスです。
メンバ変数やメソッドはどう使うかはAPIリファレンスを読めばわかります。
discord.Message
image.png
今回の場合だと
A.送信者がBotかを判定
B.メッセージ内容に.logoffとあればログオフさせる関数を実行

それぞれの処理詳細について説明していきます。

2.2.1(A) Bot判定

.py
import discord
import os, sys, datetime, json

class MyClient(discord.Client):
  #メッセージが書き込まれた時
  async def on_message(self, message):

  #送信者がbot自身の場合はコマンドを無効にする
  if message.author.bot:
    print("bot送信\n")
    return

APIリファレンスが読めないと、この記述にたどり着けないと思います。
(他の解説記事を読むと別の記述でBot判定していました)

まずはmessage.authorから見ていきましょう。
image.png
こちらを見ると今回の場合はMemberが取得できるようです。
リンクをクリックしてMemberの中身をみていきましょう。
image.png
discord.Memberクラスを取得できるようです。
この中にあるメンバ変数BotはBotの場合Trueを返します。

長かったので今までの流れをまとめると以下の記述となります。

discord.Messageクラスはdiscord.Memberクラスを持っている。
→ discord.Memberクラスのメンバ変数botを使ってBot判定をする。

図解すると、こんな感じです。

on_message(message)

message = discord.Messageクラス
 L message.author = discord.Memberクラス
     L bot(Botの場合はTrue)

2.2.1(B) メッセージ内容判定

.py
import discord
import os, sys, datetime, json

class MyClient(discord.Client):
  #メッセージが書き込まれた時
  async def on_message(self, message):
  if ".logoff" in message.content:
    #ログオフ
    await self.Logoff(message)
    return

message.contentはメンバ変数でメッセージ内容を取得できます。
image.png

2.2.2 Botをログオフさせる

まずはコードから

.py
import discord
import os, sys, datetime, json

class MyClient(discord.Client):

  #ログオフ
  async def Logoff(self, message):
    print("実行:Logoff\n")
    await message.channel.send("ログオフします")
    await self.close()

ココでは2つの処理をしています。
A.チャンネルにメッセージを送信
B.ログオフする

では1つずつ見ていきましょう。

2.2.2(A) チャンネルにメッセージを送信

messageはdiscord.Messageクラスです。
message.channelを見てみましょう。
image.png
今回の場合だとdiscord.TextChannelクラスが取れます。
(メッセージを送信したテキストチャンネルの情報)
discord.TextChannelのsend()メソッドでメッセージを送信しています。

2.2.2(B) ログオフ

self.close()となってますが、これはdiscord.Clientクラスのclose()メソッドです。
(自作クラスMyClientはdiscord.Clientを継承している)
image.png
image.png

2.2.3 コード上でログオフを検知してシステム自体を落とす

まずはコードから

.py
import discord
import os, sys, datetime, json

class MyClient(discord.Client):
  #先ほど説明したので省略

def main():
  #環境変数からtokenを取ってくる
  TOKEN = os.getenv("TOKEN")
  #すべての機能を使えるようにする
  intents = discord.Intents.all()
  #intentsは必須パラメータ
  client = MyClient(intents=intents)
  #Discord接続
  client.run(TOKEN)

  #pythonを落とす
  if (client.is_closed()):
    #discord.errors.HTTPException: 429 Too Many Requests対策
    print("osを切ります")
    os.system("kill 1")

if __name__ == "__main__":
  main()

discord.Clientクラスのis_closed()メソッド
これはcloseされた場合にTrueを返します。
この判定が通ったときに呼び出されるos.system("kill 1")

コレはに引数内容のコマンドを実行させます。
今回の記述内容は「今動いてるシステムを終了させる」です。

※対策の追記内容があります! 対策の追記

2.3 実際に動かしてみた

起動時
image.png
Discordの画面
image.png
image.png
StopからRunに変わったので実装できてます。
ココまでお付き合いいただき、ありがとうございました。

※何か連絡や依頼がありましたらDMをお願いします。
Twitter: Don't Pray Debug

0
2
0

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
0
2