discord.py my mute command blocks other commands - python-3.x

I'm making a timed mute command for my Discord server but when I use .mute command, the bot doesn't respond for a while, then it works. But while the member is muted, other commands are not working and when mute time ends, the commands that i wrote in the mute time are working. Here is the command:
#commands.command()
async def mute(self, ctx, member: discord.Member, time1, reason):
time1 = int(time1) * 60
guild = ctx.guild
var1 = 0
for role in guild.roles:
if role.name == "Muted":
var2 = var1
continue
else:
var1 += 1
for channel in guild.channels:
await channel.set_permissions(guild.roles[var2], send_messages=False)
for rol in guild.roles:
if rol.name == "Muted":
await member.add_roles(rol)
await ctx.send(f"{member.mention} muted by {ctx.author.mention}, reason : {reason}")
time.sleep(time1)
await member.remove_roles(rol)
await ctx.send(f"{member.mention} can type now.")
And when member is unmuted automatically, "on_ready" event works again with no reason.

Nothing else in your code will run when someone is mutted because you use time.sleep. Using time.sleep will freeze your entire code.
To solve your problem, you can use the asyncio library, especially, asyncio.sleep.

Related

Discord py mute command specifying reason without time

So I made a mute command and converted it to an optional tempmute yesterday, it worked fine except for when I specified a reason and no time. Obviously that would create a problem but sadly I could not figure out how to fix it. i.e: N?mute user time reason works but N?mute user reason doesn't. If I don't specify the reason nor time it mutes them for 2 years. I want to be able to perm mute people with a reason and also temp mute people with a reason (already works). Hereby the code:
#commands.command()
#commands.has_permissions(manage_roles=True)
async def mute(self, ctx, member: discord.Member, time="670d", *, reason="no reason provided"):
role = discord.utils.get(ctx.guild.roles, name="Muted")
admin = discord.utils.get(ctx.guild.roles, name="Admin")
mod = discord.utils.get(ctx.guild.roles, name="Moderator")
guild = ctx.guild
pfp = member.avatar_url
time_convert = {"s":1, "m":60, "h":3600,"d":86400}
tempmute= int(time[0]) * time_convert[time[-1]]
if admin in member.roles or mod in member.roles:
embed = discord.Embed(title="Mute failed", description="Staff cannot be muted.", color=0xff4654)
await ctx.channel.send(embed=embed)
return
if role in member.roles:
embed = discord.Embed(title="Mute failed", description="**{0}** is already muted!".format(member), color=0xff4654)
await ctx.channel.send(embed=embed)
if role not in guild.roles:
perms = discord.Permissions(send_messages=False, speak=False)
await guild.create_role(name="Muted", permissions=perms)
await member.add_roles(role, reason=reason) #User muted
embed = discord.Embed(title="User muted!", description="**{0}** was succesfully muted by **{1}** for **{2}**.".format(member, ctx.message.author, reason), color=0xff4654)
await ctx.channel.send(embed=embed)
channel = discord.utils.get(guild.channels, name="logs")
embed = discord.Embed(title=" ", description="**{0}** was muted by **{1}**. Reason: **{2}**".format(member, ctx.message.author, reason), color=0xff4654)
embed.set_author(name="{0}".format(member), icon_url=pfp)
await channel.send(embed=embed) #Log
await asyncio.sleep(tempmute)
await member.remove_roles(role)
else:
await member.add_roles(role, reason=reason) #User muted
embed = discord.Embed(title="User muted!", description="**{0}** was succesfully muted by **{1}** for **{2}**.".format(member, ctx.message.author, reason), color=0xff4654)
await ctx.channel.send(embed=embed)
channel = discord.utils.get(guild.text_channels, name="logs")
embed = discord.Embed(title=" ", description="<#{0}> was muted by <#{1}>. Reason: **{2}**".format(member.id, ctx.message.author.id, reason), color=0xff4654)
embed.set_author(name="{0}".format(member), icon_url=pfp)
await channel.send(embed=embed) #Log
await asyncio.sleep(tempmute)
await member.remove_roles(role)
I tried doing time: Optional[int] as someone else suggested but alas it broke it entirely.
To answer bluntly, there isn't a nice way of doing this. What I recommend is that you split the command into two separate ones, mute and tempmute.
If you really do want it as one function, you could do something like this:
import re
async def mute(self, ctx, member: discord.Member, *options):
if len(options) == 2: # User specified date and reason
expiry, reason = options
if len(options) == 1: # User specified one of the above so we need to find out which
if re.match(r"\d+\D", options[0]):
# Regex to check for one or more digit then a single non-digit
expiry = options[0]
reason = None
else:
expiry = None
reason = options[0]
On a slightly unrelated note, you should not do await asyncio.sleep(tempmute). Long sleeps are innacurate and if the bot restarts, the person will never be unmuted. You should create a database with datetimes of when the user should be unmuted and have a looping task which queries the database and unmutes users when their time is up.

Discord.py bot sending messages multiple times

I'm new to coding in python, and I'm having trouble with this code.
#client.event
async def on_message(message):
if message.author == client.user:
return
if 'choose my pick' in message.content:
channel = message.channel
await channel.send('Que role tu ta?')
def check(m):
return m.content == 'top' or 'jg' or 'mid' or 'adc' or 'sup' and m.channel == channel
role = await client.wait_for('message', check=check)
sentence_start = random.choice(inu_exp)
iten = random.choice(itens)
if 'top' in role.content:
champion = random.choice(top_champs)
await channel.send(f'{sentence_start} {champion} de {iten}')
await client.process_commands(message)
It works as I want to, when someone type 'choose my pick' it asks 'Que role tu ta', but it asks many times, and it also sends the answer await channel.send(f'{sentence_start} {champion} de {iten}') many times.
Here's the output: https://prnt.sc/y1cucv
I'm using python 3.8.6
I have tested your code onto another bot and it only sent the message once! Make sure that there aren't multiple clients running at the same time! Another thing to make sure of is your internet ping as this could cause lag and result in having multiple messages! (Past Experience)
In addition, if your still having problems please send the entire code (without the token of course) because many variables are missing and I can't do anything without those variables. For example the inu_exp!

discord.py on_message cancel when new command is executed

How can I cancel my on_message event when I execute another command? My code:
#client.event
async def on_message(message):
channel = message.author
def check(m):
return m.channel == message.channel and m.author != client.user
if message.content.startswith("!order"):
await channel.send("in game name")
in_game_name = await client.wait_for('message', check=check)
await channel.send("in game ID")
in_game_ID = await client.wait_for('message', check=check)
else:
await client.process_commands(message)
on_message should realistically only be reserved for events that require an on_message event (say if you are writing an auto-moderation feature).
For commands, you should be using the #client.command or #bot.command decorators before a function. Here is the usage for commands. Here are a few reasons on why you should use commands (taken directly from the ?tag commands on the discord.py discord):
Prevents spaghetti code
Better performance
Easy handling and processing of command arguments
Argument type converters
Easy sub commands
Command cooldowns
Built-in help function
Easy prefix management
Command checks, for controlling when they're to be invoked
Ability to add command modules via extensions/cogs
Still able to do everything you can do with Client
If you have any questions, feel free to comment on this answer!
You can put your on_message event inside a cog. That way, the on_message event (or any other event/command) will only be triggered when the cog is active.
class Foo(commands.Cog):
#commands.Cog.listener()
async def on_message(self, message):
# Do something
To register the cog (activate):
bot.add_cog(Foo(bot))
To remove the cog (deactivate):
bot.remove_cog('Foo')
Link to cog doc

How can I delete bot message in DM?

I'm making a bot with a command that send a file with all the previously executed commands in DM but I can't find a way to delete bot messages. Is there a way to do it or it's just impossible ?
I've tried to make a clear command for this specific case, I've tried this : https://www.reddit.com/r/Discord_Bots/comments/c1tf6t/dm_message_deletion_scriptbot/
but it didn't work for me.
The reddit code :
#client.command()
async def clear_dm(ctx):
user_dm = (client.get_user(610774599684194307)).dm_channe
messages_to_remove = 1000
async for message in user_dm.history(limit=messages_to_remove):
if message.author.id == client.user.id:
await message.delete()
await asyncio.sleep(0.5)
The bot messages should be deleted but when I run the command I get an exception AttributeError: 'ClientUser' object has no attribute 'dm_channel' the others methodes that I've tried raised similar errors (but I can't show you the code since I've delted it :c)
Users have a User.history attribute that you can use directly.
#client.command()
async def clear_dm(ctx):
messages_to_remove = 1000
async for message in client.get_user(610774599684194307).history(limit=messages_to_remove):
if message.author.id == client.user.id:
await message.delete()
await asyncio.sleep(0.5)

Can't Make A Command Only For specific Channel

Disocord.py Rewrite
Error: No
The command below is not working as expected
#bot.event
async def on_message(message):
x = (559253532759425044)
er = bot.get_channel(559253532759425044)
if not message.channel.id != x:
return
else:
if "p/" in message.content.lower():
await message.channel.send('Write this command in {}'.format(er.mention))
The p/ is the bots prefix, This code above tells (Write this command in {}'.format(er.mention)) when used p/ in the right channl the bot doesn't say anything but i use any command like p/help it doesn't works.actually The event should allow members use bot commands (#bot.command) only in the channel specified not any other channel but the thing is no commands work in the channel specified nor in any channel in the server. Any help would be great :) Edit: (Specified my question and made it a bit clear)
Edit:
From the comments, you may actually want something like
#bot.event
async def on_message(message):
cmdChannel = bot.get_channel(559253532759425044)
if message.content.lower().startswith('p/'):
if message.channel.id == cmdChannel.id:
#command invoked in command channel - execute it
await bot.process_commands(message)
else:
#command attempted in non command channel - redirect user
await message.channel.send('Write this command in {}'.format(cmdChannel.mention))

Resources