Discord.py Snipe command

Question:

Im trying to make a command where the bot "snipes" the last deleted message. this is my current code:


snipe_message_content = None
snipe_message_author = None

@client.event
async def on_message_delete(message):
    snipe_message_author.remove(None)
    snipe_message_content.remove(None)
    snipe_message_content.append(message.content) 
    snipe_message_author.append(message.author.id) 
    await asyncio.sleep(str(60))
    snipe_message_author.remove(message.author.id)
    snipe_message_content.remove(message.content)
    

@client.command()
async def snipe(message):
    if snipe_message_content==None:
        await message.channel.send("Theres nothing to snipe.")
    else:
        embed = discord.Embed(description=f"{snipe_message_content}")
        embed.set_footer(text=f"Asked by {message.author.name}#{message.author.discriminator}", icon_url=message.author.avatar_url)
        embed.set_author(name= f"<@{snipe_message_author}>")
        await message.channel.send(embed=embed)
        return

the await message.channel.send("Theres nothing to snipe.") part works perfectly fine, but the rest wont work. Can anyone help?

Asked By: Willwell

||

Answers:

Well your on_message_delete() function is just not working.

First of all, your variables snipe_message_author and snipe_message_content are of the type None, but the methods remove and append are part of the type list, so you’d have to declare lists

snipe_message_content = []
snipe_message_author = []

in order for them to work.

Still, you wouldn’t have to do this anyway. Just give your current variables a new value:

snipe_message_content = None
snipe_message_author = None

@client.event
async def on_message_delete(message):

    global snipe_message_content
    global snipe_message_author
    # Variables outside a function have to be declared as global in order to be changed

    snipe_message_content = message.content
    snipe_message_author = message.author.id
    await asyncio.sleep(60)
    snipe_message_author = None
    snipe_message_content = None

Also, do not convert 60 to a string. time.sleep and asyncio.sleep both need an integer in order to work (side note: if you wanted 60 to be a string, just write "60" in quotation marks).

At last, be aware of the following case: If a message x gets deleted, but 50 seconds after that, a new message y gets deleted, snipe_message_author and snipe_message_content would be assigned to the new message y. But 10 seconds later, the function executed by message x would set the value of snipe_message_author and snipe_message_content to None.

Therefore, after await asyncio.sleep(60), check whether your message is still the same as before:

snipe_message_content = None
snipe_message_author = None
snipe_message_id = None

@client.event
async def on_message_delete(message):

    global snipe_message_content
    global snipe_message_author
    global snipe_message_id

    snipe_message_content = message.content
    snipe_message_author = message.author.id
    snipe_message_id = message.id
    await asyncio.sleep(60)

    if message.id == snipe_message_id:
        snipe_message_author = None
        snipe_message_content = None
        snipe_message_id = None
Answered By: Thörni

Your command works now probably, but there’s a problem. If I delete a message in my server, and you run the command in your server, you’ll probably see the message.

What you should do is make the snipe_message_author and snipe_message_content variables dictionaries.

This is how the event should be:

snipe_message_author = {}
snipe_message_content = {}

@client.event
async def on_message_delete(message):
     snipe_message_author[message.channel.id] = message.author
     snipe_message_content[message.channel.id] = message.content
     await sleep(60)
     del snipe_message_author[message.channel.id]
     del snipe_message_content[message.channel.id]

@client.command(name = 'snipe')
async def snipe(ctx):
    channel = ctx.channel
    try: #This piece of code is run if the bot finds anything in the dictionary
        em = discord.Embed(name = f"Last deleted message in #{channel.name}", description = snipe_message_content[channel.id])
        em.set_footer(text = f"This message was sent by {snipe_message_author[channel.id]}")
        await ctx.send(embed = em)
    except KeyError: #This piece of code is run if the bot doesn't find anything in the dictionary
        await ctx.send(f"There are no recently deleted messages in #{channel.name}")


#If the bot sends the embed, but it's empty, it simply means that the deleted message was either a media file or another embed.


To summarize it, here’s what this fixes for you:

  • Doesn’t show deleted messages from other servers
  • Doesn’t show deleted messages from other channels
  • Deleted message in one server won’t replace the deleted message in another server

Hope this helped 🙂

Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.