Experimental Discord bot written in Python
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

crosspostcog.py 2.0KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. from discord import Guild, Message
  2. from cogs.basecog import BaseCog
  3. class CrossPostCog(BaseCog):
  4. class SpamContext:
  5. def __init__(self, member):
  6. self.member = member
  7. self.is_warned = False
  8. STATE_KEY_RECENT_MESSAGES = "crosspost_recent_messages"
  9. STATE_KEY_SPAM_CONTEXT = "crosspost_spam_context"
  10. def __init__(self, bot):
  11. super().__init__(bot)
  12. self.max_recent_messages = 20
  13. self.messages_per_user = 3
  14. self.min_message_length = 10
  15. def __record_message(self, message: Message) -> None:
  16. recent_messages = Storage.get_state_value(message.guild, self.STATE_KEY_RECENT_MESSAGES) or []
  17. recent_messages.append(message)
  18. while len(recent_messages) > self.max_recent_messages:
  19. recent_messages.pop(0)
  20. Storage.set_state_value(message.guild, self.STATE_KEY_RECENT_MESSAGES, recent_messages)
  21. def __check_for_spam(self, guild: Guild) -> None:
  22. recent_messages = Storage.get_state_value(guild, self.STATE_KEY_RECENT_MESSAGES)
  23. if recent_messages is None:
  24. return
  25. user_id_to_count = {}
  26. spamming_members = set()
  27. for message in recent_messages:
  28. content = message.content
  29. if len(content) < self.min_message_length:
  30. continue
  31. key = str(message.author.id) + '|' + hash(content)
  32. count = (user_id_to_count.get(key) or 0) + 1
  33. user_id_to_count[key] = count
  34. if count >= self.messages_per_user:
  35. spamming_members.add(message.author)
  36. for member in spamming_members:
  37. context = self.__spam_context_for_user(member, True)
  38. def __spam_context_for_user(self,
  39. member: Member,
  40. create_if_missing: bool = False) -> SpamContext:
  41. spam_lookup = Storage.get_state_value(member.guild, self.STATE_KEY_SPAM_CONTEXT) or {}
  42. context = spam_lookup.get(member.id)
  43. if context:
  44. return context
  45. if not create_if_missing:
  46. return None
  47. context = SpamContext(member)
  48. spam_lookup[member.id] = context
  49. Storage.set_state_value(member.guild, self.STATE_KEY_SPAM_CONTEXT, spam_lookup)
  50. return context
  51. @commands.Cog.listener()
  52. def on_message(self, message: Message):
  53. self.__record_message(message)
  54. self.__check_for_spam(message.guild)