I am trying to make a command that waits for a reaction on a DM and then gets the reaction emoji. I'm using discord.py. My code works in a normal text channel but not in DMs I also am getting no error messages it just doesn't work!
#bot.command()
async def ping(ctx, user: discord.User):
if user != None:
if user != ctx.author:
players = [ctx.author, user]
for player in players:
message = await player.send("test")
await message.add_reaction('👍')
await message.add_reaction('👎')
def check(reaction, user):
return user == player and str(reaction.emoji) in ['👍', '👎']
response = await bot.wait_for("reaction_add", check=check)
if str(response[0]) == "👍":
await player.send(str(response[0]))
else:
await player.send("👎")
Many thanks in advance
Edit: I do not have intents enabled
Related
I'm making a simple game in discord.py/pycord and I would like my bot to be able to delete a specific reaction. Is there a way to do this?
I want the reaction to delete after I click.
Like this:
Here is my code (I'm using pycord):
import discord
from discord.ext import commands
intents = discord.Intents().all()
bot = commands.Bot(intents=intents)
#bot.event
async def on_message(message):
if message.author == bot.user:
return
if message.content == 'test':
me = await message.reply('Is this cool?')
await me.add_reaction("👎")
await me.add_reaction("👍")
try:
reaction, user = await bot.wait_for("reaction_add", check=lambda reaction, user:
user == message.author and reaction.emoji in ["👎", "👍"], timeout=30.0)
except asyncio.TimeoutError:
await message.reply("Tmieout bro")
else:
if reaction.emoji == "👍":
await message.reply('Like it.')
await reaction.delete()
else:
await message.reply("NO like")
await reaction.delete()
You first get the reaction object, then you remove it. Docs
Code:
#bot.slash_command(name='removereaction', description="I'm helping someone with their Stack post")
async def removereaction(ctx, message: discord.Option(discord.Message)):
print(message)
for i in message.reactions:
async for user in i.users():
await i.remove(user)
await ctx.respond(message.reactions)
How this works is it gets the message from the parameter message that has type discord.Option. The discord.Option is set so that you can use a message from a link or ID. Then, it uses this to cycle through all of the message's reactions. Then it cycles through each user that reacted with said reaction. It must be async, because i.users() is async (See here).
The full code that may help you:
import discord
from discord.ext import commands
intents = discord.Intents().all()
bot = commands.Bot(intents=intents)
#bot.event
async def on_message(message):
if message.author == bot.user:
return
if message.content == 'test':
me = await message.reply('Is this cool?')
await me.add_reaction("👎")
await me.add_reaction("👍")
try:
reaction, user = await bot.wait_for("reaction_add", check=lambda reaction, user:
user == message.author and reaction.emoji in ["👎", "👍"], timeout=30.0)
except asyncio.TimeoutError:
await message.reply("Tmieout bro")
else:
if reaction.emoji == "👍":
await message.reply('Like it.')
async for user in reaction.users():
await reaction.remove(user)
else:
await message.reply("NO like")
async for user in reaction.users():
await reaction.remove(user)
If you want to remove JUST the bot's reactions change the following line:
async for user in reaction.users():
await reaction.remove(user)
To:
await reaction.remove(bot.user)
I'm creating a discordpy bot that will allow users to compete against each other to see who can react to a message the fastest. Right now, when a user reacts to a message, the bot displays the message multiple times and I'm not too sure why.
I've tried the message.author == bot.user but it hasn't appeared to be working at all and I've looked at other sites but they've not solved my problem at all...
#bot.listen('on_message')
async def on_message(message):
if message.author == bot.user:
return
channel = bot.get_channel("CHANNEL_ID")
messages = [message async for message in channel.history(limit=15)]
await asyncio.sleep(random.randint(0, 3))
msg = messages[random.randint(0, 14)].add_reaction("\N{Snowman}")
await msg
def check(reaction, user):
return str(reaction.emoji) == '\N{Snowman}' and user != bot.user
try:
reaction, user = await bot.wait_for('reaction_add', timeout = 30, check=check)
embed = discord.Embed(description=f'{user.mention} received a snowman!', color=discord.Color.random())
await channel.send(embed=embed)
except asyncio.TimeoutError:
pass
its because you are using the await channel.send in a try loop and this will "try run" the code before and if it works it will really run but by api requests this will just trigger the request 2times.
so you should make something like
try:
reaction, user = await bot.wait_for('reaction_add', timeout = 30, check=check)
except asyncio.TimeoutError:
return
embed = discord.Embed(description=f'{user.mention} received a snowman!', color=discord.Color.random())
await channel.send(embed=embed)
where the send request is not tried and only the check
msg = await ctx.channel.send(f"`Now playing: {var3}` \n{url}")
await msg.add_reaction(u"\u23F8")
await msg.add_reaction(u"\u25B6")
while True:
try:
reaction, user = await client.wait_for("reaction_add", check=lambda reaction, user: reaction.emoji in [u"\u23F8", u"\u25B6"], timeout=90.0)
except asyncio.TimeoutError:
return await msg.clear_reactions()
else:
if reaction.emoji == u"\u23F8":
await msg.remove_reaction(reaction.emoji, ctx.author)
await ctx.voice_client.pause()
elif reaction.emoji == u"\u25B6":
await msg.remove_reaction(reaction.emoji, ctx.author)
await ctx.voice_client.resume()
This is a snippet of code from a play command, it's supposed send a message showing what is playing, and bring up pause and play reactions which will pause and play the audio when reacted to by a user. Right now it only runs once during a run of the whole code, this means it will only respond the first time a user calls the command and does a reaction. For example, if a user plays something then pauses through the pause reaction it will pause, but if he then does the play reaction right after he will get no response. Likewise, if he plays another song after the first one and tries pausing or playing through the reaction he will get no response.
What you can do is wrap the reaction handler under a asyncio.create_task(), this'll prevent these code from blocking the wait_for().
import asyncio
msg = await ctx.channel.send(f"`Now playing: {var3}` \n{url}")
await msg.add_reaction("\u23F8")
await msg.add_reaction("\u25B6")
while True:
try:
reaction, user = await bot.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"],
timeout=90.0)
except asyncio.TimeoutError:
return await msg.clear_reactions()
async def process():
if reaction.emoji == "\u23F8":
await msg.remove_reaction(reaction.emoji, ctx.author)
await ctx.voice_client.pause()
elif reaction.emoji == "\u25B6":
await msg.remove_reaction(reaction.emoji, ctx.author)
await ctx.voice_client.resume()
asyncio.create_task(process())
In addition to using create_task(), your wait_for check should include checking for the same user and same message. Otherwise someone else could be reacting to some message with these two emojis and your wait_for will think its valid. Also, unicode strings u"..." no longer requires the u prefix, in Python 3 all strings are unicode by default.
I am trying to actually let my bot wait till it receives a reaction on its message and meanwhile do nothing. Just waiting. First as soon as it receives the reaction it should continue with the rest of the code. Here is a (shitty) example code:
#client.command()
async def test(ctx):
await ctx.send("waiting for players to join ...")
for i in range(5):
botMsg = await ctx.send("User X do you want to play?")
await botMsg.add_reaction("✔️")
await botMsg.add_reaction("❌")
try:
reaction, player = await client.wait_for('reaction_add', timeout=20, check=lambda reaction, player: reaction.emoji in ["✔️", "❌"])
except asyncio.TimeoutError:
await ctx.send("No one reacted.")
if client.user != player and reaction.emoji == "✔️":
await ctx.send(f"{player.mention} reacted with ✔️.")
elif client.user != player and reaction.emoji == "❌":
await ctx.send(f"{player.mention} reacted with ❌.")
Excecuting this code ends up in a big mess without the bot waiting in between the messages. How can I implement that the bot waits for a reaction between every message without already sending all of the other ones?
I'd appreciate anyone's help
There might be some problems with the way you check the emojis... I'm not really sure :/
Anyways here's what I got working:
#client.command()
async def test(ctx):
for i in range(5):
msg = await ctx.send("Waiting for reactions...")
emojis = [u"\u2714", u"\u274C"]
await msg.add_reaction(emojis[0])
await msg.add_reaction(emojis[1])
try:
reaction, user = await client.wait_for('reaction_add', timeout=20.0, check=lambda reaction, user: user.id != client.user.id and reaction.emoji in emojis)
if reaction.emoji == emojis[0]:
await ctx.send(f"{user.mention} said yes!")
else:
await ctx.send(f"{user.mention} said no :(")
except asyncio.TimeoutError:
await ctx.send("You\'re out of time!")
I ran into an issue when making this discord bot. Whenever a user runs the command !!bug, there shall be a private message where the user has to answer a few questions. The issue is that whenever you run the command, you can still answer the question in the chat you ran the command.
I want it to only wait for the user response if the user wrote in private messages, and not the chat the command was run at. So this line of code:
responseDesc = await self.client.wait_for('message', check=lambda message: message.author == ctx.author, timeout=300)
Should only work when the user writes in private messages.
Here is my code:
import discord
from discord.ext import commands
import asyncio
emojis = ["\u2705", "\U0001F6AB", "\u274C"]
class Bug(commands.Cog):
def __init__(self, client):
self.client = client
#commands.command()
async def bug(self, ctx, desc=None, rep=None):
await ctx.channel.purge(limit=1)
user = ctx.author
await ctx.author.send('```Please explain the bug```')
responseDesc = await self.client.wait_for('message', check=lambda message: message.author == ctx.author, timeout=300)
description = responseDesc.content
await ctx.author.send('```Please provide pictures/videos of this bug```')
responseRep = await self.client.wait_for('message', check=lambda message: message.author == ctx.author, timeout=300)
replicate = responseRep.content
await ctx.author.send('Your bug report has been sent.')
embed = discord.Embed(title='Bug Report', color=0x00ff00)
embed.add_field(name='Description',
value=description, inline=False)
embed.add_field(name='Replicate', value=replicate, inline=True)
embed.add_field(name='Reported By', value=user, inline=True)
adminBug = self.client.get_channel(733721953134837861)
message = await adminBug.send(embed=embed)
for emoji in emojis:
await message.add_reaction(emoji)
#commands.Cog.listener()
async def on_reaction_add(self, reaction, user):
reaction_message = reaction.message
message = await reaction_message.channel.fetch_message(reaction_message.id)
my_embed = message.embeds[0]
emoji = reaction.emoji
if user.bot:
return
if emoji == "\u2705":
fixed_channel = self.client.get_channel(733722567449509958)
await fixed_channel.send(embed=my_embed)
elif emoji == "\U0001F6AB":
notBug = self.client.get_channel(733722584801083502)
await notBug.send(embed=my_embed)
elif emoji == "\u274C":
notFixed = self.client.get_channel(733722600706146324)
await notFixed.send(embed=my_embed)
else:
return
def setup(client):
client.add_cog(Bug(client))
You can check if the channel is private like if isinstance(message.channel, discord.DMChannel)