How to make a timer command in discord.py? - python

I want to make a timer command.
#commands.command()
async def timer(self, ctx, seconds):
try:
secondint = int(seconds)
if secondint > 300:
await ctx.send("I dont think im allowed to do go above 300 seconds.")
raise BaseException
if secondint < 0 or secondint == 0:
await ctx.send("I dont think im allowed to do negatives")
raise BaseException
message = await ctx.send("Timer: " + seconds)
while True:
secondint = secondint - 1
if secondint == 0:
await message.edit(new_content=("Ended!"))
break
await message.edit(new_content=("Timer: {0}".format(secondint)))
await asyncio.sleep(1)
await ctx.send(ctx.message.author.mention + " Your countdown Has ended!")
except ValueError:
await ctx.send("Must be a number!")
I tried this but this doesn't work , it doesn't edit message like I want it to and no errors.

Alright, so here's a modified version of that script above marked with the green checkmark. I made some changes to make it more user-friendly (unit converter which converts for example "5m" to 300 seconds, and instead of displaying say, "90 seconds" it would display "1 minute 30 seconds" etc.), and easier for the general public to use. I'm not that great at coding, I'm at a beginners level, but I hope this helps!
#commands.command()
async def timer(self, ctx, timeInput):
try:
try:
time = int(timeInput)
except:
convertTimeList = {'s':1, 'm':60, 'h':3600, 'd':86400, 'S':1, 'M':60, 'H':3600, 'D':86400}
time = int(timeInput[:-1]) * convertTimeList[timeInput[-1]]
if time > 86400:
await ctx.send("I can\'t do timers over a day long")
return
if time <= 0:
await ctx.send("Timers don\'t go into negatives :/")
return
if time >= 3600:
message = await ctx.send(f"Timer: {time//3600} hours {time%3600//60} minutes {time%60} seconds")
elif time >= 60:
message = await ctx.send(f"Timer: {time//60} minutes {time%60} seconds")
elif time < 60:
message = await ctx.send(f"Timer: {time} seconds")
while True:
try:
await asyncio.sleep(5)
time -= 5
if time >= 3600:
await message.edit(content=f"Timer: {time//3600} hours {time %3600//60} minutes {time%60} seconds")
elif time >= 60:
await message.edit(content=f"Timer: {time//60} minutes {time%60} seconds")
elif time < 60:
await message.edit(content=f"Timer: {time} seconds")
if time <= 0:
await message.edit(content="Ended!")
await ctx.send(f"{ctx.author.mention} Your countdown Has ended!")
break
except:
break
except:
await ctx.send(f"Alright, first you gotta let me know how I\'m gonna time **{timeInput}**....")

It doesn't edit the message since new_content isn't a Message.edit() method argument.It only has: content / embed / suppress / delete_after / allowed_mentions.
The one you're looking for is content:
#commands.command()
async def timer(self, ctx, seconds):
try:
secondint = int(seconds)
if secondint > 300:
await ctx.send("I dont think im allowed to do go above 300 seconds.")
raise BaseException
if secondint <= 0:
await ctx.send("I dont think im allowed to do negatives")
raise BaseException
message = await ctx.send("Timer: {seconds}")
while True:
secondint -= 1
if secondint == 0:
await message.edit(content="Ended!")
break
await message.edit(content=f"Timer: {secondint}")
await asyncio.sleep(1)
await ctx.send(f"{ctx.author.mention} Your countdown Has ended!")
except ValueError:
await ctx.send("Must be a number!")

The only way it works is if you do something like this
import asyncio
#client.command()
async def count(ctx, number:int):
try:
if number < 0:
await ctx.send('number cant be a negative')
elif number > 300:
await ctx.send('number must be under 300')
else:
message = await ctx.send(number)
while number != 0:
number -= 1
await message.edit(content=number)
await asyncio.sleep(1)
await message.edit(content='Ended!')
except ValueError:
await ctx.send('time was not a number')

Related

Python, a timer that able to check time every minute/second without stopping everything else

#my_group.child
#lightbulb.command('five', '5 minute countdown')
#lightbulb.implements(lightbulb.SlashSubCommand)
async def subcommand(ctx):
await ctx.respond("Timer for 5 minute⌛ start!")
await ctx.respond("https://upload.wikimedia.org/wikipedia/commons/7/7a/Alarm_Clock_GIF_Animation_High_Res.gif")
for i in range(5*60):
time.sleep(1) #5 min
if i % 60 == 0 and i != 0:
await ctx.respond(str(int(i/60)) + " minute⌛ has passed!")
await ctx.respond("Timer ended!")
#my_group.child
#lightbulb.command('ten', '10 minute countdown')
#lightbulb.implements(lightbulb.SlashSubCommand)
async def subcommand(ctx):
await ctx.respond("Timer for 10 minute⌛ start!")
await ctx.respond("https://upload.wikimedia.org/wikipedia/commons/7/7a/Alarm_Clock_GIF_Animation_High_Res.gif")
for i in range(10*60):
time.sleep(1) #10 min
if i % 60 == 0 and i != 0:
await ctx.respond(str(int(i/60)) + " minute⌛ has passed!")
await ctx.respond("Timer ended!")
#my_group.child
#lightbulb.command('thirty', '30 minute countdown')
#lightbulb.implements(lightbulb.SlashSubCommand)
async def subcommand(ctx):
await ctx.respond("Timer for 30 minute⌛ start!")
await ctx.respond("https://upload.wikimedia.org/wikipedia/commons/7/7a/Alarm_Clock_GIF_Animation_High_Res.gif")
for i in range(30*60):
time.sleep(1) #30 min
if i % 300 == 0 and i != 0:
await ctx.respond(str(int(i/300)) + " minute⌛ has passed!")
await ctx.respond("Timer ended!")
When run, the timer will start however every other script is unable to run due to it being stuck in the for loop while the timer is still going. Is there an alternate way of making a timer that won't stop other scripts from running?
The issue here is probably that your threads while sleeping, are not releasing the resources for the other threads.
It should work once you change the time.sleep(1) to await asyncio.sleep(1)
You can find more information here and here.

A typeracer in discord.py

What I'm doing: I'm trying to make a typeracer in discord.py, but first I'm trying to wrap my head around using def check and def inner_check.
Problem: As seen in the image below, when I type the correct sentence it still tells me that I'm wrong. There is no error as far as I have checked. I used the code from this link here, which helped with the author input in case that helps.
Code:
#client.command()
async def tr(ctx):
starttime = time.time()
C = "Just a nice little test"
await ctx.send(f"Type: {C}")
a = 1
def check(author):
def inner_check(message):
return message.author == author and message.content == C
return inner_check
while a == 1:
msg = await client.wait_for('message', check=check(ctx.author))
if msg == True:
a = a - 1
else:
await ctx.send("wrong")
fintime = time.time()
total = fintime - starttime
await ctx.send(round(total,2),"seconds")
Based off of Doyousketch2's answer, I've written the other way to do it with the #client.command since it required a bit more tweaking. I've included the time taken (rounded to the nearest whole second) as well.
What was changed:
Used #client.command rather than `if message.content == '!type'
message.channel.send is now ctx.send here
message.author was changed to ctx.author, since message would give an error of name 'message' is not defined
#client.command()
async def type(ctx):
starttime = time.time()
answer = 'Just a nice little test'
timer = 17.0
await ctx.send(f"You have {timer} seconds to type: {answer}")
def is_correct(msg):
return msg.author==ctx.author
try:
guess = await client.wait_for('message', check=is_correct, timeout=timer)
except asyncio.TimeoutError:
return await ctx.send("You took too long :(")
if guess.content == answer:
await ctx.send("You got it!")
fintime = time.time()
total = fintime - starttime
await ctx.send(f"{round(total)} seconds")
else:
await ctx.send("Nope, that wasn't really right")
fintime = time.time()
total = fintime - starttime
await ctx.send(f"{round(total)} seconds")
Basically their Github example, just tweaked a bit.
#! /usr/bin/env python3
import discord
import random
import asyncio
token = 'bot_token'
class MyClient(discord.Client):
async def on_ready(self):
print('Logged in as: ', self.user.name, self.user.id)
print('--------------------------------------------------')
async def on_message(self, message):
## no need for bot to reply to itself
if message.author.id == self.user.id:
return
if message.content == '!type': ## begin typeracer game with "!type" command
answer = 'Just a nice little test'
timer = 5.0
await message.channel.send(f'You have {timer} seconds to type: {answer}')
def is_correct(msg):
return msg.author == message.author
try:
guess = await self.wait_for('message', check=is_correct, timeout=timer)
except asyncio.TimeoutError:
return await message.channel.send('Sorry, you took too long.')
if guess.content == answer:
await message.channel.send('Right on!')
else:
await message.channel.send('Oops.')
client = MyClient()
client.run(token)

I'm trying to create a discord.py giveaway command

I've tried this and i didn't really get the logic through it, I need some help making it have:
🎉 Emoji
Message
Setting the time
My Code:
#bot.command()
async def giveaway(ctx, msg, duration):
embed=discord.Embed()
embed.title=msg
embed.description="React To Giveaway With 🎉 To Join."
embed.set_footer(text="👑 MTND Bot Development")
embed.color=0x00ffff
msg = await ctx.send(embed=embed)
await msg.add_reaction('🎉')
Please help if you could.
Here is one.
def convert(time):
pos = ["s","m","h","d"]
time_dict = {"s" : 1, "m" : 60, "h" : 3600, "d": 3600*24}
unit = time[-1]
if unit not in pos:
return -1
try:
val = int(time[:-1])
except:
return -2
return val * time_dict[unit]
#client.command()
#commands.has_permissions(kick_members=True)
async def giveaway(ctx):
await ctx.send("Let's start with this giveaway! Answer these questions within 15 seconds!")
questions = ["Which channel should it be hosted in?", "What should be the duration of the giveaway? (s|m|h|d)", "What is the prize of the giveaway?"]
answers = []
def check(m):
return m.author == ctx.author and m.channel == ctx.channel
for i in questions:
await ctx.send(i)
try:
msg = await client.wait_for('messsage', timeout=15.0, check=check)
except asyncio.TimeoutError:
await ctx.send('You didn\'t answer in time, please be quicker next time!')
return
else:
answers.append(msg.content)
try:
c_id = int(answers[0][2:-1])
except:
await ctx.send(f"You didn't mention a channel properly. Do it like this {ctx.channel.mention} next time.")
return
channel = client.get_channel(c_id)
time = convert(answers[1])
if time == -1:
await ctx.send(f"You didn't answer with a proper unit. Use (s|m|h|d) next time!")
return
elif time == -2:
await ctx.send(f"The time just be an integer. Please enter an integer next time.")
return
prize = answers[2]
await ctx.send(f"The giveaway will be in {channel.mention} and will last {answers[1]} seconds!")
embed = discord.embed(title = "Giveaway!", description = f"{prize}", color = ctx.author.color)
embed.add_field(name = "Hosted by:", value = ctx.author.mention)
embed.set_footer(text = f"Ends {answers[1]} from now!")
my_msg = await channel.send(embed = embed)
await my_msg.add_reaction("🎉")
await asyncio.sleep(time)
new_msg = await channel.fetch_message(my_msg.id)
users = await new_msg.reactions[0].users().flatten()
users.pop(users.index(client.user))
winner = random.choice(users)
await channel.send(f"Congratulations! {winner.mention} won the prize: {prize}!")
#client.command()
#commands.has_permissions(kick_members=True)
async def reroll(ctx, channel : discord.TextChannel, id_ : int):
try:
new_msg = await channel.fetch_message(id_)
except:
await ctx.send("The ID that was entered was incorrect, make sure you have entered the correct giveaway message ID.")
users = await new_msg.reactions[0].users().flatten()
users.pop(users.index(client.user))
winner = random.choice(users)
await channel.send(f"Congratulations the new winner is: {winner.mention} for the giveaway rerolled!")
This is my whole code for my gcreate command
This is a command with embeds and steps
#client.command()
#commands.has_role("Giveaways")
async def gcreate(ctx):
await ctx.send("Let's start with this giveaway!\n`Answer these questions within 15 seconds!`")
questions = ["**Which channel should it be hosted in?**",
"**What should be the duration of the giveaway?** `(s|m|h|d)`",
"**What is the prize of the giveaway?**"]
answers = []
def check(m):
return m.author == ctx.author and m.channel == ctx.channel
for i in questions:
await ctx.send(i)
try:
msg = await client.wait_for('message', timeout=15.0, check=check)
except asyncio.TimeoutError:
await ctx.send('You didn\'t answer in time, please be quicker next time!')
return
else:
answers.append(msg.content)
try:
c_id = int(answers[0][2:-1])
except:
await ctx.send(f"You didn't mention a channel properly. **Do it like this {ctx.channel.mention} next time.**")
return
channel = client.get_channel(c_id)
time = convert(answers[1])
if time == -1:
await ctx.send("You didn't answer the time with a proper unit. Use `(s|m|h|d)` next time!")
return
elif time == -2:
await ctx.send("The time must be a number. Please enter a number next time")
return
elif time < 10:
await ctx.send("Time Cannot Be Less Than 10s!!")
return
prize = answers[2]
await ctx.send(f"The Giveaway will be in {channel.mention} and will last {answers[1]}!")
embed = discord.Embed(title = "Giveaway!", description = "React To 🎉 To Enter The **Giveaway**!", color = discord.Color.blue())
embed.add_field(name=":gift: Prize:-", value=f"{prize}", inline=False)
embed.add_field(name=":timer: Ends In:-", value=f"{answers[1]}", inline=False)
embed.set_thumbnail(url=ctx.guild.icon_url)
embed.set_footer(text=f"Hosted By {ctx.author.name}", icon_url=ctx.author.avatar_url)
my_msg = await channel.send(embed = embed)
await my_msg.add_reaction("🎉")
await asyncio.sleep(time)
new_msg = await channel.fetch_message(my_msg.id)
users = await new_msg.reactions[0].users().flatten()
users.pop(users.index(self.client.user))
users.pop(users.index(ctx.author))
if len(users) == 0:
await channel.send("No Winner Was Decided!")
return
winner = random.choice(users)
embed2 = discord.Embed(title = "Giveaway!", description ="**Giveaway Has Ended**!", color = discord.Color.blue())
embed2.add_field(name=":gift: Prize:-", value=f"{prize}", inline=False)
embed2.add_field(name=":trophy: Winner:-", value=f"{winner.mention}", inline=False)
embed2.set_thumbnail(url=ctx.guild.icon_url)
embed2.set_footer(text=f"Hosted By {ctx.author.name}", icon_url=ctx.author.avatar_url)
await my_msg.edit(embed=embed2)
await channel.send(f"Congratulations! {winner.mention} Won The Prize:-`{prize}`!\nhttps://discord.com/channels/{channel.guild.id}/{channel.id}/{my_msg.id}")
def convert(time):
pos = ["s", "m", "h", "d"]
time_dict = {"s" : 1, "m" : 60, "h" : 3600, "d" : 3600*24}
unit = time[-1]
if unit not in pos:
return -1
try:
val = int(time[:-1])
except:
return -2
return val * time_dict[unit]#client.command()
#commands.has_role("Giveaways")
async def gcreate(ctx):
await ctx.send("Let's start with this giveaway!\n`Answer these questions within 15 seconds!`")
questions = ["**Which channel should it be hosted in?**",
"**What should be the duration of the giveaway?** `(s|m|h|d)`",
"**What is the prize of the giveaway?**"]
answers = []
def check(m):
return m.author == ctx.author and m.channel == ctx.channel
for i in questions:
await ctx.send(i)
try:
msg = await client.wait_for('message', timeout=15.0, check=check)
except asyncio.TimeoutError:
await ctx.send('You didn\'t answer in time, please be quicker next time!')
return
else:
answers.append(msg.content)
try:
c_id = int(answers[0][2:-1])
except:
await ctx.send(f"You didn't mention a channel properly. **Do it like this {ctx.channel.mention} next time.**")
return
channel = client.get_channel(c_id)
time = convert(answers[1])
if time == -1:
await ctx.send("You didn't answer the time with a proper unit. Use `(s|m|h|d)` next time!")
return
elif time == -2:
await ctx.send("The time must be a number. Please enter a number next time")
return
elif time < 10:
await ctx.send("Time Cannot Be Less Than 10s!!")
return
prize = answers[2]
await ctx.send(f"The Giveaway will be in {channel.mention} and will last {answers[1]}!")
embed = discord.Embed(title = "Giveaway!", description = "React To 🎉 To Enter The **Giveaway**!", color = discord.Color.blue())
embed.add_field(name=":gift: Prize:-", value=f"{prize}", inline=False)
embed.add_field(name=":timer: Ends In:-", value=f"{answers[1]}", inline=False)
embed.set_thumbnail(url=ctx.guild.icon_url)
embed.set_footer(text=f"Hosted By {ctx.author.name}", icon_url=ctx.author.avatar_url)
my_msg = await channel.send(embed = embed)
await my_msg.add_reaction("🎉")
await asyncio.sleep(time)
new_msg = await channel.fetch_message(my_msg.id)
users = await new_msg.reactions[0].users().flatten()
users.pop(users.index(self.client.user))
users.pop(users.index(ctx.author))
if len(users) == 0:
await channel.send("No Winner Was Decided!")
return
winner = random.choice(users)
embed2 = discord.Embed(title = "Giveaway!", description ="**Giveaway Has Ended**!", color = discord.Color.blue())
embed2.add_field(name=":gift: Prize:-", value=f"{prize}", inline=False)
embed2.add_field(name=":trophy: Winner:-", value=f"{winner.mention}", inline=False)
embed2.set_thumbnail(url=ctx.guild.icon_url)
embed2.set_footer(text=f"Hosted By {ctx.author.name}", icon_url=ctx.author.avatar_url)
await my_msg.edit(embed=embed2)
await channel.send(f"Congratulations! {winner.mention} Won The Prize:-`{prize}`!\nhttps://discord.com/channels/{channel.guild.id}/{channel.id}/{my_msg.id}")
def convert(time):
pos = ["s", "m", "h", "d"]
time_dict = {"s" : 1, "m" : 60, "h" : 3600, "d" : 3600*24}
unit = time[-1]
if unit not in pos:
return -1
try:
val = int(time[:-1])
except:
return -2
return val * time_dict[unit]**strong text**
```
In order to make an giveaway command you need first of all, on going giveaways variables:
cmdsettings = {}
allowedRiggers = config.riggers
ongoingGiveaways = {}
like that then embed:
actualTitle = 'Giveaway: ' + str(msg)
embed = discord.Embed(color=0x0040ff,title=actualTitle)
info = "React with 🎉 on this message to enter"
embed.add_field(name='Message from creator', value=message, inline=False)
embed.add_field(name='How to enter', value=info, inline=False)
embed.add_field(name='Giveaway end date', value=endDate, inline=False)
that end date can be anything, but I am not going to show how to do it since i assume you know python. and them use those vars what i sent before, also this code is based on https://github.com/AnimeHasFallen/discordbot-giveaway/ so view the full source code there.
key39

Can someone tell me what am I doing wrong?

I am trying to make an alarm discord bot using python. No errors are happening, but also no output from the bot past the try, except function
Please note: alarm, not timer
#client.command(aliases = ["alarm"])
async def alarm_at(ctx, time):
alarm = False
if alarm == False:
alarm = True
now = datetime.now()
mtimeA = time
mtimeB = mtimeA.split(":")
hr = int(mtimeB[0])
min = int(mtimeB[1])
secsleft = int((timedelta(hours=24) - (now - now.replace(hour=hr, minute=min, second=0, microsecond=0))).total_seconds() % (24 * 3600))
print(secsleft)
await ctx.send(f"OK\Alarm go off at {time}")
def check(message):
return message.author == ctx.author and message.content.lower() == "cancel alarm"
try:
await client.wait_for("message", check=check, timeout=time)
await ctx.send("alarm cancelled")
except:
if secsleft == 0:
await ctx.send(f"{ctx.guild.default_role} alarm finished")
elif alarm == True:
await ctx.send("Please cancel the current alarm to run a new alarm")
If the error is happening in the try ... except, you won't see anything. Try this instead:
try:
await client.wait_for("message", check=check, timeout=time)
await ctx.send("alarm cancelled")
except Exception as e:
print(f"Error: {e}")
if secsleft == 0:
await ctx.send(f"{ctx.guild.default_role} alarm finished")

How do I make a bot say a message activated by a variable rather than a reply command?

I'm trying to make a trivia bot and it has a command that makes it countdown from 30-1 in seconds. When it hits 1 I don't know how to make say something in the discord chat.
I've already tried looking through the API.
questionTimer = 30
#while questionTimer > 1:
#questionTimer = questionTimer - 1
#time.sleep(1)
#print (questionTimer)
I'm hoping that it can say Times up in the chat when questionTimer = 1
If you want it to print out every number you can do something like
#client.command()
async def quiz():
seconds = 30
while seconds > 0:
await client.say(seconds)
await asyncio.sleep(1)
seconds-=1
await client.say("Done")
But if you just want to make it wait 30 seconds and then display a message you can do something like
#client.command()
async def quiz():
await asyncio.sleep(30)
await client.say("Done")
Depending if you are using the rewrite or the old async version of discord.py I would recommend the following :
Discord.py async (0.16.x) :
#client.event
async def on_message(self, message):
if message.content.startswith('!quiz'):
quizMsg = 'Question of the quiz'
msg = await client.say(f"{quizMsg}\n\n{secs}s left !")
secs = 30
while secs > 0:
await asyncio.sleep(1)
await client.edit_message(msg, f"{quizMsg}\n\n{secs}s left !")
secs--
await client.say("Time is up ! The answer was...")
Discord.py rewrite (1.0.x) :
#commands.command(name="quiz", aliases=["q"])
async def quiz():
quizMsg = 'Question of the quiz'
msg = await ctx.send(f"{quizMsg}\n\n{secs}s left !")
secs = 30
while secs > 0:
await asyncio.sleep(1)
await msg.edit(content = f"{quizMsg}\n\n{secs}s left !")
secs--
await ctx.send("Time is up ! The answer was...")
Mind the difference between the two methods

Categories