Discord.py Команда с таймером

Хотелось бы попросить помощи.

Хочу сделать бота, который будет после команды создавать сообщение и создавать реакцию под своим сообщением, а после определенного промежутка времени (которое я укажу в команде) он будет выбирать рандомно тех людей, которые прожали реакцию бота и пингом, выбирать их.

Облазил много вариантов, но так и не нашел ни инфы, ни примера команды. Либо я глупый, либо не умею искать. Буду благодарен даже за информацию по моему вопросу!

Заранее благодарю.


Ответы (1 шт):

Автор решения: denisnumb

Не ищите готовый код, а постарайтесь придумать реализацию самостоятельно. Искать в этом деле нужно только отдельные, непонятные вам этапы создания команды.

На самом деле здесь главное начать)

*Cразу извините за длинный ответ, просто хочется, чтобы вы разобрались, а не просто скопировали код)


Создайте команду, которая принимает необходимые для полной работы параметры и создает сообщение - на вряд ли здесь возникнут трудности:

@bot.command()
async def random_pick(ctx, wait_seconds: int):
    msg = await ctx.send('Нажмите ? внизу, чтобы участвовать')

Команда принимает время для ожидания и создает сообщение, но реакции под ним пока нет.

Что делать, если не знаете как работать с реакциями? Гуглить или читать документацию, где все подробно расписано. Советую почитать краткое руководство.

Вбиваем в поиск ключевое слово reaction и в списке видим что-то похожее на то, что мы ищем:

введите сюда описание изображения

Выходит, теперь известно, как поставить реакцию под сообщением - добавляем это и подключим в функцию ожидание в течение wait_seconds:

@bot.command()
async def random_pick(ctx, wait_seconds: int):
    msg = await ctx.send('Нажмите ? внизу, чтобы участвовать')
    await msg.add_reaction('?')
    await asyncio.sleep(wait_seconds)

Теперь нужно узнать список пользователей, которые поставили реакцию.

На изображении выше видим, что класс discord.Message имеет свойство reactions. Если открыть страницу, то можно узнать, что свойство хранит в себе список объектов типа discord.Reaction:

введите сюда описание изображения

А у объекта discord.Reaction есть метод users() - переходим к нему:

введите сюда описание изображения

И, что достаточно забавно, здесь даже есть пример выбора случайного пользователя, прям в документации)

Можете посмотреть самостоятельно


Также здесь надо отметить, что сообщение msg на данный момент не имеет реакций, так как в переменной хранится его состояние на момент отправки, а реакцию мы добавили позже. Поэтому нужно получить объект сообщения заново:

msg = await ctx.channel.fetch_message(msg.id)

И вот теперь уже можно получить список пользователей. Нашу реакцию поставил бот, поэтому она в списке первая, то есть индекс - 0:

users = await msg.reactions[0].users().flatten()

Вбиваем в гугл "python получить случайный элемент списка" и находим функцию choice() из стандартного модуля random.

Выбираем случайного пользователя, исключая самого бота (он-то тоже поставил реакцию) и отправляем сообщение, вызывая у выбранного юзера свойство mention, чтобы упомянуть:

del users[0] # бот первым ставит реакцию, поэтому его индекс - 0
await ctx.send(f'Победитель: {random.choice(users).mention}!')

Почитать про свойства других объектов, по типу mention у объекта пользователя можно все в той же документации, это вообще очень полезная штука)


Полный код:

import discord, asyncio
from random import choice
from discord.ext import commands

bot = commands.Bot(command_prefix='!', intents = discord.Intents.all())

@bot.command()
async def random_pick(ctx, wait_seconds: int):
    msg = await ctx.send('Нажмите ? внизу, чтобы участвовать')
    await msg.add_reaction('?')

    await asyncio.sleep(wait_seconds)

    msg = await ctx.channel.fetch_message(msg.id)
    users = await msg.reactions[0].users().flatten()
    del users[0]
    await ctx.send(f'Победитель: {choice(users).mention}!')


bot.run('TOKEN')
→ Ссылка