import discord from discord.ext import commands from discord import app_commands import config class HelpView(discord.ui.View): def __init__(self, mapping, ctx): super().__init__(timeout=180) self.ctx = ctx self.mapping = mapping self.add_item(HelpSelect(mapping, ctx)) class HelpSelect(discord.ui.Select): def __init__(self, mapping, ctx): self.mapping = mapping self.ctx = ctx options = [ discord.SelectOption( label='Home', description='Back to main menu', emoji='🏠', value='home' ) ] # Dynamically add categories (Cogs) for cog, cmds in mapping.items(): if not cmds: continue # Use attributes safely cog_name = getattr(cog, "name", "Other").replace("đŸŽļ ", "") emoji = getattr(cog, "emoji", "📄") options.append(discord.SelectOption( label=cog_name, description=f"{len(cmds)} commands available", emoji=emoji, value=cog_name )) super().__init__(placeholder="Select a category...", min_values=1, max_values=1, options=options) async def callback(self, interaction: discord.Interaction): if interaction.user != self.ctx.author: return await interaction.response.send_message("Create your own help command with /help", ephemeral=True) value = self.values[0] if value == 'home': await interaction.response.edit_message(embed=get_home_embed(self.ctx), view=self.view) return # Find the selected cog selected_cog = None selected_commands = [] for cog, cmds in self.mapping.items(): cog_name_clean = getattr(cog, "name", "Other").replace("đŸŽļ ", "") if cog_name_clean == value: selected_cog = cog selected_commands = cmds break embed = discord.Embed( title=f"{getattr(selected_cog, 'emoji', '')} {value} Commands", color=config.get_color("main") if hasattr(config, 'get_color') else discord.Color.blue() ) for cmd in selected_commands: # Get description desc = cmd.short_doc or cmd.description or "No description provided." embed.add_field( name=f"/{cmd.name}", value=desc, inline=False ) await interaction.response.edit_message(embed=embed, view=self.view) def get_home_embed(ctx): embed = discord.Embed( title="🤖 Bot Help Menu", description=f"Hello **{ctx.author.name}**! Select a category below to see available commands.", color=discord.Color.purple() ) if ctx.bot.user.avatar: embed.set_thumbnail(url=ctx.bot.user.avatar.url) embed.add_field(name="â„šī¸ How to use", value="Use the dropdown menu below to navigate categories.\nMost commands work as `/command` or `=command`.", inline=False) return embed class GroovyHelp(commands.Cog): def __init__(self, client): self.client = client self.name = "Help" self.emoji = "🆘" @commands.hybrid_command(name="help", description="Show the help menu") async def help(self, ctx: commands.Context): bot = ctx.bot mapping = {} for cog_name in bot.cogs: cog = bot.get_cog(cog_name) # --- FIXED FILTERING LOGIC --- visible_cmds = [] for cmd in cog.get_commands(): if cmd.hidden: continue try: # Check if user has permission to run this command if await cmd.can_run(ctx): visible_cmds.append(cmd) except commands.CommandError: continue # ----------------------------- if visible_cmds: # Sort alphabetically visible_cmds.sort(key=lambda x: x.name) mapping[cog] = visible_cmds embed = get_home_embed(ctx) view = HelpView(mapping, ctx) await ctx.send(embed=embed, view=view)