I was trying to create a discord bot with giveaway command which updates time left every 1-2 mins in giveaway embed . I have been trying it since 3 days but wasn't able to find a solution. I managed to make it update seconds, but if I specify time more than 1m i.e. 60 seconds it automatically converts it to seconds and starts giveaway with time left in just seconds . I want it to keep time in given unit and update time in --days, --hours, --minutes, --seconds left.
Here are a few images what i mean:
What it currently do:
What i want it to do:
Its just Ends In Or Time remaining what i want to be changed!
My current code:
#commands.command()
#commands.guild_only()
async def gstart(self, ctx, duration, *, prize):
time = self.convert(duration)
if time == -1:
await ctx.send(f'Answer Time With A Proper Unit (s, m, h, d)')
return
elif time == -2:
await ctx.send(f'Time Must Be A Integer!')
return
giveawayembed = discord.Embed(
title="🎉 New Giveaway! 🎉",
description=f"**Prize:** {prize}\n"
f"**Hosted By:** {ctx.author.mention}\n"
f"**Ends In:** {time} Seconds",
colour=discord.Color.green()
)
msg = await ctx.send(embed=giveawayembed)
reactions = await msg.add_reaction("🎉")
while time:
await sleep(10)
time -= 10
giveawayembed.description= f"**Prize:** {prize}\n**Hosted By:** {ctx.author.mention}\n**Ends In:** {time} Seconds"
await msg.edit(embed=giveawayembed)
new_msg = await ctx.fetch_message(msg.id)
users = await new_msg.reactions[0].users().flatten()
users.pop(users.index(self.client.user))
winner = random.choice(users)
endembed = discord.Embed(
title="Giveaway ended!",
description=f"Prize: {prize}\nWinner: {winner.mention}")
await msg.edit(embed=endembed)
await ctx.send(f"🎉 Giveaway Winner: {winner.mention} | Prize: {prize}")
For Converting Time I Have:
class Giveaway(commands.Cog):
def __init__(self, client):
self.client = client
def convert(self, 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]
Any help is highly appreciated! 😁
And I m sorry if I wasn't able to make you understand my problem. 😅
I understand your problem as it is actually a very simple fix, you can either import time, or use await asyncio.sleep(time)
Before using the code I am providing, make sure to import asyncio in your imports.
Your code:
#commands.command()
#commands.guild_only()
async def gstart(self, ctx, duration, *, prize):
time = self.convert(duration)
if time == -1:
await ctx.send(f'Answer Time With A Proper Unit (s, m, h, d)')
return
elif time == -2:
await ctx.send(f'Time Must Be A Integer!')
return
giveawayembed = discord.Embed(
title="🎉 New Giveaway! 🎉",
description=f"**Prize:** {prize}\n"
f"**Hosted By:** {ctx.author.mention}\n"
f"**Ends In:** {time} Seconds",
colour=discord.Color.green()
)
msg = await ctx.send(embed=giveawayembed)
reactions = await msg.add_reaction("🎉")
while time:
await sleep(10)
time -= 10
giveawayembed.description= f"**Prize:** {prize}\n**Hosted By:** {ctx.author.mention}\n**Ends In:** {time} Seconds"
await msg.edit(embed=giveawayembed)
new_msg = await ctx.fetch_message(msg.id)
users = await new_msg.reactions[0].users().flatten()
users.pop(users.index(self.client.user))
winner = random.choice(users)
endembed = discord.Embed(
title="Giveaway ended!",
description=f"Prize: {prize}\nWinner: {winner.mention}")
await msg.edit(embed=endembed)
await ctx.send(f"🎉 Giveaway Winner: {winner.mention} | Prize: {prize}")
In both fixes I will fix a slight problem that could easily be fixed, you have it so while time, it will go down by 10, I recommend doing it so it says while time > 0: so that once it hits 0 it wont keep counting down.
Easy fix using await asyncio.sleep(time):
#commands.command()
#commands.guild_only()
async def gstart(self, ctx, duration, *, prize):
time = self.convert(duration)
if time == -1:
await ctx.send(f'Answer Time With A Proper Unit (s, m, h, d)')
return
elif time == -2:
await ctx.send(f'Time Must Be A Integer!')
return
giveawayembed = discord.Embed(
title="🎉 New Giveaway! 🎉",
description=f"**Prize:** {prize}\n"
f"**Hosted By:** {ctx.author.mention}\n"
f"**Ends In:** {time} Seconds",
colour=discord.Color.green()
)
msg = await ctx.send(embed=giveawayembed)
reactions = await msg.add_reaction("🎉")
while time >= 0:
if time <= 60:
giveaway.remove_field(index=1)
giveaway.insert_field_at(index=1, name='Ends:', value=f'{time} second(s) from now')
await my_msg.edit(embed=giveaway)
time -= 10
await asyncio.sleep(10)
elif 60 <= time < 3600:
giveaway.remove_field(index=1)
giveaway.insert_field_at(index=1, name='Ends:', value=f'{time/60} minute(s) from now')
await my_msg.edit(embed=giveaway)
time -= 6
await asyncio.sleep(6)
elif 3600 <= time < 86400:
giveaway.remove_field(index=1)
giveaway.insert_field_at(index=1, name='Ends:', value=f'{time/3600} hour(s) from now')
await my_msg.edit(embed=giveaway)
time -= 360
await asyncio.sleep(360)
elif time >= 86400:
giveaway.remove_field(index=1)
giveaway.insert_field_at(index=1, name='Ends:', value=f'{time/86400} day(s) from now')
await my_msg.edit(embed=giveaway)
time -= 8640
await asyncio.sleep(8640)
if time <= 0:
giveaway.remove_field(index=1)
giveaway.insert_field_at(index=1, name='Ends:', value=f'Ended at {datetime.datetime.now().strftime("%B %d, %I:%M %p")}') # noqa
await my_msg.edit(embed=giveaway)
await asyncio.sleep(time)
new_msg = await ctx.fetch_message(msg.id)
users = await new_msg.reactions[0].users().flatten()
users.pop(users.index(self.client.user))
winner = random.choice(users)
endembed = discord.Embed(
title="Giveaway ended!",
description=f"Prize: {prize}\nWinner: {winner.mention}")
await msg.edit(embed=endembed)
await ctx.send(f"🎉 Giveaway Winner: {winner.mention} | Prize: {prize}")
If you are still confused or have any more questions you can contact me on discord at killrebeest#7187 or comment on this answer. Have a good day!
Related
I'm trying to make a discord bot but the bot is not responding to any of my commands.
He is writing the command when going online but nothing more.
I have given him every permission and intent but it did not help.
import discord
import time
intents = discord.Intents.default()
intents.members = True
client = discord.Client(intents=intents)
# Dictionary to store the brake times for each user
brb_times = {}
#client.event
async def on_message(message):
# Only process messages from other users, not the bot itself
if message.author == client.user:
return
if message.content.startswith("!brb 5"):
brb_times[message.author.name] = time.time() + 5 * 60
await message.channel.send(f"{message.author.mention} has taken a 5-minute brake.")
elif message.content.startswith("!brb 10"):
brb_times[message.author.name] = time.time() + 10 * 60
await message.channel.send(f"{message.author.mention} has taken a 10-minute brake.")
elif message.content.startswith("!brb 15"):
brb_times[message.author.name] = time.time() + 15 * 60
await message.channel.send(f"{message.author.mention} has taken a 15-minute brake.")
elif message.content.startswith("!back"):
if message.author.name in brb_times:
brake_time = brb_times[message.author.name]
del brb_times[message.author.name]
elapsed_time = time.time() - brake_time
if elapsed_time > 0:
await message.channel.send(f"{message.author.mention} is back, but was late by {int(elapsed_time)} seconds.")
else:
await message.channel.send(f"{message.author.mention} is back.")
else:
await message.channel.send(f"{message.author.mention} was not on a brake.")
#client.event
async def on_ready():
print("Bot is ready!")
await client.get_channel(CENSORED).send("Bot is ready to track breaks!")
client.run("CENSORED")
You need message_content to be True in intents.
def convert(time):
time_dict = {"s": "seconds", "m": "minutes", "h": "hours", "d": "days"} # pulling your idea, but replacing the seconds with the full name of the acronym.
val = time[:-1] # everything before the last character
unit = time[-1] # the last character
return f"{val} {time_dict[unit]}"
convert("5d") # 5 days
convert("10s") # 10 seconds
#client.command()
#commands.has_permissions(manage_messages=True)
async def gcreate(ctx, time: str, *, prize: str):
time = convert(time)
embed = discord.Embed(title=prize,
description=f"Hosted by - {ctx.author.mention} React with :tada: to enter! Time Remaining: **{time}**",
colour = discord.Colour.purple())
msg = await ctx.channel.send(content=":tada: **GIVEAWAY** :tada:", embed=embed)
await msg.add_reaction("🎉")
await asyncio.sleep(3)
await asyncio.sleep(int(time))
new_msg = await ctx.channel.fetch_message(msg.id)
user_list = [user for user in await new_msg.reactions[0].users().flatten() if
user != client.user]
if len(user_list) == 0:
await ctx.send("No one reacted.")
else:
winner = random.choice(user_list)
await ctx.send(f"{winner.mention} You have won the {prize}!")
I get no errors, it just won't send the winner message.
I am doing a giveaway command call =gstart <time> <prize and the giveaway will be held in the channel I use this command and After sending the embed giveaway message it will delete the gstart command. Here is the code:
#bot.command()
async def gstart(ctx,time,*,prize):
time = convert(time)
if time == -1:
await ctx.send("Error, can't identify time unit")
if time == -2:
await ctx.send("Error, can't identify time value")
embed = discord.Embed(title=prize, description = f"React with :tada: to enter\nHosted by: {ctx.author.mention}", color=discord.Color.red())
embed.set_footer(text = f"Ends at {time} from now!")
#delete-command
await ctx.send(":tada: **GIVEAWAY** :tada:")
my_msg = await ctx.send(embed = embed)
await my_msg.add_reaction("🎉")
await asyncio.sleep(time)
new_msg = await ctx.fetch_message(my_msg.id)
users = await new_msg.reactions[0].users().flatten()
users.pop(users.index(bot.user))
winner = random.choice(users)
await ctx.send(f"Congratulations {winner.mention}! You won the {prize}!")
msg_link = my_msg.jump_url
winner_embed = discord.Embed(title=f"Hey {winner}",description=f"You just won a [giveaway]({msg_link}) in {ctx.guild}",color=discord.Color.red())
winner_embed.add_field(name=prize,value=f"Hosted by: {ctx.author.mention}",inline=True)
await winner.send(embed=winner_embed)
By the way the convert() function looks like this:
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]
Reply you with the discord.Context object and delete the message user sent.
Example:
import asyncio
#bot.command()
async def deleteCommandAfterSent(ctx):
await ctx.send("blablabla ") #REPLY MESSAGE
await asyncio.sleep(1)
await ctx.message.delete()
Here is the code I have, the time is not being converted, and I don't know what to do anymore. If you know what to do, let me know how to do this
Here is what I got so far:
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(manage_messages = True)
async def giveaway(ctx, time : str, *, prize: str):
embed = discord.Embed(title=prize,
description=f"Hosted by - {ctx.author.mention}\nReact with :tada: to enter!\nTime Remaining: **{time}** seconds",
color=ctx.guild.me.top_role.color, )
msg = await ctx.channel.send(content=":tada: **GIVEAWAY** :tada:", embed=embed)
await msg.add_reaction("🎉")
await asyncio.sleep(3)
new_msg = await ctx.channel.fetch_message(msg.id)
user_list = [u for u in await new_msg.reactions[0].users().flatten() if u != client.user] # Check the reactions/don't count the bot reaction
if len(user_list) == 0:
await ctx.send("No one reacted.")
else:
winner = random.choice(user_list)
await ctx.send(f"{winner.mention} You have won the {prize}!")
When I type in 2m meaning 2 minutes, it shows 2m seconds remaining, now I know why it says seconds because I have not updated the response yet, but the time is only 2 seconds plus the 3 seconds delay time. Basically a total of around 6 seconds.
I did just throw 2 commands from stack overflow together, and it is like putting in a Lamborghini head gasket and a dodge engine block, I know it should not work, even with the little bit of modifications, I kinda do see whats wrong now, but I don't know how to fix it
So I revised your code and changed the giveaway command a little bit. After a few modifications, the command worked as it should for me. Here is how I re-defined it:
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(manage_messages=True)
async def giveaway(ctx, time: str, *, prize: str):
time = convert(time)
embed = discord.Embed(title=prize,
description=f"Hosted by - {ctx.author.mention}\nReact with :tada: to enter!\nTime Remaining: **{time}** seconds",
color=ctx.guild.me.top_role.color)
msg = await ctx.channel.send(content=":tada: **GIVEAWAY** :tada:", embed=embed)
await msg.add_reaction("🎉")
await asyncio.sleep(3)
await asyncio.sleep(int(time))
new_msg = await ctx.channel.fetch_message(msg.id)
user_list = [user for user in await new_msg.reactions[0].users().flatten() if
user != client.user] # Check the reactions/don't count the bot reaction
if len(user_list) == 0:
await ctx.send("No one reacted.")
else:
winner = random.choice(user_list)
await ctx.send(f"{winner.mention} You have won the {prize}!")
You can use this for converting time.
import re
from discord.ext.commands import BadArgument
time_regex = re.compile(r"(?:(\d{1,5})(h|s|m|d))+?")
time_dict = {"h": 3600, "s": 1, "m": 60, "d": 86400}
def convert(argument):
args = argument.lower()
matches = re.findall(time_regex, args)
time = 0
for key, value in matches:
try:
time += time_dict[value] * float(key)
except:
raise BadArgument
return round(time)
This chunk of code is a timer with a set duration of 90 seconds, using the command '!t90' to start.
How would I write the option to use command '!t' with any number of seconds?
(or 30, 45, 60, 90, 120 in one file (as these are the only timers that my server will use 99.9% of the time))
Thanks
import discord
from discord.ext import commands
import asyncio
bot = commands.Bot(command_prefix="!")
counter_channel = None
task = None
async def ex(message):
global counter_channel
if counter_channel is not None:
await bot.send_message(
message.channel,
embed=discord.Embed("There is a counter in {}".format(counter_channel.mention), color=discord.Color.red() ))
return
counter_channel = message.channel
await bot.send_message(message.channel, "1:30")
await asyncio.sleep(30)
await bot.send_message(message.channel, "1:00")
await asyncio.sleep(30)
await bot.send_message(message.channel, "0:30")
await asyncio.sleep(20)
await bot.send_message(message.channel, "0:10")
await asyncio.sleep(10)
await bot.send_message(message.channel, "time")
counter_channel = None
#bot.command(pass_context=True)
async def t90(ctx):
global task
task = bot.loop.create_task(ex(ctx.message))
#bot.command(pass_context=True)
async def cancel(ctx):
global task, counter_channel
await bot.send_message(message.channel, "timer reset")
task.cancel()
task = None
counter_channel = None
bot.run('###token###')
Here's one way you could make such a command
from datetime import timedelta
from asyncio import sleep
def time_repr(td: timedelta) -> str:
"Time formatter with optional dates/hours"
minutes, seconds = divmod(int(td.total_seconds()), 60)
hours, minutes = divmod(minutes, 60)
days , hours = divmod(hours, 24)
res = f"{minutes:>02}:{seconds:>02}"
if hours or days:
res = f"{hours:>02}:" + res
if days:
res = f"{td.days} days, " + res
return res
#bot.command(pass_context=True)
async def countdown(ctx, seconds: int):
td = timedelta(seconds=seconds)
while True:
await bot.say(time_repr(td))
if td.total_seconds() > 30:
td -= timedelta(seconds=30)
await sleep(30)
elif td.total_seconds > 10:
td -= timedelta(seconds=10)
await sleep(10)
elif td.total_seconds > 1:
td -= timedelta(seconds=1)
await sleep(1)
else:
break
Note that this won't always make the best timer: sleep(10) guarantees the event loop will wait at least 10 seconds, but it may wait longer. It'll usually be pretty close though.