import discord from discord.ext import commands from discord import app_commands import random import datetime import logging import json import os # Set up logging logger = logging.getLogger(__name__) # Define the path for the JSON file to store timeout chance TIMEOUT_CONFIG_FILE = os.path.join(os.path.dirname(__file__), "../data/timeout_config.json") class RandomTimeoutCog(commands.Cog): def __init__(self, bot): self.bot = bot self.target_user_id = 748405715520978965 # The specific user ID to target self.timeout_chance = 0.005 # Default: 0.5% chance (0.005) self.timeout_duration = 60 # 1 minute in seconds self.log_channel_id = 1363007131980136600 # Channel ID to log all events # Ensure data directory exists os.makedirs(os.path.dirname(TIMEOUT_CONFIG_FILE), exist_ok=True) # Load timeout chance from JSON file self.load_timeout_config() logger.info(f"RandomTimeoutCog initialized with target user ID: {self.target_user_id} and timeout chance: {self.timeout_chance}") def load_timeout_config(self): """Load timeout configuration from JSON file""" if os.path.exists(TIMEOUT_CONFIG_FILE): try: with open(TIMEOUT_CONFIG_FILE, "r") as f: data = json.load(f) if "timeout_chance" in data: self.timeout_chance = data["timeout_chance"] logger.info(f"Loaded timeout chance: {self.timeout_chance}") except Exception as e: logger.error(f"Error loading timeout configuration: {e}") def save_timeout_config(self): """Save timeout configuration to JSON file""" try: config_data = { "timeout_chance": self.timeout_chance, "target_user_id": self.target_user_id, "timeout_duration": self.timeout_duration } with open(TIMEOUT_CONFIG_FILE, "w") as f: json.dump(config_data, f, indent=4) logger.info(f"Saved timeout configuration with chance: {self.timeout_chance}") except Exception as e: logger.error(f"Error saving timeout configuration: {e}") async def create_log_embed(self, message, roll, was_timed_out): """Create an embed for logging the timeout event""" # Create the embed with appropriate color based on timeout status color = discord.Color.red() if was_timed_out else discord.Color.green() embed = discord.Embed( title=f"{'⚠️ TIMEOUT TRIGGERED' if was_timed_out else '✅ No Timeout'}", description=f"Message from <@{self.target_user_id}> was processed", color=color, timestamp=datetime.datetime.now(datetime.timezone.utc) ) # Add user information embed.add_field( name="👤 User Information", value=f"**User:** {message.author.mention}\n**User ID:** {message.author.id}", inline=False ) # Add roll information embed.add_field( name="🎲 Roll Information", value=f"**Roll:** {roll:.6f}\n**Threshold:** {self.timeout_chance:.6f}\n**Chance:** {self.timeout_chance * 100:.2f}%\n**Result:** {'TIMEOUT' if was_timed_out else 'SAFE'}", inline=False ) # Add message information embed.add_field( name="💬 Message Information", value=f"**Channel:** {message.channel.mention}\n**Message Link:** [Click Here]({message.jump_url})", inline=False ) # Set footer embed.set_footer(text=f"Random Timeout System | {datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC')}") # Set author with user avatar embed.set_author(name=f"{message.author.name}#{message.author.discriminator}", icon_url=message.author.display_avatar.url) return embed @commands.Cog.listener() async def on_message(self, message: discord.Message): """Event listener for messages to randomly timeout the target user""" # Ignore bot messages if message.author.bot: return # Check if the message author is the target user if message.author.id == self.target_user_id: # Generate a random number between 0 and 1 roll = random.random() was_timed_out = False # If the roll is less than the timeout chance (1%), timeout the user if roll < self.timeout_chance: try: # Calculate timeout until time (1 minute from now) timeout_until = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(seconds=self.timeout_duration) # Apply the timeout await message.author.timeout(timeout_until, reason="Random 0.5% chance timeout") was_timed_out = True # Send a message to the channel await message.channel.send( f"🎲 Bad luck! {message.author.mention} rolled a {roll:.4f} and got timed out for 1 minute! (0.5% chance)", delete_after=10 # Delete after 10 seconds ) logger.info(f"User {message.author.id} was randomly timed out for 1 minute") except discord.Forbidden: logger.warning(f"Bot doesn't have permission to timeout user {message.author.id}") except discord.HTTPException as e: logger.error(f"Failed to timeout user {message.author.id}: {e}") except Exception as e: logger.error(f"Unexpected error when timing out user {message.author.id}: {e}") # Log the event to the specified channel regardless of timeout result try: # Get the log channel log_channel = self.bot.get_channel(self.log_channel_id) if log_channel: # Create and send the embed embed = await self.create_log_embed(message, roll, was_timed_out) await log_channel.send(embed=embed) else: logger.warning(f"Log channel with ID {self.log_channel_id} not found") except Exception as e: logger.error(f"Error sending log message: {e}") @commands.command(name="set_timeout_chance") @commands.has_permissions(moderate_members=True) async def set_timeout_chance(self, ctx, percentage: float): """Set the random timeout chance percentage (Moderator only, max 10% unless owner)""" # Convert percentage to decimal (e.g., 5% -> 0.05) decimal_chance = percentage / 100.0 # Check if user is owner is_owner = await self.bot.is_owner(ctx.author) # Validate the percentage if not is_owner and (percentage < 0 or percentage > 10): await ctx.reply(f"❌ Error: Moderators can only set timeout chance between 0% and 10%. Current: {self.timeout_chance * 100:.2f}%") return elif percentage < 0 or percentage > 100: await ctx.reply(f"❌ Error: Timeout chance must be between 0% and 100%. Current: {self.timeout_chance * 100:.2f}%") return # Store the old value for logging old_chance = self.timeout_chance # Update the timeout chance self.timeout_chance = decimal_chance # Save the updated timeout chance to the JSON file self.save_timeout_config() # Create an embed for the response embed = discord.Embed( title="Timeout Chance Updated", description=f"The random timeout chance has been updated.", color=discord.Color.blue(), timestamp=datetime.datetime.now(datetime.timezone.utc) ) embed.add_field( name="Previous Chance", value=f"{old_chance * 100:.2f}%", inline=True ) embed.add_field( name="New Chance", value=f"{self.timeout_chance * 100:.2f}%", inline=True ) embed.add_field( name="Updated By", value=f"{ctx.author.mention} {' (Owner)' if is_owner else ' (Moderator)'}", inline=False ) embed.set_footer(text=f"Random Timeout System | User ID: {self.target_user_id}") # Send the response await ctx.reply(embed=embed) # Log the change logger.info(f"Timeout chance changed from {old_chance:.4f} to {self.timeout_chance:.4f} by {ctx.author.name} (ID: {ctx.author.id})") # Also log to the log channel if available try: log_channel = self.bot.get_channel(self.log_channel_id) if log_channel: await log_channel.send(embed=embed) except Exception as e: logger.error(f"Error sending log message: {e}") @set_timeout_chance.error async def set_timeout_chance_error(self, ctx, error): """Error handler for the set_timeout_chance command""" if isinstance(error, commands.MissingPermissions): await ctx.reply("❌ You need the 'Moderate Members' permission to use this command.") elif isinstance(error, commands.MissingRequiredArgument): await ctx.reply(f"❌ Please provide a percentage. Example: `!set_timeout_chance 0.5` for 0.5%. Current: {self.timeout_chance * 100:.2f}%") elif isinstance(error, commands.BadArgument): await ctx.reply(f"❌ Please provide a valid number. Example: `!set_timeout_chance 0.5` for 0.5%. Current: {self.timeout_chance * 100:.2f}%") else: await ctx.reply(f"❌ An error occurred: {error}") logger.error(f"Error in set_timeout_chance command: {error}") @app_commands.command(name="set_timeout_chance", description="Set the random timeout chance percentage") @app_commands.describe(percentage="The percentage chance (0-10% for moderators, 0-100% for owner)") @app_commands.checks.has_permissions(moderate_members=True) async def set_timeout_chance_slash(self, interaction: discord.Interaction, percentage: float): """Slash command version of set_timeout_chance""" # Convert percentage to decimal (e.g., 5% -> 0.05) decimal_chance = percentage / 100.0 # Check if user is owner is_owner = await self.bot.is_owner(interaction.user) # Validate the percentage if not is_owner and (percentage < 0 or percentage > 10): await interaction.response.send_message( f"❌ Error: Moderators can only set timeout chance between 0% and 10%. Current: {self.timeout_chance * 100:.2f}%", ephemeral=True ) return elif percentage < 0 or percentage > 100: await interaction.response.send_message( f"❌ Error: Timeout chance must be between 0% and 100%. Current: {self.timeout_chance * 100:.2f}%", ephemeral=True ) return # Store the old value for logging old_chance = self.timeout_chance # Update the timeout chance self.timeout_chance = decimal_chance # Save the updated timeout chance to the JSON file self.save_timeout_config() # Create an embed for the response embed = discord.Embed( title="Timeout Chance Updated", description=f"The random timeout chance has been updated.", color=discord.Color.blue(), timestamp=datetime.datetime.now(datetime.timezone.utc) ) embed.add_field( name="Previous Chance", value=f"{old_chance * 100:.2f}%", inline=True ) embed.add_field( name="New Chance", value=f"{self.timeout_chance * 100:.2f}%", inline=True ) embed.add_field( name="Updated By", value=f"{interaction.user.mention} {' (Owner)' if is_owner else ' (Moderator)'}", inline=False ) embed.set_footer(text=f"Random Timeout System | User ID: {self.target_user_id}") # Send the response await interaction.response.send_message(embed=embed) # Log the change logger.info(f"Timeout chance changed from {old_chance:.4f} to {self.timeout_chance:.4f} by {interaction.user.name} (ID: {interaction.user.id})") # Also log to the log channel if available try: log_channel = self.bot.get_channel(self.log_channel_id) if log_channel: await log_channel.send(embed=embed) except Exception as e: logger.error(f"Error sending log message: {e}") @set_timeout_chance_slash.error async def set_timeout_chance_slash_error(self, interaction: discord.Interaction, error): """Error handler for the set_timeout_chance slash command""" if isinstance(error, app_commands.errors.MissingPermissions): await interaction.response.send_message( "❌ You need the 'Moderate Members' permission to use this command.", ephemeral=True ) else: await interaction.response.send_message( f"❌ An error occurred: {error}", ephemeral=True ) logger.error(f"Error in set_timeout_chance slash command: {error}") @commands.Cog.listener() async def on_ready(self): logger.info(f'{self.__class__.__name__} cog has been loaded.') async def setup(bot: commands.Bot): await bot.add_cog(RandomTimeoutCog(bot)) print("RandomTimeoutCog loaded successfully!")