--- tags: 1101,Discord Bot --- # Discord Bot#3 Cog ## Cog簡介 - 將我們所有的指令整理成一個一個的**物件** - 將這些指令做成物件後,我們的機器人本體(bot.py)就只需要負責載入或移除這些物件 - **完成之後,我們就可以更方便地去DEBUG囉!** ## Cog實作 ### 幫你的指令及事件搬家 1. 在bot.py的所在的資料夾中,開一個資料夾Cog ![](https://i.imgur.com/VYPfoms.png) 2. 在Cog資料夾底下新增 event.py image.py main.py 三個檔案 ![](https://i.imgur.com/YUaVaDV.png) 3. 打開main檔案,開始把指令搬家囉 4. 先打出這個基本的Cog結構 - **class Main(command.Cog)**: 一個叫做 Main 的物件,它擁有 command.Cog 的特性,裡面會存放各種你想放的指令以及事件 - **__ init __(self, bot)**:生成 Main 這個物件的時候會呼叫的 function, 這裡的用意是想讓Main這個物件也可以讀取到bot.py裡的 Bot物件 - **def setup(bot)**: 這個函式會在每次載入Main這個Cog的時候執行,讓bot.py裡的機器人載入Cog ```python= import discord from discord.ext import commands class Main(commands.Cog): def __init__(self, bot): self.bot = bot def setup(bot): bot.add_cog(Main(bot)) ``` 5. 將 ping 和 purge 兩個指令剪下貼上到class Main裡面 6. 修改 ping 和 purge 指令 >Note: 直接寫在 bot.py和寫成Cog主要有兩個不同,第一是修飾器,第二個則是 function的參數一定要有self,Cog因為是一個class,所以每個function的**第一個**參數都必須是self - 修飾器比較 | | command | event | |:------:|:-------------------:|:------------------------:| | bot.py | @bot.command() | @bot.event | | Cog | @commands.command() | @commands.Cog.listener() | - Main.py (記得bot也要改成self.bot喔) ```python= import discord from discord.ext import commands class Main(commands.Cog): def __init__(self, bot): self.bot = bot @commands.command() async def ping(self, ctx): await ctx.send(self.bot.latency) @commands.command() async def purge(self, ctx, num=1): deleted = await ctx.channel.purge(limit=num+1) await ctx.send(f'{len(deleted)} messages deleted!') def load(bot): bot.add_cog(Main(bot)) ``` 7. 接著把傳送圖片相關的指令搬到 image.py,注意這裡也會需要另外import random和json兩個module,且在程式一開始也需要讀取json檔案 ```python= import discord from discord.ext import commands import random import json with open('setting.json', 'r', encoding='utf8') as jsonFile: setting = json.load(jsonFile) class Image(commands.Cog): def __init__(self, bot): self.bot = bot @commands.command() async def image(self, ctx): dcFile = discord.File(random.choice(setting['image'])) await ctx.send(file=dcFile) @commands.command() async def webimage(self, ctx): await ctx.send(random.choice(setting['webimage'])) def setup(bot): bot.add_cog(Image(bot)) ``` 8. 最後是 event.py,我們需要把on_member_join,on_member_remove,on_message三個指令搬至 event.py >Note: 由於這個Cog全部都是event,修飾器是用@commands.Cog.listener(),而不是之前的@commands.command() ```python= import discord from discord.ext import commands import json with open('setting.json', 'r', encoding='utf8') as jsonFile: setting = json.load(jsonFile) class Event(commands.Cog): def __init__(self, bot): self.bot = bot @commands.Cog.listener() async def on_member_join(self, member): ch = self.bot.get_channel(int(setting['channel_id'])) await ch.send(f'{member} Ya hello') @commands.Cog.listener() async def on_member_remove(self, member): ch = self.bot.get_channel(int(setting['channel_id'])) await ch.send(f'{member} Bye bye') @commands.Cog.listener() async def on_message(self, msg): if 'Yo' in msg.content and msg.author != self.bot.user: await msg.channel.send('Yo') await self.bot.process_commands(msg) def setup(bot): bot.add_cog(Event(bot)) ``` ### 在bot.py中使用Cog - 在bot.py的run前面加入下列程式碼,它會找到Cog資料夾中所有的py檔案,並用load_extension載入這些cog,**記得在檔案開頭加入 from pathlib import Path** >Note: 這裡的load功能其實就有點像是程式開頭的from ... import ... ```python= for cog in [p.stem for p in Path(".").glob("./Cog/*.py")]: bot.load_extension(f'Cog.{cog}') print(f'Loaded {cog}.') print('Done.') ``` ### 實用的Debug函式 - load ```python= @bot.command() async def load(ctx, ext): bot.load_extension(f'Cog.{ext}') await ctx.send(f'{ext} loaded successfully.') ``` - unload ```python= @bot.command() async def unload(ctx, ext): bot.unload_extension(f'Cog.{ext}') await ctx.send(f'{ext} unloaded successfully.') ``` - reload (DEBUG神器) ```python= @bot.command() async def reload(ctx, ext): bot.reload_extension(f'Cog.{ext}') await ctx.send(f'{ext} reloaded successfully.') ``` ## 小小指令報錯功能 - 我們可以直接使用內建的 on_command_error 事件,幫助我們把這些錯誤訊息傳送至頻道 ![](https://i.imgur.com/C6uF0A2.png) - 示意圖 ![](https://i.imgur.com/dj05P9k.png) ```python= @commands.Cog.listener() async def on_command_error(self, ctx, err): await ctx.send(err) ``` ## 一些自學資源 [Proladon - Code a Discord bot](https://www.youtube.com/watch?v=odIQEJW0m1M&list=PLSCgthA1Anif1w6mKM3O6xlBGGypXtrtN&ab_channel=Proladon) [彭彭 - Python 入門課程](https://www.youtube.com/playlist?list=PL-g0fdC5RMboYEyt6QS2iLb_1m7QcgfHk)