discord.pyでcogを使う

# バージョン情報
Python 3.8.12
discord.py 2.1.0

# 最小限に近いもの
## メインファイル
```Python:main.py
import discord
from discord.ext import commands

prefix = '!'
COGS = [
  "Greeting"
]

class MyBot(commands.Bot):
  """起動用のあれこれ"""
  async def setup_hook(self):
    for cog in COGS:
      try:
        await self.load_extension(cog)
      except Exception as e:
        print(e)
    await self.tree.sync()
    
# 接続に必要なオブジェクトを生成
intents = discord.Intents.default()
intents.messages = True
bot = MyBot(
  command_prefix = prefix,
  intents = intents, 
  )
)

bot.run(str型のtoken)
```
## 同ディレクトリの別ファイルのcog例
```Python:Greeting.py
import discord
from discord.ext import commands

class Greeting(commands.Cog):
  @commands.hybrid_command()
  async def meow(self, ctx):
    await ctx.send('にゃーん')

async def setup(bot):
  await bot.add_cog(Greeting(bot))
```

# 個人的に好みな書き方
## メインファイル
```Python:main.py
import discord
from discord.ext import commands
import os #getenvに必須

prefix = ['!', '?'] #list型で複数の接頭辞に対応
MY_GUILD = discord.Object(int(os.getenv('guild_id')))
COGS = [
  #"Second_Cog", #list型でコグを好きなだけ追加する
  "Greeting"
]

class JapaneseHelpCommand(commands.DefaultHelpCommand):
  def __init__(self):
    super().__init__()
    self.commands_heading = "コマンド:"
    self.no_category = "その他"
    self.command_attrs["help"] = "コマンド一覧と簡単な説明を表示"

  def get_ending_note(self):
    return (f"各コマンドの説明: {prefix[0]}help コマンド名\n"
            f"各カテゴリの説明: {prefix[0]}help カテゴリ名\n")

class MyBot(commands.Bot):
  """起動用のあれこれ"""
  async def setup_hook(self):
    for cog in COGS:
      try:
        await self.load_extension(cog)
      except Exception as e:
        print(e)
    #self.tree.copy_global_to(guild = MY_GUILD) #ギルドコマンドにコピーして実験をしたい時にコメントアウトを解除する
    await self.tree.sync(guild = MY_GUILD) #何故かこれを入れると、グローバルコマンドも即同期される
    await self.tree.sync()

  async def on_ready(self):
    print('Logged in as') #seetup_hookの完遂を知らせる
    for cog in COGS:
      try:
        await self.reload_extension(cog) #コグをリロードする
      except Exception as e:
        print(e)
    #self.tree.copy_global_to(guild = MY_GUILD) #setup_hookと意図は同じ
    #await self.tree.sync(guild = MY_GUILD) #setup_hookと意図は同じ
    await self.tree.sync() #リロードしたコグを再同期する
    print(self.user.name) #リロードの完遂を知らせる
    print(self.user.id)
    print('------')
    
# 接続に必要なオブジェクトを生成
intents = discord.Intents.default()
intents.messages = True
intents.message_content = True
intents.presences = True
bot: commands.Bot = MyBot(
  command_prefix = prefix,
  case_insensitive = True, #コマンドの大文字小文字を無視する(True)
  intents = intents, 
  status = discord.Status.online, 
  activity = discord.Activity(
    type = discord.ActivityType.listening,
    name = "!help してみて！"
  ),
  help_command = JapaneseHelpCommand()
)
  
#エラー処理
@bot.event
async def on_command_error(ctx: commands.Context, error):
  if ctx.author.bot: #botが起こしたエラーなら
      return #何もしない
  if isinstance(error, commands.errors.CheckFailure): #スラッシュコマンドでのみ動作するように制約
    await ctx.send(f'勘の良いガキは嫌いだよ', ephemeral = True) #権限を持たずにコマンドを実行した際に警告する

bot.run(os.getenv('TOKEN'))
```

:::note info
参考：[helpコマンドの表示内容を日本語化する](https://cod-sushi.com/discord-py-help-command-japanese/)
:::
## 同ディレクトリの別ファイルのcog例
```Python:Greeting.py
import discord
from discord.ext import commands

class Greeting(commands.Cog, name = 'あいさつ'):
  """あいさつを返すよ"""
  
  def __init__(self, bot: commands.Bot):
    super().__init__()
    self.bot: commands.Bot = bot

  async def cog_check(self, ctx: commands.Context):
    if ctx.author.bot:
      return False
    else:
      return True
  
  @commands.hybrid_command(name = "にゃーん", aliases = ["にゃ", "にゃん", "cat"])
  async def meow(self, ctx: commands.Context):
    """鳴き声を返すにゃ"""
    await ctx.send(
      f'{ctx.author.mention} にゃーん'
    )

async def setup(bot: commands.Bot):
  await bot.add_cog(Greeting(bot))
```

## コンバーター
```Python
bot: commands.Bot = MyBot(
```
のように`○○: △△`と書いているのは、コンバーターを指定している。
str型、int型などのよく知られている型だけでなく、[公式ガイド](https://discordpy.readthedocs.io/ja/latest/ext/commands/commands.html)で示される、多数のdiscord.py独自の型に指定できる。
最小限のコードには不要だが、コンバーターを使う事で例外を弾きやすくなり、扱いやすくなるだろう。
特にスラッシュコマンドの引数では、Discordサーバー側でエラーメッセージを表示してくれる。楽チンである。