on_reaction_add not being run - python

I'm new to discord.py and trying to make a translator bot. When the user reacts with a certain flag, the bot translates it, but the event is never getting called hence I have no code to translate any messages yet. I know it's not getting called because the program isn't printing an 'x' to the console.
#client.event
async def on_reaction_add(reaction, user):
channel = reaction.message.channel
print('x')
await client.send_message(channel, '{} has added {} to the the message {}'.format(user.name, reaction.emoji, reaction.message.content))
await client.process_commands(reaction.message)

Probably a bit late to this thread but, the answer above is a valid answer. But you can also use on_raw_reaction_add which gets called even if the messages aren't in the Bot's cache.
Called when a message has a reaction added. Unlike on_reaction_add(), this is called regardless of the state of the internal message cache.
Documentation Link
Example:
#commands.Cog.listener()
async def on_raw_reaction_add(self, payload):
channel = await self.bot.fetch_channel(payload.channel_id)
message = await channel.fetch_message(payload.message_id)
user = await self.bot.fetch_user(payload.user_id)
emoji = payload.emoji
await channel.send("Hello")

There isn't much valid reason for why the event isn't registered/called.
One of which is stated in the docs: http://discordpy.readthedocs.io/en/async/api.html#discord.on_reaction_add. Try adding a reaction immediately to a message that is sent after the bot is online. Since messages sent before the bot is online will not be recognized by the bot (not in Client.messages).
if the message is not found in the Client.messages cache, then this
event will not be called.
Another possible reason is that this function was never defined before the client loop commenced. Verify your indentation. And/Or try placing the function directly under client = Bot(...), to check if this is the problem.
If neither of the aforementioned solves your problem, please post a minimal, complete, verifiable example (a short runnable code from top to bottom that indicates your problem).

Related

bot.get_channel() occasionally returning none in discord.py,

I am trying to write a discord.py bot. The following is an abridgement of my full code.
intents = discord.Intents.default()
intents.message_content = True
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
bot = commands.Bot(intents=intents, command_prefix="!", sort_commands=False)
client = discord.Client(intents=intents)
#bot.event
async def on_ready():
print(f'{bot.user.name} has connected to Discord!')
channel = bot.get_channel(12345678912345678912)
await channel.send("This is a test.")
bot.run(TOKEN)
Sometimes, the code above will work as intended, printing the connection message and sending the desired message into the target channel.
This is not always the case, however! I am getting an issue where the bot.get_channel() command returns none instead of the correct data. I assume this means that the channel cannot be found, except for the fact that the channel does exist.
The error that is sent to the console is;
AttributeError: 'NoneType' object has no attribute 'send'
I am very, very new to discord.py so I would appreciate any help I can get to better understand what's going on under the hood here. Thank you very much for your help.
The get_channel method is a cache lookup method, so it's not always reliable, or the bot doesn't have access to the channel, and since it doesn't raise an exception if the cache wasn't found and returns None instead, you can't know the reason for sure. You can use fetch_channel to make an API request after get_channel if it returns none; this method will raise an exception if the channel was not found or it doesn't have permission to fetch.
channel = (bot.get_channel(1234567890) or await bot.fetch_channel(1234567890))
await channel.send("This is a test.")
Also it seems like you have both discord.ext.commands.Bot and discord.Client instance, please choose one and remove the other.
The accepted answer is not recommended.
The reason it doesn't work is because the cache isn't populated yet in on_ready, but you should not make API requests (fetch_X & send) in on_ready! Making API calls in there has a high chance for Discord to just disconnect your bot.
Also, on_ready gets triggered multiple times, so you'll end up sending this message constantly even though you only started it once.
There's rarely a reason to do anything at all in there. If you want something to run once on startup you can create a Task & start it in setup_hook.

Verification system. (discordpy)

Okay so im trying to make a verify system, but im stuck with it. How could i fix it? (The reason for why i dont use simply ctx, is that this is in an on_ready event.)
guild = client.get_guild(id)
if client.fetch_guild(guild) == '928779004654256239':
channel = client.get_channel('930910261332819968')
text = discord.Embed(title="React below to verify.", color=discord.colour.blue())
moji = await client.send_message(channel, text, embed=text)
await client.add_reaction(moji, emoji='✔')
else:
return
Traceback:
C:\Users\User\Desktop\Dexton\Dexton.py:19: RuntimeWarning: coroutine 'Client.fetch_guild' was never awaited
if client.fetch_guild(guild) == '928779004654256239'
To answer your question, fetch_guild makes an API call and is a coroutine, so any calls to it should be awaited. It also accepts an int as a parameter, not a Guild, and you probably don't want to be comparing a Guild to an int either.
However, it seems that you're making unnecessary function calls anyway - you shouldn't need to call get_guild or fetch_guild at all. Just calling get_channel should be enough since the return type will be None if your bot account isn't in the guild anyway (as the channel won't be found).
With that in mind, you can change your code as such:
channel = client.get_channel(930910261332819968)
text = discord.Embed(title="React below to verify.", color=discord.Colour.blue())
if channel:
moji = await channel.send(embed=text)
await moji.add_reaction('✔')
A few other improvements were also made in the above code snippet, namely using TextChannel.send and Message.add_reaction in favor of Client.send_message and Client.add_reaction, respectively.
You should also keep in mind that a new verification message will be sent each time you run your bot unless you add a mechanism to prevent that. You may also want to use fetch_channel rather than get_channel to prevent any cache issues.

How to forward message from a specific chat in Telethon?

This is a continuation of this short forum (How forward message to other contact with telethon).
Problem
I replaced entity with the group id for GC A and it works since I type something in GC B the bot forwards it to GC A however, when I message GC A the bot still forwards the messages to GC A which I don't want, I just want it to not react.
await client.forward_messages(entity, event.message)
The bot forwards every new message because the event type is new messages so I was thinking, is there a way to filter it so that it only triggers when there are new messages on a specific group?
#client.on(events.NewMessage)
async def main(event):
Solutions Ive tried
Looking at the documentation (https://docs.telethon.dev/en/latest/modules/client.html#telethon.client.messages.MessageMethods.forward_messages) there is an example with the argument "from_chat". So I placed the group id of GC B but it doesn't work.
await client.forward_messages(chat, message_id, from_chat)
I also tried making the argument look like this to copy the examples better but It does not work
await client.forward_messages(entity("group ID"), event.message, from_chat("group_id"))
For me worked this code:
#client.on(events.NewMessage(chats = FROM_CHANNEL_ID))
async def main(event):
await event.forward_to(TO_CHAT_ID)
Try it, may it will work for you to.

How does discord.py detect that a message is sent using just a coroutine which is being defined in the code itself?

I am a intermediate python programmer and just started coding discord bots using the discord.py module. One question that always revolves around my head is, how does the module detect that a message is sent using on_message() coroutine which is declared in our code and no such detection construct is there?
async def on_message(mssg):
#our conditions and responses
Consider the above code. Is there an equivalent predefined coroutine in the module that calls when we declare the on_message() in our code or is there something else that makes it to detect messages and pass it to the function argument, or detect any other event? On youtube or elsewhere, they just make you learn the syntax for some reason that you have to use async...await from the documentation.
so if memory serves me correct, the on_message() is what calls the bot to listen to each message that is sent, every time a message is sent. So with your code there:
async def on_message(mssg):
#our conditions and responses
we can actually dress that up a bit with some inter-workings, like so:
#bot.listen('on_message')
it's a bot event, so every-time a message is sent, this function is called.
async def stuff(message):
pass message so that the bot knows what to scan.
if message.content.startswith("buttlerprefix"):
start it off with an if statement so that the bot has something to check the user's message against
If I typed buttlerprefix and hit enter, it would respond with this message:
msg = await message.channel.send("my prefix is `>`")
if you want to go an extra step, and keep the channels declutterd, you can set the response equal to a variable msg in the event that you want to manipulate it later, thus in this scenario, it's set to auto delete with
await asyncio.sleep(10)
await msg.delete()
So if we put all of that together:
#bot.listen('on_message')
async def stuff(message):
if message.content.startswith("buttlerprefix"):
msg = await message.channel.send("my prefix is `>`")
await asyncio.sleep(10)
await msg.delete()
we get a function that is now scanning every message that comes through the guild that this bot functions in, no matter the channel, due to the on_message() function being called every-time a message is sent which is triggered by the #bot.listen

How do I make a bot write a certain message when it first joins a server?

I want my Discord bot to send a certain message, For example: "Hello" when he joins a new server. The bot should search for the top channel to write to and then send the message there.
i saw this, but this isn't helpful to me
async def on_guild_join(guild):
general = find(lambda x: x.name == 'general', guild.text_channels)
if general and general.permissions_for(guild.me).send_messages:
await general.send('Hello {}!'.format(guild.name))```
The code you used is actually very helpful, as it contains all of the building blocks you need:
The on_guild_join event
The list of all channels in order from top to bottom (according to the official reference). If you want to get the "top channel" you can therefore just use guild.text_channels[0]
checking the permissions of said channel
async def on_guild_join(guild):
general = guild.text_channels[0]
if general and general.permissions_for(guild.me).send_messages:
await general.send('Hello {}!'.format(guild.name))
else:
# raise an error
Now one problem you might encounter is the fact that if the top channel is something like an announcement channel, you might not have permissions to message in it. So logically you would want to try the next channel and if that doesn't work, the next etc. You can do this in a normal for loop:
async def on_guild_join(guild):
for general in guild.text_channels:
if general and general.permissions_for(guild.me).send_messages:
await general.send('Hello {}!'.format(guild.name))
return
print('I could not send a message in any channel!')
So in actuality, the piece of code you said was "not useful" was actually the key to doing the thing you want. Next time please be concise and say what of it is not useful instead of just saying "This whole thing is not useful because it does not do the thing I want".

Categories