I want to send every new message from one channel to another.
But when there are albums in the message, they are sent separately to the destination channel.
How can I send them as an album (as one message)?
#client.on(events.NewMessage('your_channel'))
async def my_event_handler(event):
await client.send_message('my_channel', event.message)
And I used events.album instead of events.NewMessage, but it didn't work!
I find a simple way, maybe someone will use it
#client.on(events.Album(chats="your_channel"))
async def handler(event):
await client.send_message(
"my_channel", #output channel
file=event.messages, #list of messages
message=event.original_update.message.message, #caption
)
Related
I'm developing a small bot for a few groups of friends that sends the same message at a specific time every Friday using Cron.
It has a "CHANNEL_ID" variable with the channel ID to send the message in, but this only works with a specific guild.
Is there any way to send the same message to multiple IDs, like a list or an array?
The method to send the message in the first text channel available to the bot in the guild can't work, because it depends from server to server.
The nearest example of what you want seems like this
async def SendMsgAll(self, ctx):
count = 0
for guild in self.client.guilds:
channel_in_guild = []
for channel in guild.text_channels:
channel_in_guild.append(channel)
send_channel = channel_in_guild[count]
try:
await send_channel.send("test")
except:
count += 1
In this example code, I am just forwarding messages from one channel to another
where watch_channels is a list of channels to observe for new messages, and output_channel is the channel to send those messages
When watch_channel has a image with caption, only the image gets sent to output_channel. The caption is left out.
#client.on(events.NewMessage(chats = watch_channels))
async def my_event_handler(event):
me = await client.get_me()
print(str(me))
print(str(event.message.text))
if me:
await client.send_message(output_channel, event.message)
why can't you just forward the message?
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.event
async def on_message(message):
author = message.author
content = message.context
channel = message.channel
if message.content.startswith('!move'):
#code to process the input, nothing special or important to this
for i in fetchedMessages:
embededMessage = discord.Embed()
embededMessage.description = i.context
embededMessage.set_author(name=i.author, icon_url=i.author.avatar_url)
await channelToPostIn.send(embeded=embededMessage)
# delete the old message
i.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.
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 provided
for message_id in message_ids:
# Holds the Message instance that should be moved
message = await ctx.channel.fetch_message(message_id)
# It is possible the bot fails to fetch the message, if it has been deleted for example
if 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 properties
embed = message.embeds[0]
# Overwrite their title
embed.title = f'Embed by: {message.author}'
else:
embed = discord.Embed(
title=f'Message by: {message.author}',
description=message.content
)
# send the message to specified channel
await channel.send(embed=embed)
# delete the original
await 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 message
content = context.message.content.split(' ')
# if the length is not three the command was used incorrectly
if 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 to
channelTo = content[1]
# get the number of messages to be moved (including the command message)
numberOfMessages = int(content[2]) + 1
# get a list of the messages
fetchedMessages = await context.channel.history(limit=numberOfMessages).flatten()
# delete all of those messages from the channel
for 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 fetched
for messages in fetchedMessages:
# get the channel object for the server to send to
channelTo = discord.utils.get(messages.guild.channels, name=channelTo)
# if the message is embeded already
if messages.embeds:
# set the embed message to the old embed object
embedMessage = messages.embeds[0]
# else
else:
# Create embed message object and set content to original
embedMessage = discord.Embed(
description = messages.content
)
# set the embed message author to original author
embedMessage.set_author(name=messages.author, icon_url=messages.author.avatar_url)
# if message has attachments add them
if messages.attachments:
for i in messages.attachments:
embedMessage.set_image(url = i.proxy_url)
# Send to the desired channel
await channelTo.send(embed=embedMessage)
Thanks to everyone that helped with this problem.
I've got a pretty decent bot that I'm planning to launch soon. It's called moderator and it's supposed to be the perfect moderator bot so that a server won't need actual moderators anymore. So I want it to send a welcome message when it joins the server, but because all servers have different channel names and channels, I can't get a generic channel name to send the welcome message too.
channel = find(lambda x: x.name == 'general', guild.text_channels)
if channel and channel.permissions_for(guild.me).send_messages:
await channel.send(embed=embedvar)
This is what I have right now and as you can see it finds a channel named general and sends the welcome embed message to the general channel. But since not every server has a general channel, I want to have the bot find the 1st channel where it has permission to send messages. Is there a way to do that?
Thanks!
You can get the first channel of the guild with this way:
channel = client.get_guild(guild id).text_channels[0]
So with this code, you can do something like that:
#client.event
async def on_guild_join(guild):
channel = guild.text_channels[0]
embed = discord.Embed(title=guild.name, description="Hello, I'm here")
await channel.send(embed=embed)
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])