Ответы пользователя по тегу Python
  • Discord py не работает help, почему?

    Аргумент arg у вас не имеет стандартного значения. Аргументы без стандартного значения считаются обязательными аргументами.

    Добавьте стандартное значение аргумента или сделайте аргумент типа Optional.

    @bot.command()  # pass_context НЕ существует в текущей версии discord.py: https://discordpy.readthedocs.io/en/v1.4.1/migrating.html#context-changes
    async def help(ctx, arg = None):
        emb = discord.Embed(title = 'Помощь', colour = 0x2e2d2d)
    
        if arg == 'poll':
            emb.add_field(name = f"{ctx.prefix}poll", value = f"Использовать:\nder poll (название голосования), (первый параметр), (второй параметр), (и так до 9 раз)\nПример создания голосования:\npoll test, 1, 2")
            await ctx.send(embed = emb)
    
        else:
            emb.add_field(name = f"{ctx.prefix}poll", value = f"Создание голосовния.")
            await ctx.send(embed = emb)


    или

    from typing import Optional
    
    @commands.command()
    async def cmd(ctx, arg: Optional[str]): ...
    Ответ написан
    Комментировать
  • Выдача прав доступа?

    Две основные проблемы:
    1. Переменная guild не определена. В данном случае Вы, скорее всего, хотите получить её из контекста - ctx.guild
    2. Guild.voice_channels и Guild.text_channels - "списки" (list) с каналами соответствующего типа. Списки не имеют атрибута set_permissions. Данный атрибут есть у каналов в списке. Для установки прав для каждого канала нужно данный список итерировать.


    @client.command()
    async def set_permissions(сtx, role: discord.Role):
        for textchannel in ctx.guild.text_channels:
            await alltext.set_permissions(
                role,
                read_messages=True,
                send_messages=True,
                manage_channels=True,
                manage_roles=True,
            )
        for voicechannel in ctx.guild.voice_channels:
            await allvoice.set_permissions(
                role, connect=True, manage_channels=True, manage_roles=True
            )
        await ctx.send(
            f"{ctx.author.mention}, вы успешно установили {role.mention} права доступа во всех текстовых/голосовых каналах"
        )
    Ответ написан
    Комментировать
  • Игнорирование команды discord.py?

    F.A.Q./Why does on_message make my commands stop w...:
    Замена стандартного `on_message` предотвращает выполнение любых дополнительных команд. Для исправления этого добавьте добавьте строку `bot.process_commands(message)` в конце вашего `on_message`, например:

    @bot.event
    async def on_message(message):
        # делаем что-нибудь тут
    
        await bot.process_commands(message)
    Ответ написан
    Комментировать
  • Как сделать так, что бы event работал на одном сервере?

    Получайте сервер из объекта сообщения: discord.Message.guild

    if message.guild.id != 282480459897027773:
        return
    Ответ написан
    Комментировать
  • Как узнать всех пользователей которые поставили реакцию на выбранное сообщение в discord.py?

    Атрибут который вам нужен называется Message.reactions. discord.Reaction - тип возвращаемых объектов в reactions.

    discord.Message.reactions

    @bot.command()
    async def start(ctx):
        mess = await channel.send('Набор в игру')
        await asyncio.sleep(10)
        mess = await ctx.channel.fetch_message(mess.id)
        if yes_react := discord.utils.get(mess.reactions, emoji=ctx.guild.get_emoji(471483388532742130)):
            async for user in yes_react.users:
                print(str(user))  # выведет всех пользователей поставивших реакцию в консоль
    Ответ написан
    Комментировать
  • Почему не работает бот для 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
    Ответ написан
    Комментировать
  • Как сделать чтобы когда пишешь !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})"
    Ответ написан
    Комментировать
  • Очень странная ошибка в 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): ...
    Ответ написан
    Комментировать
  • Как правильно реализовать удаление сообщения через некоторое время?

    Используйте аргумент 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.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 комментария
  • Как исправить то что не работает 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 комментария
  • Как сделать так, чтобы бот считал сообщения различных пользователей и выводил их отдельно?

    Использовать Counter из стандартной библиотеки collections: https://docs.python.org/3/library/collections.html...

    from collections import Counter
    
    ...
    
    msg_count = Counter()
    
    @client.event
    async def on_message(msg):
        if msg.author == client.user:
            return
        global msg_count
        msg_count[msg.author.id] += 1
        print(f"Message by {msg.author}: {msg.content}")
    
    ...
    Ответ написан
    Комментировать
  • Как определить кол-во различный реакций, которые находятся на последнем сообщении бота?

    Всё что в данном коде неверно:
    1. @Bot.event только у события добавления реакции. Декоратор события должен быть у всех событий.
    2. Аргумент self у событий есть только в модулях (cogs). И представляет собой сам модуль
    3. if Y > N: ... выполняется только один раз - при запуске файла. Необходимо сделать чтобы оно либо менялось при обновлении (получении/удалении реакции), либо непосредственно перед выводом результата
    4. Ключевой (kwarg) аргумент pass_context не существует в текущей версии discord.py. Контекст передаётся в функцию команды первым аргументом всегда (за исключением момента с нахождением команды в вышеупомянутом "модуле")
    5. Объект "сообщение" не итерируемый
    6. PEP8 Naming Conventions: "CamelCase" названия переменных обозначают classы.


    Один из вариантов решения:
    voting_message = None
    @Bot.command()
    @commands.has_permissions(administrator=True)
    async def startvote(ctx):
        embed = discord.Embed(...)  # embed goes here
        voting_message = await ctx.send(embed=embed)
    
    @Bot.command()
    @commands.has_permissions(administrator=True)
    async def endvote(ctx):
        msg = await bot.get_channel(voting_message.channel.id).fetch_message(voting_message.id)
        y = discord.utils.get(msg.reactions, emoji="\N{WHITE HEAVY CHECK MARK}").count
        n = discord.utils.get(msg.reactions, emoji="\N{CROSS MARK}").count
        if y>n:
            result = "Принято"
        elif y==n:
            result = "Отказано (да = нет)"
        else:
            result = "Отказано"
        emb = discord.Embed(title=f'Окончено голосование.', description = 'Результат: ' + result, colour=discord.Color.purple())
        return await ctx.send(embed=emb) # **Возвращаем** сообщение после отправки.
        y, n = 0, 0
    Ответ написан
    Комментировать