• Почему не работает бот для Discord?

    Декоратор bot.event используется только для событий.

    Для команд необходим декоратор @bot.command() или @commands.command() в модулях.

    А так же: Сравнение текущей даты с датой рождения - некорректно. Дата с текущим годом != дате с годом рождения.

    from datetime import date
    
    import discord
    from datetime import date
    
    
    @bot.command()
    async def bdays4(ctx):
        cur_year = date.today().year
        bdays = {
            "Kenshi": date(day=12, month=8, year=1997),
            "Broody": date(day=11, month=11, year=1009),
            "Melanie": date(day=22, month=1, year=1941),
            "Blueface Baby": date(day=18, month=8, year=2020),
        }
    
        for bday_name, date in bdays.items():
            bday = date.update(year=cur_year)
            if bday == date.today():
                await ctx.send(
                    embed=discord.Embed(
                        description=f"Happy birthday {bday_name}",
                        colour=discord.Color.green(),
                    )
                )
    Ответ написан
    Комментировать
  • Как сделать страницы?

    Самый простой способ - использовать discord.ext.menus.

    Примеры постраничного вывода приведены в README.md
    Ответ написан
    Комментировать
  • Как обновить сообщение в discord.py?

    discord.Message.edit

    from asyncio import sleep
    @commands.command()
    async def test(self, ctx):
        embed = discord.Embed(title="No")
        msg = await ctx.send(embed=embed)
        embed.description = "Well, actually, yes"
        await sleep(5)
        await msg.edit(embed=embed)
    Ответ написан
    Комментировать
  • Как сделать чтобы когда пишешь !avatar @ (без пользователя, просто с @), не выдавало ошибку?

    Ловить ошибку в событии on_error_command(context, error): https://discordpy.readthedocs.io/en/v1.4.1/ext/com...

    Либо в наследуемом классе:
    from discord.ext import commands
    from contextlib import suppress
    
    class MyBot(commands.Bot):
        async def on_command_error(self, ctx, error):
            if isinstance(error, commands.BadArgument):
                await ctx.send(f"Неверный аргумент: {error.message}")
            else:
                await super().on_command_error(ctx, error)  # вызывает изначальное поведение on_error_message
    
    bot = MyBot(command_prefix="!")


    Либо просто в функции-"слушателе":
    from discord.ext import commands
    from contextlib import suppress
    
    bot = commands.Bot(command_prefix="!")
    
    @bot.event
    async def on_command_error(ctx, error):
        if isinstance(error, commands.BadArgument):
            await ctx.send(f"Неверный аргумент: {error.message}")
    Ответ написан
    Комментировать
  • Как отправить embed типа object в дискорд используя webhook?

    По названию функции .post, рискну предположить что Disc - экземпляр объекта типа aiohttp.ClientSession. Он не знает что такое дискорд.

    Несколько вариантов развития событий решения:
    1. Вы продолжаете использовать сессию для подключения и отправки запросов вручную. В таком случае вам необходимо самостоятельно передавать json endpoint'у вебхука. Получить dict для передачи в аргумент json функции post можно через Embed.to_dict().
    import discord
    import aiohttp
    
    session = aiohttp.ClientSession()
    
    # Discord поддерживает только markdown для форматирования. html-теги (<i> и прочие) будут отображаться напрямую
    embed_obj = discord.Embed(
        title="*Заголовок*", colour=0x21D3CD, url="https://example.com"
    )  # Цвет в HEX более читаемый
    embed_obj.set_image(url="https://via.placeholder.com/140x100")
    embed_obj.set_thumbnail(url="https://via.placeholder.com/140x100")
    embed_obj.set_footer(text="*Текст*", icon_url="https://via.placeholder.com/140x100")
    embed_obj.set_author(
        name="*Текст*",
        url="https://example.com",
        icon_url="https://via.placeholder.com/140x100",
    )
    embed_obj.add_field(
        name="*Текст*", value="\N{Zero Width Space}"
    )  # Значение поля не может быть пустым, такой embed дискорд отклонит. Используем визуально пустой символ для этого.
    await session.post(
        "https://discord.com/api/webhooks/%WEBHOOK_ID%/%WEBHOOK_TOKEN",
        json={"embeds": [embed_obj.to_dict()]},
    )


    2. Использовать поддержку вебхуков из discord.py: https://discordpy.readthedocs.io/en/v1.4.1/api.htm....
    import aiohttp
    import discord
    
    session = aiohttp.ClientSession()
    webhook = discord.Webhook.from_url(
        "https://discord.com/api/webhooks/%WEBHOOK_ID%/%WEBHOOK_TOKEN",
        adapter=discord.AsyncWebhookAdapter(session),
    )
    embed_obj = ...
    await webhook.send(embed=embed_obj)
    Ответ написан
    Комментировать
  • Как вывести название дс сервера?

    В on_guild_join передаётся аргумент guild, который и является сервером, к которому присоединился бот.
    https://discordpy.readthedocs.io/en/v1.4.1/api.htm...

    import logging
    
    @listener  # client.event / commands.Cog.listener / etc...
    async def on_guild_join(guild):
        logging.info(f"Joined guild {guild.name} ({guild.id})"
    Ответ написан
    Комментировать
  • Как сделать автовыдачу ролей?

    >on_member_join(member)<
    @Bot.event
    async def on_member_join(member):
        if role := member.guild.get_role(418187634689139935):
            await member.add_roles(role)
    Ответ написан
    4 комментария
  • Дискорд сервер, как сделать такой значок возле канала в дискорд?

    С недавних пор (примерно с неделю как) достаточно включить функции сообщества. Теперь они доступны всем серверам.

    Включить их можно в настройках сервера
    4UsAYDk.png

    После включения вам будут доступны каналы для оповещений и меню приветствия
    2nmy6eZ.png
    Ответ написан
    Комментировать
  • Очень странная ошибка в Discord.py связанная с "ctx"?

    Поярдковые аргументы со стандартными значениями могут находиться только перед такими же аргументами со стандартными значениями.

    def func(a, b: int = 0, c) - не работает, так как a, b и c являются порядковым аргументом.
    def func(a, b: int = 0, c = 0) - работает

    В вашем случае, если вы хотите чтобы аргумент member был опциональным, используйте typing.Optional:
    from typing import Optional
    
    ...
    
    @commands.command()
    async def cmd(ctx, member: Optional[discord.Member], count: int): ...
    Ответ написан
    Комментировать
  • Как отреагировать на реакцию пользователя?

    bot.wait_for("reaction_add"): https://discordpy.readthedocs.io/en/v1.3.4/api.htm...

    @bot.command(ctx):
    async def test(ctx):
        accept_decline = await ctx.send('Test')
        await accept_decline.add_reaction('one')
        try:
            reaction = await bot.wait_for("reaction_add", timeout=60, check = lambda r, u: r=='one' )
        except asyncio.TimeoutError:
            await channel.send("\N{THUMBS DOWN SIGN}")
        else:
            await channel.send("\N{THUMBS UP SIGN}")
    Ответ написан
    Комментировать
  • Как отправить сообщение в чат по ID чата - discord.py rewrite?

    bot.get_channel в качестве аргумента принимает ID в типе int. По умолчанию все аргументы передаваемые в команду парсером, передаются туда как str, если не указан иной тип. В вашем случае эта функция никогда не вернёт канал.

    Самый адекватный метод решения в контексте discord.py: Использовать конвертеры.
    @bot.command()
    async def news(ctx, channel: discord.TextChannel, *, text):  # используем kwargs для отсутствия необходимости написания ковычек: https://discordpy.readthedocs.io/en/stable/ext/commands/commands.html#keyword-only-arguments
        emb= discord.Embed(title='Новость!!!',description=f'{text}', timestamp=ctx.message.created_at)
        await channel.send(embed=emb)

    Это позволит получать канал в команде не только по ID, но так же по его упоминанию или просто по названию
    Ответ написан
    1 комментарий
  • Как правильно реализовать удаление сообщения через некоторое время?

    Используйте аргумент delete_after функции send.
    @client.command(aliases = ['очистить', 'клеар', 'clr' ,'клр'])
    @commands.has_permissions(administrator = True)
    async def clear( ctx, amount : int):
        await ctx.message.delete()
        await ctx.channel.purge(limit = amount)
        await ctx.send(embed = discord.Embed(description = f':white_check_mark: удалено {amount} сообщений(я)'), delete_after=5)
    Ответ написан
    1 комментарий
  • Почему не запускается бот на discord.py?

    Обновите библиотеку. Дискорд добавил два новых поля в API, что не было предусмотренно библиотекой. Это исправлено в версии 1.3.4.
    Подробнее: discord.py#5109
    Ответ написан
  • Discord.py как сделать глобальный чат?

    Через discord.utils.get вы получаете канал того сервера, в котором было написано сообщение.

    Он принадлежит тому серверу, в котором написано сообщение. Объект канала с таким же названием на других серверах будет другим.

    Следовательно: вам нужно искать канал на том сервере, на который сообщение отправляется
    GLOBAL_CHAT = 'глобальный-чат'  # PEP8: Названия констант пишутся капсом
    
    @client.event
    async def on_message(message):
        channel = discord.utils.get(message.guild.text_channels, name=GLOBAL_CHAT)
        if message.author.id == client.user.id:
            return  # return предотвратит выполнение следующего кода
        if message.channel.id != channel.id:
            return
        await message.delete()  # удаляем сообщение один раз
        for guild in client.guilds:
            if channel := discord.utils.get(guild.text_channels, name=GLOBAL_CHAT):
                # py3.8: walrus operator ("моржовый" оператор)
                # равносильно следующему:
                # channel = discord.utils.get(guild.text_channels, name=GLOBAL_CHAT)
                # if channel: ...
                try:
                    await channel.send('**{0.author}:** {0.content}'.format(message))
                except discord.Forbidden:
                    print(f"Невозможно отправить сообщение на сервер {guild.name}: Недостаточно прав")
                except discord.HTTPException as e:
                    print(f"Невозможно отправить сообщение на сервер {guild.name}: {e}")
    Ответ написан
    1 комментарий
  • Как ограничить доступ к каналу пользователям с одинаковыми никами?

    У discord.Member есть аттрибут id.

    @bot.event
    async def on_voice_state_update(member, before, after):
        clients = [969338428647912064, 424184503818564866, 424184503818564866]
        role = bot.get_role(240688302893711904)
        if not before.channel and after.channel:
            if member.id in clients:
                await member.add_roles(role)
        elif before.channel and not after.channel:
            await member.remove_roles(role)
    Ответ написан
    3 комментария
  • Как сделать "раздельные команды" в discord.py?

    Для обычных "вложенных" команд используйте группы команд

    Впрочем, в ситуации в изложенной в вашем вопросе это не поможет.

    В вашей ситуации я вижу два варианта:
    1. Отказаться от встроенной команды help и создать свою, с методом группы команд
    bot.remove_command("help")
    
    @bot.group(invoke_without_command=True)
    async def help(ctx, ...):
        ...  # вручную построенная/собирающая команда help.
    
    @help.command()
    async def islam(ctx, ...):
        ...  # подкоманда help

    2. Просто использовать docstring в методе команды для вывода нужной информации
    @bot.command()
    async def islam(ctx):
        """Описание команды"""
        ...

    2.1 Так же можно использовать аргументы декоратора:
    @bot.command(
        help="Данный текст будет использоваться в полноразмерной помощи (help islam)", 
        brief="Данный текст будет отображаться в help рядом с командой", 
        usage="Данный текст будет отображаться вместо автоматического построенного текста для аргументов (таких как <arg> [arg] и т.д.)"
    )
    async def islam(ctx):
        ...
    Ответ написан
    Комментировать
  • Как перенаправлять сообщения от пользователи, в embed бота?

    Два варианта:
    1. То как предложил Александр, использовать параметры команды:
    @bot.command()
    async def report(ctx, user: discord.Membmer, *, reason: str):  # первый kwarg используется как "собирающий" аргумент
    # https://discordpy.readthedocs.io/en/v1.3.4/ext/commands/commands.html#keyword-only-arguments
        ...

    Команда в таком случае будет вызываться следующим образом: [p]report User#0000 Нарушение правила 42
    2. Ждать ответа:
    Для этого вам понадобиться ждать события сообщения:
    https://discordpy.readthedocs.io/en/v1.3.4/api.htm...
    from asyncio import TimeoutError as AsyncTimeoutError
    
    @bot.command()
    async def report(ctx):
        ...
        try:
            member = await bot.wait_for("message", check=lambda m: m.author == ctx.author, timeout = 60)  # Базовая проверка - будет ловить сообщения от пользователя запустившего команду везде.
        except AsyncTimeoutError:
            await ctx.send("Вы уснули, я ушёл")
            return
         # На данный момент переменная "member" является лишь строкой, и не факт что это реальный пользователь
         # Используем конвертер для перевода из строки в пользователя
         # https://discordpy.readthedocs.io/en/v1.3.4/ext/commands/api.html#discord.ext.commands.MemberConverter
         try:
             member = commands.MemberConverter().convert(ctx, member)
         except commands.BadArgument:
             await ctx.send("Это не пользователь, кого вы пытаетесь ~~на...~~ обмануть")
             return
          # и тоже самое для причины
    Ответ написан
    4 комментария
  • Как добавить пару функций в on_member_update?

    Получать данные из лога аудита.
    @client.event
    async def on_member_update(before, after):
        if before.roles != after.roles:
            channel = client.get_channel(729733881129074768)
            emb = discord.Embed(description = f'**Обновление ролей пользователя -  {before.mention}**', colour = discord.Color.red())
            emb.add_field(name = '**Роли до**', value = ", ".join([r.mention for r in before.roles])) 
            emb.add_field(name = '**Роли после**', value = ", ".join([r.mention for r in after.roles])) 
            async for event in before.guild.audit_logs(limit=1, action=discord.AuditLogAction.member_role_update): # https://discordpy.readthedocs.io/en/v1.3.4/api.html#discord.AuditLogAction.member_role_update
                # event: AuditLogEntry — https://discordpy.readthedocs.io/en/v1.3.4/api.html#discord.AuditLogEntry
                if getattr(event.target, "id", None) != before.id:
                    # изменение ролей пользователя прошло без записи в логах аудита, или в лог аудита попала другая запись перед выполнением текущего участка кода
                    continue
                emb.add_field(name="Изменённые роли", value = ", ".join([getattr(r, "mention", r.id) for r in event.before.roles or event.after.roles]))  # event.before, event.after: AuditLogDiff — https://discordpy.readthedocs.io/en/v1.3.4/api.html#discord.AuditLogDiff 
                emb.add_field(name="Модератор", value = event.user)
                break
            await channel.send(embed = emb)
    Ответ написан
  • Как исправить то что не работает await и код выполняется дальше без данных с DB?

    Выполнение синхронного кода в пулах треда или процесса

    Как говорит import this:
    Simple is better than complex.

    Я чисто не вижу смысла во всех этих sync_to_asyncи прочих.
    database_sync_to_async вовсе не используется в данном коде.

    Используйте расширение discord.py называемое "commands". Оно идёт вместе с библиотекой и значительно упрощает жизнь при написании команд.
    Errors should never pass silently.
    Unless explicitly silenced.


    Переподключать бота при любой ошибке - смахивает на ОЧЕНЬ плохую идею.

    import asyncio
    import os
    from functools import partial
    
    import discord
    from discord.ext import commands
    from allauth.socialaccount.models import SocialAccount
    
    from main.models import Game, Purchase, Key
    
    
    bot = commands.Bot()
    
    
    @bot.event
    async def on_ready():
        print('We have logged in as {0.user}'.format(bot))
    
    @commands.command()
    async def hello(ctx):
        game = (await bot.loop.run_in_executor(None, Game.objects.all))[0]
        await ctx.send(game.name)
    
    @bot.event
    async def on_member_join(member):
        allAccounts = await bot.loop.run_in_executor(None, SocialAccount.objects.all)
        for acc in allAccounts:
            if acc.extra_data['id'] == str(member.id):
                account_id = acc.extra_data['id']
                purchases = await bot.loop.run_in_executor(None, partial(Key.objects.filter, user__id=account_id))
                keys = [await bot.loop.run_in_executor(None, partial(Key.objects.filter, purchase__id=purchase.id)) for purchase in purchases]
        for key in keys:
            role = discord.utils.get(member.guild.roles, id=key.cheat.ds_role_id)
            print(str(key.cheat.ds_role_id))
            await member.add_roles(role)
            break
    
    
    bot.run(os.environ.get('DS_BOT_TOKEN'))

    Возможно данный код вам чем-то поможет. Написано без учёта содержимого SocialAccount и main.models, поэтому код затрагивающий их остался примерно неизменным.
    Отступы так же были угаданы чисто по коду.
    Ответ написан
    2 комментария