4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

pythonでdiscordbotを作るライブラリに、pycordというのがあります。
pycordでは、cogsという機能があり、DiscordBotにおけるモジュール的な構成をすることができます。

モジュールやエクステンションとして知られるコグは、コマンドをグループにまとめるのに使われます。
これは、一般的な考え方が同じコマンドをグループ化するのに便利です(モデレーションコマンドなど)。
また、ボットのファイルが乱雑になるのを防ぐのにも役立ちます。

その中に、関数を定期的に実行する動作を書くことができるので
なかなかにマニアックなテクニックですが紹介します。

環境

py-cord >= 2.4

cogsファイルの読み込み

main.py
import discord
from discord.ext import commands

intents = discord.Intents.default()
bot = commands.AutoShardedBot(intents=intents)
path = "./cogs"

...

bot.load_extensions(
    'cogs.hoge',
    store=True
)
# store=Falseにすると、Cogでエラーが発生していた際にクリティカル警告となる

bot.run(TOKEN)

importで読み込むのではなく、load_extensionsという関数で読み込みます。

main.py
...

bot.load_extensions(
    'cogs.hoge',
    'cogs.huga',
    store=True
)

もちろん、cogsは増やせます。

また、コメントしていますが
storeというオプションがあり、エラーが発生した際にクリティカルにするか設定できます。

main.py
...
cogs_list = [
    'greetings',
    'moderation',
    'fun',
    'owner'
]

for cog in cogs_list:
    bot.load_extension(f'cogs.{cog}')

cogsはリストでも読み込むことができます。

Cogsの書き方

hoge.py
import discord
from discord.ext import commands 
from discord.commands import Option, OptionChoice, SlashCommandGroup

# クラス名にCogと付けたほうが分かりやすい
class HogeCog(commands.Cog):

    def __init__(self, bot:commands.bot):
        print(f"init -> {self.__class__}")
        self.bot = bot

    # nameは全て小文字
    group = SlashCommandGroup(name="name", description="description")

    # コマンド名は全て小文字。関数名の重複に注意。
    @group.command(name="ping", description="通信テスト")
    async def ping(self, ctx: discord.ApplicationContext):
        await ctx.response.send_message(content="pong!")

def setup(bot: commands.bot):
    bot.add_cog(HogeCog(bot))

気を付けること

discord.Botまたはdiscord.ext.commands.Botのインスタンスであるbotを参照するには、
self.bot経由でアクセスする必要があります。

また、クラスの中にいるので、コマンドはすべてそのクラスのメソッドです。
このため、すべての関数は最初のパラメータとしてselfを持つ必要があります。
これがないと、ボットのインスタンスにアクセスできないのです。

例として、特定のチャンネルIDへメッセージを送信する場合、

    async def send_channel_something(self): # 最初にselfを持つ
    
        # self.botからbotにアクセスしてチャンネルを取得
        channel = self.bot.get_partial_messageable(id=hoge_id) 

        # チャンネルにメッセージを送信
        await channel.send(content=message, embed=embed)

となるわけです。

定期実行を作ってみる

class TaskCog(commands.Cog):

    def __init__(self, bot: discord.AutoShardedBot):
        print(f"init -> {self.__class__}")
        self.bot = bot
        self.something_loop_task.start()

    @tasks.loop(seconds=20)
    async def something_loop_task(self):
        print("hello task!")

    @something_loop_task.before_loop
    async def before_something_loop_task(self):
        print('waiting...')
        await self.bot.wait_until_ready()


def setup(bot):
    bot.add_cog(TaskCog(bot))

このCogsを読み込むと、20秒おきにhello task!とプリントされます。

この方法だと、asyncio地獄や「インターネットが切れたらどうしよう」「再接続はどうしよう」といった頭を悩ませるようなことを気にすることなく、バックグラウンド・タスクを作ることができます。

最後に

このようにcogsで分割すると、それぞれのコマンドや動作を便利に管理できるようになります。
ぜひ試してみてください!

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?