From b3dac5802f70370e52b4f3a790f0442344e8ebf2 Mon Sep 17 00:00:00 2001 From: Lilac-Rose Date: Wed, 12 Nov 2025 00:17:51 +0100 Subject: [PATCH] consolodated sparkles and fixed the help command --- commands/help.py | 143 ++++++++++-------------------- sparkle/leaderboard.py | 73 ---------------- sparkle/sparkle_commands.py | 168 ++++++++++++++++++++++++++++++++++++ sparkle/sparkleinfo.py | 28 ------ sparkle/sparkles.py | 63 -------------- 5 files changed, 215 insertions(+), 260 deletions(-) delete mode 100644 sparkle/leaderboard.py create mode 100644 sparkle/sparkle_commands.py delete mode 100644 sparkle/sparkleinfo.py delete mode 100644 sparkle/sparkles.py diff --git a/commands/help.py b/commands/help.py index c164094..bfc93a1 100644 --- a/commands/help.py +++ b/commands/help.py @@ -3,6 +3,7 @@ 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]]): @@ -20,7 +21,9 @@ class HelpView(discord.ui.View): "suggestion": {"name": "Suggestions", "emoji": "💡"}, "birthday": {"name": "Birthdays", "emoji": "🎂"}, "embed": {"name": "Embed", "emoji": "📝"}, - "profiles": {"name": "Profiles", "emoji": "👤"} + "embeds": {"name": "Embeds", "emoji": "📜"}, + "profiles": {"name": "Profiles", "emoji": "👤"}, + "wordle": {"name": "Wordle", "emoji": "🟩"}, } self.add_cog_buttons() @@ -34,13 +37,15 @@ class HelpView(discord.ui.View): ) home_button.callback = self.show_home self.add_item(home_button) - + def add_cog_buttons(self): - """Add buttons for each cog category""" row = 0 col = 0 - - for cog_key in ["commands", "moderation", "xp", "sparkle", "image", "suggestion", "birthday", "embed", "profiles"]: + 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()}) @@ -52,7 +57,6 @@ class HelpView(discord.ui.View): row=row ) - # Use default argument to capture the current value def make_callback(cog_name=cog_key): async def callback(interaction: discord.Interaction): try: @@ -66,7 +70,7 @@ class HelpView(discord.ui.View): except: pass return callback - + button.callback = make_callback() self.add_item(button) @@ -74,26 +78,14 @@ class HelpView(discord.ui.View): 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: - # If already responded, use followup - try: - await interaction.followup.edit_message(interaction.message.id, embed=embed, view=self) - except Exception as e2: - print(f"Followup edit error: {e2}") - except Exception as e: - print(f"Show home error: {e}") - import traceback - traceback.print_exc() - try: - await interaction.response.send_message(f"Error: {e}", ephemeral=True) - except: - pass + await interaction.followup.edit_message(interaction.message.id, embed=embed, view=self) async def show_cog(self, interaction: discord.Interaction, cog_name: str): try: @@ -101,22 +93,9 @@ class HelpView(discord.ui.View): embed = self.create_cog_embed(interaction, cog_name) await interaction.response.edit_message(embed=embed, view=self) except discord.errors.InteractionResponded: - # If already responded, use followup - try: - await interaction.followup.edit_message(interaction.message.id, embed=embed, view=self) - except Exception as e2: - print(f"Followup edit error: {e2}") - except Exception as e: - print(f"Show cog error for {cog_name}: {e}") - import traceback - traceback.print_exc() - try: - await interaction.response.send_message(f"Error: {e}", ephemeral=True) - except: - pass + await interaction.followup.edit_message(interaction.message.id, embed=embed, view=self) def create_home_embed(self, interaction: discord.Interaction) -> discord.Embed: - # Get user color from EmbedColor cog color = discord.Color.purple() try: embed_color_cog = self.bot.get_cog("EmbedColor") @@ -145,13 +124,11 @@ class HelpView(discord.ui.View): ) 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()}) - # Get user color from EmbedColor cog color = discord.Color.blue() try: embed_color_cog = self.bot.get_cog("EmbedColor") @@ -168,12 +145,10 @@ class HelpView(discord.ui.View): 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)) @@ -182,10 +157,8 @@ class HelpView(discord.ui.View): 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) @@ -194,82 +167,64 @@ class HelpView(discord.ui.View): 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") - + 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 + 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 = {} - - # Track primary command names to avoid duplicates from aliases - seen_commands = {} - # Process slash commands + # Process slash commands safely for command in self.bot.tree.get_commands(): - cog = command.binding + cog = getattr(command, "binding", None) # <-- FIX HERE if cog: - # Get the folder from the cog's module path module = cog.__class__.__module__ - folder = module.split('.')[0] if '.' in module else "other" - - if folder == "events": - continue - - if folder not in cog_commands: - cog_commands[folder] = [] - - cmd_desc = command.description or "No description" - cog_commands[folder].append(f"`/{command.name}` - {cmd_desc}") - else: - if "other" not in cog_commands: - cog_commands["other"] = [] - cmd_desc = command.description or "No description" - cog_commands["other"].append(f"`/{command.name}` - {cmd_desc}") - - # Process prefix commands (only show the primary command, not aliases) - for cmd_name, command in self.bot.all_commands.items(): - # Skip if this is an alias (check if command.name != cmd_name) - if command.name != cmd_name: - continue - - if command.cog: - module = command.cog.__class__.__module__ - folder = module.split('.')[0] if '.' in module else "other" + folder = module.split(".")[0] if "." in module else "other" else: folder = "other" if folder == "events": continue - if folder not in cog_commands: - cog_commands[folder] = [] + 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" + else: + folder = "other" + + if folder == "events": + continue + + cog_commands.setdefault(folder, []) cmd_desc = command.help or command.brief or "No description" - - # Show aliases in the description if they exist - alias_text = "" - if command.aliases: - alias_text = f" (aliases: {', '.join(f'!{a}' for a in command.aliases)})" - + 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) - - # Debug: Print what cogs were found + 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") @@ -278,21 +233,17 @@ class Help(commands.Cog): except Exception as e: import traceback - error_msg = ''.join(traceback.format_exception(type(e), e, e.__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() ) - try: await interaction.followup.send(embed=error_embed) except: - try: - await interaction.response.send_message(embed=error_embed) - except: - pass + await interaction.response.send_message(embed=error_embed) + async def setup(bot): - await bot.add_cog(Help(bot)) \ No newline at end of file + await bot.add_cog(Help(bot)) diff --git a/sparkle/leaderboard.py b/sparkle/leaderboard.py deleted file mode 100644 index 1aeff09..0000000 --- a/sparkle/leaderboard.py +++ /dev/null @@ -1,73 +0,0 @@ -import discord -from discord.ext import commands -from discord import app_commands -from discord.utils import escape_markdown -from .database import get_db -import asyncio - -class SparkleLeaderboard(commands.Cog): - def __init__(self, bot): - self.bot = bot - # Updated emoji mapping - self.sparkle_emojis = { - "epic": "💫", - "rare": "🌟", - "regular": "✨" - } - - @commands.hybrid_command(name="sparkleleaderboard", aliases=["sparklelb"], description="Show server Sparkle leaderboard") - @app_commands.describe(limit="Number of users to show (max 20)") - async def sparkle_leaderboard(self, ctx: commands.Context, limit: int = 10): - limit = max(1, min(20, limit)) - guild_member_ids = {str(member.id) for member in ctx.guild.members} - - if not guild_member_ids: - await ctx.send("This server has no members to display.", ephemeral=True) - return - - def db_task(): - conn = get_db() - placeholders = ",".join(["?"] * len(guild_member_ids)) - query = f""" - SELECT user_id, epic, rare, regular, - (epic + rare + regular) as total - FROM sparkles - WHERE server_id = ? AND user_id IN ({placeholders}) - ORDER BY RANDOM() - LIMIT ? - """ - params = [str(ctx.guild.id), *guild_member_ids, limit] - cursor = conn.execute(query, params) - results = cursor.fetchall() - conn.close() - return results - - results = await asyncio.to_thread(db_task) - - if not results: - await ctx.send("No sparkle data available for members of this server.", ephemeral=True) - return - - embed = discord.Embed( - title=f"{escape_markdown(ctx.guild.name)} Random Sparkle List", - color=discord.Color.random() - ) - - for rank, (user_id, epic, rare, regular, total) in enumerate(results, 1): - user = ctx.guild.get_member(int(user_id)) - display_name = escape_markdown(user.display_name) if user else f"Unknown User ({user_id})" - sparkles = ( - f"{self.sparkle_emojis['epic']} {epic} | " - f"{self.sparkle_emojis['rare']} {rare} | " - f"{self.sparkle_emojis['regular']} {regular} | " - f"**Total:** {total}" - ) - embed.add_field(name=f"{rank}. {display_name}", value=sparkles, inline=False) - if rank == 1 and user: - embed.set_thumbnail(url=user.display_avatar.url) - - embed.set_footer(text="💫 Epic | 🌟 Rare | ✨ Regular") - await ctx.send(embed=embed) - -async def setup(bot): - await bot.add_cog(SparkleLeaderboard(bot)) \ No newline at end of file diff --git a/sparkle/sparkle_commands.py b/sparkle/sparkle_commands.py new file mode 100644 index 0000000..0c06c12 --- /dev/null +++ b/sparkle/sparkle_commands.py @@ -0,0 +1,168 @@ +import discord +from discord.ext import commands +from discord import app_commands +from discord.utils import escape_markdown +from .database import get_db +import asyncio + + +class SparkleCommands(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.sparkle_emojis = { + "epic": "💫", + "rare": "🌟", + "regular": "✨" + } + + # Create sparkle command group + sparkle_group = app_commands.Group(name="sparkle", description="Sparkle tracking and information") + + @sparkle_group.command(name="check", description="Check your sparkle count or another user's") + @app_commands.describe(user="The user to check sparkle count for (leave empty for yourself)") + async def sparkle_check(self, interaction: discord.Interaction, user: discord.User = None): + user = user or interaction.user + + def db_task(): + conn = get_db() + cursor = conn.execute( + """ + SELECT epic, rare, regular, + (epic + rare + regular) as total + FROM sparkles + WHERE server_id = ? AND user_id = ? + """, + (str(interaction.guild.id), str(user.id)) + ) + result = cursor.fetchone() + conn.close() + return result + + result = await asyncio.to_thread(db_task) + + if not result: + await interaction.response.send_message( + f"{user.display_name} has no sparkles yet!", + ephemeral=True + ) + return + + epic, rare, regular, total = result + embed = discord.Embed( + title=f"{user.display_name}'s Sparkles", + color=discord.Color.gold() + ) + embed.set_thumbnail(url=user.display_avatar.url) + embed.add_field( + name="Totals", + value=( + f"{self.sparkle_emojis['epic']} **Epic:** {epic}\n" + f"{self.sparkle_emojis['rare']} **Rare:** {rare}\n" + f"{self.sparkle_emojis['regular']} **Regular:** {regular}\n" + f"**Total:** {total}" + ), + inline=False + ) + + await interaction.response.send_message(embed=embed) + + @sparkle_group.command(name="info", description="Learn about sparkles and how they work") + async def sparkle_info(self, interaction: discord.Interaction): + embed = discord.Embed( + title="✨ Sparkles ✨", + description=( + "Sparkles are **random reactions** that can appear on messages! " + "Sometimes, when you send a message, you might get a sparkle reaction and a little notification.\n\n" + "**Types of Sparkles:**\n" + "✨ **Regular Sparkle** – Appears randomly (1/1,000 chance per message)\n" + "🌟 **Rare Sparkle** – Appears less often (1/10,000 chance per message)\n" + "💫 **Epic Sparkle** – Extremely rare! (1/100,000 chance per message)\n\n" + "You can track your sparkles and compare with others using `/sparkle leaderboard`." + ), + color=discord.Color.purple() + ) + embed.set_footer(text="Keep sending messages to try your luck!") + + await interaction.response.send_message(embed=embed) + + @sparkle_group.command(name="leaderboard", description="Show server sparkle leaderboard") + @app_commands.describe(limit="Number of users to show (max 20, default 10)") + async def sparkle_leaderboard(self, interaction: discord.Interaction, limit: int = 10): + limit = max(1, min(20, limit)) + + guild_member_ids = {str(member.id) for member in interaction.guild.members} + + if not guild_member_ids: + await interaction.response.send_message( + "This server has no members to display.", + ephemeral=True + ) + return + + await interaction.response.defer() + + def db_task(): + conn = get_db() + placeholders = ",".join(["?"] * len(guild_member_ids)) + query = f""" + SELECT user_id, epic, rare, regular, + (epic + rare + regular) as total + FROM sparkles + WHERE server_id = ? AND user_id IN ({placeholders}) + ORDER BY total DESC + LIMIT ? + """ + params = [str(interaction.guild.id), *guild_member_ids, limit] + cursor = conn.execute(query, params) + results = cursor.fetchall() + conn.close() + return results + + results = await asyncio.to_thread(db_task) + + if not results: + await interaction.followup.send( + "No sparkle data available for members of this server.", + ephemeral=True + ) + return + + embed = discord.Embed( + title=f"✨ {escape_markdown(interaction.guild.name)} Sparkle Leaderboard", + color=discord.Color.gold() + ) + + # Add medal emojis for top 3 + medal_emojis = {1: "🥇", 2: "🥈", 3: "🥉"} + + for rank, (user_id, epic, rare, regular, total) in enumerate(results, 1): + user = interaction.guild.get_member(int(user_id)) + display_name = escape_markdown(user.display_name) if user else f"Unknown User ({user_id})" + + # Add medal emoji for top 3 + rank_display = medal_emojis.get(rank, f"{rank}.") + + sparkles = ( + f"{self.sparkle_emojis['epic']} {epic} | " + f"{self.sparkle_emojis['rare']} {rare} | " + f"{self.sparkle_emojis['regular']} {regular} | " + f"**Total:** {total}" + ) + + embed.add_field( + name=f"{rank_display} {display_name}", + value=sparkles, + inline=False + ) + + # Set thumbnail to #1 user's avatar + if rank == 1 and user: + embed.set_thumbnail(url=user.display_avatar.url) + + embed.set_footer(text="💫 Epic | 🌟 Rare | ✨ Regular") + + await interaction.followup.send(embed=embed) + + +async def setup(bot): + await bot.add_cog(SparkleCommands(bot)) \ No newline at end of file diff --git a/sparkle/sparkleinfo.py b/sparkle/sparkleinfo.py deleted file mode 100644 index 682143a..0000000 --- a/sparkle/sparkleinfo.py +++ /dev/null @@ -1,28 +0,0 @@ -import discord -from discord.ext import commands -from discord import app_commands - -class SparkleInfo(commands.Cog): - def __init__(self, bot): - self.bot = bot - - @app_commands.command(name="sparkleinfo", description="Learn about sparkles and how they work") - async def sparkleinfo(self, interaction: discord.Interaction): - embed = discord.Embed( - title="✨ Sparkles ✨", - description=( - "Sparkles are **random reactions** that can appear on messages! " - "Sometimes, when you send a message, you might get a sparkle reaction and a little notification.\n\n" - "**Types of Sparkles:**\n" - "✨ **Regular Sparkle** – Appears randomly (1/1,000 chance per message)\n" - "🌟 **Rare Sparkle** – Appears less often (1/10,000 chance per message)\n" - "💫**Epic Sparkle** – Extremely rare! (1/100,000 chance per message)\n\n" - "You can track your sparkles and compare with others using `/sparkleleaderboard`." - ), - color=discord.Color.purple() - ) - embed.set_footer(text="Keep sending messages to try your luck!") - await interaction.response.send_message(embed=embed) - -async def setup(bot: commands.Bot): - await bot.add_cog(SparkleInfo(bot)) \ No newline at end of file diff --git a/sparkle/sparkles.py b/sparkle/sparkles.py deleted file mode 100644 index f5aa00c..0000000 --- a/sparkle/sparkles.py +++ /dev/null @@ -1,63 +0,0 @@ -import discord -from discord.ext import commands -from discord import app_commands -from .database import get_db -import asyncio - -class Sparkles(commands.Cog): - def __init__(self, bot): - self.bot = bot - self.sparkle_emojis = { - "epic": "💫", - "rare": "🌟", - "regular": "✨" - } - - @app_commands.command(name="sparkles", description="Check your sparkle count or another user's") - @app_commands.describe(user="The user to check sparkle count for (leave empty for yourself)") - async def sparkles(self, interaction:discord.Interaction, user: discord.User= None): - user= user or interaction.user - - def db_task(): - conn = get_db() - cursor = conn.execute( - """ - SELECT epic, rare, regular, - (epic + rare + regular) as total - FROM sparkles - WHERE server_id = ? AND user_id = ? - """, - (str(interaction.guild.id), str(user.id)) - ) - result = cursor.fetchone() - conn.close() - return result - - result = await asyncio.to_thread(db_task) - - if not result: - await interaction.response.send_message(f"{user.display_name} has no sparkles yet!", ephemeral=True) - return - - epic, rare, regular, total = result - - embed = discord.Embed( - title=f"{user.display_name}'s Sparkles", - color=discord.Color.gold() - ) - embed.set_thumbnail(url=user.display_avatar.url) - embed.add_field( - name="Totals", - value=( - f"{self.sparkle_emojis['epic']} **Epic:** {epic}\n" - f"{self.sparkle_emojis['rare']} **Rare:** {rare}\n" - f"{self.sparkle_emojis['regular']} **Regular:** {regular}\n" - f"**Total:** {total}" - ), - inline=False - ) - - await interaction.response.send_message(embed=embed) - -async def setup(bot): - await bot.add_cog(Sparkles(bot)) \ No newline at end of file