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

# 経緯
以前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#