Search code examples
pythondiscordbotspycord

py-cord: How do I delete the last n messages of a user?


I am writing an anti-spam bot in py-cord and I would like to delete a users last n messages automatically once they reach the pressure limit (= too much spam). My code for just deleting the messages so far is:

95 counter = 0
96 while counter < 10:
97    for channel in message.guild.channels:
98        for msg in channel.messages:
99            if msg.author.id == message.author.id and counter < 10:
100               await msg.delete()
101               counter += 1

and the error that I get is

Ignoring exception in on_message
Traceback (most recent call last):
  File "C:\Users\Username\AppData\Local\Programs\Python\Python310\lib\site-packages\discord\client.py", line 343, in _run_event
    await coro(*args, **kwargs)
  File "c:\Users\Username\OneDrive\Desktop\Dateien\Python\MessageCheck\messagecheck.py", line 98, in on_message
    for msg in channel.messages:
AttributeError: 'CategoryChannel' object has no attribute 'messages'

I tried searching for similar questions on StackOverflow, but the closest I got was 50301090, which doesn't quite answer my question as I don't want to use a command for this and it seems like it could put some strain onto the cache if it's run for some time.


Solution

  • message.guild.channels iterates over all channels, categories and voice channels included. Since you can't send a message in either of the mentioned channel types, they don't have the channel.messages attribute, resulting in the error you are getting.

    You should iterate over the guild's text channels instead: message.guild.text_channels. That way, the attribute will always be set and you won't get this error anymore


    That said, your code does in no way delete the user's last 10 messages. It will search the text channels from top to bottom. If a user wrote 10 messages in the first text channel of the server 2 years ago and spammed 100 in the second text channel right now, your bot will delete the 2 year old messages and leave the spam untouched.

    Since you're already using the on_message event, why not keep track of any user's last 10 messages? You could achieve that quite easily by storing the channel and message IDs in a dictionary keyed to the guild and user IDs. That way, if a user exceeds the pressure limit, you can simply iterate over those 10 messages and delete them. Your deletion code would then look something like this (USER_MESSAGES being a placeholder for the offending user's last 10 channel/message ID pairs and assuming your bot client is called bot):

    for chl_id, msg_id in USER_MESSAGES:
        msg = await bot.get_channel(chl_id).fetch_message(msg_id)
        await msg.delete()