mirror of
https://github.com/Lilac-Rose/Lacie.git
synced 2026-09-12 02:56:30 -05:00
python programming at 6pm gone wrong cops called
This commit is contained in:
482
commands/help.py
482
commands/help.py
@@ -1,249 +1,255 @@
|
||||
"""
|
||||
Custom help command that works as both !help and /help
|
||||
Supports searching for specific commands
|
||||
Place in commands/ folder
|
||||
"""
|
||||
|
||||
import discord
|
||||
from discord import app_commands
|
||||
from discord.ext import commands
|
||||
from typing import Dict, List
|
||||
|
||||
|
||||
class HelpView(discord.ui.View):
|
||||
|
||||
def __init__(self, bot, cog_commands: Dict[str, List[str]]):
|
||||
super().__init__(timeout=180)
|
||||
self.bot = bot
|
||||
self.cog_commands = cog_commands
|
||||
self.current_page = "home"
|
||||
|
||||
self.cog_info = {
|
||||
"commands": {"name": "General", "emoji": "⚙️"},
|
||||
"moderation": {"name": "Moderation", "emoji": "🛡️"},
|
||||
"xp": {"name": "XP & Leveling", "emoji": "⭐"},
|
||||
"sparkle": {"name": "Sparkle", "emoji": "✨"},
|
||||
"image": {"name": "Image", "emoji": "🖼️"},
|
||||
"suggestion": {"name": "Suggestions", "emoji": "💡"},
|
||||
"birthday": {"name": "Birthdays", "emoji": "🎂"},
|
||||
"embed": {"name": "Embed", "emoji": "📝"},
|
||||
"embeds": {"name": "Embeds", "emoji": "📜"},
|
||||
"profiles": {"name": "Profiles", "emoji": "👤"},
|
||||
"wordle": {"name": "Wordle", "emoji": "🟩"},
|
||||
}
|
||||
|
||||
self.add_cog_buttons()
|
||||
|
||||
home_button = discord.ui.Button(
|
||||
label="Home",
|
||||
emoji="🏠",
|
||||
style=discord.ButtonStyle.primary,
|
||||
custom_id="help_home",
|
||||
row=4
|
||||
)
|
||||
home_button.callback = self.show_home
|
||||
self.add_item(home_button)
|
||||
|
||||
def add_cog_buttons(self):
|
||||
row = 0
|
||||
col = 0
|
||||
for cog_key in [
|
||||
"commands", "moderation", "xp", "sparkle",
|
||||
"image", "suggestion", "birthday",
|
||||
"embed", "embeds", "profiles", "wordle"
|
||||
]:
|
||||
if cog_key in self.cog_commands and self.cog_commands[cog_key]:
|
||||
info = self.cog_info.get(cog_key, {"emoji": "📦", "name": cog_key.title()})
|
||||
|
||||
button = discord.ui.Button(
|
||||
label=info["name"],
|
||||
emoji=info["emoji"],
|
||||
style=discord.ButtonStyle.secondary,
|
||||
custom_id=f"help_{cog_key}",
|
||||
row=row
|
||||
)
|
||||
|
||||
def make_callback(cog_name=cog_key):
|
||||
async def callback(interaction: discord.Interaction):
|
||||
try:
|
||||
await self.show_cog(interaction, cog_name)
|
||||
except Exception as e:
|
||||
print(f"Button callback error for {cog_name}: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
try:
|
||||
await interaction.response.send_message(f"Error: {e}", ephemeral=True)
|
||||
except:
|
||||
pass
|
||||
return callback
|
||||
|
||||
button.callback = make_callback()
|
||||
self.add_item(button)
|
||||
|
||||
col += 1
|
||||
if col >= 5:
|
||||
col = 0
|
||||
row += 1
|
||||
|
||||
async def show_home(self, interaction: discord.Interaction):
|
||||
try:
|
||||
self.current_page = "home"
|
||||
embed = self.create_home_embed(interaction)
|
||||
await interaction.response.edit_message(embed=embed, view=self)
|
||||
except discord.errors.InteractionResponded:
|
||||
await interaction.followup.edit_message(interaction.message.id, embed=embed, view=self)
|
||||
|
||||
async def show_cog(self, interaction: discord.Interaction, cog_name: str):
|
||||
try:
|
||||
self.current_page = cog_name
|
||||
embed = self.create_cog_embed(interaction, cog_name)
|
||||
await interaction.response.edit_message(embed=embed, view=self)
|
||||
except discord.errors.InteractionResponded:
|
||||
await interaction.followup.edit_message(interaction.message.id, embed=embed, view=self)
|
||||
|
||||
def create_home_embed(self, interaction: discord.Interaction) -> discord.Embed:
|
||||
color = discord.Color.purple()
|
||||
try:
|
||||
embed_color_cog = self.bot.get_cog("EmbedColor")
|
||||
if embed_color_cog:
|
||||
color = embed_color_cog.get_user_color(interaction.user)
|
||||
except:
|
||||
pass
|
||||
|
||||
embed = discord.Embed(
|
||||
title="🤖 Lacie Bot - Help",
|
||||
description=(
|
||||
"Welcome to Lacie! Use the buttons below to explore the different command categories.\n\n"
|
||||
"**💡 Found a bug or have an idea?**\n"
|
||||
"Use `/suggest` to report bugs or suggest new features! Your feedback helps improve the bot."
|
||||
),
|
||||
color=color
|
||||
)
|
||||
|
||||
embed.add_field(
|
||||
name="🔗 Links",
|
||||
value=(
|
||||
"• [GitHub Repository](https://github.com/Lilac-Rose/Lacie)\n"
|
||||
"• [Web Dashboard](https://bots.lilacrose.dev/lacie/)"
|
||||
),
|
||||
inline=False
|
||||
)
|
||||
|
||||
embed.set_footer(text="Created with 💜 by Lilac Aria Rose")
|
||||
return embed
|
||||
|
||||
def create_cog_embed(self, interaction: discord.Interaction, cog_name: str) -> discord.Embed:
|
||||
info = self.cog_info.get(cog_name, {"emoji": "📦", "name": cog_name.title()})
|
||||
|
||||
color = discord.Color.blue()
|
||||
try:
|
||||
embed_color_cog = self.bot.get_cog("EmbedColor")
|
||||
if embed_color_cog:
|
||||
color = embed_color_cog.get_user_color(interaction.user)
|
||||
except:
|
||||
pass
|
||||
|
||||
embed = discord.Embed(
|
||||
title=f"{info['emoji']} {info['name']} Commands",
|
||||
description="Here are all the commands in this category:",
|
||||
color=color
|
||||
)
|
||||
|
||||
if cog_name in self.cog_commands:
|
||||
commands_list = "\n".join(sorted(set(self.cog_commands[cog_name])))
|
||||
if len(commands_list) > 4096:
|
||||
chunks = []
|
||||
current_chunk = []
|
||||
current_length = 0
|
||||
for cmd in sorted(set(self.cog_commands[cog_name])):
|
||||
if current_length + len(cmd) + 1 > 1024:
|
||||
chunks.append("\n".join(current_chunk))
|
||||
current_chunk = [cmd]
|
||||
current_length = len(cmd)
|
||||
else:
|
||||
current_chunk.append(cmd)
|
||||
current_length += len(cmd) + 1
|
||||
if current_chunk:
|
||||
chunks.append("\n".join(current_chunk))
|
||||
for i, chunk in enumerate(chunks):
|
||||
field_name = "Commands" if i == 0 else f"Commands (cont. {i+1})"
|
||||
embed.add_field(name=field_name, value=chunk, inline=False)
|
||||
else:
|
||||
embed.description = commands_list
|
||||
else:
|
||||
embed.description = "No commands found in this category."
|
||||
|
||||
embed.set_footer(
|
||||
text=f"Use the buttons to navigate • Total: {len(set(self.cog_commands.get(cog_name, [])))} commands"
|
||||
)
|
||||
return embed
|
||||
|
||||
async def on_timeout(self):
|
||||
for item in self.children:
|
||||
item.disabled = True
|
||||
|
||||
from discord import app_commands
|
||||
from typing import Optional
|
||||
import difflib
|
||||
|
||||
class Help(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
@app_commands.command(name="help", description="Shows all available commands organized by category")
|
||||
async def help_command(self, interaction: discord.Interaction):
|
||||
try:
|
||||
await interaction.response.defer(thinking=True)
|
||||
cog_commands = {}
|
||||
|
||||
# Process slash commands safely
|
||||
for command in self.bot.tree.get_commands():
|
||||
cog = getattr(command, "binding", None) # <-- FIX HERE
|
||||
if cog:
|
||||
module = cog.__class__.__module__
|
||||
folder = module.split(".")[0] if "." in module else "other"
|
||||
|
||||
def get_command_signature(self, command):
|
||||
"""Get the usage signature for a command"""
|
||||
if isinstance(command, commands.HybridCommand):
|
||||
# For hybrid commands, show both formats
|
||||
params = []
|
||||
for name, param in command.clean_params.items():
|
||||
if param.default == param.empty:
|
||||
params.append(f"<{name}>")
|
||||
else:
|
||||
folder = "other"
|
||||
|
||||
if folder == "events":
|
||||
continue
|
||||
|
||||
cog_commands.setdefault(folder, [])
|
||||
cmd_desc = command.description or "No description"
|
||||
cog_commands[folder].append(f"`/{command.name}` - {cmd_desc}")
|
||||
|
||||
# Process prefix commands
|
||||
for cmd_name, command in self.bot.all_commands.items():
|
||||
if command.name != cmd_name:
|
||||
continue
|
||||
|
||||
if command.cog:
|
||||
module = command.cog.__class__.__module__
|
||||
folder = module.split(".")[0] if "." in module else "other"
|
||||
params.append(f"[{name}]")
|
||||
param_str = " ".join(params)
|
||||
return f"!{command.name} {param_str}\n/{command.name} {param_str}"
|
||||
else:
|
||||
return f"{command.qualified_name} {command.signature}"
|
||||
|
||||
def get_all_commands(self):
|
||||
"""Get all commands organized by cog"""
|
||||
cog_commands = {}
|
||||
|
||||
for cog_name, cog in self.bot.cogs.items():
|
||||
commands_list = []
|
||||
|
||||
# Get regular commands
|
||||
for cmd in cog.get_commands():
|
||||
if not cmd.hidden:
|
||||
commands_list.append(cmd)
|
||||
|
||||
# Get app commands (slash only)
|
||||
if hasattr(cog, '__cog_app_commands__'):
|
||||
for cmd in cog.__cog_app_commands__:
|
||||
if isinstance(cmd, app_commands.Command):
|
||||
commands_list.append(cmd)
|
||||
elif isinstance(cmd, app_commands.Group):
|
||||
# Add group commands
|
||||
commands_list.append(cmd)
|
||||
|
||||
if commands_list:
|
||||
cog_commands[cog_name] = commands_list
|
||||
|
||||
# Get commands not in cogs
|
||||
no_cog_commands = [cmd for cmd in self.bot.commands if not cmd.cog and not cmd.hidden]
|
||||
if no_cog_commands:
|
||||
cog_commands["Other"] = no_cog_commands
|
||||
|
||||
return cog_commands
|
||||
|
||||
def search_commands(self, query):
|
||||
"""Search for commands matching the query"""
|
||||
query = query.lower()
|
||||
results = []
|
||||
|
||||
for cog_name, cog in self.bot.cogs.items():
|
||||
for cmd in cog.get_commands():
|
||||
if not cmd.hidden:
|
||||
# Check command name
|
||||
if query in cmd.name.lower():
|
||||
results.append((cmd, cog_name, 100))
|
||||
# Check command aliases
|
||||
elif any(query in alias.lower() for alias in cmd.aliases):
|
||||
results.append((cmd, cog_name, 90))
|
||||
# Check description
|
||||
elif cmd.description and query in cmd.description.lower():
|
||||
results.append((cmd, cog_name, 70))
|
||||
# Check help text
|
||||
elif cmd.help and query in cmd.help.lower():
|
||||
results.append((cmd, cog_name, 60))
|
||||
|
||||
# Sort by relevance
|
||||
results.sort(key=lambda x: x[2], reverse=True)
|
||||
return results
|
||||
|
||||
def create_help_embed(self, title, description=None):
|
||||
"""Create a base help embed"""
|
||||
embed = discord.Embed(
|
||||
title=title,
|
||||
description=description,
|
||||
color=discord.Color.blurple()
|
||||
)
|
||||
embed.set_footer(text="Use !help <command> or /help <command> for more info on a specific command")
|
||||
return embed
|
||||
|
||||
@commands.hybrid_command(name="help", description="Shows help information for commands")
|
||||
@app_commands.describe(command="The command to get help for")
|
||||
async def help_command(self, ctx: commands.Context, *, command: Optional[str] = None):
|
||||
"""
|
||||
Get help for bot commands
|
||||
|
||||
Usage:
|
||||
!help - Show all commands
|
||||
!help <command> - Get detailed help for a specific command
|
||||
!help <search> - Search for commands
|
||||
"""
|
||||
|
||||
if command:
|
||||
# Try to find exact command match first
|
||||
cmd = self.bot.get_command(command.lower())
|
||||
|
||||
if cmd:
|
||||
# Show detailed help for specific command
|
||||
embed = self.create_help_embed(
|
||||
title=f"Help: {cmd.name}",
|
||||
description=cmd.help or cmd.description or "No description available"
|
||||
)
|
||||
|
||||
# Usage
|
||||
embed.add_field(
|
||||
name="Usage",
|
||||
value=f"```\n{self.get_command_signature(cmd)}\n```",
|
||||
inline=False
|
||||
)
|
||||
|
||||
# Aliases
|
||||
if cmd.aliases:
|
||||
embed.add_field(
|
||||
name="Aliases",
|
||||
value=", ".join(f"`{alias}`" for alias in cmd.aliases),
|
||||
inline=False
|
||||
)
|
||||
|
||||
# Category
|
||||
if cmd.cog:
|
||||
embed.add_field(name="Category", value=cmd.cog.qualified_name, inline=True)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
else:
|
||||
# Search for commands
|
||||
results = self.search_commands(command)
|
||||
|
||||
if not results:
|
||||
# Suggest similar commands
|
||||
all_cmd_names = [c.name for c in self.bot.commands]
|
||||
suggestions = difflib.get_close_matches(command.lower(), all_cmd_names, n=3, cutoff=0.6)
|
||||
|
||||
embed = discord.Embed(
|
||||
title="❌ Command Not Found",
|
||||
description=f"No command found matching `{command}`",
|
||||
color=discord.Color.red()
|
||||
)
|
||||
|
||||
if suggestions:
|
||||
embed.add_field(
|
||||
name="Did you mean?",
|
||||
value="\n".join(f"• `{s}`" for s in suggestions),
|
||||
inline=False
|
||||
)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
else:
|
||||
folder = "other"
|
||||
|
||||
if folder == "events":
|
||||
continue
|
||||
|
||||
cog_commands.setdefault(folder, [])
|
||||
cmd_desc = command.help or command.brief or "No description"
|
||||
alias_text = f" (aliases: {', '.join(f'!{a}' for a in command.aliases)})" if command.aliases else ""
|
||||
cog_commands[folder].append(f"`!{command.name}`{alias_text} - {cmd_desc}")
|
||||
|
||||
view = HelpView(self.bot, cog_commands)
|
||||
embed = view.create_home_embed(interaction)
|
||||
|
||||
print(f"DEBUG: Found cogs: {list(cog_commands.keys())}")
|
||||
for cog_name, cmds in cog_commands.items():
|
||||
print(f" {cog_name}: {len(set(cmds))} unique commands")
|
||||
|
||||
await interaction.followup.send(embed=embed, view=view)
|
||||
|
||||
except Exception as e:
|
||||
import traceback
|
||||
error_msg = "".join(traceback.format_exception(type(e), e, e.__traceback__))
|
||||
error_embed = discord.Embed(
|
||||
title="❌ Error in /help command",
|
||||
description=f"```py\n{error_msg[:4000]}```",
|
||||
color=discord.Color.red()
|
||||
# Show search results
|
||||
embed = self.create_help_embed(
|
||||
title=f"🔍 Search Results for '{command}'",
|
||||
description=f"Found {len(results)} matching command(s)"
|
||||
)
|
||||
|
||||
for cmd, cog_name, score in results[:10]: # Limit to 10 results
|
||||
desc = cmd.description or cmd.help or "No description"
|
||||
if len(desc) > 100:
|
||||
desc = desc[:97] + "..."
|
||||
|
||||
embed.add_field(
|
||||
name=f"{cmd.name} ({cog_name})",
|
||||
value=desc,
|
||||
inline=False
|
||||
)
|
||||
|
||||
if len(results) > 10:
|
||||
embed.set_footer(text=f"Showing top 10 of {len(results)} results. Use !help <command> for details.")
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
else:
|
||||
# Show all commands organized by category
|
||||
cog_commands = self.get_all_commands()
|
||||
|
||||
embed = self.create_help_embed(
|
||||
title="📚 Bot Commands",
|
||||
description=f"Prefix: `!` | Total Commands: {len(list(self.bot.commands))}\n\n"
|
||||
"Commands work with both `!` and `/`"
|
||||
)
|
||||
try:
|
||||
await interaction.followup.send(embed=error_embed)
|
||||
except:
|
||||
await interaction.response.send_message(embed=error_embed)
|
||||
|
||||
|
||||
for cog_name, cmds in sorted(cog_commands.items()):
|
||||
if not cmds:
|
||||
continue
|
||||
|
||||
# Group commands by name
|
||||
cmd_names = []
|
||||
seen = set()
|
||||
|
||||
for cmd in cmds:
|
||||
if isinstance(cmd, (commands.Command, commands.HybridCommand)):
|
||||
name = cmd.name
|
||||
elif isinstance(cmd, (app_commands.Command, app_commands.Group)):
|
||||
name = cmd.name
|
||||
else:
|
||||
continue
|
||||
|
||||
if name not in seen:
|
||||
cmd_names.append(f"`{name}`")
|
||||
seen.add(name)
|
||||
|
||||
if cmd_names:
|
||||
embed.add_field(
|
||||
name=f"**{cog_name}**",
|
||||
value=" • ".join(cmd_names),
|
||||
inline=False
|
||||
)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_command_error(self, ctx: commands.Context, error):
|
||||
"""Show help if command not found"""
|
||||
if isinstance(error, commands.CommandNotFound):
|
||||
# Extract the attempted command
|
||||
cmd_used = ctx.message.content.split()[0][len(ctx.prefix):]
|
||||
|
||||
# Suggest similar commands
|
||||
all_cmd_names = [c.name for c in self.bot.commands]
|
||||
suggestions = difflib.get_close_matches(cmd_used, all_cmd_names, n=3, cutoff=0.6)
|
||||
|
||||
embed = discord.Embed(
|
||||
title="❓ Unknown Command",
|
||||
description=f"Command `{cmd_used}` not found.",
|
||||
color=discord.Color.orange()
|
||||
)
|
||||
|
||||
if suggestions:
|
||||
embed.add_field(
|
||||
name="Did you mean?",
|
||||
value="\n".join(f"• `!{s}` or `/{s}`" for s in suggestions),
|
||||
inline=False
|
||||
)
|
||||
|
||||
embed.set_footer(text="Use !help to see all commands")
|
||||
await ctx.send(embed=embed, delete_after=10)
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(Help(bot))
|
||||
# Remove default help command
|
||||
bot.remove_command('help')
|
||||
await bot.add_cog(Help(bot))
|
||||
@@ -269,7 +269,7 @@ class Suggestion(commands.Cog):
|
||||
print(f"Error in suggest command: {e}")
|
||||
await interaction.followup.send(f"❌ An error occurred: {e}")
|
||||
|
||||
suggestion = app_commands.Group(name="suggestion", description="Manage suggestions")
|
||||
suggestion = app_commands.hybrid_group(name="suggestion", description="Manage suggestions")
|
||||
|
||||
@suggestion.command(name="view", description="View full details of a suggestion")
|
||||
async def suggestion_view(self, interaction: discord.Interaction, suggestion_id: int):
|
||||
|
||||
Reference in New Issue
Block a user