2.파이썬을 이용한 디스코드 봇 만들기: discord.py API

3 분 소요

discord.py API에 대해

지난 글에 이어서 이번에는 저희가 만들었던 코드에 대해 자세하게 알아보기 위해 discord.py의 API에 대해 알아보겠습니다.

1. Bot 클래스

import discord
from discord.ext import commands

bot = commands.Bot(command_prefix='!')

먼저 discord.ext 라이브러리에 들어가보시면 아래와 같이 commands.Bot 클래스가 가지는 속성 값들이 매우 다양하게 존재하는것을 알 수 있습니다.

discord1
각각의 속성들은 사용자의 편의에 따라 설정해줄 수 있으므로 자신이 원하는 기능을 구현하고 싶을 경우 그 부분에 대해 알아보는것이 매우 중요합니다.

이때 저희가 알아볼것은 status, activity, help_command 입니다.

  1. status
    먼저 status는 말그대로 봇의 상태를 의미합니다. 이는 디스코드 사용자가 자신의 현재 상태를 설정하는 것과 동일한 기능입니다.
    discord2
    이처럼 디스코드에서의 상태는 4가지로 구분됩니다. 이때 상태는 discord.Status 클래스이며 각각의 상태값은 아래와 같이 표현이 가능합니다.

    • 온라인 -> online
    • 자리 비움 -> idle
    • 다른 용무 중 -> dnd / do_not_disturb
    • 오프라인 표시 -> invisible
    • 오프라인 -> offline

    봇의 상태를 적용하는것은 간단합니다. 저희가 설정하고 싶은 것은 봇의 status 이므로 봇의 인스턴스를 생성할 때 discord.Status클래스를 이용하여 설정해줄 수 있습니다.

    bot = commands.Bot(status=discord.Status.dnd) # 다른 용무 중
    

    discord3

    이때 오프라인 표시 인 invisible의 경우 봇에게 적용하려면 기존의 방법과는 다르게 commands.Bot.change_presence 함수를 이용해야 합니다. 자세한 내용은 API를 참조하세요.

  2. activity 디스코드에서는 사용자가 어떤 활동을 하고있는지를 인식하여 다른 사용자들에게 표현할 수 있습니다. 이는 대부분 하는 중, 듣는 중, 방송 중과 같습니다.
    모든 활동은 discord.Activity, discord.Game 또는 discord.Streaming 클래스로 표현합니다.
    여기서 저희는 discord.Game 클래스로 현재 봇의 활동을 표현해보겠습니다.

    bot_activity = discord.Game(name='블로그 작성')
    bot = commands.Bot(activity=bot_activity)
    

    discord4

  3. help_command discord.py 라이브러리에서는 봇의 명령어에 대한 help 명령어를 자동으로 지원합니다. 이는 간단히 어떤 명령어들이 사용 가능한지를 확인할 수 있을 뿐만 아니라 해당 명령어에 필요한 세부 조건들을 쉽게 알아볼 수도 있습니다. 간단하게 help 또는 help (명령어)로 확인할 수 있습니다.

    discord5

    하지만 봇을 개발하면서 직접 도움말 명령어를 자신의 입맛에 맞게 표현하고 싶을 경우에는 discord.py에서 제공하는 help 기능을 사용하지 않을 수 있습니다.

    bot = commands.Bot(help_command=None)
    

    commands.HelpCommand 클래스를 통하여 discord.py에서 기본으로 제공하는 help 명령어를 수정하는것도 가능합니다. 관심있으신 분은 해당 API 문서를 참고하시기 바랍니다!

Context 클래스

두번째로 Context에 대해 알아봅시다!

저희가 작성했던 봇의 명령어를 잠깐 보시면

@bot.command()
async def 안녕(ctx):
    await ctx.send("반갑습니다")

이와 같이 봇의 명령어를 통해 ctx라는 변수를 매개변수로 받는것을 알 수 있습니다. 이때의 ctx가 바로 Context를 의미합니다. commands.Context 클래스는 여러가지 값들을 가지고있기 때문에 이를 응용하여 여러 표현이 가능합니다.

@bot.command()
async def 안녕(ctx):
    await ctx.send("{}이라고 하셨군요, 반갑습니다 {}님!".format(
        ctx.message.content, ctx.author.name))

discord6

Context가 중요한 이유는 모든 봇의 명령어들은 ctx*args를 매개변수로 받을 수 있기 때문입니다. 따라서 봇은 사용자의 ctx를 통해 답장을 보낼 수 있는 것입니다!

3. Guild 클래스

다음으로 알아볼 것은 discord.Guild 클래스 입니다. 디스코드에서 길드는 디스코드의 서버를 의미합니다! 따라서 개인이 만든 각각의 디스코드 서버들을 길드로 표현한다고 생각하시면 됩니다.

discord.Guild를 통해 디스코드 서버에 대한 다양한 데이터들에 접근이 가능합니다. 저희는 간단하게 현재 봇이 접속해있는 서버의 정보에 대해 알아보겠습니다.

@bot.command()
async def 정보(ctx):
    members = [member.name for member in ctx.guild.members]
    await ctx.send(
        "{} 서버는 {} 서버이며 구성원은 {} 이고 총 {} 명입니다.".format(
            ctx.guild.name, 
            ctx.guild.region, 
            members, 
            ctx.guild.member_count
        )
    )

discord7

이와 같이 디스코드 서버와 관련된 여러 정보들을 얻을 수 있으며 해당 API 문서에서 더 많은 정보를 찾으실 수 있습니다!

그러면 앞서 배운 discord.py 라이브러리의 여러 클래스들과 디스코드에서 제공하는 @bot.event를 응용하여 봇에게 간단한 기능을 추가해보고 마무리 하겠습니다. 감사합니다!

@bot.event
async def on_voice_state_update(member, before, after):
    if before.channel is None and after.channel is not None:
        await member.guild.system_channel.send(
            "{}님이 보이스 채널에 접속했습니다.".format(member.name)
        )

discord8

부록.

1. 디스코드의 namenick의 차이

디스코드의 사용자들은 자신의 이름과 별개로 각각의 서버마다 자신의 별명을 설정할 수 있습니다. 따라서 디스코드 봇을 개발할때도 내가 유저의 이름을 표현할 것인지 별명을 표현할 것인지 구분지어야 합니다. 이는 discord.Member.name 또는 discord.Member.nick으로 접근 가능합니다.

@bot.command()
async def 이름(ctx):
    await ctx.send("이름: {}, 별명: {}".format(
        ctx.author.name, ctx.author.nick))

만약 해당 사용자가 별명이 없는경우는 None을 리턴합니다.

2. Intents의 필요성

앞서 코드를 예로 들겠습니다.

@bot.command()
async def 어드민(ctx):
    await ctx.send("서버의 어드민은 {} 입니다.".format(
        ctx.guild.owner
    ))

이 명령어는 해당 디스코드 서버의 주인이 누군지 출력하는 간단한 명령어입니다.
discord.Guild 클래스의 속성인 owner를 통해 값에 접근하는것이지요.
하지만 기본적으로 이 속성값은 None을 리턴합니다. 이유가 무엇일까요?

discord9

discord.py 1.5 버전부터는 디스코드 봇에 대한 Intents(의도)를 명시해야 합니다. 하지만 이는 필수적인 것은 아니고 대부분의 경우는 Intents를 코딩하지 않아도 잘 작동합니다. 이것은 나의 봇이 어떤 행동을 할 것이고, 어떤 행동을 하지 않을 것인지를 문서화하는 것입니다.

하지만 이와 다르게 반드시 Intents를 명시해야 하는, Privileged Intents가 존재합니다. 앞서 예로 든 코드처럼 discord.Guild.owner와 같이 Privileged Intents에는 두가지 경우가 있습니다.

  1. PRESENCE INTENT
  2. SERVER MEMBERS INTENT

Intents를 명시하는 방법은 해당 API 문서에서 자세히 볼 수 있습니다. 간단하게 코드로 설명하자면

intents = discord.Intents.default()
intents.members = True

bot = commands.Bot(intents=intents)

discord10

이와 같이 코드를 통해 Intents를 설정한후에 Discord Developer Portal에 접속하여 Bot에 자신이 사용할 Privileged Intents를 체크해주면 됩니다.

discord11

댓글남기기