Set a cooldown in commands - discord.py

I wanted to set a cooldown for my bot in discord.py, I tried to do this with time.sleep(30), but it didn't work because it stops the full bot, but I need that you can do other commands in the time. Please in content.split and not discord ext. Can someone help me?

What you want is to use a decorator on your command.
The decorator for a cooldown is #commands.cooldown
#bot.command()
#commands.cooldown(x, y, commands.BucketType.z)
#your code here
...
x is how many times a command can be used in a given timeframe
y is that timeframe (in seconds)
z is who this applies to (a user, a channel, a server, or even global(default))
So: ...cooldown(2, 10, commands.BucketType.user) will allow every user to use the command 2 times within 10 seconds.
Good luck!
You can read up on it here: Discord.py commands.cooldown
As a sidenote: time.sleep() is something you can use to "pause" the bot within a command
print("hi")
time.sleep(30)
print("there")
This will put a delay between the two messages, instead of having them be printed immediately, one after the other. You should test this out in!

You can use asyncio.sleep() for waiting inside the function, ex. inside on_ready() event or #commands.cooldown decorator (designed only for commands):
asyncio.sleep()
import asyncio
asyncio.sleep(seconds)
Asyncio.sleep works like time.sleep, but it doesn't block the entire code. It stops only one event. You can read more about the difference between time.sleep and asyncio.sleep here.
#commands.cooldown()
#client.command()
#commands.cooldown(rate, per, type)
async def example(ctx):
...
rate - The number of times a command can be used before triggering a cooldown.
per - The number of seconds to wait for a cooldown when it’s been triggered.
type - The type of cooldown (cooldown that blocks only one user would be commands.BucketType.user. Check all types and choose one that suits your needs.

this is because time.sleep is blocking, you can use
#commands.cooldown(1, 5, commands.BucketType.user)

Related

Creating an automatic closing time for registrations with a discord bot

I've been learning how to make a discord bot for a while and for the most part I've grasped the fundamentals already and I'm working my way through the more advanced concepts.
At the moment, I'm stuck on formulating the logic on making a time out with registrations.
So for example, I set up a tournament with a set deadline for registrations, what would be a good approach to close the registrations?
At the moment I already have the deadline saved in the database and whenever users register via a command, it checks if the current date is > the deadline date. But this I want the bot to be able to send a message by itself and prompt in the channel that "Registrations are closed".
I realized wait_for only waits for a single command. If I put that in a loop, I have to set how many registrations I should wait for (but with this I can use reacts).
A scheduler would have to loop every few minutes/hours and check if current datetime is > deadline which isn't very accurate.
The good thing is, there can only be one tournament at a time running.
You can fetch current event from your database in on_ready, wait for that event and then send a message to channel (You also can store channel_id in your database).
Check the example below.
#bot.event
async def on_ready():
event_data = something # fetch current event data from your database
if event_data[‘end_time’] > datetime.utcnow().tinestamp():
await asyncio.sleep(event_data[‘end_time'] - datetime.utcnow().timestamp()) # wait for event
channel = bot.get_channel(event_data[‘channel_id’])
if channel is not None:
await channel.send(“Event has been finished!”)
# you can delete this event from your database here
You also can use scheduler to schedule a task instead of asyncio.wait(). For example APScheduler.

discord bot python running a task while waiting for user response?

I was wondering if there's a way to run a task as I wait for a user's message or reaction. I plan on making a game command where a blurred image slowly gets less blurrier and the players have to be the first one to guess what the image is showing before it's completely visible, however the wait_for coroutine forces me to wait for a message which makes me unable to decrease the blur on the image until a player guesses what it is.
You can use client.loop.create_task() to asynchronously run a function.
async def makeLessBlurry(interval):
while True:
await asyncio.sleep(interval)
# run your code to make image less blurry
# break and return if finished
# Your command function, depending of what you use (ext or not) this will look different
async def guessImage():
# Start showing image...
client.loop.create_task(makeLessBlurry(1))
def check():
# Define your own check method if needed
await client.wait_for('message', check=check)

Discord.py Bot Autodelete

Im new to python (i learned the basics at a school course),
and for the moment im trying to create simple bots for my discord server.
And for the moment, the bot i really want, is an autodelete bot so that i can say, (for example) delete every message in the ...Channel after 24h. because i really dont wanna do that manually.
I know there are a few good bots that do that,
but for example MEE6 wants me to buy Premium to use the funktion.The other reason why i dont want to use any finished bot is that i really want to understand and learn the code,
i watched many tutorials and tried to put the parts of the scripts that i understood together, but it did not work. I also didnt find a tutorial which explained it to me so that i understood, so now im here and hope that im going to understand it.
I hope there are some ppl to help me. :)
Thanks
-Yami.Code
#bot.event()
async def on_ready(ctx):
while requirement == 1:
await ctx.channel.purge
time.sleep(20)
#the Error is:
line 11, in <module>
#bot.event()
TypeError: event() missing 1 required positional argument: 'coro'
Process finished with exit code 1
You shouldn't call bot.event (remove the parenthesis),
time.sleep is a blocking call, use asyncio.sleep instead (What does "blocking" mean)
on_ready doens't take ctx as an argument, if you want to send a message to a channel you should get the channel object first, and then use the send method
You're missing a parenthesis in your channel.purge method...
import asyncio # if you haven't already
#bot.event
async def on_ready():
channel = bot.get_channel(channel_id) # replace `channel_id` with an actual channel ID
while requirement == 1:
await channel.purge(limit=x) # change `x` accordingly...
await asyncio.sleep(20)

discord.py save every message in specific channel (using channel id)

How can a python bot read every message that is sent in a certain channel or read every message that was sent in one using a command like $save 421345187663708161. Thanks in advance, havent been able to find the answer anywhere.
I made this in an on_message Function which scans the message content for "$save" on the beginning, then gets the channel per the given ID.
#client.event
async def on_message(message):
if message.content.startswith("$save"):
splittedcontent = message.content.split()
channel = client.get_channel(splittedcontent[1])
all_messages = channel.history()
What your job now is, is to understand this code, maybe inform about the things that are going on here (like channel.history) and implement this to your code (preferably also with some try/except cases).

Gathering coin volumes - Is my code running asynchronously?

I'm fairly new to programming in python, I've been programming for about half a year. I've decided to try to build a functional trading bot. While trying to code this bot, I stumbled upon the asyncio module. I would really like to understand the module better but it's hard finding any simple tutorials or documentation about asyncio.
For my script I'm gathering per coin the volume. This works perfectly, but it takes a really long time to gather all the volumes. I would like to ask if my script is running synchronously, and if so how do I fix this? I'm using an API wrapper to communicate with the Binance Exchange.
import binance
import asyncio
import time
s = time.time()
names = [name for name in binance.ticker_prices()] #Gathering all the coin names
loop = asyncio.get_event_loop()
async def get_volume(name):
async def get_data():
return binance.ticker_24hr(name) #Returns per coin a dict of the data of the last 24hr
data = await get_data()
return (name, data['volume'])
tasks = [asyncio.ensure_future(get_volume(name)) for name in names]
results = loop.run_until_complete(asyncio.gather(*tasks))
print('Total time:', time.time() - s)
Since binance.ticker_24hr does not look like it's a coroutine, it is almost certainly blocking the event loop and therefore preventing asyncio.gather to do its job. As a quick fix, you can use run_in_executor to run the blocking function in a separate thread:
async def get_volume(name):
loop = asyncio.get_event_loop()
data = await loop.run_in_executor(None, binance.ticker_24hr, name)
return name, data['volume']
This will work just fine for a reasonable number of parallel tasks. The downside is that it uses threads, so it might not scale to a huge number of parallel requests (or it would require unnecessary waiting). The correct solution in the long run is to use a library that natively supports asyncio.
Maarten firstly you are calling get_ticker for every symbol which means you're making many unnecessary requests. If you call it without a symbol value, you get all tickers in one request. This removes any loops or async as well if you aren't performing other tasks. It looks like the binance library you're using doesn't support this. You can use python-binance to do it
return client.get_ticker()
That said I've been testing an asyncio version of python-binance. It's currently in a feature branch now if you want to try it.
pip install git+https://github.com/sammchardy/python-binance#feature/asyncio
Include the asyncio version of the client and initialise the client
from binance.client_async import AsyncClient as Client
client = Client("<api_key>", "<api_secret>")
Then you can await the calls to get the ticker for a particular symbol
return await client.get_ticker(symbol=name)
Or for all symbol tickers don't pass the symbol parameter
return await client.get_ticker()
Hope that helps

Resources