経緯
以前Python3.6を利用したDiscordのメッセージをボイスロイドに読ませるために作ったプログラムが、Python3.7にしたら使えなくなっていた。(1年前から)
それとDiscord.pyのバージョンがかなり古かったので更新したかったためです。(更新してから動かないことが発覚)
いろいろダメになっているのと、Pythonを久しぶりに使いたかったので改修しよう!
環境
今回想定している環境は以下の通りです。
・Python 3.7.4
・Discord.py 1.2.4
・Windows10
Pythonの環境設定などは他のページとかを参考にしてください。
エディタなどお好きなのをどうぞ
エコーボットの改修
簡単なエコーボットを作りたいと思います。
前回Discord.py 0.xの時に作ったものなので今は使えませんでした。
# 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
の中です。
@client.event
async def on_message(message):
if message.author.bot: # メッセージ送信者がBotだった場合は無視する
return
# 投稿されたチャンネルに送信
await message.channel.send(f"{message.author.name}さんからのメッセージは{message.content}です")
エコーボットなのでこの程度の修正で済んでいますが、多機能なアプリの場合は大変そうですね。
修正ついでに改修
いろいろ書きなおしたのがこちら
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
にするとその人のギルドでのニックネームを取得することができます。
おまけ
更新ついでにいろいろ調べるために作った、クライアントの機能詰め合わせ(私的に使うと思う機能)です。
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#