Get message from RawReactionActionEvent (discord.py) - python

How can I get the message a reaction is used on? I know you can get the message with context, but how can I use the attributes
channel_id guild_id and message_id
to get the original message? This seems like enough information
I have tried using client.http.edit_message and client.http.delete_message which seems to work until using an embed. Whenever used, TypeError: Object of type Embed is not JSON serializable is raised

There are multiple ways of doing this:
Independent of the bot's cache, requires more API calls:
async def fetch_message(payload):
channel = await bot.fetch_channel(payload.channel_id)
message = await channel.fetch_message(payload.message_id)
return message
Depends on bot's cache, requires less API calls:
async def get_message(payload):
channel = bot.get_channel(payload.channel_id)
message = await bot.fetch_message(payload.message_id)
return message

Related

How to make my bot send message in a specific channel in discord.py

PROBLEM
I dont know where I am wrong but the below code seems to throw me NoneType error even though I have used this thing in my other cogs too.
CODE
#tasks.loop(seconds=10.0)
async def remind(self):
remind_channel = self.bot.get_channel(#id of channel)
await remind_channel.send("Passed")
ERROR
'NoneType' object has no attribute 'send'
I am sure there is no mistake in channel id and also I am new to tasks so if this problem is arising due to it how do I solve it?
NoneType means in that case that either the channel id is invalid or the channel is not in the bot's cache because he's starting currently or whatever.
But in most cases, is the channel just not in the bot's cache.
You should add await self.client.wait_until_ready() at the start of the task, to wait until the bot's cache is ready.
Like this:
#tasks.loop(seconds=10.0)
async def remind(self):
await self.client.wait_until_ready()
remind_channel = self.bot.get_channel(#id of channel)
await remind_channel.send("Passed")
Sources
https://discordpy.readthedocs.io/en/latest/api.html?highlight=wait_until_ready#discord.Client.wait_until_ready

Discord.py How to use the message that the bot WILL send?

import discord
from discord.ext import commands
async def anyfunc(ctx):
await ctx.send(f"{ctx.message.author.mention}, "Hi!")
bot_message_id = ((bot's_last_message)).id
What to put in (()) to make the bot remember the id of the message that it will send?
Is there a way to take the id of the next (for example, user's) message (that hasn't been sent yet) as a variable?
ctx.send() returns the discord.Message instance of the message it sent, so you can store it in a variable.
message = await ctx.send(f"{ctx.message.author.mention}, Hi!")
# do what you want with the message, in your case getting it's id
bot_message_id = message.id
As for your second question, if you want to get the response of a user to that message (so the next message a specific user will send), you can use the built-in wait_for for this.
def check(message):
return message.author.id == the_id_of_that_user
message = await bot.wait_for("message", check=check)
That way, the bot will literally wait for a message that makes your check function return True, or in this case a message sent by that very user. More info on that in the relevant API documentation.
I couldn't understand your question very good but I'll try to answer. according to API References you can get someone's last message with using channel.history().get(). So here is a example:
import discord
from discord.ext import commands
async def anyfunc(ctx):
await ctx.send(f"{ctx.message.author.mention}, Hi!")
bot_message_id = await ctx.channel.history().get(author__name="Bot's name").id
This will probably work but in case of error, maybe you can try author__id=bot's id instead of author__name.

How to copy an embed in discord.py?

I want the bot fetch a message(embed) and send it to channel where command is invoked.
Following code works fine for normal text message:
#bot.command()
async def fetch(ctx):
channel = bot.get_channel(736984092368830468)
msg = await channel.fetch_message(752779298439430164)
await ctx.send(msg.content)
For sending embeds I tried:
#bot.command()
async def fetch(ctx):
channel = bot.get_channel(736984092368830468)
msg = await channel.fetch_message(752779298439430164)
await ctx.send(msg.embeds.copy())
It sends this instead of sending embed:
How do I make the bot copy and send embed?
The problem is that you are trying to send a list of discord.Embed objects as a string in your await ctx.send(msg.embeds.copy())
The ctx.send() method has a parameter called embed to send embeds in a message.
await ctx.send(embed=msg.embeds[0])
Should do the trick. This way you are sending an actual discord.Embed object, instead of a list of discord.Embeds
You should not need the .copy() method in
await ctx.send(embed=msg.embeds[0].copy())
although you can use it
The only downside of using the index operator [0] is that you can only access one embed contained in your message. The discord API does not provide a way to send multiple embeds in a single message. (see this question).
A workaround could be iterating over every embed in the msg.embeds list and send a message for every embed.
for embed in msg.embeds:
await ctx.send(embed=embed)
This unfortunately results in multiple messages being sent by the bot, but you don't really notice.
You have to select the first embed like this and use [copy] if you want to change into it before sending again.(https://discordpy.readthedocs.io/en/latest/api.html?highlight=embed#discord.Embed.copy)
#bot.command()
async def fetch(ctx):
channel = bot.get_channel(736984092368830468)
msg = await channel.fetch_message(752779298439430164)
await ctx.send(embed=msg.embeds[0])

How can I read the message someone has reacted to?

I want to read the message content of the message that got reacted to. I believe that the payload doesn't have a message object but does have the message_id. How can I even get the message? There is nothing I can use to get the contents of the message?
Specifically, if its am embeded message, I want to read the footer
async def on_raw_reaction_add(self, payload):
message_id = payload.message_id
Sorry for the late answer!
When using the payload from the RawReactionEvent, you're able to get the channel_id as well. Using this, it means you can do:
async def on_raw_reaction_add(self, payload):
channel = self.bot.get_channel(payload.channel_id)
message = await channel.fetch_message(payload.message_id)
print(message.content) # now you can view the message's content!
References:
Client.get_channel()
TextChannel.fetch_message()

How to add a reaction to a message using the message ID

I want to make a Bot command, that adds a reaction to a message when given emoji and ID of the message.
It seems like I need to turn the string I get from the original message into the discord.Message class for the code to work, but I don't find any way of doing that.
I've already read through the documentation and it just says
"There should be no need to create one of these manually."
import discord
token = "Token Here"
client = discord.Client()
#client.event
async def on_message(message):
if message.content.lower().startswith("e react"):
msg_id = message.content[8:26] #This filters out the ID
emoji = message.content[27:] #This filters out the Emoji
await msg_id.add_reaction(emoji)
client.run(token)
I get the following error:
AttributeError: 'str' object has no attribute 'add_reaction'
This is made much easier by using converters. Specifically, we can use MessageConverter to get the target Message object and PartialEmojiConverter to get the emoji we want to react with:
from discord.ext.commands import Bot
from discord import Message, PartialEmoji
bot = Bot("e ")
#bot.command()
async def react(ctx, message: Message, emoji: PartialEmoji):
await message.add_reaction(emoji)
bot.run("TOKEN")

Categories

Resources