본문으로 바로가기
728x90
반응형

이전글보기

[정보/Discord Bot] - [discord.py 2.0] 04. discord.py 라이브러리 설치하기

[정보/Discord Bot] - [discord.py 2.0] 05. 봇 기본설정하기

[정보/Discord Bot] - [discord.py 2.0] 06. 봇 명령어 추가하기

[정보/Discord Bot] - [discord.py 2.0] 07. 대화에 Embed 추가하기

[정보/Discord Bot] - [discord.py 2.0] 08. Embed 꾸미기


이번엔 Cogs를 통해 소스코드를 기능별로 나누어 관리하기 용이하도록 할겁니다.

Main.py 소스코드가 있는 폴더에 Cogs 폴더를 생성합니다

현재 작성된 코드의 동작이 ping 명령어 밖에 없지만.. ping이라도 분리해서 관리할 수 있도록 나눠보겠습니다.

 

Cogs 파일의 기본 구조는 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
import discord
from discord.ext import commands
 
 
class Ping(commands.Cog):
    def __init__(self, app):
        self.app = app
 
 
async def setup(app):
    await app.add_cog(Ping(app))
cs

5~7 : Main에서 호출할 클래스를 정의합니다.

10~11 : Main에서 호출 할 수 있도록 setup 메소드를 작성합니다.

 

그럼 위 기본 구조를 토대로 Ping기능이 포함된 Ping.py를 Cogs 폴더 아래에 생성해줍니다.

폴더구조는 다음과 같습니다

main.py가 있는 위치에 Cogs 폴더가 있고, 그 아래에 ping.py 를 생성하였습니다.

그리고 위에 입력한 기본 Cogs 코드와 Main에 있는 ping 명령어들을 ping.py 로 옮겨줍니다.

 

그럼 완성된 ping.py는 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import discord
from discord.ext import commands
 
 
class Ping(commands.Cog):
    def __init__(self, app):
        self.app = app
 
    @commands.command()
    async def ping(self, ctx):
        await ctx.send('pong')
 
    @commands.command(name="핑")
    async def ping2(self, ctx):
        embed = discord.Embed(title="ping pong", description="핑퐁", colour=0xffffff)
        embed.set_author(name='Author name', icon_url="https://han.gl/XBMeC")
        embed.set_footer(text="footer", icon_url="https://han.gl/XBMeC")
        embed.set_image(url="https://han.gl/XBMeC")
        embed.set_thumbnail(url="https://han.gl/XBMeC")
        embed.add_field(name="필드1", value="inline false 필드1 내용", inline=False)
        embed.add_field(name="필드2", value="inline false 필드2 내용", inline=False)
        embed.add_field(name="필드3", value="inline True 필드3 내용", inline=True)
        embed.add_field(name="필드4", value="inline True 필드4 내용", inline=True)
        await ctx.reply('퐁', embed=embed)
 
 
async def setup(app):
    await app.add_cog(Ping(app))
cs

사용된 코드 설명

class Ping(commands.Cog):
    def __init__(self, app):
        self.app = app

5~7 : Ping 클래스를 선언합니다. 클래스의 이름은 본인 마음대로 변경하셔도 상관없습니다.

    @commands.command()
    async def ping(self, ctx):
        await ctx.send('pong')

9 : @app.command() 에서 @commands.command() 로 변경되었습니다

10 : 기존엔 전역 메소드였으나, Ping 클래스의 메소드로 포함되었으므로, self 인자가 추가되었습니다.

    @commands.command(name="핑")
    async def ping2(self, ctx):

13 : @app.command(name="핑") 에서 @command.command(name="핑") 으로 변경되었습니다

14 : 함수명이 ping 이었으나 "async def ping(ctx)" 클래스 내에 동일한 이름의 메소드가 존재할 경우 정상적으로 동작하지 않아 메소드 이름을 변경하였습니다 "async def ping2(self, ctx).   / 그외 self가 추가된 이유는 10 line과 같습니다

27~28 : Main에서 호출 할 수 있도록 정해진 메소드 setup 을 구현합니다.

 

이렇게 작성하면 ping.py 작성 및 준비는 끝났습니다.

Cogs의 요소를 작성했으니, 이제 Main에서 작성한 코드를 불러와야겠지요?

Main에서 app.start를 해주기 전에 cogs들을 로드 할 수 있도록 다음 동작을 추가합니다.

await app.load_extension(f"Cogs.ping")

그럼 main 메소드는 다음과 같이 되겠죠 !

async def main():
    async with app:
        await app.load_extension(f"Cogs.ping")
        file = open("discord_token.txt")
        bot_token = file.readline()
        file.close()
        await app.start(bot_token)

위 처럼 해주시면, 분리되어있는 ping.py 를 포함하여 Bot 이 동작하는것을 확인하실 수 있습니다.


Bot에 넣고싶은 기능이 한두가지가 아닌데, 하나씩 추가할때마다 일일히 넣긴 귀찮잖아요?

Cogs들을 알아서 불러올 수 있도록 소스코드를 추가해봅시다.

1
2
3
4
async def load_extensions():
    for filename in os.listdir("Cogs"):
        if filename.endswith(".py"):
            await app.load_extension(f"Cogs.{filename[:-3]}")
cs
async def load_extensions():

Cogs들을 load 하는 메소드를 하나 생성해줍니다.

for filename in os.listdir("Cogs"):

Cogs 디렉터리 안에 있는 모든 파일 내용을 읽어오는 반복문 입니다.

     if filename.endswith(".py"):
            # cut off the .py from the file name
            await app.load_extension(f"Cogs.{filename[:-3]}")

.py로 끝나는 파일들을 모두 load_extension을 통해 호출합니다

 

완성된 main 소스코드는 다음과 같습니다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import asyncio
import os
import discord
from discord.ext import commands
 
intents = discord.Intents.all()
app = commands.Bot(command_prefix='!', intents=intents)
 
 
async def load_extensions():
    for filename in os.listdir("Cogs"):
        if filename.endswith(".py"):
            await app.load_extension(f"Cogs.{filename[:-3]}")
    # cog 하나씩 불러오기
    # activate_list = ["ping"]
    # for name in activate_list:
    #     await app.load_extension(f"Cogs.{name}")
 
 
async def main():
    async with app:
        await load_extensions()
        file = open("discord_token.txt")
        bot_token = file.readline()
        file.close()
        await app.start(bot_token)
 
 
asyncio.run(main())
cs

포스팅에 사용된 모든 소스코드는 아래 Github에서 확인하실 수 있습니다.

https://github.com/aochfl/ChoRi_TestBot

 

GitHub - aochfl/ChoRi_TestBot

Contribute to aochfl/ChoRi_TestBot development by creating an account on GitHub.

github.com


참고자료

https://discord.com/developers/docs/reference - ( Discord Developer API )

https://discordpy.readthedocs.io/en/latest/index.html  -  ( discord.py library 문서 )

 

728x90
반응형