Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Discord.py wait for message or reaction

I'm quite new to both Python and Discord.py, and I'm trying to find how to make the bot wait for either a message or reaction from user at the same time.

I tried separating each but just resulted in the bot needing a message response before a reaction.

Here's a similar code I'm trying to do:

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

    if ctx.content == "$respond":
        message = await ctx.send("Waiting for response...")

        while True:
            try:
                response = #Will wait for a message(Yes or No) or reaction(Check or Cross) from ctx.author for 30 secs
            except asyncio.TimeoutError:
                await message.edit(content=f"{ctx.author} did not respond anymore!")
                break

            if response.content == "yes":
                await message.edit(content=f"{ctx.author} said yes!")
                continue
            
            elif response.content == "no":
                await message.edit(content=f"{ctx.author} said nyo!")
                continue
            
            #These are reactions
            elif str(response.emoji) == "✅":
                await message.edit(content=f"ctx.author reacted ✅!")
                continue
            
            elif str(response.emoji) == "❌":
                await messave.edit(content=f"Stopped listening to responses.")
                break
like image 213
BaraHinozuka Avatar asked Nov 02 '25 20:11

BaraHinozuka


1 Answers

bot.wait_for is what you're looking for here.

I would recommend using bot.command() for command handling purposes but this is fine as well.

This is how you wait for specific events (provided as the first argument) with specific conditions (as provided in the check param)

@bot.event
async def on_message(msg):
    if msg.author == bot.user:
        # if the author is the bot itself we just return to prevent recursive behaviour
        return
    if msg.content == "$response":

        sent_message = await msg.channel.send("Waiting for response...")
        res = await bot.wait_for(
            "message",
            check=lambda x: x.channel.id == msg.channel.id
            and msg.author.id == x.author.id
            and x.content.lower() == "yes"
            or x.content.lower() == "no",
            timeout=None,
        )

        if res.content.lower() == "yes":
            await sent_message.edit(content=f"{msg.author} said yes!")
        else:
            await sent_message.edit(content=f"{msg.author} said no!")

This would result in : result

Listening for multiple events is a rather a bit interesting, Replace the existing wait_for with this snippet :

done, pending = await asyncio.wait([
                    bot.loop.create_task(bot.wait_for('message')),
                    bot.loop.create_task(bot.wait_for('reaction_add'))
                ], return_when=asyncio.FIRST_COMPLETED)

and you can listen for two events simultaneously

Here's how you can handle this using @bot.command()

import discord
import os
from discord.ext import commands

bot = commands.Bot(command_prefix="$", case_insensitive=True)


@bot.event
async def on_ready():
    print(f"Logged in as {bot.user}")


@bot.command()
async def response(ctx):
    sent_message = await ctx.channel.send("Waiting for response...")
    res = await bot.wait_for(
        "message",
        check=lambda x: x.channel.id == ctx.channel.id
        and ctx.author.id == x.author.id
        and x.content.lower() == "yes"
        or x.content.lower() == "no",
        timeout=None,
    )

    if res.content.lower() == "yes":
        await sent_message.edit(content=f"{ctx.author} said yes!")
    else:
        await sent_message.edit(content=f"{ctx.author} said no!")


bot.run(os.getenv("DISCORD_TOKEN"))

new_result which would get you the same result.

like image 50
Achxy_ Avatar answered Nov 04 '25 10:11

Achxy_