最初に
前回にも同じような記事(Custom prefix を導入しよう!!)を書きましたが、こちらの記事で紹介しているコードだと Github + Heroku で動かしているBotには対応していないので、その動かし方でもちゃんと動くように改良しました。
※ それ以外のところも多少改良されています
開発環境
OS - Windows10 home
エディタ - Atom 1.54.0
実行シェル - コマンドプロンプト
Python - 3.9.1
PIP - 20.3.3
discord.py - 1.6.0
本題
コード
※ 基本的にどのコードでも同じ書き方になるものは テンプレ
とコメントが打ってあります
※ テンプレ
部分の解説は省略させていただきます
コードは長いのでこの表示方法をとらせていただきます
# テンプレ
import discord
from discord.ext import commands
BACKUP_CHANNEL_ID =
DEFAULT_PREFIX = ''
TOKEN = ''
def _change_command_prefix(bot: commands.Bot, msg: discord.Message):
if str(msg.guild.id) in prefix_dict.keys():
return prefix_dict[str(msg.guild.id)]
else:
return DEFAULT_PREFIX
# テンプレ
bot = commands.Bot(command_prefix=_change_command_prefix, intents=discord.Intents.all())
@bot.event
async def on_ready():
global backup_ch
global prefix_dict
backup_ch = await bot.fetch_channel(BACKUP_CHANNEL_ID)
prefix_dict = {}
async for m in backup_ch.history():
splited = m.content.split(' ', 1)
prefix_dict[splited[0]] = splited[1]
print('ready')
@bot.command(aliases=['cp'])
async def change_prefix(ctx, new_prefix: str = None):
guild_id = str(ctx.guild.id)
if new_prefix == None:
if guild_id in prefix_dict.keys():
old_prefix = prefix_dict[guild_id]
async for m in backup_ch.history():
if m.content.startswith(guild_id):
await m.delete()
prefix_dict.pop(guild_id)
await ctx.send(embed=discord.Embed(title='This server\'s prefix was reseted', description=f'{old_prefix} -> default({DEFAULT_PREFIX})'))
return
else:
return
if guild_id in prefix_dict.keys():
async for m in backup_ch.history():
if m.content.startswith(guild_id):
await m.edit(content=f'{guild_id} {new_prefix}')
break
old_prefix = prefix_dict[guild_id]
prefix_dict.pop(guild_id)
prefix_dict[guild_id] = new_prefix
await ctx.send(embed=discord.Embed(title='This server\'s prefix was changed', description=f'{old_prefix} -> {prefix_dict[guild_id]}'))
return
else:
await backup_ch.send(f'{guild_id} {new_prefix}')
prefix_dict[guild_id] = new_prefix
await ctx.send(embed=discord.Embed(title='This server\'s prefix was changed', description=f'default({DEFAULT_PREFIX}) -> {prefix_dict[guild_id]}'))
return
# テンプレ
bot.run(TOKEN)
解説
定数の定義
BACKUP_CHANNEL_ID =
DEFAULT_PREFIX = ''
TOKEN = ''
上から
・カスタムPrefix情報をバックアップしておくためのメッセージを送信するチャンネルのチャンネルID
└ 作成者とBotのみが閲覧できるような設定にしておくことをお勧めします
・デフォルトとするPrefix
・BotのTOKEN
サーバーごとのPrefixを返す関数
def _change_command_prefix(bot: commands.Bot, msg: discord.Message):
if str(msg.guild.id) in prefix_dict.keys():
return prefix_dict[str(msg.guild.id)]
else:
return DEFAULT_PREFIX
これは、
prefix_dictという辞書型変数のKeyにコマンドを実行したサーバーのサーバーIDが入っているかどうかを確認し、
├ 入っていれば対応するPrefixを返し、
└ 入っていなければデフォルトのPrefixを返す
という関数になっています。
on_ready内
@bot.event
async def on_ready():
global backup_ch
global prefix_dict
backup_ch = await bot.fetch_channel(BACKUP_CHANNEL_ID)
prefix_dict = {}
async for m in backup_ch.history():
splited = m.content.split(' ', 1)
prefix_dict[splited[0]] = splited[1]
print('ready')
global backup_ch
global prefix_dict
他の関数(change_prefix)でも使用する変数をグローバル変数として定義する
backup_ch = await bot.fetch_channel(BACKUP_CHANNEL_ID)
カスタムPrefix情報をバックアップしておくためのメッセージを送信するチャンネルのチャンネルオブジェクトを取得する
prefix_dict = {}
サーバーごとのPrefixを保存するための辞書型変数の定義
async for m in backup_ch.history():
splited = m.content.split(' ', 1)
prefix_dict[splited[0]] = splited[1]
上のほうで取得した、カスタムPrefix情報をバックアップしておくためチャンネルの履歴からサーバーごとのPrefixを保存する辞書を構成する
※ あまりにも数が多すぎると取得に時間がかかる可能性がありますが、Bot起動時に発動する関数なのであまり影響はないと思います。
以下、各々でカスタム可能
change_prefix内
@bot.command(aliases=['cp'])
async def change_prefix(ctx, new_prefix: str = None):
guild_id = str(ctx.guild.id)
if new_prefix == None:
if guild_id in prefix_dict.keys():
old_prefix = prefix_dict[guild_id]
async for m in backup_ch.history():
if m.content.startswith(guild_id):
await m.delete()
prefix_dict.pop(guild_id)
await ctx.send(embed=discord.Embed(title='This server\'s prefix was reseted', description=f'{old_prefix} -> default({DEFAULT_PREFIX})'))
return
else:
return
if guild_id in prefix_dict.keys():
async for m in backup_ch.history():
if m.content.startswith(guild_id):
await m.edit(content=f'{guild_id} {new_prefix}')
break
old_prefix = prefix_dict[guild_id]
prefix_dict.pop(guild_id)
prefix_dict[guild_id] = new_prefix
await ctx.send(embed=discord.Embed(title='This server\'s prefix was changed', description=f'{old_prefix} -> {prefix_dict[guild_id]}'))
return
else:
await backup_ch.send(f'{guild_id} {new_prefix}')
prefix_dict[guild_id] = new_prefix
await ctx.send(embed=discord.Embed(title='This server\'s prefix was changed', description=f'default({DEFAULT_PREFIX}) -> {prefix_dict[guild_id]}'))
return
※ 一応エイリアスとして cp
が設定されていますが、なくても大丈夫です
guild_id = str(ctx.guild.id)
guild_id
という変数にstr型に変換したサーバーIDを格納する
if new_prefix == None:
if guild_id in prefix_dict.keys():
old_prefix = prefix_dict[guild_id]
async for m in backup_ch.history():
if m.content.startswith(guild_id):
await m.delete()
prefix_dict.pop(guild_id)
await ctx.send(embed=discord.Embed(title='This server\'s prefix was reseted', description=f'{old_prefix} -> default({DEFAULT_PREFIX})'))
return
else:
return
引数として渡される new_prefix
が指定されていなければ(==None)
├ コマンドを実行したサーバーのサーバーIDが prefix_dict
のKeyに入っていれば(==カスタムPrefixが設定されている)
│ └ ¹古いPrefixを old_prefix
変数に格納
│ ↓
│ バックアップチャンネルの履歴からコマンドを実行したサーバーのPrefix情報が格納されているメッセージを削除
│ ↓
│ prefix_dict
からコマンドを実行したサーバーの情報を削除
│ ↓
│ ²デフォルトのPrefixに戻したという旨のメッセージを送信
└ それ以外
└ 何もしない
※ 1 - 2で送信するメッセージに使用
※ 1, 2 - Prefix変更のメッセージのため、省略可能
if guild_id in prefix_dict.keys():
async for m in backup_ch.history():
if m.content.startswith(guild_id):
await m.edit(content=f'{guild_id} {new_prefix}')
break
old_prefix = prefix_dict[guild_id]
prefix_dict.pop(guild_id)
prefix_dict[guild_id] = new_prefix
await ctx.send(embed=discord.Embed(title='This server\'s prefix was changed', description=f'{old_prefix} -> {prefix_dict[guild_id]}'))
return
コマンドを実行したサーバーのサーバーIDが prefix_dict
のKeyに入っていれば(==カスタムPrefixが設定されている)
└ バックアップチャンネルの履歴からコマンドを実行したサーバーのPrefix情報が格納されているメッセージの内容を変数
↓
¹古いPrefixを old_prefix
変数に格納
↓
prefix_dict
からサーバーIDに対応する要素を削除
↓
prefix_dict
にサーバーのPrefix情報を格納
↓
²Prefixを変更したという旨のメッセージを送信
※ 1 - 2で送信するメッセージに使用
※ 1, 2 - Prefix変更のメッセージのため、省略可能
else:
await backup_ch.send(f'{guild_id} {new_prefix}')
prefix_dict[guild_id] = new_prefix
await ctx.send(embed=discord.Embed(title='This server\'s prefix was changed', description=f'default({DEFAULT_PREFIX}) -> {prefix_dict[guild_id]}'))
return
コマンドを実行したサーバーのサーバーIDが prefix_dict のKeyに入ってなければ(==カスタムPrefixが設定されていない)
└ バックアップチャンネルに新しくサーバーのPrefix情報を送信
↓
prefix_dict
にサーバーのPrefix情報を格納
↓
¹Prefixをデフォルトからカスタムに変更したという旨のメッセージを送信
※ 1 - Prefix変更のメッセージのため、省略可能
後書き
今回は少し書き方を変えてみました。どうでしょうか?見やすかったらうれしいです。
今のところ不具合は確認されていませんが、もしうまく動かない等ありましたらコメントにてその旨をお伝えください。
今回はPythonの基礎は理解できているていで解説しています。わからないことがあれば、少し調べればでてくるようなものしか使っていないので各自調べて下さい。