Discord.py logging messages - discord.py

I've got this code, which when I type !snapshot should log the last 100 messages in the channel, and make them into a text file:
snapshot_channel = (my snapshot channel ID)
#commands.has_permissions(administrator=True)
#bot.command()
async def snapshot(ctx):
channel = bot.get_channel(snapshot_channel)
await ctx.message.delete()
messages = message in ctx.history(limit=100)
numbers = "\n".join(
f"{message.author}: {message.clean_content}" for message in messages
)
f = BytesIO(bytes(numbers, encoding="utf-8"))
file = discord.File(fp=f, filename="snapshot.txt")
await channel.send("Snapshot requested has completed.")
await channel.send(file=file)
I've got BytesIO imported, and it works fine for a different command which purges messages and logs them, but this code which should just make a log and then send it in the channel doesn't work. Please can you send me what it should look like for it to work. Thanks!

TextChannel.history is an async generator, you're not using it properly
messages = await ctx.channel.history(limit=100).flatten()
numbers = "\n".join([f"{message.author}: {message.clean_content}" for message in messages])
Another option would be
numbers = ""
async for message in ctx.channel.history(limit=100):
numbers += f"{message.author}: {message.clean_content}"

Related

The bot should sent a message but it doesn't

So I got this script, and it doesn't work but does not write any errors in console. Just doesn't send message at all.
async def run(ctx,channel,arg1,arg2,arg3):
color = arg3
if color in color_table:
actual_color = getattr(discord.Colour, color)()
embed=discord.Embed(title=arg1, description=arg2, color=actual_color)
embed.set_footer(text="Powered by T.A.D.S.")
channel_id = channel.id
channel = discord.utils.get(ctx.guild.text_channels, id=int(channel_id))
await channel.send(embed=embed)
else:
await ctx.channel.send("This color doesn't exist in discord databeses. Type !colours to show all colors that are available.")
I want the bot to send a message to specified channel but it does nothing.

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 file logging, change number of messages

I've got this code that I use for discord channel logging. It basically gets the last 10,000 messages in a channel, and makes a .txt file with those messages in it, with the !log command. However, how would I make it so optionally users can type a number after !log, and it will log that number of previous messages? EG: "!log" on it's own logs the last 10,000 messages, but "!log 100" would log the last 100 messages. But I have no clue how to do that.
Here's my code:
#commands.has_any_role('Logger', 'logger')
#bot.command()
async def log(ctx):
try:
channel = ctx.message.channel
await ctx.message.delete()
await channel.send(ctx.message.author.mention+" Creating a log now. This may take up to 5 minutes, please be patient.")
messages = await ctx.channel.history(limit=10000).flatten()
numbers = "\n".join([f"{message.author}: {message.clean_content}" for message in messages])
f = BytesIO(bytes(numbers, encoding="utf-8"))
file = discord.File(fp=f, filename='Log.txt')
await channel.send(ctx.message.author.mention+" Message logging has completed.")
await channel.send(file=file)
except:
embed = discord.Embed(title="Error creating normal log:", description="The bot doesn't have necessary permissions to make this log type. Please confirm the bot has these permissions for this channel: View Channel, Read and Send Messages, Attatch Files (used for sending the log file), Manage Messages (used for deleting the command the user sends when making a log).", color=0xf44336)
await channel.send(embed=embed)
Any help about how to make it so they can optionally provide a number, which would then log that amount, would help a lot. Thanks!
Take the number of messages to be logged as a parameter
...
#bot.command()
async def log(ctx, limit: int=1000):
...
then use the value of the parameter
...
messages = await ctx.channel.history(limit=limit).flatten()
...
docs: https://discordpy.readthedocs.io/en/latest/ext/commands/commands.html#parameters

Asyncio: Fastapi with aio-pika, consumer ignores Await

I am trying to hook my websocket endpoint with rabbitmq (aio-pika). Goal is to have listener in that endpoint and on any new message from queue pass the message to browser client over websockets.
I tested the consumer with asyncio in a script with asyncio loop. Works as I followed and used aio-pika documentation. (source: https://aio-pika.readthedocs.io/en/latest/rabbitmq-tutorial/2-work-queues.html, worker.py)
However, when I use it in fastapi in websockets endpoint, I cant make it work. Somehow the listener:
await queue.consume(on_message)
is completely ignored.
This is my attempt (I put it all in one function, so its more readable):
#app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
print("Entering websockets")
await manager.connect(websocket)
print("got connection")
# params
queue_name = "task_events"
routing_key = "user_id.task"
con = "amqp://rabbitmq:rabbitmq#rabbit:5672/"
connection = await connect(con)
channel = await connection.channel()
await channel.set_qos(prefetch_count=1)
exchange = await channel.declare_exchange(
"topic_logs",
ExchangeType.TOPIC,
)
# Declaring queue
queue = await channel.declare_queue(queue_name)
# Binding the queue to the exchange
await queue.bind(exchange, routing_key)
async def on_message(message: IncomingMessage):
async with message.process():
# here will be the message passed over websockets to browser client
print("sent", message.body)
try:
######### Not working as expected ###########
# await does not await and websockets finishes, as there is no loop
await queue.consume(on_message)
#############################################
################ This Alternative code atleast receives some messages #############
# If I use this part, I atleast get some messages, when I trigger a backend task that publishes new messages to the queue.
# It seems like the messages are somehow stuck and new task releases all stucked messages, but does not release new one.
while True:
await queue.consume(on_message)
await asyncio.sleep(1)
################## one part #############
except WebSocketDisconnect:
manager.disconnect(websocket)
I am quite new to async in python. I am not sure where is the problem and I cannot somehow implement async consuming loop while getting inspired with worker.py from aio-pika.
You could use an async iterator, which is the second canonical way to consume messages from a queue.
In your case, this means:
async with queue.iterator() as iter:
async for message in iter:
async with message.process():
# do something with message
It will block as long as no message is received and will be suspended again after processing a message.
The solution was simply.
aio-pika queue.consume even though we use await is nonblocking, so
this way we consume
consumer_tag = await queue.consume(on_message, no_ack=True)
and at the end of connection we cancel
await queue.cancel(consumer_tag)
The core of the solution for me, was to make something asyncio blocking, so I used
this part of the code after consume
while True:
data = await websocket.receive_text()
x = await manager.send_message(data, websocket)
I dont use this code, but its useful as this part of the code waits for frontend websocket response. If this part of the code is missing, then what happens is that client connects just to get disconnected (the websocket endpoit is succefully executed), as there is nothing blocking

bot.get_all_channels() gets ignored discord.py

When obtaining all channels to send a message to all, the bot ignores the command. Here's my code.
async def lockdown(ctx):
allchannels = bot.get_all_channels()
overwrite = channel.overwrites_for(ctx.guild.default_role)
locked = overwrite.send_messages = False
await locked.send(allchannels, 'This server has been locked down.')
Try printing allchannel, you'll see where you did an error.
You can't use bot.get_all_channels() in this way that's all

Resources