6.5 KiB
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:
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.Forbiddenwhen 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:
- Create a role named "Deez Watch" in your Discord server (recommended)
- Set the role as mentionable OR ensure bot has "Mention Everyone" permission
Manual Testing:
- Start the bot in development mode
- Post a message with
||test||in the configured guild - 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:
-
Configurable Response:
- Custom responses per guild
- Random selection from multiple responses
- Embed responses with more context
-
Cooldown System:
- Prevent spam by rate-limiting responses
- Per-channel or per-user cooldowns
- Configurable cooldown duration
-
Statistics Tracking:
- Track spoiler counts per user
- Leaderboard of "most spoiler-prone" users
- Channel statistics
-
Advanced Detection:
- Detect spoiler context (movie, game, book)
- Different responses based on content
- Integration with spoiler databases
-
Permissions:
- Allow certain roles to bypass detection
- Channel-specific enable/disable
- Opt-in/opt-out system
Related Files
utils/listeners.py- Shared message filtering utilitiescommands/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