Better alternative to time.sleep() for discord.py? - python

I am a new developer trying to learn by making a Discord bot with python. For a part of my bot, I want it to reply to a message, wait 10 seconds and then delete both the reply and the referenced message. Instinctively, I used time.sleep() for the delay, however, this puts my entire bot on hold for 10 seconds, so I tried looking for an alternative with no luck. Any helpful code with explanations for the changes is very much appreciated!
Current code:
# Delete the referred to message
#client.event
async def on_reaction_add(reaction, user):
# <A bunch of other irrelevant code>
if successCounter == 1:
await reaction.message.reply("Image successfully added!")
time.sleep(10)
await reaction.message.delete()
# Delete the "Image successfully added!" message
#client.event
async def on_message(message):
if message.author.id == botID:
if message.reference is not None:
time.sleep(10)
await message.delete()
Thanks heaps in advance!

asyncio has a function called sleep() too, which does work asynchronously. So just use await asyncio.sleep(10) instead of time.sleep()

Related

How do I delete the messages from a user's DMS

I want to make a command where the bot can clear every message that it sent to the author's by DMs. How do I do this?
You can define the message that is sent to the author and then delete it after condition x is fullfilled.
Take a look at the following example:
import asyncio
#client.command()
async def testdm(ctx):
test = await ctx.author.send("This is a test")
await asyncio.sleep(5) # For example if you want to wait 5 seconds
await test.delete()
Based on the comment from Łukasz Kwieciński you, can also use:
await ctx.author.send("This is a test", delete_after=5) # Seconds are customizable
Note that the bot can't delete your messages.

discord.py bot isn't answering when mentioned from phone app

I made recently a discord bot for small server with friends. It is designed to answer when mentioned, depending on user asking. But the problem is, when someone mention bot from a phone app, bot is just not responding. What could be the problem?
Code:
import discord
from discord.ext import commands
from discord.ext.commands import Bot
import asyncio
bot = commands.Bot(command_prefix = '=')
reaction = "🤡"
#bot.event
async def on_ready():
print('Bot is ready.')
#bot.listen()
async def on_message(message):
if str(message.author) in ["USER#ID"]:
await message.add_reaction(emoji=reaction)
#bot.listen()
async def on_message(message):
mention = f'<#!{BOT-DEV-ID}>'
if mention in message.content:
if str(message.author) in ["user1#id"]:
await message.channel.send("Answer1")
else:
await message.channel.send("Answer2")
bot.run("TOKEN")
One thing to keep in mind is that if you have multiple functions with the same name, it will only ever call on the last one. In your case, you have two on_message functions. The use of listeners is right, you just need to tell it what to listen for, and call the function something else. As your code is now, it would never add "🤡" since that function is defined first and overwritten when bot reaches the 2nd on_message function.
The message object contains a lot of information that we can use. Link to docs
message.mentions gives a list of all users that have been mentioned in the message.
#bot.listen("on_message") # Call the function something else, but make it listen to "on_message" events
async def function1(message):
reaction = "🤡"
if str(message.author.id) in ["user_id"]:
await message.add_reaction(emoji=reaction)
#bot.listen("on_message")
async def function2(message):
if bot.user in message.mentions: # Checks if bot is in list of mentioned users
if str(message.author.id) in ["user_id"]: # message.author != message.author.id
await message.channel.send("Answer1")
else:
await message.channel.send("Answer2")
If you don't want the bot to react if multiple users are mentioned, you can add this first:
if len(message.mentions)==1:
A good tip during debugging is to use print() So that you can see in the terminal what your bot is actually working with.
if you print(message.author) you will see username#discriminator, not user_id

Discord.py: Why do the welcome and goodbye messages repeat?

Problem: I am trying to have it so that the bot sends a single message in general, but the messages continuously repeat, seemingly increasing each time this occurs. Also, if I switch the message to something else, the repeated parts are of the old message.
Code:
import discord
from discord.ext import commands
client=commands.Bot(command_prefix = '.')
#client.event
async def on_ready():
print('ok')
#client.event
async def on_member_join(member):
channel=discord.utils.get(member.guild.channels, name="general")
await channel.send("Hi {}".format(member))
#client.event
async def on_member_remove(member):
channel=discord.utils.get(member.guild.channels, name="general")
await channel.send("Bye")
client.run(token)
Since the code is under the function variable then you have to end each function.
It might be due to multiple instances of the application are running. Check your task manager and search for python process, End it if there are multiple and re-run the script.

How to delete a specific user's messages instantly?

I am trying to code a command into my Discord Bot that when triggered will actively delete new messages from a specific user.
I have tried a couple variations of using ctx but I honestly I don't entirely understand how I could use it to accomplish this.
This block of code deletes the message that triggers it. Because of this, I think I am taking the wrong approach because it only deletes from whoever triggers it and only if they type the command. Obviously, I am new to this. I would appreciate any and all help. Thanks so much :)
#client.event
async def on_message(ctx):
message_author = ctx.author.id
if message_author == XXXXXXXXXXXXXXXXX:
await ctx.message.delete()
There is no more CTX in discord rewrite (DiscordPy 1.0+) instead you should do:
#client.event
async def on_message(message):
if message.author.id == XXXXXXXXXXXXXXXXX:
await message.delete()
Source: link
You can make a command to add the users to a list then use on_message to check if a user is in that list and then delete it if true
dels=[]
#bot.event
async def on_message(msg):
if msg.author.id in dels:
await bot.delete_message(msg)
await bot.process_commands(msg)
#bot.command(name='del_msg')
async def delete_message(con,*users:discord.Member):
for i in users:
dels.append(i.id)
await con.send("Users {} have been added to delete messages list".format(" ,".join(users)))

How to add a function to discord.py event loop?

I am using Python with discord.py. Documentation here
I've got a bot that is running on a Discord server that links the server with a subreddit. Users have various commands that do things like getting the top submissions, getting the latest submissions, and so on.
I want to add some features to the bot, with one of them being a keyword notifier. The bot should search the subreddit for keywords in the title, and then notify users if they are on the list for that keyword. I know how to do this, I've done it plenty of times, but I don't know how to do it with a Discord bot. I have no experience with asynchio or any kind of asynchronous programming.
The way I've tried to do it works, but it is very janky and definitely not good. At the top of the on message() function, I just add a call to the search_submissions() function, so that whenever someone puts sends a new message on the server, the bot will scan the Reddit submissions. The server is busy enough that this would work relatively okay, but I really want to do it the "proper" way.
I don't know how to call the search_submissions() function without putting it inside of on_message().
Edit for extra code:
import discord
TOKEN = "redacted"
client = discord.Client()
#client.event
async def reddit_search():
print("Searching")
#client.event
async def on_message(message):
if message.content.startswith("reddit!hot"):
# Get hot
# Do other things.
#client.event
async def on_ready():
print("Connected to Discord as {}.".format(client.user.name))
client.run(TOKEN)
You can add a function to the bot event loop with Client.loop.create_task(search_submissions()) like this:
async def search_submissions():
pass
client = discord.Client()
client.loop.create_task(search_submissions())
client.run(TOKEN)
Update:
If you want your function to continue working you can put it in a while loop with some sleeping in between:
async def search_submissions():
while(true):
# do your stuff
await asyncio.sleep(1)
The other answers here don't take into account discord.py's helpful tasks.loop decorator.
To make an event occur every 5 seconds, you would use
from discord.ext import tasks, commands
class MyCog(commands.Cog):
def __init__(self):
self.foo.start()
def cog_unload(self):
self.printer.cancel()
#tasks.loop(seconds=5.0)
async def foo(self):
print('bar')
More can be found here: https://discordpy.readthedocs.io/en/latest/ext/tasks/
You want your search_submissions() function to be async so other functions of your bot can still be invoked and your bot stays responsive. Define it to be def async and use aiohttp to send async HTTP requests to reddit -- what this does is send off the request, relinquish control to the event loop, and then take back control once the results have been transmitted back. If you use a standard HTTP library here instead then your whole bot will be blocked until the result comes back. This of course only makes sense if the task is mainly I/O-bound and less CPU-bound.
Then call search_submissions() in on_message(message) -- but call it asynchronously using result = await search_submissions(). This will resume execution of on_message once the result of search_submissions is ready.
If you truly want to do something else in the same context while waiting on search_submissions (which I think is unlikely), dispatch it as task = asyncio.create_task(search_submissions()). This will start the task immediately and allow you to do something else within the same function. Once you need the result you will have to result = await task.
async def search_submissions():
async with aiohttp.ClientSession() as session:
async with session.get(some_reddit_url) as response:
return await response.read()
#client.event
async def on_message(message):
if message.content.startswith("reddit!hot"):
result = await search_submissions()
await message.channel.send(result)

Categories