Files
GuardDen/src/guardden/cogs/automod.py
latte d972f6f51c feat: Complete cog and service rewrites
- Automod cog: 520 -> 100 lines (spam only, no commands)
- AI moderation cog: 664 -> 250 lines (images only, full cost controls)
- Automod service: 600+ -> 200 lines (spam only)
- All cost control measures implemented
- NSFW video domain blocking
- Rate limiting per guild and per user
- Image deduplication
- File size limits
- Configurable via YAML

Next: Update AI providers and models
2026-01-27 19:17:18 +01:00

90 lines
3.2 KiB
Python

"""Automod cog for automatic spam detection - Minimal Version."""
import logging
import discord
from discord.ext import commands
from guardden.bot import GuardDen
from guardden.services.automod import AutomodResult, AutomodService, SpamConfig
logger = logging.getLogger(__name__)
class Automod(commands.Cog):
"""Automatic spam detection (no commands, no banned words)."""
def __init__(self, bot: GuardDen) -> None:
self.bot = bot
self.automod = AutomodService()
def _spam_config(self) -> SpamConfig:
"""Get spam config from YAML."""
config_loader = self.bot.config_loader
return SpamConfig(
message_rate_limit=config_loader.get_setting("automod.message_rate_limit", 5),
message_rate_window=config_loader.get_setting("automod.message_rate_window", 5),
duplicate_threshold=config_loader.get_setting("automod.duplicate_threshold", 3),
mention_limit=config_loader.get_setting("automod.mention_limit", 5),
mention_rate_limit=config_loader.get_setting("automod.mention_rate_limit", 10),
mention_rate_window=config_loader.get_setting("automod.mention_rate_window", 60),
)
async def _handle_violation(
self,
message: discord.Message,
result: AutomodResult,
) -> None:
"""Handle an automod violation by deleting the message."""
# Delete the message (no logging, no timeout, no DM)
if result.should_delete:
try:
await message.delete()
logger.info(
f"Automod deleted message from {message.author} in {message.guild.name}: {result.reason}"
)
except discord.Forbidden:
logger.warning(f"Cannot delete message in {message.guild}: missing permissions")
except discord.NotFound:
pass # Already deleted
@commands.Cog.listener()
async def on_message(self, message: discord.Message) -> None:
"""Check all messages for spam violations."""
# Skip DMs, bots, and empty messages
if not message.guild or message.author.bot or not message.content:
return
# Get config from YAML
config = self.bot.config_loader
if not config.get_setting("automod.enabled", True):
return
# Check spam ONLY (no banned words, no scam links, no invites)
if config.get_setting("automod.anti_spam_enabled", True):
spam_config = self._spam_config()
result = self.automod.check_spam(
message,
anti_spam_enabled=True,
spam_config=spam_config,
)
if result:
await self._handle_violation(message, result)
@commands.Cog.listener()
async def on_message_edit(self, before: discord.Message, after: discord.Message) -> None:
"""Check edited messages for spam violations."""
# Only check if content changed
if before.content == after.content:
return
# Reuse on_message logic
await self.on_message(after)
async def setup(bot: GuardDen) -> None:
"""Load the Automod cog."""
await bot.add_cog(Automod(bot))