I've been learning how to code a discord bot recently and I've hit a wall. I am wanting to create a method that allows me to move messages from one channel to another. I created a solution that works but not how I would like it to. Idealy I would want to just have the bot almost do a reddit repost where it takes the exact message and just has it embedded. Currently what I have for the method is
@client.eventasync def on_message(message):author = message.authorcontent = message.contextchannel = message.channelif message.content.startswith('!move'):#code to process the input, nothing special or important to thisfor i in fetchedMessages:embededMessage = discord.Embed()embededMessage.description = i.contextembededMessage.set_author(name=i.author, icon_url=i.author.avatar_url)await channelToPostIn.send(embeded=embededMessage)# delete the old messagei.delete()
Now this works perfectly for text messages but not for images or for example if the post was embedded in the first place. If someone has a more elegant solution or is able to point me in the right direction in the documentation I would be much appreciative. Thanks.
Best Answer
This would be a lot easier if you were to use the commands.Bot
extension: discord.ext.commands.Bot()
(check out a basic bot)
bot = commands.Bot(...)@bot.command()async def move(ctx, channel: discord.TextChannel, *message_ids: int): # Typehint to a Messageable'''Moves the message content to another channel'''# Loop over each message id providedfor message_id in message_ids:# Holds the Message instance that should be movedmessage = await ctx.channel.fetch_message(message_id)# It is possible the bot fails to fetch the message, if it has been deleted for exampleif not message:return# Check if message has an embed (only webhooks can send multiple in one message)if message.embeds:# Just copy the embed including all its propertiesembed = message.embeds[0]# Overwrite their titleembed.title = f'Embed by: {message.author}'else:embed = discord.Embed(title=f'Message by: {message.author}',description=message.content)# send the message to specified channelawait channel.send(embed=embed)# delete the originalawait message.delete()
Possible problems:
- The message has both an embed and content (easy fix, just add the message.content to the embed.description, and check whether the length isn't over the limit)
- The command isn't used in the channel where the message resides, so it can't find the message (can be fixed by specifying a channel to search the message in, instead of using Context)
- A video being in an embed, I am unsure what would happen with for example a youtube link that is embedded, as a bot can't embed videos afaik
@Buster's solution worked correctly except for when a user uploaded a picture as a file attached to the message. To fix this I ended up setting the image of the embedded message with the proxy_url of the image attached. my whole move command is as followed.
# Move: !move {channel to move to} {number of messages}# Used to move messages from one channel to another.@client.command(name='move')async def move(context):if "mod" not in [y.name.lower() for y in context.message.author.roles]:await context.message.delete()await context.channel.send("{} you do not have the permissions to move messages.".format(context.message.author))return# get the content of the messagecontent = context.message.content.split(' ')# if the length is not three the command was used incorrectlyif len(content) != 3 or not content[2].isnumeric():await context.message.channel.send("Incorrect usage of !move. Example: !move {channel to move to} {number of messages}.")return# channel that it is going to be posted tochannelTo = content[1]# get the number of messages to be moved (including the command message)numberOfMessages = int(content[2]) + 1# get a list of the messagesfetchedMessages = await context.channel.history(limit=numberOfMessages).flatten()# delete all of those messages from the channelfor i in fetchedMessages:await i.delete()# invert the list and remove the last message (gets rid of the command message)fetchedMessages = fetchedMessages[::-1]fetchedMessages = fetchedMessages[:-1]# Loop over the messages fetchedfor messages in fetchedMessages:# get the channel object for the server to send tochannelTo = discord.utils.get(messages.guild.channels, name=channelTo)# if the message is embeded alreadyif messages.embeds:# set the embed message to the old embed objectembedMessage = messages.embeds[0]# elseelse:# Create embed message object and set content to originalembedMessage = discord.Embed(description = messages.content)# set the embed message author to original authorembedMessage.set_author(name=messages.author, icon_url=messages.author.avatar_url)# if message has attachments add themif messages.attachments:for i in messages.attachments:embedMessage.set_image(url = i.proxy_url)# Send to the desired channelawait channelTo.send(embed=embedMessage)
Thanks to everyone that helped with this problem.