본문 바로가기
Discord/Discord Bot Python

Examples - 디스코드 봇 길드 기본(discord py)

by 깐테 2023. 8. 13.

Examples - Discord Guild 기본

https://github.com/Rapptz/discord.py/blob/master/examples/app_commands/basic.py

원본 코드는 위 페이지를 참조.

 

 

실행 전 설정 사항

1. dico_token.py 파일 내부에 길드 ID 정보 추가(서버 ID)

디스코드에서 Guild는 일반적으로 ‘서버’를 의미하며, 이 ID 값을 확인하기 위해서는 본인이 서버장 역할을 가지고 있는 서버의 아이콘 → 마우스 우클릭 → 서버 ID 복사하기를 통해 ID 정보를 확인 할 수 있다.

 

dico_token.py라는 이름으로 파일 생성 후 다음과 같이 작성하여 사용했다.

dico_token.py 내부에 토큰 정보를 적어준다. 토큰별로 파일을 개별 분리해도 좋다.

2. 채널 ID도 token에 함께 추가.

과정은 위와 동일하며, 본인이 서버장 역할을 가지고 있는 서버 → 채팅 채널 마우스 우클릭 → 채널 ID 복사

위 코드에 원하는 이름으로 만들고 동일하게 사용.

채널 아이디도 dico_token.py 파일 내부에 적어준다. 파일명은 마음대로.

 


 

해당 코드에는 길드와 관련된 기본적인 여러 기능들이 들어 있다.

 

서버 내에서 메시지를 보내거나 신고 기능, 기본적인 응답 기능들을 포함하고 있으며 슬래시 커맨드(’/’), context menu를 활성화 하여 사용할 수 있는 코드도 포함하고 있다.

 

해당 코드는 길드 멤버 전체가 사용 가능하도록 처리했기 때문에 권한 별로 사용하기 위해서는 따로 코드를 수정하거나 권한을 수정해줘야 한다.

 

 

async def setup_hook(self):
        # This copies the global commands over to your guild.
        self.tree.copy_global_to(guild=MY_GUILD)
        await self.tree.sync(guild=MY_GUILD)

setup_hook 설명 살펴보기

  • setup_hook에는 봇이 로그인 한 다음 비동기 설정을 수행할 코드를 작성한다.
    login() 에서 한 번만 호출되고, 다른 이벤트들이 전달되기 전에 호출되기 때문에 on_ready() 에서 설정하는 것보다 더 나은 솔루션이 될 수 있다.
  • copy_global_to 명령어를 통해 해당 길드에서 Global Commands를 사용할 수 있도록 설정한다.
  • @client.tree.command() 어노테이션을 통해 해당 커맨드를 슬래시 커맨드로 사용할 수 있도록 설정한다.
  • 여기서 MY_GUILD는 discord.object 로 위에서 작성한 guild_id 값을 호출하여 사용한다.

 

  • 디스코드에서 / 를 입력하면 사진과 같이 커맨드가 표시된다.

 

 

Context Menu 기능

https://discordpy.readthedocs.io/en/latest/interactions/api.html?highlight=context_menu#discord.app_commands.CommandTree.context_menu

# This context menu command only works on members
@client.tree.context_menu(name='Show Join Date')
async def show_join_date(interaction: discord.Interaction, member: discord.Member):
    # The format_dt function formats the date time into a human readable representation in the official client
    await interaction.response.send_message(f'{member} joined at {discord.utils.format_dt(member.joined_at)}')
  • context_menu 어노테이션이 붙어있는 경우 봇이 실행 중인 동안 서버 내 유저를 우클릭 → 앱 → [작성한 기능 이름]을 클릭하여 확인할 수 있다.
  • 위 코드는 해당 유저가 언제 서버에 들어왔는지를 표시하는 기능 코드.

 

  • 서버 내 유저 우클릭 → 앱 선택 시 표시되는 context menu에서 확인 가능하다.
  • 해당 메뉴 클릭 시 언제 서버에 들어왔는지 메시지로 출력.

 

 

Context Menu - Message

# This context menu command only works on messages
# 해당 메뉴는 메시지를 우클릭 했을 때만 보여지는 기능.
# 길드에 권한을 가진 유저가 메시지를 신고하면, 해당 메시지가 설정한 채널에 embed 형식으로 전달됨.
@client.tree.context_menu(name='Report to Moderators')
async def report_message(interaction: discord.Interaction, message: discord.Message):
    # We're sending this response message with ephemeral=True, so only the command executor can see it
    
    await interaction.response.send_message(
        f'Thanks for reporting this message by {message.author.mention} to our moderators.', ephemeral=True
    )

    # Handle report by sending it into a log channel
    # 사용자가 설정한 channel ID에 해당하는 채널로 신고 리포트 메시지가 전송된다.
    log_channel = interaction.guild.get_channel(channel3_id)  # replace with your channel id

    embed = discord.Embed(title='Reported Message')
    if message.content:
        embed.description = message.content

    embed.set_author(name=message.author.display_name, icon_url=message.author.display_avatar.url)
    embed.timestamp = message.created_at

    url_view = discord.ui.View()
    url_view.add_item(discord.ui.Button(label='Go to Message', style=discord.ButtonStyle.url, url=message.jump_url))

    await log_channel.send(embed=embed, view=url_view)
  • 사용자가 설정한 channel ID에 해당하는 채널로 신고 메시지 전송. (본인은 여러 채널을 만들어서 하나의 채널에 메시지가 가도록 설정)
  • 위에 설명한 내용은 유저 클릭 → 메시지 → 앱 클릭 시 나타나는 Context Menu.
  • report 클릭 시 접수되었다는 안내 메시지가 출력 되고, 설정해둔 채널에 메시지 전달
  • Go to Message 클릭 시 해당 메시지가 있던 위치로 이동.
    웹 개발 시 볼 수 있는 앵커와 같은 기능을 한다고 생각하면 된다.

 

 

전체 코드

from typing import Optional

import discord
from discord import app_commands
from dico_token import Token, guild_id, channel3_id

# Guild = 디스코드의 서버를 의미
# @client.tree.command() 함수를 이용하면 디스코드 슬래시 커맨드에 등록하여 사용할 수 있도록 처리

MY_GUILD = discord.Object(id=guild_id)  # replace with your guild id


class MyClient(discord.Client):
    def __init__(self, *, intents: discord.Intents):
        super().__init__(intents=intents)
        # A CommandTree is a special type that holds all the application command
        # state required to make it work. This is a separate class because it
        # allows all the extra state to be opt-in.
        # Whenever you want to work with application commands, your tree is used
        # to store and work with them.
        # Note: When using commands.Bot instead of discord.Client, the bot will
        # maintain its own tree instead.
        self.tree = app_commands.CommandTree(self)

    # In this basic example, we just synchronize the app commands to one guild.
    # Instead of specifying a guild to every command, we copy over our global commands instead.
    # By doing so, we don't have to wait up to an hour until they are shown to the end-user.
    async def setup_hook(self):
        # This copies the global commands over to your guild.
        self.tree.copy_global_to(guild=MY_GUILD)
        await self.tree.sync(guild=MY_GUILD)


intents = discord.Intents.default()
client = MyClient(intents=intents)


@client.event
async def on_ready():
    print(f'Logged in as {client.user} (ID: {client.user.id})')
    print('------')


@client.tree.command()
async def hello(interaction: discord.Interaction):
    """Says hello!"""
    await interaction.response.send_message(f'Hi, {interaction.user.mention}')


@client.tree.command()
@app_commands.describe(
    first_value='The first value you want to add something to',
    second_value='The value you want to add to the first value',
)
async def add(interaction: discord.Interaction, first_value: int, second_value: int):
    """Adds two numbers together."""
    await interaction.response.send_message(f'{first_value} + {second_value} = {first_value + second_value}')


# The rename decorator allows us to change the display of the parameter on Discord.
# In this example, even though we use `text_to_send` in the code, the client will use `text` instead.
# Note that other decorators will still refer to it as `text_to_send` in the code.
@client.tree.command()
@app_commands.rename(text_to_send='text') # 파라미터 설명 부분에 표시되는 텍스트를 해당 이름으로 표시한다.
@app_commands.describe(text_to_send='Text to send in the current channel')
async def send(interaction: discord.Interaction, text_to_send: str):
    """Sends the text into the current channel."""
    await interaction.response.send_message(text_to_send)


# To make an argument optional, you can either give it a supported default argument
# or you can mark it as Optional from the typing standard library. This example does both.
# 해당 멤버가 언제 서버에 들어왔는지를 명령어를 이용하여 보여준다.
@client.tree.command()
@app_commands.describe(member='The member you want to get the joined date from; defaults to the user who uses the command')
async def joined(interaction: discord.Interaction, member: Optional[discord.Member] = None):
    """Says when a member joined."""
    # If no member is explicitly provided then we use the command user here
    member = member or interaction.user

    # The format_dt function formats the date time into a human readable representation in the official client
    await interaction.response.send_message(f'{member} joined {discord.utils.format_dt(member.joined_at)}')


# A Context Menu command is an app command that can be run on a member or on a message by
# accessing a menu within the client, usually via right clicking.
# It always takes an interaction as its first parameter and a Member or Message as its second parameter.
# 아래에 작성한 코드들은 메뉴에 표시하도록 처리한 코드들.
# 메시지 또는 서버 내의 멤버를 마우스로 우클릭 했을 때 표시되는 context menu에서 확인 가능

# This context menu command only works on members
@client.tree.context_menu(name='Show Join Date')
async def show_join_date(interaction: discord.Interaction, member: discord.Member):
    # The format_dt function formats the date time into a human readable representation in the official client
    await interaction.response.send_message(f'{member} joined at {discord.utils.format_dt(member.joined_at)}')


# This context menu command only works on messages
# 해당 메뉴는 메시지를 우클릭 했을 때만 보여지는 기능.
# 길드에 권한을 가진 유저가 메시지를 신고하면, 해당 메시지가 설정한 채널에 embed 형식으로 전달됨.
@client.tree.context_menu(name='Report to Moderators')
async def report_message(interaction: discord.Interaction, message: discord.Message):
    # We're sending this response message with ephemeral=True, so only the command executor can see it
    await interaction.response.send_message(
        f'Thanks for reporting this message by {message.author.mention} to our moderators.', ephemeral=True
    )

    # Handle report by sending it into a log channel
    # 사용자가 설정한 channel ID에 해당하는 채널로 신고 리포트 메시지가 전송된다.
    log_channel = interaction.guild.get_channel(channel3_id)  # replace with your channel id

    embed = discord.Embed(title='Reported Message')
    if message.content:
        embed.description = message.content

    embed.set_author(name=message.author.display_name, icon_url=message.author.display_avatar.url)
    embed.timestamp = message.created_at

    url_view = discord.ui.View()
    url_view.add_item(discord.ui.Button(label='Go to Message', style=discord.ButtonStyle.url, url=message.jump_url))

    await log_channel.send(embed=embed, view=url_view)


client.run(Token)

 

반응형