Refactored listener logic and added SpoilerListener
This commit is contained in:
parent
003d8e32b6
commit
913827b5f3
2
bot.py
2
bot.py
@ -120,6 +120,7 @@ class SBABot(commands.Bot):
|
|||||||
from commands.help import setup_help_commands
|
from commands.help import setup_help_commands
|
||||||
from commands.profile import setup_profile_commands
|
from commands.profile import setup_profile_commands
|
||||||
from commands.soak import setup_soak
|
from commands.soak import setup_soak
|
||||||
|
from commands.spoiler import setup_spoiler
|
||||||
from commands.injuries import setup_injuries
|
from commands.injuries import setup_injuries
|
||||||
from commands.gameplay import setup_gameplay
|
from commands.gameplay import setup_gameplay
|
||||||
|
|
||||||
@ -137,6 +138,7 @@ class SBABot(commands.Bot):
|
|||||||
("help", setup_help_commands),
|
("help", setup_help_commands),
|
||||||
("profile", setup_profile_commands),
|
("profile", setup_profile_commands),
|
||||||
("soak", setup_soak),
|
("soak", setup_soak),
|
||||||
|
("spoiler", setup_spoiler),
|
||||||
("injuries", setup_injuries),
|
("injuries", setup_injuries),
|
||||||
("gameplay", setup_gameplay),
|
("gameplay", setup_gameplay),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -3,20 +3,16 @@ Soak Message Listener
|
|||||||
|
|
||||||
Monitors all messages for soak mentions and responds with disappointment GIFs.
|
Monitors all messages for soak mentions and responds with disappointment GIFs.
|
||||||
"""
|
"""
|
||||||
import re
|
|
||||||
import os
|
|
||||||
import logging
|
import logging
|
||||||
import discord
|
import discord
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
|
|
||||||
|
from utils.listeners import should_process_message, COMMAND_FILTERS
|
||||||
from .tracker import SoakTracker
|
from .tracker import SoakTracker
|
||||||
from .giphy_service import get_tier_for_seconds, get_disappointment_gif
|
from .giphy_service import get_tier_for_seconds, get_disappointment_gif
|
||||||
|
|
||||||
logger = logging.getLogger(f'{__name__}.SoakListener')
|
logger = logging.getLogger(f'{__name__}.SoakListener')
|
||||||
|
|
||||||
# Regex pattern to detect soak variations (whole word only)
|
|
||||||
SOAK_PATTERN = re.compile(r'\b(soak|soaking|soaked|soaker)\b', re.IGNORECASE)
|
|
||||||
|
|
||||||
|
|
||||||
class SoakListener(commands.Cog):
|
class SoakListener(commands.Cog):
|
||||||
"""Listens for soak mentions and responds with appropriate disappointment."""
|
"""Listens for soak mentions and responds with appropriate disappointment."""
|
||||||
@ -34,21 +30,13 @@ class SoakListener(commands.Cog):
|
|||||||
Args:
|
Args:
|
||||||
message: Discord message object
|
message: Discord message object
|
||||||
"""
|
"""
|
||||||
# Ignore bot messages to prevent loops
|
# Apply common message filters
|
||||||
if message.author.bot:
|
if not should_process_message(message, *COMMAND_FILTERS):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Ignore messages that start with command prefix (legacy pattern)
|
# Check if message contains ' soak' (listener-specific filter)
|
||||||
if message.content.startswith('!'):
|
msg_text = message.content.lower()
|
||||||
return
|
if ' soak' not in msg_text:
|
||||||
|
|
||||||
# Check guild ID matches configured guild (optional security)
|
|
||||||
guild_id = os.environ.get('GUILD_ID')
|
|
||||||
if guild_id and message.guild and message.guild.id != int(guild_id):
|
|
||||||
return
|
|
||||||
|
|
||||||
# Check if message contains soak
|
|
||||||
if not SOAK_PATTERN.search(message.content):
|
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.info(f"Soak detected in message from {message.author.name} (ID: {message.author.id})")
|
logger.info(f"Soak detected in message from {message.author.name} (ID: {message.author.id})")
|
||||||
|
|||||||
207
commands/spoiler/CLAUDE.md
Normal file
207
commands/spoiler/CLAUDE.md
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
# Spoiler Package Documentation
|
||||||
|
**Discord Bot v2.0 - Spoiler Detection System**
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The spoiler package monitors all messages for Discord spoiler tags (`||text||`) and pings the "Deez Watch" role when detected. This provides a fun, automated alert when users post spoilers in the server.
|
||||||
|
|
||||||
|
## Package Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
commands/spoiler/
|
||||||
|
├── CLAUDE.md # This documentation
|
||||||
|
├── __init__.py # Package setup with resilient loading
|
||||||
|
└── listener.py # Spoiler detection listener
|
||||||
|
```
|
||||||
|
|
||||||
|
## Components
|
||||||
|
|
||||||
|
### **SpoilerListener** (`listener.py`)
|
||||||
|
|
||||||
|
**Purpose:** Monitors all messages for Discord spoiler syntax and posts role ping alerts.
|
||||||
|
|
||||||
|
**Implementation:**
|
||||||
|
```python
|
||||||
|
class SpoilerListener(commands.Cog):
|
||||||
|
"""Listens for spoiler tags and responds with Deez Watch role ping."""
|
||||||
|
|
||||||
|
@commands.Cog.listener(name='on_message')
|
||||||
|
async def on_message_listener(self, message: discord.Message):
|
||||||
|
# Uses shared message filters from utils.listeners
|
||||||
|
if not should_process_message(message, *COMMAND_FILTERS):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Detect Discord spoiler syntax (||)
|
||||||
|
spoiler_count = message.content.count("||")
|
||||||
|
if spoiler_count < 2:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Find and ping the "Deez Watch" role
|
||||||
|
deez_watch_role = discord.utils.get(message.guild.roles, name="Deez Watch")
|
||||||
|
if deez_watch_role:
|
||||||
|
await message.channel.send(f"{deez_watch_role.mention}!")
|
||||||
|
else:
|
||||||
|
# Fallback if role doesn't exist
|
||||||
|
await message.channel.send("Deez Watch!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Discord Spoiler Syntax
|
||||||
|
|
||||||
|
Discord uses `||` markers to create spoiler tags:
|
||||||
|
- `||hidden text||` creates a single spoiler
|
||||||
|
- Multiple spoilers can exist in one message: `||spoiler 1|| some text ||spoiler 2||`
|
||||||
|
- The listener detects any message with 2+ instances of `||` (i.e., at least one complete spoiler tag)
|
||||||
|
|
||||||
|
## Message Filtering
|
||||||
|
|
||||||
|
Uses the shared `COMMAND_FILTERS` from `utils.listeners`, which includes:
|
||||||
|
- **Ignore bot messages** - Prevents bot loops
|
||||||
|
- **Ignore empty messages** - Messages with no content
|
||||||
|
- **Ignore command prefix** - Messages starting with '!' (legacy commands)
|
||||||
|
- **Ignore DMs** - Only process guild messages
|
||||||
|
- **Guild validation** - Only process messages from configured guild
|
||||||
|
|
||||||
|
See `utils/listeners.py` for filter implementation details.
|
||||||
|
|
||||||
|
## Logging
|
||||||
|
|
||||||
|
The listener logs:
|
||||||
|
- **Startup:** When the cog is initialized
|
||||||
|
- **Detection:** When a spoiler is detected (with user info and spoiler count)
|
||||||
|
- **Success:** When the alert is posted with role mention
|
||||||
|
- **Warning:** When the Deez Watch role is not found (falls back to text)
|
||||||
|
- **Errors:** Permission issues or send failures
|
||||||
|
|
||||||
|
**Example log output (with role):**
|
||||||
|
```
|
||||||
|
INFO - SpoilerListener cog initialized
|
||||||
|
INFO - Spoiler detected in message from Username (ID: 123456789) with 2 spoiler tag(s)
|
||||||
|
DEBUG - Spoiler alert posted with role mention
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example log output (without role):**
|
||||||
|
```
|
||||||
|
INFO - Spoiler detected in message from Username (ID: 123456789) with 1 spoiler tag(s)
|
||||||
|
WARNING - Deez Watch role not found, posted without mention
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
**Permission Errors:**
|
||||||
|
- Catches `discord.Forbidden` when bot lacks send permissions
|
||||||
|
- Logs error with channel ID for troubleshooting
|
||||||
|
|
||||||
|
**General Errors:**
|
||||||
|
- Catches all exceptions during message sending
|
||||||
|
- Logs with full stack trace for debugging
|
||||||
|
- Does not crash the bot or stop listening
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
**Discord Role:**
|
||||||
|
- A role named **"Deez Watch"** must exist in the guild
|
||||||
|
- Bot automatically looks up the role by name at runtime
|
||||||
|
- If role doesn't exist, bot falls back to posting "Deez Watch!" without mention
|
||||||
|
|
||||||
|
**Permissions:**
|
||||||
|
- Bot needs **Send Messages** permission in channels
|
||||||
|
- Bot needs **Mention Everyone** permission to ping roles (if role is not mentionable)
|
||||||
|
- Role can be set as mentionable to avoid needing special permissions
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
**Single Spoiler (with role):**
|
||||||
|
```
|
||||||
|
User: Hey did you know that ||Bruce Willis is dead the whole time||?
|
||||||
|
Bot: @Deez Watch!
|
||||||
|
```
|
||||||
|
|
||||||
|
**Multiple Spoilers:**
|
||||||
|
```
|
||||||
|
User: ||Darth Vader|| is ||Luke's father||
|
||||||
|
Bot: @Deez Watch!
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fallback (no role):**
|
||||||
|
```
|
||||||
|
User: Hey did you know that ||Bruce Willis is dead the whole time||?
|
||||||
|
Bot: Deez Watch!
|
||||||
|
```
|
||||||
|
|
||||||
|
**Edge Cases:**
|
||||||
|
- Single `||` marker - **Not detected** (incomplete spoiler)
|
||||||
|
- Text with `||` in code blocks - **Detected** (Discord doesn't parse spoilers in code blocks)
|
||||||
|
- Empty spoilers `||||` - **Detected** (valid Discord syntax)
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
**Setup:**
|
||||||
|
1. Create a role named "Deez Watch" in your Discord server (recommended)
|
||||||
|
2. Set the role as mentionable OR ensure bot has "Mention Everyone" permission
|
||||||
|
|
||||||
|
**Manual Testing:**
|
||||||
|
1. Start the bot in development mode
|
||||||
|
2. Post a message with `||test||` in the configured guild
|
||||||
|
3. Verify bot responds with @Deez Watch! (role mention)
|
||||||
|
|
||||||
|
**Test Cases:**
|
||||||
|
- ✅ Single spoiler tag with role mention
|
||||||
|
- ✅ Multiple spoiler tags
|
||||||
|
- ✅ Fallback to text if role doesn't exist
|
||||||
|
- ✅ Bot ignores own messages
|
||||||
|
- ✅ Bot ignores DMs
|
||||||
|
- ✅ Bot ignores messages from other guilds
|
||||||
|
- ✅ Bot ignores command messages (starting with '!')
|
||||||
|
|
||||||
|
## Performance Considerations
|
||||||
|
|
||||||
|
**Impact:**
|
||||||
|
- Listener processes every non-filtered message in the guild
|
||||||
|
- String counting (`message.content.count("||")`) is O(n) but fast for typical message lengths
|
||||||
|
- Only sends one message per detection (no loops)
|
||||||
|
|
||||||
|
**Optimization:**
|
||||||
|
- Early returns via message filters reduce processing
|
||||||
|
- Simple string operation (no regex needed)
|
||||||
|
- Async operations prevent blocking
|
||||||
|
|
||||||
|
## Future Enhancements
|
||||||
|
|
||||||
|
Potential improvements for the spoiler system:
|
||||||
|
|
||||||
|
1. **Configurable Response:**
|
||||||
|
- Custom responses per guild
|
||||||
|
- Random selection from multiple responses
|
||||||
|
- Embed responses with more context
|
||||||
|
|
||||||
|
2. **Cooldown System:**
|
||||||
|
- Prevent spam by rate-limiting responses
|
||||||
|
- Per-channel or per-user cooldowns
|
||||||
|
- Configurable cooldown duration
|
||||||
|
|
||||||
|
3. **Statistics Tracking:**
|
||||||
|
- Track spoiler counts per user
|
||||||
|
- Leaderboard of "most spoiler-prone" users
|
||||||
|
- Channel statistics
|
||||||
|
|
||||||
|
4. **Advanced Detection:**
|
||||||
|
- Detect spoiler context (movie, game, book)
|
||||||
|
- Different responses based on content
|
||||||
|
- Integration with spoiler databases
|
||||||
|
|
||||||
|
5. **Permissions:**
|
||||||
|
- Allow certain roles to bypass detection
|
||||||
|
- Channel-specific enable/disable
|
||||||
|
- Opt-in/opt-out system
|
||||||
|
|
||||||
|
## Related Files
|
||||||
|
|
||||||
|
- **`utils/listeners.py`** - Shared message filtering utilities
|
||||||
|
- **`commands/soak/listener.py`** - Similar listener pattern (template used)
|
||||||
|
- **`bot.py`** - Package registration and loading
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Last Updated:** October 2025
|
||||||
|
**Maintenance:** Keep logging and error handling consistent with other listeners
|
||||||
|
**Next Review:** When additional listener features are requested
|
||||||
54
commands/spoiler/__init__.py
Normal file
54
commands/spoiler/__init__.py
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
"""
|
||||||
|
Spoiler Commands Package
|
||||||
|
|
||||||
|
This package contains the spoiler listener that watches for Discord spoiler tags
|
||||||
|
and posts "Deez Watch!" alerts.
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
from discord.ext import commands
|
||||||
|
|
||||||
|
from .listener import SpoilerListener
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
async def setup_spoiler(bot: commands.Bot):
|
||||||
|
"""
|
||||||
|
Setup spoiler listener module.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: (successful_count, failed_count, failed_modules)
|
||||||
|
"""
|
||||||
|
# Define spoiler cogs to load
|
||||||
|
spoiler_cogs = [
|
||||||
|
("SpoilerListener", SpoilerListener),
|
||||||
|
]
|
||||||
|
|
||||||
|
successful = 0
|
||||||
|
failed = 0
|
||||||
|
failed_modules = []
|
||||||
|
|
||||||
|
for cog_name, cog_class in spoiler_cogs:
|
||||||
|
try:
|
||||||
|
await bot.add_cog(cog_class(bot))
|
||||||
|
logger.info(f"✅ Loaded {cog_name}")
|
||||||
|
successful += 1
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ Failed to load {cog_name}: {e}", exc_info=True)
|
||||||
|
failed += 1
|
||||||
|
failed_modules.append(cog_name)
|
||||||
|
|
||||||
|
# Log summary
|
||||||
|
if failed == 0:
|
||||||
|
logger.info(f"🎉 All {successful} spoiler module(s) loaded successfully")
|
||||||
|
else:
|
||||||
|
logger.warning(
|
||||||
|
f"⚠️ Spoiler modules loaded with issues: "
|
||||||
|
f"{successful} successful, {failed} failed"
|
||||||
|
)
|
||||||
|
|
||||||
|
return successful, failed, failed_modules
|
||||||
|
|
||||||
|
|
||||||
|
# Export the setup function for easy importing
|
||||||
|
__all__ = ['setup_spoiler', 'SpoilerListener']
|
||||||
94
commands/spoiler/listener.py
Normal file
94
commands/spoiler/listener.py
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
"""
|
||||||
|
Spoiler Message Listener
|
||||||
|
|
||||||
|
Monitors all messages for Discord spoiler tags and responds with "Deez Watch!".
|
||||||
|
Discord spoilers use || markers, so we detect messages with two or more instances.
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
import random
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
|
||||||
|
from utils.listeners import should_process_message, COMMAND_FILTERS
|
||||||
|
|
||||||
|
logger = logging.getLogger(f'{__name__}.SpoilerListener')
|
||||||
|
|
||||||
|
|
||||||
|
class SpoilerListener(commands.Cog):
|
||||||
|
"""Listens for spoiler tags and responds with Deez Watch!"""
|
||||||
|
|
||||||
|
def __init__(self, bot: commands.Bot):
|
||||||
|
self.bot = bot
|
||||||
|
logger.info("SpoilerListener cog initialized")
|
||||||
|
|
||||||
|
@commands.Cog.listener(name='on_message')
|
||||||
|
async def on_message_listener(self, message: discord.Message):
|
||||||
|
"""
|
||||||
|
Listen for messages containing Discord spoiler tags (||).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
message: Discord message object
|
||||||
|
"""
|
||||||
|
# Apply common message filters
|
||||||
|
if not should_process_message(message, *COMMAND_FILTERS):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check if message contains two or more instances of "||" (spoiler syntax)
|
||||||
|
spoiler_count = message.content.count("||")
|
||||||
|
if spoiler_count < 2:
|
||||||
|
return
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"Spoiler detected in message from {message.author.name} "
|
||||||
|
f"(ID: {message.author.id}) with {spoiler_count // 2} spoiler tag(s)"
|
||||||
|
)
|
||||||
|
|
||||||
|
split_text = message.content.split('||')
|
||||||
|
spoiler_text = split_text[1]
|
||||||
|
if len(split_text) > 3 and 'z' not in spoiler_text:
|
||||||
|
chance = 'Low'
|
||||||
|
elif 8 <= len(spoiler_text) <= 10:
|
||||||
|
chance = 'High'
|
||||||
|
elif 'z' in spoiler_text:
|
||||||
|
chance = 'Medium'
|
||||||
|
else:
|
||||||
|
d1000 = random.randint(1, 1000)
|
||||||
|
if d1000 <= 300:
|
||||||
|
chance = 'Low'
|
||||||
|
elif d1000 <= 600:
|
||||||
|
chance = 'Medium'
|
||||||
|
elif d1000 <= 900:
|
||||||
|
chance = 'High'
|
||||||
|
elif d1000 <= 950:
|
||||||
|
chance = 'Miniscule'
|
||||||
|
elif d1000 <= 980:
|
||||||
|
chance = 'Throbbing'
|
||||||
|
else:
|
||||||
|
chance = 'Deez Nuts'
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Find the "Deez Watch" role in the guild
|
||||||
|
deez_watch_role = None
|
||||||
|
if message.guild:
|
||||||
|
deez_watch_role = discord.utils.get(message.guild.roles, name="Deez Watch")
|
||||||
|
|
||||||
|
# Post response to channel with role ping if available
|
||||||
|
if deez_watch_role:
|
||||||
|
await message.channel.send(f"{deez_watch_role.mention} there is a **{chance}** chance this is a deez nuts joke!")
|
||||||
|
logger.debug("Spoiler alert posted with role mention")
|
||||||
|
else:
|
||||||
|
# Fallback if role doesn't exist
|
||||||
|
await message.channel.send("Deez Watch!")
|
||||||
|
logger.warning("Deez Watch role not found, posted without mention")
|
||||||
|
|
||||||
|
except discord.Forbidden:
|
||||||
|
logger.error(
|
||||||
|
f"Missing permissions to send message in channel {message.channel.id}"
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error sending spoiler response: {e}", exc_info=True)
|
||||||
|
|
||||||
|
|
||||||
|
async def setup(bot: commands.Bot):
|
||||||
|
"""Load the spoiler listener cog."""
|
||||||
|
await bot.add_cog(SpoilerListener(bot))
|
||||||
141
utils/listeners.py
Normal file
141
utils/listeners.py
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
"""
|
||||||
|
Message Listener Utilities
|
||||||
|
|
||||||
|
Provides reusable components for on_message listeners including common message
|
||||||
|
filtering patterns.
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
from typing import Callable
|
||||||
|
import discord
|
||||||
|
from config import get_config
|
||||||
|
|
||||||
|
logger = logging.getLogger(f'{__name__}.message_filters')
|
||||||
|
|
||||||
|
|
||||||
|
def should_ignore_bot_messages(message: discord.Message) -> bool:
|
||||||
|
"""
|
||||||
|
Check if message should be ignored because it's from a bot.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
message: Discord message object
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if message should be ignored (author is a bot)
|
||||||
|
"""
|
||||||
|
return message.author.bot
|
||||||
|
|
||||||
|
|
||||||
|
def should_ignore_empty_messages(message: discord.Message) -> bool:
|
||||||
|
"""
|
||||||
|
Check if message should be ignored because it has no content.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
message: Discord message object
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if message should be ignored (no content)
|
||||||
|
"""
|
||||||
|
return not message.content
|
||||||
|
|
||||||
|
|
||||||
|
def should_ignore_command_prefix(message: discord.Message, prefix: str = '!') -> bool:
|
||||||
|
"""
|
||||||
|
Check if message should be ignored because it starts with a command prefix.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
message: Discord message object
|
||||||
|
prefix: Command prefix to check for (default: '!')
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if message should be ignored (starts with prefix)
|
||||||
|
"""
|
||||||
|
return message.content.startswith(prefix)
|
||||||
|
|
||||||
|
|
||||||
|
def should_ignore_dms(message: discord.Message) -> bool:
|
||||||
|
"""
|
||||||
|
Check if message should be ignored because it's a DM (no guild).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
message: Discord message object
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if message should be ignored (no guild)
|
||||||
|
"""
|
||||||
|
return not message.guild
|
||||||
|
|
||||||
|
|
||||||
|
def should_ignore_wrong_guild(message: discord.Message) -> bool:
|
||||||
|
"""
|
||||||
|
Check if message should be ignored because it's from the wrong guild.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
message: Discord message object
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if message should be ignored (wrong guild or no guild)
|
||||||
|
"""
|
||||||
|
if not message.guild:
|
||||||
|
return True
|
||||||
|
|
||||||
|
guild_id = get_config().guild_id
|
||||||
|
return message.guild.id != guild_id
|
||||||
|
|
||||||
|
|
||||||
|
def should_process_message(
|
||||||
|
message: discord.Message,
|
||||||
|
*filters: Callable[[discord.Message], bool]
|
||||||
|
) -> bool:
|
||||||
|
"""
|
||||||
|
Check if a message should be processed based on provided filters.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
message: Discord message object
|
||||||
|
*filters: Variable number of filter functions that return True if message should be ignored
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if message should be processed (all filters returned False),
|
||||||
|
False if message should be ignored (any filter returned True)
|
||||||
|
|
||||||
|
Example:
|
||||||
|
if should_process_message(
|
||||||
|
message,
|
||||||
|
should_ignore_bot_messages,
|
||||||
|
should_ignore_empty_messages,
|
||||||
|
should_ignore_dms,
|
||||||
|
should_ignore_wrong_guild
|
||||||
|
):
|
||||||
|
# Process the message
|
||||||
|
pass
|
||||||
|
"""
|
||||||
|
for filter_func in filters:
|
||||||
|
if filter_func(message):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
# Pre-defined filter sets for common use cases
|
||||||
|
|
||||||
|
BASIC_FILTERS = (
|
||||||
|
should_ignore_bot_messages,
|
||||||
|
should_ignore_empty_messages,
|
||||||
|
)
|
||||||
|
"""Basic filters: Ignore bots and empty messages."""
|
||||||
|
|
||||||
|
GUILD_FILTERS = (
|
||||||
|
should_ignore_bot_messages,
|
||||||
|
should_ignore_empty_messages,
|
||||||
|
should_ignore_dms,
|
||||||
|
should_ignore_wrong_guild,
|
||||||
|
)
|
||||||
|
"""Guild filters: Basic filters + guild validation."""
|
||||||
|
|
||||||
|
COMMAND_FILTERS = (
|
||||||
|
should_ignore_bot_messages,
|
||||||
|
should_ignore_empty_messages,
|
||||||
|
should_ignore_command_prefix,
|
||||||
|
should_ignore_dms,
|
||||||
|
should_ignore_wrong_guild,
|
||||||
|
)
|
||||||
|
"""Command filters: Guild filters + command prefix check."""
|
||||||
Loading…
Reference in New Issue
Block a user