I have a bot with a giveaway command.
Info
API: Discord API via Nextcord
Language: Python
The module that interprets time (from human time [1m | 1h | 1d] to seconds): humanfriendly
Expectations
I wanted a sort of... uh... a "ends in" thing. Discord has a built-in Unix Time thingy that's syntax is this:
<t:UNIX:type>
Unix is the UNIX time, type is the- well... type. E.g., R as relative time
Result
Well, I met this when I used 1m (1 minute):
Ends in [some whole 2 months!]
Yes, it appeared as two months there. The actual time was working correctly. The giveaway can end in one minute. But my problem is with the time display.
Code
#commands.command(name="gstart")
#commands.has_permissions(manage_guild=True)
async def gquickStart(self, ctx, gtime, *, gprize: str):
if gtime == None:
return await ctx.send("Include a time.")
elif gprize == None:
return await ctx.send("How are we gonna giveaway nothing?")
gawtime = humanfriendly.parse_timespan(gtime)
gawtimetuple = nextcord.utils.utcnow() + datetime.timedelta(gawtime)
gwembed = nextcord.Embed(
title=f"**:tada: {gprize} :tada:**",
description=f"Ends in <t:{int(time.mktime(gawtimetuple.timetuple()))}:R> <t:{int(time.mktime(gawtimetuple.timetuple()))}:T> \n {ctx.author.mention} is giving away **{gprize}**!",
color=nextcord.Colour.green())
gwemend = nextcord.Embed(
title=f"**:tada: GIVEAWAY ENDED :tada:**",
description = f"{ctx.author.mention} has gave away **{gprize}**!",
color=nextcord.Colour.red()
)
gwembed.set_footer(text=f"Giveaway ends in {gtime}")
gaw_msg = await ctx.send(embed=gwembed)
await ctx.message.delete()
await gaw_msg.add_reaction('🎉')
await asyncio.sleep(gawtime)
global new_gaw_msg
new_gaw_msg = await ctx.channel.fetch_message(gaw_msg.id)
global users
users = await new_gaw_msg.reactions[0].users().flatten()
users.pop(users.index(client.user))
try:
winner = random.choice(users)
await ctx.send(f"{winner.mention} has won the giveaway for **{gprize}**")
await new_gaw_msg.edit(embed=gwemend)
except IndexError:
await new_gaw_msg.reply("1 Winner needed for the giveaway, 0 provided")
await new_gaw_msg.edit(embed=gwemend)
BTW, if it matters, I use the command in a category.
Please answer if you can.
Thanks in advance,
Beedful
Explanation
When constructing the timedelta, the first positional argument is days. So, by adding timedelta(60) to utcnow, you add 60 days to the current time.
An easier method would be simply to convert utcnow to a float with .timestamp(), then sum that with gawtime.
Code
#commands.command(name="gstart")
#commands.has_permissions(manage_guild=True)
async def gquickStart(self, ctx, gtime, *, gprize: str):
if gtime is None:
return await ctx.send("Include a time.")
elif gprize is None:
return await ctx.send("How are we gonna giveaway nothing?")
gawtime = humanfriendly.parse_timespan(gtime)
end_time = nextcord.utils.utcnow().timestamp() + gawtime
gwembed = nextcord.Embed(
title=f"**:tada: {gprize} :tada:**",
description=f"Ends in <t:{int(end_time)}:R> <t:{int(end_time)}:T> \n {ctx.author.mention} is giving away **{gprize}**!",
color=nextcord.Colour.green()
)
Unrelated: From PEP 8
Comparisons to singletons like None should always be done with is or is not, never the equality operators.
Reference
parse_timestamp
utcnow
timedelta
Related
so this might sound like I am a noob, but I have been trying for a while now and I cant make it work so I hope you can help me.
I want to make a timeout command so I can just type ".mute [user] [time in either days (with d after the amount of days) or hours (with h after the amount of hours)] [reason]". So for example if I want to mute Alex for 7 days, I have to type .mute #Alex#0001 7d Reason. Now I've tried to check if it's a "h" or "d" at the end (for hours and days) which works, but if I then try to remove the letter from the string it doesnt work. (and the other code doesnt work either for some reason) Here is my code:
#bot.command()
#commands.has_permissions(kick_members = True)
async def mute(ctx, member: discord.Member, time, reason):
if ctx.author.id == member.id:
await ctx.channel.send(":x: You can't ban yourself!")
return
if "h" in time:
time.replace("h","")
print(time)
await member.timeout(until=datetime.timedelta(hours=time), reason=reason)
if "d" in time:
time.replace("d","")
print(time)
await member.timeout(until=datetime.timedelta(days=time), reason=reason)
embed = discord.Embed(title=f":white_check_mark: {member.name} has been successfully muted.")
await ctx.send(embed=embed)
So I actually solved it myself... it could've been multiple problems but what got it to work in the end is that I used member.timeout_for instead of member.timeout. (I also had to do some other things, but they don't really matter here.)
For other people seeing this question, here i put in some code to timeout a user for a specific time
Note: made it within a cog and with slash commands
#app_commands.command(name='timeout', description='timeouts a user for a specific time')
#app_commands.checks.has_permissions(moderate_members=True)
async def timeout(self, interaction: Interaction, member: Member, seconds: int = 0, minutes: int = 0, hours: int = 0, days: int = 0, reason: str = None):
duration = datetime.timedelta(seconds=seconds, minutes=minutes, hours= hours, days=days)
await member.timeout(duration, reason=reason)
await interaction.response.send_message(f'{member.mention} was timeouted until for {duration}', ephemeral=True)
Hi so I've changed the code from past questions to try and simplify it, however now I'm having another problem,
So I have this code which checks for a certain role and changes the roles, however when I input the command into discord which is //leave #name time reason, neither the 'if' or 'elif' statements run.
I get no feedback, no errors, just no reaction from the bot whatsoever.
Here's the code, if someone can tell me what's going on for the statements to not run properly I'd appreciate it.
(I've tried interchanging the 'elif' statements with 'if' statements but to no avail.)
#client.command()
#commands.has_role(876994087214018571)
async def leave(ctx, member: discord.Member = None, time: str = '', *, reason: str = ''):
if not member:
member = ctx.author
loa = ctx.guild.get_role(848032714715561985)
mod = ctx.guild.get_role(848032880709074944)
smod = ctx.guild.get_role(851617257138028645)
amod = ctx.guild.get_role(848057125283954688)
if member.has_role(848032880709074944):
await member.add_roles(loa)
await member.remove_roles(mod)
await ctx.send("I have filed your Leave, take care, we look forward to your return!")
elif member.has_role(851617257138028645):
await member.add_roles(loa)
await member.remove_roles(smod)
await ctx.send("I have filed your Leave, take care, we look forward to your return!")
elif member.has_role(848057125283954688):
await member.add_roles(loa)
await member.remove_roles(amod)
await ctx.send("I have filed your Leave, take care, we look forward to your return!")
modLogEmbed = discord.Embed(title='Leave Logs',
description="A member of Staff is going on leave! " + '<#' + str(member.id) + '>', color=0x000000)
modLogEmbed.add_field(name="Time",
value=(time), inline=False)
modLogEmbed.add_field(name="Reason for Leave:",
value=(reason), inline=False)
modLogEmbed.set_footer(text="LeaveManager Bot")
modLogEmbed.set_author(name='Leave Manager')
botLogChannel = client.get_channel(874959002172268685)
await botLogChannel.send(embed=modLogEmbed)
Also I really do sincerely apologise for the way the code is set out, I genuinely can't figure out how to get it to layout properly like other members questions.
Well, member.has_roles is the problem, member does not have the attribute 'has_role'
maybe try this- using find and lambda to find if your id in any element of roles
I've test it using other role, it works fine.
#commands.command()
#commands.has_role(876994087214018571)
async def leave(ctx, member: discord.Member = None, time: str = '', *, reason: str = ''):
if not member:
member = ctx.author
loa = ctx.guild.get_role(848032714715561985)
mod = ctx.guild.get_role(848032880709074944)
smod = ctx.guild.get_role(851617257138028645)
amod = ctx.guild.get_role(848057125283954688)
result = find(lambda x: x.id == 848032880709074944, member.roles)
if result:
await member.add_roles(loa)
await member.remove_roles(mod)
await ctx.send("I have filed your Leave, take care, we look forward to your return!")
await ctx.send('done')
I'm making a Discord bot with Python that's basically an all-in-one bot. One of the features it has is a slot machine system, as part of its economy system. I have already worked out all the logic for the slot machine. My code is really long, so I'm only going to show the slot machine's function:
#bot.command(name="slots")
async def slots(ctx, amount = None):
await open_account(ctx.author)
if amount == None:
await ctx.send("Kid you gotta bet some actual omegas (bob's currency)")
return
bal = await update_bank(ctx.author)
amount = int(amount)
if amount > bal[0]:
await ctx.send("Imaginary omegas don't work here sunny boi, you don't have enough omegas for that transaction")
return
if amount < 0:
await ctx.send("Did ya ever learn about money in school? Give a positive value")
return
final = []
for i in range(3):
a = random.choice([":apple:", ":banana:", ":watermelon:"])
final.append(a)
for i in final:
realfinal = str(final).replace("[", " ")
for j in realfinal:
realREALfinal = str(realfinal).replace("]", " ")
for k in realREALfinal:
absfinal = str(realREALfinal).replace("'", " ")
for l in absfinal:
finalfinal = str(absfinal).replace(",", " | ")
slotem = discord.Embed(title=str(finalfinal), color=0xff9966)
slotem.add_field(name="SLOT MACHINE", value="Let's see if ya win kid")
await ctx.send(embed=slotem)
if final[0] == final[1] or final[0] == final[2] or final[1] == final[2]:
await update_bank(ctx.author, 2*amount, "pocket")
slotwinem = discord.Embed(title=f"Good job kid, you won `Ω{2*amount}`", color=0xccff66)
await ctx.send(embed=slotwinem)
elif final[0] == final[1] == final[2]:
await update_bank(ctx.author, 3*amount, "pocket")
slotallwinem = discord.Embed(title=f"Wow, sweet victory kid, you got `Ω{3*amount}`", color=0xccff66)
await ctx.send(embed=slotallwinem)
else:
await update_bank(ctx.author, -1*amount, "pocket")
slotloseem = discord.Embed(title=f"Oooh, tough luck kid- you lost `Ω{amount}`", color=0xff3300)
await ctx.send(embed=slotloseem)
This code is definitely extremely inefficient, but it works for now. What I want to do is for the slot machine to look like a real slot machine. To be more specific, I want the embed to be edited so all the emojis look like they are scrolling through all the choices. After two seconds, the first emoji scrolling stops and falls into place. After another two seconds, the second emoji falls into its place. After another two seconds, the third emoji falls into place. For example, this is a visual representation of what I mean: https://th.bing.com/th/id/Rd55e38b55c9ae007a4ffa1c5616bccd5?rik=iQ6wFZblIMc4pQ&pid=ImgRaw
How could I replicate this in Discord.py? Thanks.
right now I am struggling to find a way to set a minimum amount of messages that can be purged. Basically I want it so whenever someone uses the command it will send an error for typing 0 or nothing for amount. I tried some things but they did not seem to work so I guess someone in here will know how to help me.
The code is this:
#commands.command()
#commands.has_permissions(manage_messages=True)
async def clear(self, ctx, *, limit=None):
await ctx.message.delete()
channel = ctx.channel
messages = await channel.history(limit=123).flatten()
if limit != 0 or None:
if not messages:
await ctx.channel.send("I am really sorry but I can not purge an empty channel!")
return
else:
try:
await channel.purge(limit = limit)
return
except discord.Forbidden:
return await ctx.channel.send('I do not have perms')
else:
ctx.channel.send('Minimum amount of purge is 1!')
return
In the beginning I had the limit=None to limit=100 and the None in the if limit != 0 or None was not working. Now I changed it but whenever I put any number that has nothing to do with 0 or None it does not work. Any ideas why and how to fix it?
This line if limit != 0 or None: has to be if limit != 0 or limit == None:. For each comparison you need to declare what it's comparing to.
Additionally, to check if it's over a certain limit, you can just use a less-than symbol comparison. E.g. if limit < 5: return
I am currently tying to make a discord bot in python. It has been about 1 week since I started learning and I thought I would give this a go. I am trying to make a clear function to have it clear the chat. I want to make the bot say "please enter a valid number". If you type anything else other than an int ex. some char.
For example when I put ".clear t" it wont do anything and it gets angry in the terminal. When I put a valid argument such as ".clear 3" it will throw up the "please enter a valid number." after clearing all of it.
I tried different variations of the if statement including placement. Can't figure it out. I have a feeling it be something about where to place the if statement. Thank you for taking the time to read.
#client.command(pass_context = True)
async def clear(ctx, number = 5):
number = int(number)
counter = 0
channel = ctx.message.channel
async for x in client.logs_from(ctx.message.channel, limit = number):
if counter < number:
await client.delete_message(x)
counter += 1
await asyncio.sleep(0.5)
if number != int():
await client.send_message(channel, "Please enter a valid number.")
You need to learn how to properly check an object's type. In your case, if number = 5, and you do if number != int():, since int() returns 0, you're basically saying if 5 != 0:, which is always.
To overcome the aforementioned, useisinstance(obj, type). However, it doesn't matter since number will always be a string (unless the default value is used).
Having the following line will raise an error if number cannot be converted into an integer.
number = int(number)
Which raises a ValueError, you need to catch that in order to send your error message.
#client.command(pass_context=True)
async def clear(ctx, number=5):
channel = ctx.message.channel
try:
number = int(number)
except ValueError:
return await client.send_message(channel, "Please enter a valid number.")
async for x in client.logs_from(channel, limit=number):
await client.delete_message(x)
await asyncio.sleep(0.5)
With discord.py however, there's an easier way to do type conversations, by using the type annotation syntax:
#client.command(pass_context=True)
async def clear(ctx, number: int=5):
channel = ctx.message.channel
async for x in client.logs_from(channel, limit=number):
await client.delete_message(x)
await asyncio.sleep(0.5)
If you desperately need to send that error message to the channel, you can do it from the on_command_error event. (Search their documentation)
You might've noticed that I removed the counter part, since limit does exactly the same thing. (Removed redundancy)