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
Related
When someone mentions the bot, I want it to respond saying, "Hey! I've been mentioned. My prefix is >. You can type >help to see my commands." I have the code written out but the bot does not respond at all when it gets mentioned. I do not get any errors when I run it or mention the bot. How do I get this to work? My code is below. Thanks in advance.
#bot.event
async def on_message(message):
if message.author.id == bot.user.id:
return
msg_content = message.content.lower()
mention = ['#830599839623675925', '#Ultimate Bot']
if any(word in msg_content for word in mention):
await message.channel.send("Hey! I've been mentioned. My prefix is `>`. You can type `>help` to see my commands.")
else:
await bot.process_commands(message)
You can use the mentioned_in() method.
So in this case it would be;
#bot.event
async def on_message(message):
if message.author.id == bot.user.id: return
if bot.user.mentioned_in(message):
await message.channel.send("Hey! I've been mentioned.")
await bot.process_commands(message)
Some things to note:
Hard-coding in values such as in your mention variable is bad practice. It makes it much harder to maintain your code, and when your project gets bigger you may question what the purpose of these seemingly random strings are referring to. For example, if you were to change the name of the bot, or to transfer your code to a new bot, going through your entire codebase and picking out and changing these values would be far from ideal.
I don't know about the rest of your application, but you probably don't want process_commands() to be in the else statement. For example, if the user mentions the bot in their message, but are using a command, the command will be blocked because you are not triggering process_commands().
Hope this answers your question
You could instead just check if bot.user is in the message mentions.
You can also check if the bot display name was used.
if bot.user in message.mentions or (message.guild and message.guild.me in message.mentions):
print("bot was mentioned")
elif message.guild and message.guild.me.display_name in message.content:
print("bot name was used")
I'm trying to make some 'fun' commands as bots call them, and I wanted to embed them. However it doesnt spit out anything, not even an error on discord, nor on the command prompt, giving me no ideas on how to improve the code. I'd also like to implement a way to use the members: commands.Greedy[discord.Members] code so I can find who was the target for the command, but I think I need to solve this first. Any suggestions on how to do so?
I also am stumped because I used the .format and the f string to try to use arguments, and I also tried using message, but that gave me a syntax error of 'Error 'list' object has no attribute 'mention''. I really cant understand the documents on the commands since they dont really give any examples of actual code, and I suck at understanding new stuff. Can someone figure this out?
from discord.ext import commands
import discord
bot= commands.Bot(command_prefix='0!')
#bot.event
async def on_message(message):
if message.author == bot.user:
return
if message.content.startswith('Sample Text'):
await message.channel.send('Sample Text')
#bot.command()
async def slap(ctx):
embed = discord.Embed(color=0x00ff00, title='OH! Z E S L A P !', description="ooh, that hurt.")
embed.add_field(name="Man behind the slaughter:", value="test")
await ctx.send(embed=embed)
bot.run('token here')```
-During this edit, when I just had the 'bot command' area, It seemed to have functioned still. This makes it even more confusing...
Overriding the default provided on_message() event forbids any extra commands from running. To fix this, add a bot.process_commands(message) line at the end of your on_message() event.
#bot.event
async def on_message(message):
if message.author == bot.user:
return
if message.content.startswith('Sample Text'):
await message.channel.send('Sample Text')
await bot.process_commands(message)
So I am just wondering, how can I create an event in discord.py where if a user pings the bot it will respond with a message?
I have not found anything concrete anywhere on how to do this and I would appreciate it if someone could help get my feet wet on how to do this. I appreciate it!
I found that the default function discord.User.mentioned_in works
In order for it to check for our bot, we add client.user (which is our bot) in front of the function, making it client.user.mentioned_in(message). The argument message, should be the same argument that you gave for the async def on_message(message) line
Example:
#client.event
async def on_message(message):
if client.user.mentioned_in(message):
await message.channel.send('You mentioned me!')
I'm not sure why but I haven't seen any others use this function though. Maybe they just aren't aware of this, and instead use client.user.id in message.content
#bot.event
async def on_message(message):
mention = f'<#!{bot.user.id}>'
if mention in message.content:
await message.channel.send("You mentioned me")
Some thing that I found to work was:
if str(client.user.id) in message.content:
await message.channel.send('You mentioned me!')
Discord pings in pure text are done with special strings. Luckily you don't have to generate these yourself as discord.py has user.mention (documentation). Your clientuser has this too documentation. So we just get the string of our own mention via client.user.mention
Now we just have to check if this particular string is in the message:
#client.event
async def on_message(message):
if client.user.mention in message.content.split():
await message.channel.send('You mentioned me!')
So I recently created a discord bot with various meme commands and moderating commands. I am relatively new to python but I understand the gist of it. I have already created a command that lets me(only me) DM a user through the bot. I now want to try and make the bot be able to read the messages that are sent back to it and send them to me, whether its printed in shell or sent to a specific channel/me I don't care, I just want to be able to see what is sent to it.
I did some reading around and found this, and from that I collected this:
#bot.event
async def on_message(message):
channel = bot.get_channel('channel ID')
if message.server is None and message.author != bot.user:
await bot.send_message(channel, message.content)
await bot.process_commands(message)
This alone has not worked for me, I get an error saying that "AttributeError: 'Message' object has no attribute 'server'" when I DM'ed the bot. I was told that discord.py rewrite does not use 'server', but rather 'guild'. So I changed it to say message.guild. From there it gave me the error "AttributeError: 'Bot' object has no attribute 'send_message'", and that's about as far as I got there. I've tinkered with it and changed things here and there and made some slight progress...I think. My new code is:
#bot.event
async def on_message(ctx, message):
channel = bot.get_channel('channel ID')
if message.guild is None and message.author != bot.user:
await ctx.send(channel, message.content)
await bot.process_commands(message)
This gives me the error "TypeError: on_message() missing 1 required positional argument: 'message'".
That is as far as I've gotten now. Any help would be appreciated, as I said, I'm still somewhat new to python, I've only started using it about 2 months ago.
You're using the ctx parameter, which is unique to commands.
'ctx' is commands.Context, which provides information about commands that are executed.
Since this isn't a command, but rather an event, you shouldn't provide it.
Untested, but this should do the trick:
(I made it so it ignores messages from ALL bots, to avoid spam)
for printing messages to console
#bot.event
async def on_message(message: discord.Message):
if message.guild is None and not message.author.bot:
print(message.content)
await bot.process_commands(message)
for dumping message contents to a channel
msg_dump_channel = 1234
#bot.event
async def on_message(message: discord.Message):
channel = bot.get_channel(msg_dump_channel)
if message.guild is None and not message.author.bot:
# if the channel is public at all, make sure to sanitize this first
await channel.send(message.content)
await bot.process_commands(message)
Your first code is using ancient, outdated and unsupported dpy version.
You mostly updated it correctly in the second code except for few mistakes like the on_message event.
It is not working because it only takes one argument message, there is no ctx in that event.
So the event is passing one argument but your function takes 2 thus the error. The correct code would be:
async def on_message(message):
But now you'll be confused what to do with this line you wrote:
await ctx.send(channel, message.content)
Even if ctx existed this wouldn't work because send doesn't take destination anymore, instead you call send on destination destination.send("Hello") so translated to your code if the channel is where you want to send it would be await channel.send(message.content)
Also one final note I noticed that you used string here:
bot.get_channel('channel ID') this could be you just giving example but just remember that IDs are ints, if you pass string it will never find that channel.
For example this is invalid:
bot.get_channel('123456789111315178')
And this would be valid: bot.get_channel(123456789111315178)
Based on that error, I'd say you're likely calling on_message() at some point and not giving the message parameter. Look through your code and see if that's maybe the case.
Alternatively, if it's some other code you haven't written that's calling your function, then it might only be calling on_message() with one argument, in which case the ctx argument might be incompatible with that function.
I need to implement some of the feature and one of the feature is implementing polls type feature. Can't use public discord bots due to some policies so we have to implement something on my own. Did some research yesterday and was able to make basic bot using python3 and commands api from discord.ext. Now what i need to figure out is:
Read reactions added by a user to a message?
Create a message with reactions (like bots which create reaction polls?)
Pin a message?
I believe from ctx i can get user tags (admin etc). Is there a better way to do so?
Couldn't find anything helpful on Commands reference page or probably i am looking at wrong documentation. any help would be appreciated.
thanks
Updated: Thanks guys. now i am stuck at how to add emoji, here is my code
poll_emojis = {0: ':zero:', 1: ':one:', 2: ':two:', 3: ':three:', 4: ':four:'}
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.startswith('$create_poll'):
poll_content = message.content.split('"')
poll_text = poll_content[1]
poll_options = []
poll_option_text = ''
count = 0
for poll_option in poll_content[2:]:
if poll_option.strip() != '':
poll_options.append(poll_option)
poll_option_text += '{0}: {1}\t'.format(poll_emojis[count], poll_option)
count += 1
posted_message = await message.channel.send('**{0}**\n{1}'.format(poll_text, poll_option_text))
count = 0
for poll_option in poll_options:
await posted_message.add_reaction(Emoji(poll_emojis[count]))
count += 1
As an aside, given you're starting this project, and are already using the rewrite documentation, make sure you're using the rewrite version. There are some questions on here about how to make sure, and how to get it if you're not, but it's better documented and easier to use. My answers below assume you are using discord.py-rewrite
Message.reactions is a list of Reactions. You could get a mapping of reactions to their counts with
{react.emoji: react.count for react in message.reactions}
You could react to the message immediately after posting it:
#bot.command()
async def poll(ctx, *, text):
message = await ctx.send(text)
for emoji in ('👍', '👎'):
await message.add_reaction(emoji)
You can use Message.pin: await message.pin()
I'm not sure what you mean by "user tags". Do you mean roles?
I would write your command as
#bot.command()
async def create_poll(ctx, text, *emojis: discord.Emoji):
msg = await ctx.send(text)
for emoji in emojis:
await msg.add_reaction(emoji)
Note that this will only work for custom emoji, the ones you have added to your own server (This is because discord.py treats unicode emoji and custom emoji differently.) This would accept commands like
!create_poll "Vote in the Primary!" :obamaemoji: :hillaryemoji:
assuming those two emoji were on the server you send the command in.
With the new commands.Greedy converter, I would rewrite the above command like so:
#bot.command()
async def create_poll(ctx, emojis: Greedy[Emoji], *, text):
msg = await ctx.send(text)
for emoji in emojis:
await msg.add_reaction(emoji)
So invocation would be a little more natural, without the quotes:
!create_poll :obamaemoji: :hillaryemoji: Vote in the Primary!
I have just seen what you are stuck and I was stuck at this too. The solution is that reactions are not actually things like ":one:" it is actual emojis, there are different ways to fix this, the simplest being adding them to the dictionary yourself. Or you can use python3 -m pip install discordhelp and use the functions for it listed here.