I want to my discord bot to forward the message to another channel after a user reacts to it Discord.py - discord.py

I know next to nothing about coding in Python but I created this bot from tutorials I found online and it does little things in my private server.
One thing we'd love to do is to react to certain messages so they will be collected in a specific channel. I've seen a few servers do this, like a highlights kind of thing.
I found something promising here in Stackoverflow but it's in javascript :<
Edit: 2023-01-19 08:53 GMT+8
#client.event
async def on_reaction_add(reaction, member):
if str(reaction.emoji) == "⭐":
channel = await bot.get_channel(channel_id)
await channel.send(reaction.message.content)
Final code
edited: 2023-01-20 17:14 GMT+8
#bot.event
async def on_reaction_add(reaction, user):
if reaction.emoji == "⭐":
astrometrics = bot.get_channel(channel id here)
embed = discord.Embed(color = 0xFEE75C)
embed.set_author(name = reaction.message.author.name, icon_url = reaction.message.author.display_avatar)
embed.add_field(name = "Message Content", value = reaction.message.content)
if len(reaction.message.attachments) > 0:
embed.set_image(url = reaction.message.attachments[0].url)
embed.add_field(name = "Go to message", value = reaction.message.jump_url, inline = False)
await astrometrics.send(embed = embed)

You can check certain messages in on_message event. And for getting a specific channel in your server, you need to have the channel id. link
Something like this:
#bot.event
async def on_message(message):
if message.content == 'the certain message':
specific_channel = await bot.get_channel(channel_id)
await specific_channel.send(message.content)
But this might have some rate-limited consequence if the 'certain message' was too much and sent at a high rate. (If yes, then there's nothing you can do since rate-limited is a discord limitation).

Related

Discord py delete voicechannel if its empty

Well im trying to create a voice channel by command so i can join it.
And as soon i leave the channel its supposed to get deleted.
What i tried:
if message.content.startswith('/voice'):
guild = message.guild
voicechannel = await guild.create_voice_channel(f"{str(message.author)}")
await asyncio.sleep(5)
while True:
if len(voicechannel.voice_states) == 0:
await voicechannel.delete()
break
doesnt even work tho
I believe that your issue is that you are stuck in an infinite while True loop. I would first suggest that you switch to using discord.ext.commands, it simplifies the process of creating a Discord Bot by a great deal. If you were using discord.ext.commands.Bot, you would be able to use the wait_for() function to wait until the voice channel is empty.
from discord.ext.commands import Bot
client = Bot(command_prefix="/")
#client.command(name="voice")
async def voice(ctx):
guild = ctx.guild
voice_channel = await guild.create_voice_channel(f"{str(ctx.author)}")
def check(member, before, after):
return member == ctx.author and before.channel == voice_channel and after.channel is None
await client.wait_for("voice_state_update", check=check)
await voice_channel.delete()
client.run("TOKEN")
The only issue that I think could happen, is if the member never joins the voice channel. To counter this, we can set up another wait_for() function to determine if the member ever joins before waiting for the member to leave the voice channel.
from asyncio import TimeoutError
#client.command(name="voice")
async def voice(ctx):
guild = ctx.guild
voice_channel = await guild.create_voice_channel(f"{str(ctx.author)}")
def check(member, before, after):
return member == ctx.author and before.channel is None and after.channel == voice_channel
try:
await client.wait_for("voice_state_update", check=check, timeout=60)
except TimeoutError:
await voice_channel.delete()
return

How do you send a private message on_ready aka on a #client.event. Discord.py

I had multiple attempts.
# One of the attempts
ch = client.get_user(USERID)
await ch.send("IDK")
#Another
client = discord.Client()
#client.event
async def on_ready():
user = "#name"
user = discord.Member
await user.send(user, "here")
#Another
client = discord.Client()
#client.event
async def on_ready():
user = discord.utils.get(client.get_all_members(), id='USERID')
if user is not None:
await client.send(user, "A message for you")
else:
await client.send(user, "A message for you")
#Another
#client.event
async def on_ready():
ch = client.get_all_members()
await ch.send("Hello")
# Another
ch = client.start_private_message(USERID)
await ch.send("IDK")
As you can see I messed with the variables because I noticed that you can send a message by channel like this
channel = client.get_channel(CHANNELID)
await channel.send("Something)
But that doesn't work with get_user. Thanks in advance also sorry how bad my post/code is.
Allow me to inform you on what is wrong with the pieces of code you have provided.
await client.send(user, "A message for you") is older syntax, and has not been used since the v1.0 migration.
client.get_all_members() shouldn't be used in this case, as you are only getting all the members the bot shares a server with rather than a single user.
client.start_private_message(USERID) does not exist as far as I have read, and therefore we can assume that this wouldn't work.
My recommendation would be to use one of the two methods I will detail.
The first method would be to use client.fetch_user(), which sends a request to the Discord API instead of its internal cache (as the second method will). The only problem you will face with this method is if you retrieve too many users in a small amount of time, which will get you ratelimited. Other than that, I recommend this method.
The second method is to get a server through client.get_guild() and getting your user through there via guild.get_member(). This method will require the user to be in its cache, however, so this shouldn't be your go-to method in my opinion.
Do view both of these methods in the code below.
#client.event
async def on_ready():
# Method 1: Using fetch
user = await client.fetch_user(USER_ID)
await user.send("A message!")
# Method 2: Using 'get'
guild = client.get_guild(GUILD_ID)
user = guild.get_member(USER_ID)
await user.send("A message!")
Other Links:
Send DM to specific User ID - Stackoverflow
DM a specific user - Stackoverflow
Sending DM through python console (Fetch user) - Stackoverflow
DPY v1.0 Migration - Discord.py Documentation

Discord sniping edited messages not working

I've scrolled through other people's posts about this, ive tried reworking their code to mine, but it doesnt seem to work
snipe_message_author = {}
#client.event
async def on_message_edit(message_before, message_after):
snipe_message_author = message_before.author
guild = message_before.guild.name
#client.command()
async def snipeedit(ctx):
channel = ctx.channel
try:
snipeEmbed = discord.Embed(colour = discord.Colour.orange(),title=f"{snipe_message_author[channel.id]}", description = f"""Original message : {message_before.content}
Updated message : {message_after.content}""")
await ctx.send(embed = snipeEmbed)
except:
await ctx.send(f"There are no edited messages in #{channel.name}")
Every time i try the code, it returns "There are no edited messages in #*channel*"
I think its because of the snipe_message_author
thanks to anyone who helps.
As Łukasz Kwieciński's comment says:
You never add anything to snipe_message_author = {}, it can't work at all. Based on other posts, you can easily come up with a solution.
Take a look at the following code:
edited_messages = {}
#client.event
async def on_message_edit(message_before, message_after):
edited_messages[message_before.guild.id] = (message_before.content, message_after.content, message_before.author)
#client.command()
async def snipeedit(ctx):
try:
content_before, content_after, message_author = edited_messages[ctx.guild.id]
snipeEmbed = discord.Embed(color=discord.Colour.orange(), title=f"{message_author}",
description=f"Original message : {content_before}
Updated message : {content_after}")
await ctx.send(embed=snipeEmbed)
except:
await ctx.send(f"There are no edited messages in #{ctx.channel.name}")
In our on_message_edit event, we first define what should be "saved" for our guild or what exactly applies.
After we define these things, they are saved in the order specified. So now we have 3 "data" stored. We query or redefine these in our try statement and then read them from edited_messages for the corresponding ctx.guild.

Discord PY Bot not responding to an event

I have this bot that when it detects that a user has written a certain message in a certain channel, it will send a message then delete the user's message and its own message.
I wrote the exact same function to do the same thing in another channel and it works just fine.
I checked the bot's permissions and it can send messages in the channel,
here is the code:
the for loop is for searching for a specific text.
#client.event
async def on_message(message):
text = message.content
chann = message.channel.id
yes = False
for strf in comms:
if text.startswith(strf):
yes = True
if yes and (message.author.id != 769302967803183124) and (message.channel.id == 331562608467509249):
print(message.author.id)
msg = await message.channel.send('mech lahne tekteb el commands ye bhim')
await message.delete()
await asyncio.sleep(4)
await msg.delete()

get channel name and send a message over at that channel

So I am working on a little project here, and pretty much, I want to have one of those "Please type the name of a channel in this server" feature.
So pretty much, the bot asks for a channel name, and I put in for example "#changelog" - and then it will ask for what it should write in that channel, etc etc.
So need to get the channel id (I am guessing), but I don't want users to write the ID, instead only writing the #server-name. And then whenever I have done that, the bot shall write in that channel.
Here is my current code!
class Changelog(commands.Cog):
def __init__(self, client):
self.client = client
#commands.Cog.listener()
async def on_ready(self):
print('Changelog is loaded')
#commands.command()
async def clhook(self, ctx):
await ctx.send('Write text-channel: ')
text_channel = await self.client.wait_for("message", check=lambda message: message.author == ctx.author, timeout=300)
clhook = self.client.get_channel(text_channel)
def setup(client):
client.add_cog(Changelog(client))
Edit:
The channel ID shall be saved "forever", meaning that I do not have to re-write the channel name where the message should go!
You can use discord.utils.get() with this example:
text_channel = await self.client.wait_for("message", check=lambda message: message.author == ctx.author, timeout=300)
channel = discord.utils.get(ctx.guild.text_channels, name=text_channel)
await channel.send('Bla Bla')
So when you type (prefix)clhook then only the channel name, for example general, it will send Bla Bla to the channel named general .
There is another way to do this and I think it's simple than the first option, here it is:
#commands.command()
async def clhook(self, ctx, channel: discord.TextChannel):
await channel.send('Bla Bla')
So in this command, usage is changed. You can use that with this: (prefix)clhook #general(mention the channel). I suggest this solution and I think it's more useful.
You can use message.channel_mentions. This will return a list of all channels that were mentioned using the #channel-name notation. That way, you can just use channel.id to get the id of the channel they mentioned.
Don't forget, however, to check if the user did in fact tag a channel (which you can also put in your check). I put it in a separate function to make it a bit more readable for the sake of this reply, but you can fit that in your lambda if you really want to.
Also, make sure to check if it's a Text Channel and not a Voice Channel or Category Channel.
#commands.command()
async def clhook(self, ctx):
def check(self, message):
author_ok = message.author == ctx.author # Sent by the same author
mentioned_channel = len(message.channel_mentions) == 1 and isinstance(message.channel_mentions[0], discord.TextChannel)
return author_ok and mentioned_channel
await ctx.send("Write text-channel: ")
text_channel = await self.client.wait_for("message", check=check)
chlhook = text_channel.channel_mentions[0]
I put two conditions on the mentioned_channel line, because if the first one fails, the second one could cause an IndexError. Alternatively you can also use an if-statement to return sooner at that place to solve the same issue.

Resources