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")
Related
How do you do it, that if someone uses a command, a timer starts and does something if a user answers in a in the given time?
Like someone does "!shoot #user#0000" and the tagged user has to answer with "!dodge" in under 10 seconds or he dies
You could use the wait_for method:
#client.command(name = "shoot")
async def shoot_user(ctx, user: discord.Member):
channel = ctx.channel
def check(m):
return m.content == '!dodge' and m.channel == channel and m.author == user
try:
await client.wait_for('message', check=check, timeout = 10.0)
except asyncio.TimeoutError:
await channel.send(f"{user.mention} did not dodge in time!")
else:
await channel.send(f"{user.mention} dodged!")
So my discord bot in python has the task to send an embed as soon as the user sends the message "$start". After this the code is starting a while loop and checking if a user has reacted. Simultaneously I want to edit the message of the bot every second so I can display some kind of timer to show the users how much time they have left to react but I dont know how to implement a timer running at the same time. Would it be useful to use multiprocessing for this one?
Here is my very specific code if anyone needs it to answer my question :)
#client.command()
async def start(ctx):
timer = 120
remTime = timer
seedCapital = 10000
sessionEmpty = True
players[ctx.author] = seedCapital
em = discord.Embed(title = "New Poker Session", description = "Waiting for players to join ...\nreact with 💸 to join or ▶️ to start (only host)", color = discord.Color.green())
#em.add_field(name = "2 minutes remaining from now on!", value = "")
botMsg = await ctx.send(embed = em)
await botMsg.add_reaction("💸")
await botMsg.add_reaction("▶️")
while True:
mom0 = time.perf_counter()
try:
reaction, user = await client.wait_for('reaction_add', timeout = remTime, check = lambda reaction, user: reaction.emoji in ["💸", "▶️"])
#msg = await client.wait_for('message', timeout = remTime, check = lambda m: m.channel == ctx.channel)
#print(f"receiving message: {msg.content}")
except asyncio.TimeoutError:
break
if reaction.emoji == "💸":
sessionEmpty = False
await ctx.send(f"{user.mention} joined the session!")
players[user] = seedCapital
elif user == ctx.author and reaction.emoji == "▶️":
break
mom1 = time.perf_counter()
neededTime = mom1 - mom0
remTime -= neededTime
print(remTime)
if not sessionEmpty:
await ctx.send("starting session ...")
#start session
else:
await ctx.send("Noone joined your session :(")
We can use asyncio.gather to run coroutines concurrently.
#after command
from datetime import datetime, timedelta
end_time = datetime.now() + timedelta(seconds=30) #30 seconds to react
async def coro():
for i in range(30, 0, 5):
await botMsg.edit(f'time remaining: {i}') #send another message if you don't want old content to be erased
await asyncio.sleep(5)
async def coro2():
while datetime.now() <= endtime:
#do stuff
await asyncio.gather(coro(), coro2())
Note: There might be a small delay between the completion of the two coroutines.
References:
asyncio.gather
Edit: Here is the small delay I mentioned
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 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')
def isAdmin(reaction, user):
for i in admins:
if user.id == i: return (str(reaction.emoji) == '👍' or str(reaction.emoji) == '👎')
try: reaction, user = await self.bot.wait_for('reaction_add', timeout=43200, check=isAdmin)
except asyncio.TimeoutError: await msg.edit(embed=embedEnd)
else:
resign_channel = discord.utils.get(ctx.guild.channels, name="resignings")
if str(reaction.emoji) == '👍':
print('{}: {} resigned {} {}.'.format(extCalls.timeNow('datetime'), ctx.channel.category.name, firstName, lastName))
await msg.edit(embed=embedFin)
await resign_channel.send(embed=embedConf)
else: await msg.edit(embed=embedEnd)
This is my code to have the bot wait for a reaction on msg. But, for some reason, when I have two msg (messages) waiting for a reaction at the same time, when I react to one message, both trigger success, even though I didn't react to the second message. This is hugely problematic for an admin-based approval system... does anyone know why this is happening or how to fix it?
This code is really messy, but if you're searching for a way to wait only for a reaction on one message you should add stuff to your check command, for example:
#bot.command(name="some_command")
async def sc(ctx):
msg = await ctx.send("Some interesting message!")
def check(reaction, user):
return reaction.message.id == msg.id
try:
reaction, user = await bot.wait_for("reaction_add", check=check,timeout=30.0)
except asyncio.TimeoutError:
await ctx.send("timeout")
return
await ctx.send(f"You reacted {str(reaction)}")