Mute Command with Time Limit - python

I was wondering how I can make my mute command mute someone for a certain amount of time. For example p/mute #User 1h would mute someone for 1 hour.
#client.command()
#commands.has_permissions(manage_roles = True)
async def mute(ctx, member : discord.Member = None):
if member == None:
await ctx.send("Please mention a user to mute")
else:
user = member
role = discord.utils.get(ctx.guild.roles, name="Muted")
if role is None:
await ctx.send("Please make a muted role name `Muted` or make sure to name the role `Muted` and not `muted` or `MUTED`")
else:
await user.add_roles(role)
await ctx.send(f"{member.name} has been muted by {ctx.author.name}")

This site has an example on one way to do this, however I found it needed some slight modifications to work - it was giving me errors in some spots prior to my edits. Below code worked in my server:
#client.command(aliases=['tempmute'])
#commands.has_permissions(manage_messages=True)
async def mute(ctx, member: discord.Member=None, time=None, *, reason=None):
if not member:
await ctx.send("You must mention a member to mute!")
return
elif not time:
await ctx.send("You must mention a time!")
return
else:
if not reason:
reason="No reason given"
#Now timed mute manipulation
try:
time_interval = time[:-1] #Gets the numbers from the time argument, start to -1
duration = time[-1] #Gets the timed manipulation, s, m, h, d
if duration == "s":
time_interval = time_interval * 1
elif duration == "m":
time_interval = time_interval * 60
elif duration == "h":
time_interval = time_interval * 60 * 60
elif duration == "d":
time_interval = time_interval * 86400
else:
await ctx.send("Invalid duration input")
return
except Exception as e:
print(e)
await ctx.send("Invalid time input")
return
guild = ctx.guild
Muted = discord.utils.get(guild.roles, name="Muted")
if not Muted:
Muted = await guild.create_role(name="Muted")
for channel in guild.channels:
await channel.set_permissions(Muted, speak=False, send_messages=False, read_message_history=True, read_messages=False)
else:
await member.add_roles(Muted, reason=reason)
muted_embed = discord.Embed(title="Muted a user", description=f"{member.mention} Was muted by {ctx.author.mention} for {reason} to {time}")
await ctx.send(embed=muted_embed)
await asyncio.sleep(int(time_interval))
await member.remove_roles(Muted)
unmute_embed = discord.Embed(title='Mute over!', description=f'{ctx.author.mention} muted to {member.mention} for {reason} is over after {time}')
await ctx.send(embed=unmute_embed)
This should create a new role called "Muted" in your server if it doesn't already exist, move the targeted member into said role for the time denoted, and then remove them from the role once time expires.
Example command using code (prefix of .):
.tempmute #SomeUser 10s Because I said so!

I have a pretty easy way of doing that. That will be efficient and less code required. I have been using that in my Bots for a long time. I have answered another question of the one user here: Bot unmuting member when use tempmute command
In the answer there I have explained on how to write a perfect command.
This command is completely another command. You don't have to modify your mute command. But just create a new command named tempmute.
I will copy and paste my answer from there to here. Please pay attention to every single statement. :)
TEMPMUTE Command.
Step 1: Define the function and permissions
We are going to define the function with some permissions restrictions on the use. People with the permissions specified permissions.
Before you use this, you need to have the following in your code:
from discord.ext import commands
(Ignore if you have it)
Here is how:
#bot.command()
#commands.has_permissions(manage_roles=True)
async def tempmute(ctx, member: discord.Member, time, *, reason=None):
You can add many more permission if you want and use True or False to allow or deny.
Step 2: Making a role finding condition. If the role doesn't exist then create a Muted role, if exist then use it.
So I am creating a condition for if the role exist. It will check if the role exist. If it exist then we will simply use it but if it doesn't we will create one with specific permissions.
Here is how:
if discord.utils.get(ctx.guild.roles, name="Muted"):
mute_role = discord.utils.get(ctx.guild.roles, name="Muted")
else:
perms = discord.Permissions(send_messages=False, add_reactions=False, connect=False, speak=False)
await bot.create_role(name="Muted", permissions=perms)
mute_role = discord.utils.get(ctx.guild.roles, name="Muted")
Step 3: Checking if someone is muted or not.
Now I am creating a condition for if the member is muted or not. We will through the member's roles and check it.
Here is how:
if mute_roles in member.roles:
await ctx.channel.send(f"{member.mention} is already muted!")
else:
# code here (more steps will explain how)
Step 4: Adding conditions and muting the member.
Now we will add restriction permissions for this command. Who all people can't be muted and who all can be.
First we add our first condition, that administrators can not be muted.
Here is how:
if member.guild_permissions.administrator:
isadminembed=discord.Embed(title="Tempmute", description=f"Hi {ctx.author.mention}, you can't mute {member.mention} as they are a Server Administrator.", color=discord.Colour.red())
isadminembed.set_author(name="Bot")
await ctx.channel.send(embed=isadminembed)
Now we will add else condition, that all other members except administrators can be muted.
Here is how:
else:
time_conversion = {"s": 1, "m": 60, "h": 3600, "d": 86400, "w": 604800, "M": 2419200, "y": 29030400}
mute_time = int(time[:-1]) * time_conversion[time[-1]]
await member.add_roles(mute_role)
mutedembed=discord.Embed(title="Tempmute", description=f"The member, {member.mention} has been muted by the moderator {ctx.author.mention}. \n \nTime: {mute_time} seconds \nReason: {reason}", color=discord.Colour.random())
mutedembed.set_author(name="Bot")
await ctx.channel.send(embed=mutedembed)
await asyncio.sleep(mute_time)
await member.remove_roles(mute_role)
await ctx.channel.send(f"{member.mention} has been unmuted!")
I have added time conversion here. The time input has to be:
1s for one second, 1m for one minute, etc. You can use it for years too.
Tempmute Command Compiled
This is all the code compiled together as the command.
#bot.command()
#commands.has_permissions(manage_roles=True)
async def tempmute(ctx, member: discord.Member, time, *, reason=None):
if discord.utils.get(ctx.guild.roles, name="Muted"):
mute_role = discord.utils.get(ctx.guild.roles, name="Muted")
else:
perms = discord.Permissions(send_messages=False, add_reactions=False, connect=False, speak=False)
await bot.create_role(name="Muted", permissions=perms)
mute_role = discord.utils.get(ctx.guild.roles, name="Muted")
if mute_roles in member.roles:
await ctx.channel.send(f"{member.mention} is already muted!")
else:
if member.guild_permissions.administrator:
isadminembed=discord.Embed(title="Tempmute", description=f"Hi {ctx.author.mention}, you can't mute {member.mention} as they are a Server Administrator.", color=discord.Colour.red())
isadminembed.set_author(name="Bot")
await ctx.channel.send(embed=isadminembed)
else:
time_conversion = {"s": 1, "m": 60, "h": 3600, "d": 86400, "w": 604800, "M": 2419200, "y": 29030400}
mute_time = int(time[:-1]) * time_conversion[time[-1]]
await member.add_roles(mute_role)
mutedembed=discord.Embed(title="Tempmute", description=f"The member, {member.mention} has been muted by the moderator {ctx.author.mention}. \n \nTime: {mute_time} seconds \nReason: {reason}", color=discord.Colour.random())
mutedembed.set_author(name="Bot")
await ctx.channel.send(embed=mutedembed)
await asyncio.sleep(mute_time)
await member.remove_roles(mute_role)
await ctx.channel.send(f"{member.mention} has been unmuted!")
TEMPMUTE Command Error Handling
Step 1: Defining the function as an event.
We will define the function in the script as tempmute command's error and declare it as an error.
Here is how:
#bot.error
async def tempmute_error(ctx, error):
Step 2: Adding the instance of the error.
We will now add a condition for the error. Our error will be: MissingRequiredArgument error as the command can lack necessary arguments.
So the isinstance will check the error and then do the stuff.
Here is how:
if isinstance(error, discord.ext.commands.MissingRequiredArgument):
tempmuteerrorembed=discord.Embed(title=f"Missing Argument! {error}", description=f"Hello {ctx.author.mention}! You have not entered the needed argument. \n Either you forgot to **mention the member** or you forgot to **enter the time of the mute** you want. \n \n Please check this again and add the necessary argument in the command. \n \nThis is the syntax: \n```!tempmute <mention member> <time: 1s, 2h, 4y etc..> <reason (optional)>```", color=discord.Colour.red())
tempmuteerrorembed.set_author(name="Bot")
await ctx.send(embed=tempmuteerrorembed)
This will work for MissingRequiredArguement and show the error with the syntax in it for the command's correct usage.
TEMPMUTE Command Error Handling Compiled
Here is the compiled code of Error Handling of TEMPMUTE Command.
#bot.error
async def tempmute_error(ctx, error):
if isinstance(error, discord.ext.commands.MissingRequiredArgument):
tempmuteerrorembed=discord.Embed(title=f"Missing Argument! {error}", description=f"Hello {ctx.author.mention}! You have not entered the needed argument. \n Either you forgot to **mention the member** or you forgot to **enter the time of the mute** you want. \n \n Please check this again and add the necessary argument in the command. \n \nThis is the syntax: \n```!tempmute <mention member> <time: 1s, 2h, 4y etc..> <reason (optional)>```", color=discord.Colour.red())
tempmuteerrorembed.set_author(name="Bot")
await ctx.send(embed=tempmuteerrorembed)
I hope I was able to explain to you the answer and how to write the command. Please ask in the comments for any issue that arises.
Thank You! :D

Related

why, discord py sending PM with send_message erroring

i’ve been trying for hours to get a fix for this issue from looking and hundreds of others overflow posts to documentation forums etc i cannot figure this out i'm trying to send an embed as a PM to the user specified in my function everything works except the part where it should send the private message, please help
error
bot has no attribute send_message
bot has no attribute send
code bellow
#bot.command()
#commands.has_role("mod")
async def mute(ctx, user: discord.Member, duration_arg: str = "30", unit: str = "s", reason: str = "null"):
await ctx.channel.purge(limit=1)
moderator = ctx.message.author
#await ctx.invoke(bot.get_command('ask.{user}'.format(use), length=duration_arg))
channel = bot.get_channel(1060922421491793981)
duration = int(duration_arg)
role = discord.utils.get(ctx.message.guild.roles, id=1060693595964842165)
units = " Null"
if unit == "s":
units = " seconds"
elif unit == "m":
units = " minutes"
else:
return
length = f"{duration_arg}{units}"
if unit == "s":
wait = 1 * duration
await asyncio.sleep(wait)
elif unit == "m":
wait = 60 * duration
await ctx.send(f":mute: Muted {user} for {duration}{units}", delete_after=wait)
await user.add_roles(role)
#button embed---------
view = Confirm()
#await ctx.send('you have been **Muted**', view=view, delete_after=45)
embedVar = discord.Embed(title="You have been Muted",description=f"this message will expire in **{duration_arg}** {units}",color=0x0ff0000)
embedVar.add_field(name="Temporary Suspension for:", value=f"{user.mention}",inline=False)
embedVar.add_field(name="Durration:", value=f"{length}", inline=False)
embedVar.add_field(name="Reason:", value=f"{reason}", inline=False)
embedVar.add_field(name="Moderator:", value=f"{moderator.display_name}", inline=False)
embedVar.add_field(name="Summary",value=f"you can confirm this in the next {duration} {units}\n\n **if you believe this is in error appeal it and a moderator will review your temporary suspension**",inline=False)
embedVar.set_footer(text='Booty Police | mute management',icon_url="http://canvaswrite.com/PI/pybot/attachments/server-icon-full.png")
await bot.send_message(user.id, embed=embedVar, view=view, delete_after=wait)
# Wait for the View to stop listening for input...
await view.wait()
if view.value is None:
print('Timed out...')
elif view.value:
print('appealing...')
elif view.value is appeal:
print('Appealing...')
channel.send("this is a test to appeal...")
else:
print('Cancelled...')
#end buttons----------
if unit == "s":
wait = 1 * duration
await asyncio.sleep(wait)
elif unit == "m":
wait = 60 * duration
await asyncio.sleep(wait)
await user.remove_roles(role)
await ctx.send(f":sound: {user} was unmuted",delete_after=15)
the value for user is defined in the command run as the user being muted not the author of the command e.g. ??mute user#1234 30 s "reason"
As the other answer pointed out, you're indeed sending it to yourself instead of the user. However, the solution in that answer is still wrong.
User.send_message() is not a thing. You're using a function that doesn't exist, and you're surprised that it errors. The error message that you didn't include in your post should also tell you that it doesn't exist.
To send something to a channel or a user, use Messageable.send().
Keep in mind that people can close their DMs to prevent you from sending them anything, which can throw another error for you, and mass-DMing will get your bot flagged for spam.

why are my if and elif statements not running properly?

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')

How to make cooldowns use the exceptions given

What i am specifically looking for is that i want is for the exception to be thrown on ("you must mention someone to x") and for the exception of if the person isn't in the guild to throw that message instead of using the cooldown.
#tasks.loop(count=1)
async def load_interaction_commands(self):
""" Load interaction commands. """
self.bot.interaction_commands = []
cooldown = commands.Cooldown(1, 600, commands.BucketType.user)
mapping = commands.CooldownMapping(cooldown)
for cmd, aliases in COMMANDS.items():
async def interaction_callback(cls, ctx, user: discord.Member):
if not user:
await ctx.send(f"You must mention someone to {ctx.command}.")
elif user == ctx.author:
await ctx.send("You can't {} yourself, silly!".format(ctx.command.name))
elif not discord.utils.find(lambda m: m.id == user.id, ctx.guild.members):
await ctx.send("you cant {} someone not in the server silly!")
else:
await cls.interact(ctx, user)
interaction_callback = commands.command(name=cmd, aliases=aliases)(interaction_callback)
interaction_callback._buckets = mapping
interaction_callback.__commands_cooldown__ = cooldown
interaction_callback.cog = self
self.bot.add_command(interaction_callback)
self.bot.interaction_commands.append(interaction_callback)

How to clear if I have member.mention?

#bot.command()
#commands.has_permissions(manage_messages=True)
async def clear(ctx,member : discord.Member,amount=200):
await ctx.channel.purge(limit=amount)
if amount > 200:
await ctx.send(f"{member.mention}merci de clear entre 0-200 message(s)")
else:
await ctx.send(f"j'ai clear {amount} message(s)",delete_after=5)```
error:
File "C:\Users\dzzdz\PycharmProjects\pythonProject12\venv\lib\site-packages\discord\ext\commands\core.py", line 451, in _actual_conversion
ret = await instance.convert(ctx, argument)
File "C:\Users\dzdz\PycharmProjects\pythonProject12\venv\lib\site-packages\discord\ext\commands\converter.py", line 195, in convert
raise MemberNotFound(argument) discord.ext.commands.errors.MemberNotFound: Member "300" not found.
In this error, we can see that the command works only if I do !clear # (amount).
If I remove the discord.member it's working. I can't remove the discord.member because one can't have an optional argument that comes before a default argument.
So what can I do?
Here are some errors that I noticed:
First) Since you are looking for the author of the message, member is not relevant here at all. We can simply use ctx.author for this and then display it as desired.
Second) You have a logic error in your code. Your if amount >200 statement is not considered the way your code is and then more than 200 messages can be deleted without the error message showing up.
One possible code would be:
#client.command() / #bot.command() / #commands.command() # Depends on what you use
#commands.has_permissions(manage_messages=True)
async def clear(ctx, amount=200):
if amount > 200:
await ctx.send(f"{ctx.author.mention} merci de clear entre 0-200 message(s)")
return # Do not proceed
else:
await ctx.send(f"j'ai clear {amount} message(s)", delete_after=5)
await ctx.channel.purge(limit=amount) # Clear messages if lower than 200
I interpreted your question as "I want to have a user, but if I don't mention the person I get an error. Help?" There are a few ways to do this of course, so I will show you two of them.
Method 1: Using None
If you do not want to use any extra imports, you can move your member to the front and make it None. For both the methods, you will need to use an if statement to change your member to the ctx.author.
#bot.command()
#commands.has_permissions(manage_messages=True)
async def clear(ctx,amount=200,member : discord.Member=None): # moved the member to the right
if member == None: # if no one is mentioned
member = ctx.author # default to ctx.author
await ctx.channel.purge(limit=amount)
if amount > 200:
await ctx.send(f"{member.mention}merci de clear entre 0-200 message(s)")
else:
await ctx.send(f"j'ai clear {amount} message(s)",delete_after=5)
Method 2: Using typing.Optional.
This is often used as an optional argument. This allows for your member to be left in the middle.
import typing
# ...
# other code
#bot.command()
#commands.has_permissions(manage_messages=True)
async def clear(ctx, member: typing.Optional[discord.Member]=None, amount=200): # member is kept in the middle
if member == None: # if no one is mentioned
member = ctx.author # default to ctx.author
await ctx.channel.purge(limit=amount)
if amount > 200:
await ctx.send(f"{member.mention}merci de clear entre 0-200 message(s)")
else:
await ctx.send(f"j'ai clear {amount} message(s)",delete_after=5)

Discord.py getting unexpected parentheses in output

This is my discord.py bot. When I type m!rate (person) It sends me a text like this. However, I don't want the (' and ',) at the beginning and end of the message.
This is my code:
#client.command()
async def rate(ctx, *member):
if len(member) == 0:
await ctx.send("You forgot to mention someone")
else:
value = random.randint(1,10)
await ctx.send(f"I rate {member} {value}/10")
When I change it, the message works but the error doesn't. I can't find any solution.
Using * in a parameter makes the function pass positional arguments into a tuple, hence the brackets. This is usually for when you want to unpack an arbitrary amount of arguments.
To fix it, just remove *, and also add a type for the parameter if you want:
#client.command()
async def rate(ctx, member: discord.Member = None): # setting a default value of None
if not member: # testing to see if the default value is None
await ctx.send("You forgot to mention someone")
else:
value = random.randint(1,10)
await ctx.send(f"I rate {member.mention} {value}/10")
References:
Using * in Python
discord.Member
Member.mention
If you want your bot to mention one person per command :
#client.command()
async def rate(ctx, *member):
if member:
"".join(member)
value = random.randint(1,10)
for user in ctx.guild.members:
if user.name.lower() == member.lower() or user.nick.lower() == member.lower():
await ctx.send(f"I rate {user.mention} {value}/10")
else:
await ctx.send("Member not found!")
else:
await ctx.send("You forgot to mention someone")
If you want your bot to mention multiple people per command :
#client.command()
async def rate(ctx, *members):
if members:
embed = Discord.embed(color = discord.color.blue(), title = "title")
count = 0
for member in members:
value = random.randint(1,10)
for user in ctx.guild.members:
if user.name.lower() == member.lower() or user.nick.lower() == member.lower():
embed.add_field(name = f"{user.mention}", value = f"I rate him {value}/10")
count += 1
if count != 0:
await ctx.send(embed=embed)
else:
await ctx.send("Members not found!")
else:
await ctx.send("You forgot to mention someone")

Categories

Resources