My purge command keeps getting rate limited - python

This is my purge command and although it works fine it keeps getting rate limited after I purge 30 massages or more.
#commands.command()
async def purge(self, ctx, num):
'''
Clears messages.
'''
embed = discord.Embed(title="🧹**MESSAGES PURGED**🧹", description=" ", color=0x0059ff)
async for message in ctx.channel.history(limit=int(num) + 1):
await message.delete(delay=0.5)
await ctx.send(embed=embed)
Any help is appreciated

I looked at your code and I understood that you are using a difficult path to create a purge command. Discord.py library has a coroutine called purge whose job is just to delete messages. Rather than using a loop and various other methods, it would be better to use it.
I created a purge command first which has the following code:
#nucleobot.command()
#commands.has_permissions(manage_messages=True)
async def purge(ctx, limit: int):
await ctx.message.delete()
await asyncio.sleep(1)
await ctx.channel.purge(limit=limit)
purge_embed = discord.Embed(title='Purge [!purge]', description=f'Successfully purged {limit} messages. \n Command executed by {ctx.author}.', color=discord.Colour.random())
purge_embed.set_footer(text=str(datetime.datetime.now()))
await ctx.channel.send(embed=purge_embed, delete_after=True)
How does this code work?
The command usage is deleted, i.e., !purge 10 would be deleted when sent into the chat.
It would pause for 1 second due to await asyncio.sleep(1). You would need to import asyncio in order to use it. (You might know that already :D)
The number of messages your entered are cleared from the channel using await ctx.message.delete(limit=limit) (This is a discord.py coroutine)
purge_embed is the embed variable which is used to send the embed after the deletion. I have used datetime module to add the time of the command completion on the embed. (You need to import datetime as well, but only if you want to use it. If not then remove the footer code.)
This would make up your complete and working purge command. :D
Examples with images.
I created a new channel and added 10 messages with numbers from 1 to 10 as shown below:
Then I entered the command in the message box and it was like (I know it was not needed but never mind):
After I sent this message and the command was executed, the purge successful embed was posted by the bot:
I was glad I could help. Any doubts of confusions are appreciated. Ask me anytime. :D
Thank You! :)

Related

Is there kind of a limit for asyncio in discord.py?

So I‘ve got a python discord bot. The idea is, there is a channel for funny quotes. In order to keep the channel organized, people can as well discuss in it, but after 24h their message should be deleted, if there‘s no %q before it. I‘ve got the following code:
#bot.event
async def on_message(ctx):
await bot.process_commands(ctx)
channel = bot.get_channel(ID_OF_CHANNEL)
if ctx.channel == channel:
if not ctx.content.lower().startswith("%q"):
await asyncio.sleep(86400)
await ctx.delete()
The problem is, it just doesn‘t work. The bot responds to other commands, but doesn‘t delete every single message after 24h. In fact, it doesn‘t delete any messages. I‘ve tried it with only 3h as well, but it didn‘t work too. Passing in only 30 seconds works…
I‘m sorry if my question may be stupid, but I‘m just clueless and I hope anybody can help me :)
May there be a limit of messages the bot can view or a limit of time it can do so?
Btw: I‘m pretty sure the bot was running all the time, so it was not interrupted.
EDIT: Just to make that clear: The idea is to start something like a timer on every single message, which works for 30 seconds, but strangely not for 3h.
Try using tasks instead of asyncio. It is made for such repetetive operations and it is easier and nicer because it is made by discord and is included in discord.ext. The way I would do it is something like this:
from discord.ext import tasks
#bot.command()
async def start(ctx):
deletingLoop.start() #here you start the loop
#tasks.loop(hours=24)
async def deletingLoop():
guild = self.bot.get_guild(guildID) #get the guild
channel = guild.get_channel(channelID) #and the channel
channel.purge(limit=1000) #clear the channel
and if you are afraid that this channel may have more than 1000 messages you can add on_message() event that would count the messages on this channel.
You have to take ctx.message as you want to delete the message of the context. This can take the parameter delay which deletes the selected message after that amount of time.
Code:
#bot.event
async def on_message(ctx):
await bot.process_commands(ctx)
channel = bot.get_channel(ID_OF_CHANNEL)
if ctx.channel == channel:
if not ctx.content.lower().startswith("%q"):
await ctx.message.delete(delay=24h_in_seconds)

Discord bot update message. (Discord.py)

Windows 10
VSCode
Discord.py
Python 3
Hey guys, I want my bot to send a message to a specific channel every time it logs on, here is the code:
#client.event
async def on_ready():
channel = client.get_channel(788532498724290641)
await channel.send('I have been updated and am now online again.')
There are no errors however no message gets sent when the program is run.
The whole program can be found here but beware it's uncommented and janky: https://github.com/DavisStanko/Discord-Bot
It's because you have multiple on_ready events. You can only have 1 type of each event, otherwise the last interpreted event will be the only one recognized. Merge the two on_ready events into 1 function.
#Kelo This is true, but also the await command must be in a print format, such as
await channel.print ('I am online')
I could be wrong, but this is how I have done it in the past with no issues.

Discord.py: Is there a way to get arguments for a command using the on_message() function?

I'm just programming my own discord bot with python, and I have a kill command. All it does is that when you type *kill and mention someone (*kill #goose.mp4), it will give you a random scenario on how you kill them similar to the Dank Memer bot. I'm trying to get that ID of the user that was mentioned, which will be the second argument to the function. But I'm stuck. After reading through the API and searching this up multiple times, I've only been given how to get the ID of the author and ping them with the bot, not the person the author mentioned.
This is the code that I am currently using. One of the variables is given a value only for testing purposes.
if message.content.startswith('*kill'):
print("kill command recieved")
kill_mention_killer = message.author.mention
kill_mention_victm = 'some guy'
print(kill_mention_killer)
kill_responses = [kill_mention_killer + ' kills ' + kill_mention_victim]
kill_message = kill_responses[random.randint(-1, len(kill_responses) -1)]
await message.channel.send(kill_message)
The way you are currently making this command will not allow you to get the arguments. If you're trying to make a command like this: *kill #user, then you will need to be able to get the user that was mentioned (which is your question). Here's how you do it:
First Step
import discord, random
from discord.ext import commands
These imports are very important. They will be needed.
Second Step
client = commands.Bot(command_prefix='*')
This will initialize the client, which is used throughout the code. Now onto the part where you will actually make the command.
#client.command()
async def kill(ctx, member: discord.Member): # This command will be named kill and will take two arguments: ctx (which is always needed) and the user that was mentioned
kill_messages = [
f'{ctx.message.author.mention} killed {member.mention} with a baseball bat',
f'{ctx.message.author.mention} killed {member.mention} with a frying pan'
] # This is where you will have your kill messages. Make sure to add the mentioning of the author (ctx.message.author.mention) and the member mentioning (member.mention) to it
await ctx.send(random.choice(kill_messages))
That's it! That's how you make a standard kill command. Just make sure to change the kill_messages array to whatever messages you would like.
if message.content.startswith('*kill'):
#Mentioned or not
if len(message.mentions) == 0:
#no one is mentioned
return
pinged_user = message.mentions[0]
killer_user = message.author
kill_messages = [
...
]
await ctx.send(random.choice(kill_messages))
here I just used message.mentions to find if any valid user is mentioned in the message or not and if mentioned! all the mentions will be in message.mentions list so i took the first mention of the message by message.mentions[0]. then you can do anything with the mentioned user object.

A scheduled task to a discord bot in python fails to do its job

I am programming a discord bot in python. It needs to sweep the member list every 24hrs, check their roles and do some actions accordingly. I started to program this, but the scheduled task apparently doesn't have access to discord. I can't seem to get a member. When I do this in a command:
#bot.command(name='sweepercmd', help='')
async def sweepercmd(ctx):
member = get(bot.get_all_members(), name="Waldstein")
print(member)
It prints "Waldstein#4164" in the bash console as expected. However if I put the same code in a task like this:
#tasks.loop(hours=24.0)
async def sweeper():
member = get(bot.get_all_members(), name="Waldstein")
print(member)
It prints "None". Adding ctx like ...sweeper(ctx)... makes it hang.
How can I access discord within my task just like in the commands?
thanks in advance for the help,
Jo
As for why your tasks are failing, I'm not entirely sure, but I'll look into it for you and edit my answer when I get some info on it. In the mean time, this should suffice:
You can use loop.create_task() as an alternative for this.
async def sweep_task():
while True:
member = discord.utils.get(bot.get_all_members(), name="Waldstein")
print(member)
await asyncio.sleep(86400)
#bot.command()
async def sweep(ctx): # doesn't necessarily need to go into a command - you could put it into
# your on_ready event if you want to
bot.loop.create_task(sweep_task())
References:
Client.loop
Client.get_all_members()
utils.get()
loop.create_task()
asyncio.sleep()

Discord Bot Python Deleting Author's Message

I made a small discord bot for some fun:
I want the author's messages to be deleted when Author run this command. But this does not work.
if message.content.startswith('Delete me.'):
async for msg in client.logs_from(message.channel, message.author):
await client.delete_message(msg)
Looking at their docs, logs_from takes a channel, along with additional arguments allowing you to
filter which messages to retrieve.
So if you just wanted to delete all messages, you can do something like
async def on_message(message):
NONSENSE_LIMIT = 999999999999
if message.content.startswith('!delete'):
async for log in client.logs_from(message.channel, limit=NONSENSE_LIMIT):
if log.author == message.author:
await client.delete_message(log)
Which will delete all messages for a user that types in that command. Your bot must have the manage messages permission for that channel.
Note that the number of messages returned is limited, and here I just write down some arbitrary nonsense limit. If you want to be accurate, you would have to figure out how many messages there are in the channel somehow, and then use that as the limit.
I just looked up discord API in the last 5 minutes so I don't know if there's a more efficient way to do it.
Your problem is in the client.logs_from(message.channel, message.author)statement. logs_from accepts the following arguments: logs_from(channel, limit=100, *, before=None, after=None, around=None, reverse=False). See the API reference. So you have two channel arguments where logs_from only accepts 1. Perhaps you intended client.logs_from(message.author) instead?

Categories

Resources