import discord import asyncio import re import time from config import BLACKLISTED_USERS, BUCKET_REACT_USERS, AUTO_DELETE_USERS, SPECIAL_RESPONSES from utils.time_parser import parse_time class MessageHandler: def __init__(self, bot): self.bot = bot # Regex for detecting "in X time" patterns self.time_pattern = re.compile( r'in\s+((?:\d+\s*(?:seconds?|minutes?|hours?|days?|s|m|h|d)\s*)+)', re.IGNORECASE ) def parse_relative_time(self, time_str): """ Parse relative time strings like "2 hours", "30 minutes" Args: time_str: String in format like "2 hours", "30 minutes" Returns: Unix timestamp (seconds since epoch) for the future time or None if invalid """ # Convert to format our parse_time can handle time_part = time_str.replace('hours', 'h').replace('hour', 'h') time_part = time_part.replace('minutes', 'm').replace('minute', 'm') time_part = time_part.replace('seconds', 's').replace('second', 's') time_part = time_part.replace('days', 'd').replace('day', 'd') # Remove spaces to match expected format like "2h30m" time_part = re.sub(r'\s+', '', time_part) seconds = parse_time(time_part) if seconds: return int(time.time() + seconds) return None def create_discord_timestamp(self, unix_time, format_code='R'): """Create a Discord timestamp string""" return f"" def replace_time_patterns(self, content): """Replace "in X time" patterns with Discord timestamps""" def replace_match(match): time_str = match.group(1) unix_time = self.parse_relative_time(time_str) if unix_time: return self.create_discord_timestamp(unix_time) return match.group(0) # Return original text if parsing fails return self.time_pattern.sub(replace_match, content) async def handle_message(self, message): # Skip bot messages if message.author.bot: return # Skip command messages (they start with . usually) if message.content.startswith('.'): return # Look for and replace time patterns original_content = message.content modified_content = self.replace_time_patterns(original_content) # If the content was modified, edit the original message if modified_content != original_content and message.author == self.bot.user: try: await message.edit(content=modified_content) except Exception as e: # If we don't have permission to edit, just ignore pass # Handle special responses for user_id, data in SPECIAL_RESPONSES.items(): if message.author.id == user_id and data["trigger"] in message.content: await message.reply(data["response"]) # Handle automatic reactions if message.channel.id in self.bot.horsin: await message.add_reaction("🐴") if message.author.id in BUCKET_REACT_USERS: await message.add_reaction("🪣") # Handle auto-delete for specific users if message.author.id in AUTO_DELETE_USERS: try: await message.delete() except: pass # Handle DM if in AFK mode if isinstance(message.channel, discord.DMChannel) and message.author != self.bot.user: # Get the AFK cog if it's loaded afk_cog = next((cog for cog_name, cog in self.bot.cog_manager.cogs.items() if hasattr(cog, 'handle_afk_dm')), None) if afk_cog and hasattr(afk_cog, 'handle_afk_dm'): await afk_cog.handle_afk_dm(message) # Don't process further if the message is not from the bot user if message.author != self.bot.user: return # Handle commands await self.handle_commands(message) async def handle_blacklist(self, message): """Handle blacklisted users""" if message.author.id in BLACKLISTED_USERS: await message.reply("no") return True return False async def handle_commands(self, message): """Handle commands issued by the bot user""" content = message.content # Skip if not a command if not content.startswith('.'): return cmd_parts = content.split() cmd_name = cmd_parts[0][1:] # Get command name without the '.' # Check if this is a command in one of our loaded cogs if hasattr(self.bot, 'loaded_commands') and cmd_name in self.bot.loaded_commands: try: await self.bot.loaded_commands[cmd_name](message) return except Exception as e: print(f"Error executing command {cmd_name}: {e}") import traceback traceback.print_exc() await message.edit(content=f"❌ Error executing command: {str(e)}") return # If we got here, command wasn't found await message.edit(content=f"❌ Command not found: `{cmd_name}`")