How to make wait_for wait for everybody's reaction? - python

embed = discord.Embed(title = "Currently Playing", colour = discord.Colour.blue())
embed.add_field(name = "Song", value = title, inline = False)
embed.add_field(name = "Length", value = str(datetime.timedelta(seconds = length)), inline = False)
embed.add_field(name = "Link", value = url, inline = False)
msg = await ctx.send(embed=embed)
await msg.add_reaction("\u23F8")
await msg.add_reaction("\u25B6")
await msg.add_reaction("\u23F9")
while True:
try:
reaction, user = await client.wait_for("reaction_add", check=lambda reaction, user: user.id == ctx.author.id and reaction.message.id == msg.id and reaction.emoji in ["\u23F8", "\u25B6", "\u23F9"], timeout = length)
except asyncio.TimeoutError:
return await msg.clear_reactions()
async def process():
if reaction.emoji == "\u23F8":
await msg.remove_reaction(reaction.emoji, ctx.author)
ctx.voice_client.pause()
elif reaction.emoji == "\u25B6":
await msg.remove_reaction(reaction.emoji, ctx.author)
ctx.voice_client.resume()
elif reaction.emoji == "\u23F9":
await msg.remove_reaction(reaction.emoji, ctx.author)
ctx.voice_client.stop()
asyncio.create_task(process())
Here I have a snippet of code from a play command, its supposed to send a message after a song is requested, the message has reactions that pause, play or stop when reacted to by a user. Additionally the bot automatically deletes the reaction immediately after it is hit so that the reactions can be used more than once by the same user.
Currently the code works well, the only problem is the reactions only respond to the person that originally invoked the play command and not anyone else in the server. The cause of this is evident, its due to the user: user.id == ctx.author.id in the wait_for causing it to only wait for reactions from the author, and the await msg.remove_reaction(reaction.emoji, ctx.author) which will cause it to only remove reactions added by the author. When I try to remove the user: user.id == ctx.author.id the play command stops working entirely. The remove_reaction requires a member argument, when I try to replace ctx.author with user while the user: user.id == ctx.author.id is removed it does the same thing, and with the user: user.id == ctx.author.id it has no effect as user is defined as author. Any help is appreciated.

Related

Delete channel on reaction | discord.py

I am creating ticket tool for my server. So whenever a user will react to the message a new channel will be created, but I want the bot to send a message in that new channel saying "React below to delete the ticket.". But can I do that without storing msg_id and other data in a global variable?
Code:
#bot.event
async def on_raw_reaction_add(payload):
if payload.member.id != bot.user.id and str(payload.emoji)== u"\U0001F3AB":
msg_id, channel_id, category_id= bot.ticket_configs[payload.guild_id]
if payload.message_id == msg_id:
guild= bot.get_guild(payload.guild_id)
for category in guild.categories:
if category.id == category_id:
break
guild = await bot.fetch_guild(460654239094669332)
channels = guild.text_channels
channel = guild.get_channel(842807548968042536)
duplicate = False
topic = f"<#!{payload.member.id}>'s ticket"
for channel in channels:
if topic == channels.topic:
duplicate = True
break
if duplicate:
return
else:
ticket_num= 1 if len(category.channels) == 0 else int(category.channels[-1].name.split("-")[1]) + 1
ticket_channel= await category.create_text_channel(f"Ticket-{ticket_num}", topic= topic, permission_synced= True)
await ticket_channel.set_permissions(payload.member, read_messages= True, send_messages= True)
print(msg_id)
embed= discord.Embed(title= "New Ticket!!!", description= f"{payload.member.mention} Thank You! for creating this ticket staff will contact you soon. Type **-close** to close the ticket.")
message= await ticket_channel.send(embed=embed)
await message.add_reaction("❌")
Help will be really appreciated
You can use bot.wait_for with a simple check
message = await ctx.send("React below to delete the ticket")
def check(reaction, user):
return reaction.message == message and str(reaction) == "✅" # you can use another emoji, or don't use it at all
try:
await bot.wait_for("reaction_add", check=check, timeout=60.0) # timeout is optional
except asyncio.TimeoutError:
...
else:
await channel.delete() # where `channel` is the channel to delete

Repeating a function when someone reacts to it

Trying to make it so when someone reacts to the message with the emoji it repeats the function - trying to find something that works similar to goto in batch files
Eg: I type $randomcar
Bot sends: Your chosen car is the bmw! with the 🔄 reaction. When I press on it it repeats the function again:
Bot sends Your chosen car is the audi! with the 🔄 reaction which I can press on to once again to repeat the function
#bot.command()
async def randomcar(ctx):
while True:
msg = await ctx.send("Your chosen car is the {}!".format(random.choice(cars)))
await msg.add_reaction("🔄")
async def on_raw_reaction_add(payload: discord.RawReactionActionEvent):
if msg.reaction=="🔄" and msg.id:
continue
I am getting the error:
Syntax error: continue not properly in loop
Thanks
This can be done using recursion:
#bot.command()
async def randomcar(ctx):
msg = await ctx.send("Your chosen car is the {}!".format(random.choice(cars)))
# you may need to check if your bot has the "add reactions" permission
await msg.add_reaction("🔄")
await bot.wait_for(
"reaction_add",
check=lambda reaction, user: user == ctx.author and reaction.emoji == "🔄" and reaction.message == msg,
)
await randomcar(ctx)
You could also add a timeout after which it will stop repeating:
#bot.command()
async def randomcar(ctx):
msg = await ctx.send("Your chosen car is the {}!".format(random.choice(cars)))
await msg.add_reaction("🔄")
try:
await bot.wait_for(
"reaction_add",
timeout=10.0, # 10 second timeout
check=lambda reaction, user: user == ctx.author and reaction.emoji == "🔄" and reaction.message == msg,
)
except asyncio.TimeoutError:
try:
await msg.remove_reaction("🔄", bot.user)
except discord.NotFound:
pass
else:
await randomcar(ctx)

discord.py : bot.wait_for() intercept message.add_reaction() and work one time

I have a problem with discord.py.
I want to do something like this:
msg = await ctx.author.send('message')
await msg.add_reaction('✅')
await msg.add_reaction('❎')
def check(reaction, user):
return user != bot.user and reaction.message.id == choice.id and reaction.emoji in ['✅', '❎']
r, u = await bot.wait_for('reaction_add', check=check)
result = r.emoji == '✅'
But it doesn't work and when I try this:
def check(reaction, user):
print(user.name)
return user != bot.user and reaction.message.id == choice.id and reaction.emoji in ['✅', '❎']
I have the name of the bot in the console, and when I try to click on a reaction nothing is printed, so I think bot.wait_for() works one time?
I hope you'll understand. Thanks for your time.
In your check, you had reaction.message.id == choice.id, and I'm not sure what choice is. This should work:
message = await ctx.author.send("message")
await message.add_reaction("✅")
await message.add_reaction("❎")
def check(reaction, user):
return user == ctx.author and reaction.message == message and reaction.emoji in ["✅", "❎"]
response = await client.wait_for("reaction_add", check=check)
result = response[0].emoji == "✅"

Get emoji from reaction in discord.py

I'm trying to make an 'accept/decline' embed with reactions, but I cannot get with which emoji the user reacted.
message = await guild.owner.send(embed=embed)
await message.add_reaction('✔')
await message.add_reaction('❌')
def check(reaction, user):
print(f"reacted")
return guild.owner == message.author and str(reaction.emoji) in ["✔", "❌"] and isinstance(message.channel, discord.DMChannel)
reaction, user = await bot.wait_for('reaction_add', timeout=1000.0, check=check)
if reaction.emoji == "✔":
print("tick")
elif reaction.emoji == "❌":
print("cross")
I get the
reacted
but I don't get anything in what refers to the cross and tick. Is there any way to get it?
Thanks in advance
Simply do the same you did in the check func, also discord by default doesn't have this reaction ✔ you're looking for ✅.
if str(reaction) == '❌': # or str(reaction.emoji)
print('cross')
elif str(reaction) == '✅':
print('tick')

Discord.py - Await for user's message

so right now I'm trying to create a type of application bot and right now the check I used for the bot doesn't allow the user to move onto the next question. There is no traceback so it's something with the check I defined.
#commands.command()
#commands.has_role("Realm OP")
async def block(self, ctx, user: discord.User):
DMchannel = await ctx.author.create_dm()
channel = ctx.message.channel
author = ctx.message.author
mentions = [role.mention for role in ctx.message.author.roles if role.mentionable]
channel2 = str(channel.name)
channel = channel2.split('-')
if len(channel2) == 2: # #real-emoji
realm, emoji = channel
else: # #realm-name-emoji
realm, emoji = channel[0], channel[-1]
realmName = realm.replace("-" , " ")
realmName1 = realmName.lower()
rolelist = []
print(realmName1)
a = solve(realmName1)
print(a)
realmName2 = str(a) + " OP"
print(realmName2)
check_role = discord.utils.get(ctx.guild.roles, name= realmName2)
if check_role not in ctx.author.roles:
return await ctx.send('You do not own this channel')
else:
await ctx.send("You own this channel!")
def check(m):
return m.channel == channel and m.author != self.bot.user
await DMchannel.send("Please fill out the questions in order to block the user!")
await DMchannel.send("User's Gamertag: (If you don't know, try using the >search command to see if they have any previous records!) ")
blocka1 = await self.bot.wait_for('message', check=check)
await DMchannel.send("Reason for block:")
blocka2 = await self.bot.wait_for('message', check=check)
Right now the bot doesn't do anything after the user responds to the first question and there is no traceback.
Any help or suggestions would help greatly!
Your check isn't returning anything. It's supposed to return either True or False. This means your wait_for will never end (as the check never returns True), so it will never ask the next question.
def check(m):
return m.channel == channel and m.author != self.bot.user
EDIT:
Your channel is the ctx.channel, while your bot waits for answers in DM. Assuming you answer your bot in DM as well, this means your check will never pass, as m.channel never equals channel.
def check(m):
return m.guild is None and m.author == ctx.author
This checks if a message was sent in DM (Guild is None), and if it was a DM by the original author.

Categories