Ok so I've tried everything for my command but nothing worked for my !say command to work and not tag #everyone. I tried doing it myself but it still doesn't want to. I'm a beginner so i'm bad but where is the problem and what do i do?
here is my code:
async def say(ctx, msg=None):
if msg is not None:
await ctx.send(msg)
await ctx.message.delete()
if message == "#everyone" or "#here":
break:
Avoid specific mention when sending a message
discord.py already has a feature built-in, to allow or not specific type of mention.
Combining discord.AllowedMentions and discord.abc.Messageable.send, as the following example.
async def avoid_everyone(ctx: commands.Context, *message: str)
# Disallow everyone when sending message
allowed = discord.AllowedMentions(everyone=False)
# Raise an exception if #everyone in message
await ctx.send(message, allowed_mentions=allowed)
Related
Why, when I have existing commands in the array, do I check with the function on_message and nothing happens in the loop.
available_commands = ['/help', '/profile', '/register', '/shop', '/daily']
#bot.event
async def on_message(message):
if message.content.startswith('/'):
msg = message.content
for x in range(len(available_commands)):
if msg != available_commands[x]:
await message.channel.send('Unknown command! Please type /help!')
return
await bot.process_commands(message)
Your logic is wrong. you are checking to see if your command is EVERY SINGLE OPTION in available_commands, what you should instead do is check if the command is in available_commands (the command being the first "word" of message.content)
try this:
available_commands = ['/help', '/profile', '/register', '/shop', '/daily']
#bot.event
async def on_message(message):
if not message.content.startswith('/'):
return
if message.content.split()[0] not in available_commands:
await message.channel.send('Unknown command! Please type /help!')
return
await bot.process_commands(message)
If you are unfamiliar with the in keyword, I suggest you try reading this
So ... first of all after seeing your code I can literally say that you have seen youtube tutorials ...
don't watch them first of all because they are bad and dont provide a good way to do things also some are even outdated I would recommend you to first read docs of discord.py and then join https://discord.gg/dpy/ and you can find pretty much good amount of help
as for why this code is bad
first of all if you don't know after april 30 , 2022 message content intent will be privileged and if your bot reached above 100 servers either you will need intent or you wil have to go with slash commands. (you will learn about them as you code further .... just join some coding communities like the one I mentioned above you will get good amount of info there)
next you really dont have need to check for commands if they exist or not.. what I mean is instead of using on_message event what you can really do is using another decorator #bot.command()
here is example how to do things with this
#bot.command()
async def shop(message):
#any function here that you want
await message.send('your msg') #this will send msg ofc
now if suppose you havent defined a function(command) so it will raise an error CommandNotFound which can be detected by another bot event on_command_error
now how to implement this?
in the same decorator under #bot.event in your code you will have to do this
#bot.event
async def on_message(message):
#if you still want to do something with this
async def on_command_error(message,error):
if isinstance(error, commands.CommandNotFound):
await message.send("This command don't exist")
#or you can simply just pass this one
and it's not your fault for following yt tutorials lol because I also followed them at a time.... but yeah they are bad :) welcome to discord.py
Im trying to make a command that repeats what a user says but when people put an #everyone ping in their message the bot pings everyone.
My code:
#bot.command()
async def say(ctx, *, arg):
everyone = ctx.message.guild.default_role
if arg == everyone:
await ctx.send(arg.replace('#every-no'))
await ctx.send(arg)
Discord has a utility function to escape mentions!
discord.utils.escape_mentions(text)
Check it out!
You can also make use of the AllowedMentions object when sending messages.
allowed = discord.AllowedMentions.all() # Make all mentions escaped. You can always change.
await ctx.send(arg, allowed_mentions=allowed)
I read the answer here and tried to adapt it for my own usage:
How to add a function to discord.py event loop?
My situation is as follows:
I'm developing a discord bot in which I have some commands users can run. These commands have a possibility of erroring, in which case I do client.loop.create_task(errorReportingFunction()) which reports the error to me by messaging me. I also have a command which uses asyncio.create_task() instead.
However I'm having memory leaks which vary from mild to crashing the bot after prolonged usage which leads me to think that I'm not using the tasks system correctly. Should I be cleaning up after the tasks I create and deleting them somehow after I'm done using them? Or is there a system that does that automatically.
I'm also not sure how asyncio.create_task() and client.loop.create_task() differ so I'd appreciate some advice on which to use when, or if they're basically the same.
I believe that what you want is to do something (for example sending a message) when an error happens. If so, there are better ways to handle this in discord.py instead of creating tasks.
In the case that you want to control this only for a certain function, you could create an error handler to track the error raised from that function and send you a message whenever one happens:
#bot.command()
async def info(ctx, *, member: discord.Member):
"""Tells you some info about the member."""
fmt = '{0} joined on {0.joined_at} and has {1} roles.'
await ctx.send(fmt.format(member, len(member.roles)))
#info.error
async def info_error(ctx, error):
if isinstance(error, commands.BadArgument):
await ctx.send('I could not find that member...')
# Send a message to the bot owner about the error
await self.bot.get_user(self.bot.owner_id).send('There has been an error in the command')
Although a common practice in discord bots is to have an error handling cog, which would allow you to centralize all the error handling in a single function. It could be something like this:
class ErrorCog(commands.Cog, name='Error'):
'''Cog in charge of the error handling functions.'''
def __init__(self, bot):
self.bot = bot
#commands.Cog.listener()
async def on_command_error(self, ctx, error):
'''Event that takes place when there is an error in a command.
Keyword arguments:
error -- error message '''
error = getattr(error, 'original', error)
# Wrong command
if isinstance(error, commands.CommandNotFound):
message = 'This is not a valid command'
return await ctx.send(message)
# Command is on cooldown
elif isinstance(error, commands.CommandOnCooldown):
if ctx.author.id is self.bot.owner_id:
ctx.command.reset_cooldown(ctx)
return await ctx.command.reinvoke(ctx)
cooldowns = {
commands.BucketType.default: f'for the whole bot.',
commands.BucketType.user: f'for you.',
commands.BucketType.guild: f'for this server.',
commands.BucketType.channel: f'for this channel.',
commands.BucketType.member: f'cooldown for you.',
commands.BucketType.category: f'for this channel category.',
commands.BucketType.role: f'for your role.'
}
return await ctx.send(f'The command `{ctx.command}` is on cooldown {cooldowns[error.cooldown.type]} ')
# Bot lacks permissions.
elif isinstance(error, commands.BotMissingPermissions):
permissions = '\n'.join([f'> {permission}' for permission in error.missing_perms])
message = f'I am missing the following permissions required to run the command `{ctx.command}`.\n{permissions}'
try:
return await ctx.send(message)
except discord.Forbidden:
try:
return await ctx.author.send(message)
except discord.Forbidden:
return
# Here you need to add more instances
# of errors according to your needs
def setup(bot):
bot.add_cog(ErrorCog(bot))
In discord.py is there some option how i can get access to msg.content (or ctx.content how everyone uses it) under a command ? Below you can see 2 examples of what i mean. The first one is event and i simply copy the message and let the bot to send it back. The second is command but there the msg.content doesnt work. My problem is that i dont want to use events so much and have everything under a command.
#bot.event
async def on_message(msg):
chat = bot.get_channel(797224597443051611)
if msg.channel.id != channel:
return
if msg.content.startswith("!rps"):
message = str(msg.content)
await chat.send(message)
Someone types !rps hello. Outpup in discord is !rps hello
#bot.command()
async def rps(msg):
if msg.channel.id != channel:
return
message = str(msg.content)
await msg.send(message)
Someone types !rps hello (my prefix is !). Output is error in console:
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'Context' object has no attribute 'content'
Commands always take commands.Context as the first argument, also you should call it ctx instead of msg, to access the message content you can use ctx.message.content
#bot.command()
async def rps(ctx):
if ctx.channel.id != channel:
return
message = str(ctx.message.content)
await ctx.send(message)
Take a look at the commands introduction
In order to get the rest of the message of a command, you need to pass another argument. This argument will include all the messages that's sent after !rps. Also, using ctx instead of msg is better in commands.
#bot.command()
async def rps(ctx, *, args):
if ctx.channel.id != channel:
return
await ctx.send(args)
In this code, args argument includes all the messages after the !rps.
i am Making a MassDM command but it dont works well, it sends a Message not to Everyone it stops automatically i think because they turn their DM's off thats why how can i Bypass it? or how can i Fix this error?
Code
#client.command()
async def massdm(self, ctx, *, message):
await ctx.message.delete()
embed = discord.Embed(description=f'**Sent everyone a DM with:** ``{message}``',color=embcolor)
await ctx.send(embed=embed, delete_after=delemb)
for user in list(ctx.guild.members):
try:
await asyncio.sleep(0.1)
await user.send(message)
except:
pass
To debug it properly, the first step would be to remove the try, except block and find out what exceptions are you actually getting. It's a bad habit to catch every exceptions at once. Without knowing what exception is it throwing, I'm unable to help more.
Another thing I would recommend is to benefit from the discord.py being an asynchronous package, and instead of iterating over the users synchronously, try something like that:
coros = [await user.send(message) for user in ctx.guild.members]
await asyncio.gather(*coros)
This way it will send the message to every user at the same time.
EDIT:
I also found another bug while using a loop like that. At some point the bot will try to send the DM to itself, and that is raising AttributeError. Make sure that you handle that, for example:
coros = [user.send(message) for user in ctx.guild.members if user != ctx.guild.me]
await asyncio.gather(*coros)
Maybe that was your issue all along.
Try this:) Hope it helps
#client.command(pass_context=True)
async def massdm(ctx):
await ctx.message.delete()
for member in list(client.get_all_members()):
try:
embed = discord.Embed(title="Test",
description="Test!",
color=discord.Colour.blurple())
embed.set_thumbnail(
url="test")
embed.set_footer(
text=
"test"
)
#delay. Set it to 10 to 20 seconds to avoid flagging
await asyncio.sleep(30)
await member.send(embed=embed)
except:
pass
#await ctx.send(f"Messaged: {member.name}")
print(f"Messaged: {member.name}")