So I'm making a user info command and when i run the command, it doesn't work and gives no error.
Heres my code:
#commands.command()
async def info(self, ctx, *, member: discord.Member):
embed=discord.Embed(color=0xFFFFF0, title=f"{ctx.author.name}'s Info", description="Displays user information.")
embed.set_thumbnail(url=f"{ctx.author.avatar_url}")
embed.add_field(name="User ID:", value=f"{ctx.author.id}", inline=True)
embed.add_field(name="Color:", value=f"{ctx.author.top_role.mention}\n[{ctx.author.top_role.colour}]")
embed.add_field(name="Join Date:", value=f"{ctx.author.joined_at}")
embed.timestamp = datetime.datetime.utcnow()
embed.set_footer(text=f"Requested by: {ctx.author}", icon_url=ctx.author.avatar_url)
await ctx.send(embed=embed)
You basically put ctx.author, which the author is you, you cant show other user's info if you did that. You should use an if statement if you want to show other user's info.
And the last thing is the Joindate. it will send this weird time 04:22:23.699000. So you should convert the time to an strftime.
The Updated Code :
#commands.command()
async def info(self, ctx, *, member: discord.Member = None): #changed the member to None so it will work if the user didnt mention the member
if member == None: # shows that if the use didnt mention the member (if statement)
member = ctx.author
# changed all embed of the ctx.author to member
embed=discord.Embed(title=f"{member.name}'s Info", description="Displays user information.", color=0xFFFFF0)
embed.set_thumbnail(url=f"{member.avatar_url}")
embed.add_field(name="User ID:", value=f"{member.id}", inline=True)
embed.add_field(name="Color:", value=f"{member.top_role.mention}\n[{member.top_role.colour}]")
embed.add_field(name="Join Date:", value= member.joined_at.strftime("%B %d %Y\n%H:%M:%S %p")) # make the time look nice
embed.timestamp = datetime.datetime.utcnow()
embed.set_footer(text=f"Requested by: {ctx.author}", icon_url=ctx.author.avatar_url) # changed member to ctx.author als
await ctx.send(embed=embed)
Related
#client.command()
async def status(current, content: str):
status = None
for member in current.guild.members:
if str(member.id) == content:
status = member.status
break
if status == discord.Status.online:
online_embed = discord.Embed(
title="awa is online", description="", color=0xF6E5E5
)
await current.send(embed=online_embed)
I would have to do #status [user id] every time, is there a way to make it #status only?
One of the simplest ways to get a member object in a command, allowing you to use a user's id, their name, etc., would be to use the converter they provide.
#client.command()
async def test(current, member: discord.Member=None):
if member == None: # if no member is provided..
member = current.author # ..make member the author
await current.send(f"Hello {member.mention}!")
Other questions like this:
Discord.py get user object from id/tag
Discord.py: How do I get a member object from a user object?
I have this code for my discord.py bot, for my tempmute command:
#bot.command()
async def tempmute(ctx, member: discord.Member, time: int, d, *, reason=None):
guild = ctx.guild
mutedRole = discord.utils.get(guild.roles, name="Muted")
if not mutedRole:
mutedRole = await guild.create_role(name="Muted")
for channel in guild.channels:
await channel.set_permissions(mutedRole, speak=False, send_messages=False)
for role in guild.roles:
if role.name == "Muted":
await member.add_roles(role)
embed = discord.Embed(title="TempMuted!", description=f"{member.mention} has been tempmuted.", colour=discord.Colour.red())
embed.add_field(name="Reason:", value=reason, inline=False)
embed.add_field(name="Time for the mute:", value=f"{time}{d}", inline=False)
await ctx.send(embed=embed)
if d == "s":
await asyncio.sleep(time)
if d == "m":
await asyncio.sleep(time*60)
if d == "h":
await asyncio.sleep(time*60*60)
if d == "d":
await asyncio.sleep(time*60*60*24)
await member.remove_roles(role)
embed = discord.Embed(title="Unmute (temp mute expired) ", description=f"Unmuted -{member.mention} ", colour=discord.Colour.light_gray())
await ctx.send(embed=embed)
return
However, when using the command, it has to be typed like this: "!tempmute #user 10 m" if I wanted a 10 minute mute. Notice how it is "10 m". How would I make it so "10m" would work (without a space). So "!tempmute #user 10m"? If a user writes it without a space at the moment, the error "discord.ext.commands.errors.BadArgument: Converting to "int" failed for parameter "time"." occurs, probably as it isn't recognising a number with the letter at the end. Thanks
The best way to solve this would be to create your own Converter and typehint the class in the argument. As documented here
So instead of converting your time in your command function, you would do it in the converter making the syntax more cleaner.
Example of a converter
time_regex = re.compile(r"(\d{1,5}(?:[.,]?\d{1,5})?)([smhd])")
time_dict = {"h":3600, "s":1, "m":60, "d":86400}
class TimeConverter(commands.Converter):
async def convert(self, ctx, argument):
matches = time_regex.findall(argument.lower())
time = 0
for v, k in matches:
try:
time += time_dict[k]*float(v)
except KeyError:
raise commands.BadArgument(f"{k} is an invalid time-key! h/m/s/d are valid!")
except ValueError:
raise commands.BadArgument(f"{v} is not a number!")
return time
This is an example of a Time converter, where it will use a regex and converts it into an int in seconds. Which accepts <number><smhd>, example 2d.
The library calls TimeConverter().convert during the command invocation, hence we create a method called convert, which accepts Context object and arguments as str. All you have to do is return something, or raise an error if there is an error.
In order to use this, you would do it as follows
#bot.command()
async def tempmute(ctx, member: discord.Member, time: TimeConverter, *, reason=None):
...
await member.add_roles(role)
await asyncio.sleep(time)
await member.remove_roles(role)
...
The command invocation would be
!tempmute #user 2d here's the reason
I have been working on a tempmute command myself. I would say the command would work fine with a simple dictionary. If you want to convert time units a simple dictionary would do it and you wouldn't require a hell lot of code.
First I would add the code and then give a brief explanation.
Code:
#MyBot.command()
#commands.has_permissions(manage_roles=True)
async def tempmute(ctx, member: discord.Member, time, *, reason=None):
await ctx.message.delete()
if member.guild_permissions.administrator:
ifadmin_embed = discord.Embed(title='Member is Administrator!', description=f'The user, {member.mention} can\'t be muted as he/she is an administrator.', color=0xff0000)
ifadmin_embed.set_author(name='NucleoBot')
ifadmin_embed.set_footer(text=ctx.author)
await ctx.channel.send(embed=ifadmin_embed, delete_after=10.0)
else:
if discord.utils.get(ctx.guild.roles, name='Muted'):
muted_role = discord.utils.get(ctx.guild.roles, name='Muted')
else:
perms = discord.Permissions(send_messages=False, add_reactions=False, connect=False, speak=False)
await ctx.guild.create_role(name='Muted', permissions=perms)
muted_role = discord.utils.get(ctx.guild.roles, name='Muted')
time_convert = {'s' : 1 , 'm' : 60 , 'h' : 3600 , 'd' : 86400, 'y' : 31536000}
mute_time = int(time[0]) * time_convert[time[-1]]
await ctx.message.delete()
role_if_muted = discord.utils.find(lambda r: r.name == 'Muted', ctx.guild.roles)
if role_if_muted in member.roles:
alreadymuted_embed = discord.Embed(title='Already Muted!', description=f'The user, {member.mention} is already muted for {mute_time} seconds.', color=0xff0000)
alreadymuted_embed.set_footer(text=ctx.author)
alreadymuted_embed.set_author(name='NucleoBot')
await ctx.channel.send(embed=alreadymuted_embed, delete_after=10.0)
else:
if reason == None:
await member.add_roles(muted_role)
tempmuted_embed = discord.Embed(title='Temporary Mute Successfull!', description=f'{member.mention} has been muted for {mute_time} seconds successfully! \n \n Reason: No reason given.', color=0x4fff4d)
tempmuted_embed.set_author(name='NucleoBot')
tempmuted_embed.set_footer(text=ctx.author)
else:
await member.add_roles(muted_role)
tempmuted_embed = discord.Embed(title='Temporary Mute Successfull!', description=f'{member.mention} has been muted for {mute_time} seconds successfully! \n \n Reason: {reason}', color=0x4fff4d)
tempmuted_embed.set_author(name='NucleoBot')
tempmuted_embed.set_footer(text=ctx.author)
await ctx.channel.send(embed=tempmuted_embed, delete_after=10.0)
await asyncio.sleep(mute_time)
await member.remove_roles(muted_role)
Explanation:
My code has almost everything here that you need for a mute command. Only the members with roles that have manage_role permissions to execute this command. Also if someone try to mute a member who is an administrator of the server, an embed would pop up to say, Member is an admin.
The code also has the aspect that if no reason is given it would not show any error but post an embed made for No Reason command, i.e., if no reason is mentioned. It also checks that if the server doesn't have a role named Muted. It the role exist it would simply use it otherwise first it would create a role named Muted with denial of important permissions and use it for the mute.
Now the time conversion. The line which is used for this:
time_convert = {'s' : 1 , 'm' : 60 , 'h' : 3600 , 'd' : 86400, 'y' : 31536000}
This command takes second as basic value for the conversion then converts every other unit in terms of seconds. Here s is equated to 1 and m is equated to 60 as I minute is equal to 60 seconds. Similarly doing that same with other units we derive everything to seconds. This dictionary turns everything to seconds and using asyncio we create a timer for mute.
Hope this helps, if you still get any doubt, please feel free to ask me.
Thank You!
Here is what I got so far
It is saying that "await" is outside of async function and I am just confused on how to fix this. I copied part of the code from a giveaway command because that is my only source of Q&A code I have
#commands.has_permissions(administrator = True)
async def cdelete(ctx):
embed=discord.Embed(title = Which channel would you like to delete?)
await ctx.send(embed=embed)
answer = []
def check(m):
return m.author == cx.author and m.channel == ctx.channel
try:
await client.wait_for('message', timeout=15, check=check)
except asyncio.TimeoutError:
await ctx.send("Timeout. Please run the command again")
else:
answer.append(message.content)
try:
c_id= int(answer[0][2:-1])
await ctx.channel.delete
await ctx.send("Channel Deleted")
except:
await ctx.send("Thats not a valid channel!")```
If you just want a command you can make it a lot easier if you just execute a command with the channel name. You can have a look at the following:
#client.command()
#commands.has_permissions(administrator=True)
async def cdelete(ctx, channel_name):
"""Deletes a channel by name or ID."""
channel_id = int(''.join(i for i in channel_name if i.isdigit())) # Get channel ID
existing_channel = client.get_channel(channel_id) # Get channel ID with defined method
if existing_channel: # If channel with the name/ID exists
await existing_channel.delete()
else: # If the channel does not exist
await ctx.send(f'**No channel named `{channel_name}` was found.**')
We have a method to catch the channel ID and also pass that in as a valid argument. If the ID or channel name then exists we delete the channel.
You can here either mention the channel or pass in the ID.
Usage would be: cdelete #channel/ID.
If you want to avoid a long console output if you input no channel/ID/name you can build in an error handler:
#cdelete.error
async def cdelete_error(ctx, error):
if isinstance(error, commands.MissingRequiredArgument):
await ctx.send("You need to name a channel.")
The problem you have here is with the check() function. According to the doc you only can use await inside of an async function. To solve the problem change def check(m): into async def check(m):
Hello so i am trying to create a report system where when a report is created it is report #0001 when a new one is it is report #0002 here is my code so far.
#commands.command()
async def report(self, ctx, member : discord.Member, reason=None):
await ctx.send(f'{member} has been reported!')
channel = discord.utils.get(ctx.guild.text_channels, name='reports')
embed = discord.Embed(name=f'Report incoming! #0001 ')
embed.add_field(name='Member', value=f'{member}', inline=False)
embed.add_field(name='Member who reported them', value=f'{ctx.author}', inline=False)
embed.add_field(name='Reason', value=f'{reason}', inline=False)
embed.add_field(name='Channel', value=f'{ctx.channel}', inline=False)
await channel.send(content=None, embed=embed)
Does anyone know how if so please respond to this thanks!
If you sure that there will be no internet problem or some other problems that will prevent the boat from running, you can simply do
count = 0
#commands.command()
async def report(self, ctx, member : discord.Member, reason=None):
count += 1
#the rest of the command
Then you can change the embed name like this
embed = discord.Embed(name=f'Report incoming! #{count}')
But if you are not completely sure that the bot will have not any problem,
you can save the numbers in a file like txt, json or yaml. I'd prefer txt in that case because you just need to save one line of text. So you can do this:
with open('counts.txt', 'r+') as file:
number = file.read()
if number == '':
file.write('0')
#commands.command()
async def report(self, ctx, member : discord.Member, reason=None):
with open('counts.txt', 'w+') as file:
count = file.read()
file.write(int(count)+1)
embed = discord.Embed(name=f'Report incoming! #{count}')
Well, you have to store the report count somewhere, preferably a proper database. For this example you can use a json file, however, keep in mind that a json file as a database is fundamentally flawed due to its lack of atomic writes which can result in data corruption and loss.
import json
#commands.command()
async def report(self, ctx, member: discord.Member, reason=None):
# Get currect report number
with open('reports.json', 'r', encoding='utf-8') as counts:
data = json.load(counts)
counter = data['count']
await ctx.send(f'{member} has been reported!')
data = {"count": counter + 1} # Add 1 everytime a report is invoked
with open('reports.json', 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=4)
channel = discord.utils.get(ctx.guild.text_channels, name='reports')
embed = discord.Embed(title=f'Report incoming! #{counter} ')
embed.add_field(name='Member', value=f'{member}', inline=False)
embed.add_field(name='Member who reported them', value=f'{ctx.author}', inline=False)
embed.add_field(name='Reason', value=f'{reason}', inline=False)
embed.add_field(name='Channel', value=f'{ctx.channel}', inline=False)
await channel.send(content=None, embed=embed)
reports.json
{
"count": 0
}
Here is my ban command! Everytime I want to ban someone it dosen't go thru else! To be honest it dosen't do anything other than the if! Please help!
#bot.command() #ban (verified works)
#commands.has_permissions(ban_members = True)
async def ban(ctx, member : discord.Member, *, reason = None):
if member == ctx.author or member.id == bot.user.id:
await ctx.send("Unfortunatly I cannot do that!")
return
else:
await ctx.send('Banned the member {}'.format(ctx.member.mention))
await member.ban(reason = reason)
await ctx.message.delete()
I recommend not using the role to check if the user can use the command, rather try using something like this:
#client.command()
#commands.has_permissions(ban_members=True)
async def ban(ctx, member : discord.Member,*,reason=None):
try:
await member.ban(reason=reason)
embed = discord.Embed(description=f":white_check_mark: succesfully banned {member.mention}!",color=0x00ced1)
await ctx.send(embed=embed)
except:
e2 = discord.Embed(description="You don't have permission to use this command",color=0xff0000)
await ctx.send(embed=e2)
This allows you to use the bot in multiple servers, who don't necessarily have the same roles, and also narrows it down to a certain permission.