Skip to content

Discord.py

discord.py는 현대적이고, 사용하기 쉽고, 많은 기능을 담고 있고, 비동기가 준비된 디스코드를 위한 API 래퍼입니다.

Features

  • async/await 구문을 사용한 최신의 Python스러운 API
  • 429 에러를 방지하기 위한 타당한 속도 제한
  • 모든 디스코드 API의 구현
  • 봇 생성에 도움을 주는 확장된 명령어
  • 객체 지향 설계로 간편한 사용
  • 속도와 메모리에 전부 최적화 됨

Install

pip install discord.py

Example

# -*- coding: utf-8 -*-

from argparse import Namespace

from discord import Intents
from discord.ext.commands import Bot
from discord.ext.commands.context import Context as CommandContext
from overrides import override

from api.aio.run import aio_run
from api.apps.discord.config import DiscordConfig
from api.arguments import version as version
from api.context.context import CommonContext
from api.logging.logging import logger


class DiscordContext(CommonContext):
    def __init__(self, args: Namespace):
        self._config = DiscordConfig.from_namespace(args)
        super().__init__(self._config)

        self._version = version()
        self._intents = Intents.default()
        self._intents.typing = False
        self._intents.presences = False
        self._intents.message_content = True
        self._bot = bot = Bot(
            command_prefix="$",
            intents=self._intents,
            sync_command=True,
            application_id=self._config.discord_application_id,
        )

        @bot.command(help="Shows version number")
        async def version(ctx: CommandContext) -> None:
            await self.on_version(ctx)

    @override
    async def on_mq_connect(self) -> None:
        logger.info("Connection to redis was successful!")

    @override
    async def on_mq_subscribe(self, channel: bytes, data: bytes) -> None:
        logger.info(f"Recv sub msg channel: {channel!r} -> {data!r}")

    @override
    async def on_mq_done(self) -> None:
        logger.warning("Redis task is done")

    async def on_version(self, ctx: CommandContext) -> None:
        await ctx.send(self._version)

    async def main(self) -> None:
        await self.open_common_context()
        try:
            await self._bot.start(token=self._config.discord_token)
        finally:
            await self.close_common_context()

    def run(self) -> None:
        aio_run(self.main(), self._config.use_uvloop)

Event

Example:

@bot.event
async def on_message(message):
    if message.author == bot.user:
        return

    # ignore all channels but the specified one
    if message.channel.id == requestsChannelID:
        # record request
        with open('requests.txt', 'a') as f:
            print(repr(message.content), file=f)
        reply = await message.channel.send('Got it!')

        # wait for 10 seconds, then delete message and reply
        await asyncio.sleep(10)
        await message.delete()
        await reply.delete()
    else:
        # process other commands (if there are none, delete this line)
        await bot.process_commands(message)

파일 다운로드

@client.event
async def on_message(message):

    if len(message.attachments) > 0:
        attachment = message.attachments[0]

    if (
        attachment.filename.endswith(".jpg")
        or attachment.filename.endswith(".jpeg")
        or attachment.filename.endswith(".png")
        or attachment.filename.endswith(".webp")
        or attachment.filename.endswith(".gif")
    ):
        img_data = requests.get(attachment.url).content
        with open("image_name.jpg", "wb") as handler:
            handler.write(img_data)

    elif (
        "https://images-ext-1.discordapp.net" in message.content
        or "https://tenor.com/view/" in message.content
    ):
        print(message.content)

Checks

To register a check for a command, we would have two ways of doing so. The first is using the check() decorator. For example:

async def is_owner(ctx):
    return ctx.author.id == 316026178463072268

@bot.command(name='eval')
@commands.check(is_owner)
async def _eval(ctx, *, code):
    """A bad example of an eval command"""
    await ctx.send(eval(code))

This would only evaluate the command if the function is_owner returns True. Sometimes we re-use a check often and want to split it into its own decorator. To do that we can just add another level of depth: content_copy

def is_owner():
    async def predicate(ctx):
        return ctx.author.id == 316026178463072268
    return commands.check(predicate)

@bot.command(name='eval')
@is_owner()
async def _eval(ctx, *, code):
    """A bad example of an eval command"""
    await ctx.send(eval(code))

See also

Favorite site