0
0

More than 3 years have passed since last update.

Discord.py 0.Xのエコーボットを1.Xに移行するだけ

Last updated at Posted at 2019-11-07

経緯

以前Python3.6を利用したDiscordのメッセージをボイスロイドに読ませるために作ったプログラムが、Python3.7にしたら使えなくなっていた。(1年前から)
それとDiscord.pyのバージョンがかなり古かったので更新したかったためです。(更新してから動かないことが発覚)

いろいろダメになっているのと、Pythonを久しぶりに使いたかったので改修しよう!

環境

今回想定している環境は以下の通りです。
・Python 3.7.4
・Discord.py 1.2.4
・Windows10

Pythonの環境設定などは他のページとかを参考にしてください。
エディタなどお好きなのをどうぞ

エコーボットの改修

簡単なエコーボットを作りたいと思います。
前回Discord.py 0.xの時に作ったものなので今は使えませんでした。

EchoBot.py
# Discord.py 0.x
import discord
client = discord.Client()

@client.event
async def on_ready():
    print("-"*35)
    print("user name:", client.user.name)
    print("user id:", client.user.id)
    print("-"*35)

@client.event
async def on_message(message):
        # 自身のメッセージには反応しないように
    if client.user != message.author:
        # メッセージを書きます
        m= message.author.name +"の送ったメッセージは"+message.content+"です"
        # メッセージが送られてきたチャンネルへメッセージを送ります
        await client.send_message(message.channel, m)


client.run("BOTのトークン")

ボット以外からのメッセージを送り返すだけの簡単なものです。
これを1.Xに合わせて修正していきます。
今回修正が必要なのはon_messageの中です。

EchoBot_after.py
@client.event
async def on_message(message):
    if message.author.bot:  # メッセージ送信者がBotだった場合は無視する
        return
    # 投稿されたチャンネルに送信
    await message.channel.send(f"{message.author.name}さんからのメッセージは{message.content}です")

エコーボットなのでこの程度の修正で済んでいますが、多機能なアプリの場合は大変そうですね。

修正ついでに改修

いろいろ書きなおしたのがこちら

EchoBot.py
import discord
import re
client = discord.Client()
CHANNEL_ID = "メインで使うチャンネルのID"


@client.event
async def on_ready():  # 起動時コンソールにIDと名前を表示
    print("-"*50)
    print(client.user.name)  # User Name
    print(str(client.user.id))  # User ID
    print(""*50)
    print("Botの招待URL")
    strURL = "https://discordapp.com/oauth2/authorize?&client_id="
    strURL += str(client.user.id) + "&scope=bot&permissions=0"
    print(strURL)
    print("-"*50)
    print(f"client : {client}")
    print(f"client.user : {client.user}")
    print("-"*50)
    channel = client.get_channel(CHANNEL_ID)
    await channel.send("起動しました。")  # 起動したら通知する


@client.event
async def on_message(message):  # メッセージ受信時に動作する処理
    if message.author.bot:  # メッセージ送信者がBotだった場合は無視する
        return

    if client.user in message.mentions:  # リプライが来たら返事をする
        await message.channel.send( f"{message.author.mention} 呼んだ?")  # 返信メッセージの送信
        return

    Msg = message.content
    if re.search(r"http(.*)", Msg):
        Msg = re.sub(r"http(.*)", "、以下URL", Msg)  # URLは省略
    await message.channel.send(f"{message.author.name}さんからのメッセージは{Msg}です")


client.run("BOTのトークン")

以上でエコーボット完成です。
message.author.nameの部分をmessage.author.nickにするとその人のギルドでのニックネームを取得することができます。

おまけ

更新ついでにいろいろ調べるために作った、クライアントの機能詰め合わせ(私的に使うと思う機能)です。

DiscordTest.py
import discord
import re
import datetime
import sys
from inspect import currentframe

client = discord.Client()
CHANNEL_ID = "チャンネルID"


@client.event
async def on_ready():  # 起動時コンソールにIDと名前を表示
    now = datetime.datetime.now()
    print(now.strftime('%Y/%m/%d %H:%M:%S'))
    print("-"*50)
    print(client.user.name)  # User Name
    print(str(client.user.id))  # User ID
    print(""*50)
    print("Botの招待URL")
    strURL = "https://discordapp.com/oauth2/authorize?&client_id="
    strURL += str(client.user.id) + "&scope=bot&permissions=0"
    print(strURL)
    print("-"*50)
    print(f"client : {client}")
    print(f"client.user : {client.user}")
    print("-"*50)
    channel = client.get_channel(CHANNEL_ID)
    await channel.send("起動しました。")  # 起動したら通知する


@client.event
async def on_typing(channel, user, when):  # 誰かがメッセージを書こうとしています
    printDate(sys._getframe().f_code.co_name, channel, user, when)


@client.event
async def on_message(message):  # メッセージ受信時に動作する処理
    printDate(sys._getframe().f_code.co_name, message)
    if message.author.bot:  # メッセージ送信者がBotだった場合は無視する
        return
    if client.user in message.mentions:  # リプライが来たら返事をする
        reply = f"{message.author.mention} 呼んだ?"  # 返信内容
        await message.channel.send(reply)  # 返信メッセージの送信
        return

    if re.search(r"まな板", message.content):  # コマンドが含まれるか判定
        e = discord.Embed(title='KOROSUZO☆')
        await message.channel.send('何か言った?', embed=e)  #
        return
    Msg = message.content
    if re.search(r"http(.*)", Msg):
        Msg = re.sub(r"http(.*)", "、以下URL", Msg)  # URLは省略
    await message.channel.send(f"{message.author.nick}さんからのメッセージは{Msg}です")


@client.event
async def on_guild_role_create(role):  # ギルドのルールが作成された時の処理
    printDate(sys._getframe().f_code.co_name, role)
    channel = client.get_channel(CHANNEL_ID)
    await channel.send(f"{role}が作成されました")


@client.event
async def on_user_update(before, after):
    printDate(sys._getframe().f_code.co_name, before, after)


@client.event
async def on_member_update(before, after):  # メンバーの情報が変わると実行される処理
    printDate(sys._getframe().f_code.co_name, before, after)


@client.event
async def on_guild_role_delete(role):
    printDate(sys._getframe().f_code.co_name, role)
    channel = client.get_channel(CHANNEL_ID)
    await channel.send(f"{role}が削除されました")


@client.event
async def on_voice_state_update(member, before, after):
    channel = client.get_channel(CHANNEL_ID)
    printDate(sys._getframe().f_code.co_name, member, before, after)
    # ボイスチャンネルから退室
    if after.channel is None:
        await channel.send(f"{member}{before.channel.name} から退室しました")
        return
    # ボイスチャンネルに参加
    if before.channel is None and after.channel is not None:
        await channel.send(f"{member}{after.channel.name} に参加しました")
        return
    # ボイスチャンネルを移動
    if before.channel != after.channel:
        await channel.send(f"{member}{after.channel.name} に移動しました")
        return


@client.event
async def on_guild_update(before, after):  # ギルドが更新された時の処理
    channel = client.get_channel(CHANNEL_ID)
    printDate(sys._getframe().f_code.co_name, before, after)
    await channel.send(f" {before}{after} に変更されました")


@client.event
async def on_guild_channel_delete(channel):  # チャンネルが削除されたとき
    printDate(sys._getframe().f_code.co_name, channel)


@client.event
async def on_guild_channel_create(channel):  # チャンネルが作成された
    printDate(sys._getframe().f_code.co_name, channel)


@client.event
async def on_guild_channel_pins_update(channel, lastPin):  # メッセージがピン止めされるか解除されたとき
    print(sys._getframe().f_code.co_name)
    chkprint(channel, lastPin)
    if lastPin is not None:
        print(f"lastPin +9h : {lastPin + datetime.timedelta(hours=9)}")  # 日本時間に修正
    print("-"*50)


def printDate(name, *args):
    print(name)
    now = datetime.datetime.now()
    print(now.strftime('%Y/%m/%d %H:%M:%S'))
    chkprint(*args)
    print("-"*50)


def chkprint(*args):
    names = {id(v): k for k, v in currentframe().f_back.f_locals.items()}
    print(', '.join(names.get(id(arg), '???') + ' = ' + repr(arg) for arg in args))


client.run('BOTのトークン')

自身のステータスを変えたり、ギルドの名前やルールを変えたりいろいろ反応する機能がありましたが、使いそうな部分を集めました。

参考サイト

[Python] 関数内からその関数の名前を取得する方法
https://qiita.com/abeken0713/items/77420c8c05e53628199a

printデバッグに最適! pythonで変数名を文字列にして、中の値と同時にprintする関数を実装
https://qiita.com/AnchorBlues/items/f7725ba87ce349cb0382

Discord.py
https://discordpy.readthedocs.io/ja/latest/migrating.html#

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