Wait for message then send response discord.py - discord

I'm looking for some help with the following code:
if message.content.startswith("keycode"):
channel = bot.get_channel(00000000000000)
await channel.send('sentence 1')
await asyncio.sleep(3)
await channel.send('sentence 2.')
await asyncio.sleep(3)
await channel.send('Please reply "yes" or "no".')
try:
await bot.wait_for('message', timeout=15.0)
except asyncio.TimeoutError:
await channel.send('You ran out of time to answer!')
if message.content == 'yes':
await channel.send('You replied yes')
else:
await channel.send('You didn't reply yes.')
Basically upon request, the discord bot will give out a response to the selected channel and then following that response it will ask if a user can reply "yes" or "no". Then, if the a user replies "yes" it will give out the "You replied yes" response and if not it will give out the "You didn't reply yes" response.
My issue is that whenever I run the command and type "yes" after its response, I always get the "You didn't reply yes" response". (It does send the "you ran out of time to answer" response if I don't respond within the given time frame).
I'm very new to all this so it would be great if someone could pick up on all my errors. Thanks in advance.

Simply put, you are currently comparing the first message's content for 'yes' rather than the one you waited for. In other words, if that first message (the one that starts with 'keycode') does not equal yes exactly (it never will since it starts with 'keycode'), you'll never send your yes reply
Instead, use the returned message event from wait_for(), which will give you the new message that you waited for to introspect:
if message.content.startswith("keycode"):
channel = bot.get_channel(00000000000000)
await channel.send('sentence 1')
...
try:
reply_message = await bot.wait_for('message', timeout=15.0)
except asyncio.TimeoutError:
await channel.send('You ran out of time to answer!')
else:
if reply_message.content == 'yes':
await channel.send('You replied yes')
else:
await channel.send('You didn\'t reply yes.')

I see what your trying to do. I would make another if message.content == "no": So something like..
if message.content.startswith("keycode"):
await message.channel.send('sentence 1')
await asyncio.sleep(3)
await message.channel.send('sentence 2.')
await asyncio.sleep(3)
await message.channel.send('Please reply "yes" or "no".')
try:
await bot.wait_for('message', timeout=15.0)
except asyncio.TimeoutError:
await message.channel.send('You ran out of time to answer!')
if message.content == 'yes':
await message.channel.send('You replied yes')
if message.content == 'no':
await message.channel.send('You replied no')
else:
await message.channel.send("You didn't reply with yes or no.")
Also I see you want your messages to be send to a certain channel seeing channel = bot.get_channel(00000000000000). If someone sends "keycode" in a different channel then that one, then the bot won't send it to the channel the author typed "keycode" if that makes since. So I changed the code in order to make the bot send these messages in the same channel the author typed in.

Related

I cannot understand how to use this code in discord.py

It regards user imput, so like I was commissioned to do a prompt but I've never done this so like this is what i found online
playerChoice = await bot.wait_for('message', check=check(ctx.author), timeout=30)
I get some of it, but I don't get the 'message' part and the 'check = check'.
Here's my full code
#client.command()
async def event(ctx):
await ctx.send("Prompt will continue in DMs.")
embed = discord.Embed(title="Event Prompt", description="Please specify the type of event.")
embed.set_footer("Prompt will expire in ## seconds")
await ctx.author.send(embed=embed)
eventType = await bot.wait_for('message', check=check(ctx.author), timeout=30) # I want it to send the event type.
await ctx.send(eventType)
I'd like an explaination and a possible way to improve that and make it work. Thanks in advance
https://discordpy.readthedocs.io/en/stable/api.html?highlight=wait_for#discord.Client.wait_for
#client.event
async def on_message(message):
if message.content.startswith('$greet'):
channel = message.channel
await channel.send('Say hello!')
def check(m):
return m.content == 'hello' and m.channel == channel
msg = await client.wait_for('message', check=check)
await channel.send('Hello {.author}!'.format(msg))
await client.wait_for('message', check=check)
message refers to the event. You could have also do it for the event reaction_add, voice_state_update, etc.
So this means you are waiting for a message. The check defines what you are waiting for exactly. It is a method and returns a True or False.
In my case I am waiting for a message event which is posted in the same channel and has the message content "hello".
If you didn't have such check it would pick up a message that might have been send by a different author, in a different channel, in a different guild.

Discord reaction_add doesn't work in Direct Message channel

I've been troubleshooting this thing for days and this is the last straw.
Reaction_add only works if I do !on_message in the server 'general' channel, if I directly message the bot, it doesn't do anything. Though, funny thing is, if I message bot directly first and the enter !on_message in server general channel, bot reacts in general channel and in direct messages.
After TimeoutError I get thumbs down in direct messages.
This is the code, straight from discord.py documentation and I'm using Bot as Client:
#bot.command(pass_context=True)
async def on_message(ctx):
channel = ctx.channel
await ctx.send('Send me that 👍 reaction, mate')
def check(reaction, user):
return user == ctx.author and str(reaction.emoji) == '👍'
try:
reaction, user = await bot.wait_for('reaction_add', timeout=60.0, check=check)
except asyncio.TimeoutError:
await channel.send('👎')
else:
await channel.send('👍')
It's funny that wait_for(message, ...) message works just fine everywhere.
Tried adding this and still no luck.
intents = discord.Intents.default()
intents.dm_reactions = True
bot = commands.Bot(command_prefix=PREFIX, description=DESCRIPTION, intents=intents)
It's because on_message is a bot event, which means it does not need to be invoked as a command, you can call the command with (), but in your case, you are trying to use the command as a event.
This is an event
#bot.event
async def on_message(message):
channel = message.channel
await message.channel.send('Send me that 👍 reaction, mate')
def check(reaction, user):
return user == message.author and str(reaction.emoji) == '👍'
try:
reaction, user = await bot.wait_for('reaction_add', timeout=60.0, check=check)
except asyncio.TimeoutError:
await message.channel.send('👎')
else:
await message.channel.send('👍')
This is a command, a command needs to be invoked with a function, in this case, it would be your prefix + thumbs !thumbs hope both of these help.
#bot.command()
async def thumbs(ctx):
channel = ctx.channel
await ctx.send('Send me that 👍 reaction, mate')
def check(reaction, user):
return user == ctx.author and str(reaction.emoji) == '👍'
try:
reaction, user = await bot.wait_for('reaction_add', timeout=60.0, check=check)
except asyncio.TimeoutError:
await ctx.send('👎')
else:
await ctx.send('👍')
I added intents = discord.Intents.all() and that seems to do the trick, though it's not efficient because I might not need all privileged intents.
Input on issue would be helpful.

Discord.py banning user not working if DM's disabled

I've got this code for my discord bot, which can ban people and DM them the reason for the ban first.
cooldown = []
#bot.command(pass_context = True)
#commands.has_role('Senior Moderator')
async def ban(ctx, member: discord.Member = None, *, reason = None):
author = str(ctx.author)
if author in cooldown:
await ctx.send('Calm down! You\'ve already banned someone less than two hours ago.')
return
try:
if reason == None:
reason = 'breaking the rules.'
await member.send(f'You have been banned from **{ctx.guild.name}** for **{reason}**')
await member.ban(reason = f"Banned by {ctx.message.author} for "+reason)
await ctx.send(f'{member.mention} has been banned.')
cooldown.append(author)
await asyncio.sleep(2 * 60 * 60) #The argument is in seconds. 2hr = 7200s
cooldown.remove(author)
except:
await ctx.send('Error. Please check you are typing the command correctly. `!ban #username (reason)`.')
However, if the user I am trying to ban has DM's disabled, the bot can't send the ban reason message, so therefore doesn't proceed to the next step, which is banning them, and returns the error message, which is Error. Please check you are typing the command correctly. !ban #username (reason)
Please can you rewrite the code to allow it to try to DM someone the reasoning before banning them, but if they have DM's disabled, it shall still ban them anyway. Thank you!
By simply moving the ban to be executed first (as it is a priority), then it will attempt to dm the user.
I also re-adjusted some parts of the code. It will now try to send a dm, if not, it will still ban but a message will be sent to the channel alerting a message was not sent to the banned user.
#bot.command(pass_context = True)
#commands.has_role('Senior Moderator')
async def ban(ctx, member: discord.Member = None, *, reason = None):
author = ctx.author
if author in cooldown:
await ctx.send('Calm down! You\'ve already banned someone less than two hours ago.')
return
if member == None:
await ctx.send('Please mention a member to ban!')
return
if reason == None:
reason = 'breaking the rules.'
await member.ban(reason = f"Banned by {ctx.message.author} for " + reason)
try:
await member.send(f'You have been banned from **{ctx.guild.name}** for **{reason}**')
except:
await ctx.send(f'A reason could not be sent to {ctx.message.author} as they had their dms off.')
await ctx.send(f'{member.mention} has been banned.')
cooldown.append(author)
await asyncio.sleep(2 * 60 * 60)
cooldown.remove(author)
I too noticed the same thing when I first made my bot ban command, I did the following to fix my ban command. First I tried a scenario where the bot could dm the user, if it can, then It will dm the user and then ban the user (Note: Do not ban the user before DMing the user as the bot can only DM the user when the user and the bot share a common server). However, I then made an Exception that if the bot couldn't dm the user, it will send a message in the channel the command was executed "Couldn't dm the user" then ban the user
try:
await member.send(embed=embo)
await ctx.guild.ban(member, reason=reason)
except Exception:
await ctx.send("Couldn't send dm to the user")
await ctx.guild.ban(member, reason=reason)
EDIT:
you can also opt for the following:
try:
await member.send(embed=embo)
await ctx.guild.ban(member, reason=reason)
except discord.HTTPException:
await ctx.send("Couldn't send dm to the user")
await ctx.guild.ban(member, reason=reason)
before I specified this, I encountered the following error.
I fixed it, afterward, adding the exception case.

discord.py bot repeating messages

hi i am trying to make a discord.py bot so i can have a gif chat channel but when someone types a message in that channel then my bot starts repeating his message, pls help if u know.
my code:
#client.event
async def on_message(message):
with open("gif_chater.json", "r+") as file:
data=json.load(file)
if str(message.channel.id) in data:
if message.content.startswith("https://tenor.com/"):
print("wOw")
if not message.content.startswith("https://tenor.com/") and not message.author.id == "760083241133932544":
await message.channel.send("lol pls use gifs in this channel : )")
await message.delete()
exit
The on_message event
The issue is that the bot is constantly responding to itself, and it's because the on_message event triggers not just when users send a message but also when the bot sends a message. As such, once it tells the user that they must only post tenor gifs, it reacts to its own message and goes into an infinite loop, posting and deleting its responses.
Preventing the bot from responding to itself
To prevent the bot from responding to it's own messages, you should add a check at the start of the event like in the discord.py docs:
#client.event
async def on_message(message):
if message.author == client.user:
return
...
Also, the ID check at the end
The last condition in your code before it decides to send a message is checking the ID of the messenger (not message.author.id == "760083241133932544"). I don't know whether it's meant to avoid deleting you or the bot's messages but regardless, the check itself is bugged. message.author.id returns an integer but is then being compared to a string, and due to the conflicting types, will always return False.
To fix it, change your ID to an integer by removing the quotes: not message.author.id == 760083241133932544. As well, you should use the not-equals operator != instead of not to improve readability: message.author.id != 760083241133932544.
Also, since you already checked if the message starts with the website link, you can use an elif statement instead of rechecking the condition, since else/elif guarantees that the previous condition was false (aka, that the message didn't start with the website link):
if message.content.startswith("https://tenor.com/"):
print("wOw")
elif message.author.id != 760083241133932544:
await message.channel.send("lol pls use gifs in this channel : )")
await message.delete()
Fixes combined
With the new changes, your function could look something like this:
#client.event
async def on_message(message):
# Don't respond to the bot's own messages
if message.author == client.user:
return
with open("gif_chater.json") as file:
data = json.load(file)
if str(message.channel.id) in data:
if message.content.startswith("https://tenor.com/"):
print("wOw")
elif message.author.id != 760083241133932544:
await message.channel.send("lol pls use gifs in this channel : )")
await message.delete()

{discord.py} Delete a specific message from a specific user

I want to delete a specific message from a specific user using discord.py
The user's id is: 462616472754323457
The message that he can't send: lmao
So if he sends lmao, it deletes the message and send "You can't do that <#462616472754323457>
Try discord.TextChannel.purge.
#client.event
async def on_message(message):
if len(await message.channel.purge(limit=200, check=lambda x: ('lmao' in x.content.strip().lower()) and x.author.id == 462616572754323457)) > 0:
await message.channel.send('You are not allowed to do that, <#462616572754323457>')
Accounting for when the bot is offline, the bot will check 200 messages before the current message and delete any that are from 462616572754323457 and have 'lmao' in the contents. (You can further enhance this by using re.)
You can use the on_message event, which triggers whenever a message is sent.
#bot.event
async def on_message(message):
await bot.process_commands(message) # add this if also using command decorators
if message.author.id == 462616472754323457 and "lmao" in message.content.lower():
await message.delete()
await message.channel.send(f"You can't do that, {message.author.mention}")
References:
discord.on_message()
Message.delete()
Bot.process_commands()
Member.mention

Resources