Discord sniping edited messages not working - discord.py

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.

Related

I want to my discord bot to forward the message to another channel after a user reacts to it 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).

is there another command should i use?

So, I can't use the "?roast" command and "?roast #(user)" at the same time...
#client.event
async def on_ready():
await client.change_presence(status=discord.Status.dnd, activity=discord.Game(' "?" Booe'))
print('Bot is ready to play!')
#client.command()
async def roast(ctx, member:discord.Member):
roast_messages = [
f'{ctx.message.author.mention}You are useless as the UEUE in Queue {member.mention}',
]
await ctx.send(random.choice(roast_messages))
There is always a way to solve that , discord gives us a way like this
#client.command()
async def roast(ctx, member:discord.Member=None):#None is if nothing is given then its None
if member == None:
member = ctx.author
roast_messages = [
f'{ctx.message.author.mention}You are useless as the UEUE in Queue {member.mention}',]
await ctx.send("imagine roasting yourself")#Your Choice Absolutely :)
await ctx.send(random.choice(roast_messages))
here if the member isnt specified , the function is called taking member as none , later gives the none value to the ctx.author itself (dont try to write ctx.author instead of none in the async def roast it gives error as ctx aint defined. also i forgot your roast messages wont make sense then so make sure to edit them too TY :)

Is there a way to record the specific user of a command for future use without a database?

So I'm working on a discord bot using discord.py and I'm trying to create a bot for the moderation team in a server, the bot will swap the 'Moderator' role with a 'Leave of absence' role for when they're not active, however the code I have come up with has a slight loopholing problem that I just can't figure out, the code for the commands is this
...
#client.command()
#commands.has_role('Moderator')
async def sl(ctx, member: discord.Member = None):
if not member:
member = ctx.author
loa = ctx.guild.get_role(848032714715561985)
mod = ctx.guild.get_role(848032880709074944)
await member.add_roles(loa)
await member.remove_roles(mod)
await ctx.send("I have filed your Leave, take care, we look forward to your return!")
#client.command()
async def sr(ctx, member: discord.Member = None):
if not member:
member = ctx.author
mod = ctx.guild.get_role(848032880709074944)
loa = ctx.guild.get_role(848032714715561985)
await member.add_roles(mod)
await member.remove_roles(loa)
await ctx.send("Welcome back!")
...
as you can see anyone could use the second command to just give themselves a moderator role, I can't set the second command to be moderator only use as the moderator will no longer have said role from using the first command, I'm racking my brain to think of a work around i.e. logging the command users id to a whitelist and having only those whitelisted id's be able to use the second command, I've done many googlesearches for this but have come back with no results, any suggestions would be appreciated, please forgive that this question is a bit lengthy and I'm still very new to coding in general so any help at all, even if you don't fully understand what I'm blabbering on about would be very appreciated, thank you.
Check for the loa role in the command (ex):
mod = None
for role in ctx.author.roles:
if role.id == 848032714715561985: mod = True
if mod:
#your code here
So from your question, I'm guessing that you would like to code basically a "storage" file and make sure the person on the leave of absence was previously a moderator.
What you could do is create a csv file, for example records.csv (in the same folder as your main .py file of course), and every time someone calls the sl command, the program will record the user that used it.
import csv
#client.command()
#commands.has_role('Moderator')
async def sl(ctx, member: discord.Member = None):
if not member:
member = ctx.author
loa = ctx.guild.get_role(848032714715561985)
mod = ctx.guild.get_role(848032880709074944)
await member.add_roles(loa)
await member.remove_roles(mod)
file = open("records.csv", "w")
file.writelines(str(ctx.author.id))
file.close()
await ctx.send("I have filed your Leave, take care, we look forward to your return!")
#client.command()
async def sr(ctx, member: discord.Member = None):
if not member:
member = ctx.author
mod = ctx.guild.get_role(848032880709074944)
loa = ctx.guild.get_role(848032714715561985)
found = False
with open('records.csv', 'r') as file:
reader = csv.reader(file)
for row in reader:
if row[0] == str(ctx.author.id):
found = True
break
if found = False:
await member.add_roles(mod)
await member.remove_roles(loa)
await ctx.send("Welcome back!")
else:
await ctx.send("We do not have history of you having a moderator role.")
Are you running the program through an online environment like Repl.it? If so, this may not be the best way to approach this problem since people would have access to your this records.csv file (which you may not care about but just in case). If you are running the program through your desktop file directories, then there should be no privacy concerns.

discord.py moving people to different voice channels

channel_a = bot.get_channel(780743421442260993)
#bot.command()
async def Movee(ctx):
i = 0
while i < len(participant):
if type(participant[i]) != str:
await participant[i].move_to(channel_a)
i += 1
I want to move people to another voice chat room,
but using this code, people are just disconnected from voice chat room.
I've already checked if the channel ID is correct...
If you know the solution, I would appreciate it if you could let me know.
channel = []
#bot.event
async def on_ready():
channel_a = bot.get_channel(780743421442260993)
channel.append(channel_a)
#bot.command()
async def setChA(ctx):
channel[0] = bot.get_channel(ctx.message.author.voice.channel.id)
await ctx.send("Done")
#bot.command()
async def Move(ctx):
i = 0
while i < len(participant):
if type(participant[i]) != str:
await participant[i].move_to(channel[0])
i += 1
It work very well change as above.
I think it's caused by the way the async function works.
It will probably work well without using list.
I post it for someone who will have the same problem as me.
Also I always welcome anyone who knows a better way :D

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