From 51393ece856508e8fb578e2c838e915f1f13fe16 Mon Sep 17 00:00:00 2001 From: neoarz Date: Sun, 28 Sep 2025 22:57:26 -0400 Subject: [PATCH] refactor(idevice): commands into a single GroupCog Merged idevice-related commands into a unified GroupCog in cogs/idevice/__init__.py, replacing individual Cog classes with command factory functions. Updated bot.py and help.py to support the new structure and improved command categorization. This refactor simplifies extension loading and command management for idevice troubleshooting features. --- bot.py | 2 +- cogs/help.py | 22 ++++-------- cogs/idevice/__init__.py | 59 +++++++++++++++++++++++++++++++ cogs/idevice/developermode.py | 13 +++---- cogs/idevice/error_codes.py | 65 ++++++++++++++--------------------- cogs/idevice/idevice.py | 14 +++----- cogs/idevice/mountddi.py | 20 ++++------- cogs/idevice/noapps.py | 13 +++---- 8 files changed, 110 insertions(+), 98 deletions(-) create mode 100644 cogs/idevice/__init__.py diff --git a/bot.py b/bot.py index fb9603e..54754d3 100644 --- a/bot.py +++ b/bot.py @@ -90,7 +90,7 @@ class DiscordBot(commands.Bot): if os.path.exists(init_file): try: await self.load_extension(f"cogs.{folder}") - if folder not in ["fun", "general"]: + if folder not in ["fun", "general", "idevice"]: self.logger.info(f"Loaded extension '{folder}'") except Exception as e: exception = f"{type(e).__name__}: {e}" diff --git a/cogs/help.py b/cogs/help.py index 1a687d0..ae4b4b2 100644 --- a/cogs/help.py +++ b/cogs/help.py @@ -38,17 +38,14 @@ class Help(commands.Cog, name="help"): category_mapping = { # General Commands - "help": "general", - "botinfo": "general", - "serverinfo": "general", - "ping": "general", - "feedback": "general", - "uptime": "general", - # "context_menus": "general", - + "general": "general", + # Fun Commands "fun": "fun", + # idevice Commands + "idevice": "idevice", + # Moderation Commands "kick": "moderation", "ban": "moderation", @@ -70,13 +67,6 @@ class Help(commands.Cog, name="help"): "afc": "sidestore", "udid": "sidestore", - # idevice Commands - "idevice": "idevice", - "noapps": "idevice", - "errorcodes": "idevice", - "developermode": "idevice", - "mountddi": "idevice", - # Owner Commands "sync": "owner", "cog_management": "owner", @@ -180,7 +170,7 @@ class Help(commands.Cog, name="help"): commands_in_category.append((app_command.name, description)) seen_names.add(app_command.name) - if hasattr(app_command, 'commands') and category == "fun": + if hasattr(app_command, 'commands') and category in ["fun", "general", "idevice"]: for subcommand in app_command.commands: if subcommand.name in seen_names: continue diff --git a/cogs/idevice/__init__.py b/cogs/idevice/__init__.py new file mode 100644 index 0000000..3bdda61 --- /dev/null +++ b/cogs/idevice/__init__.py @@ -0,0 +1,59 @@ +import discord +from discord.ext import commands +from discord.ext.commands import Context + +from .idevice import idevice_command +from .error_codes import errorcodes_command +from .developermode import developermode_command +from .noapps import noapps_command +from .mountddi import mountddi_command + +class Idevice(commands.GroupCog, name="idevice"): + def __init__(self, bot) -> None: + self.bot = bot + super().__init__() + + @commands.hybrid_command( + name="idevice", + description="Get help with idevice commands and troubleshooting." + ) + async def idevice(self, context): + return await idevice_command()(self, context) + + @commands.hybrid_command( + name="errorcodes", + description="Look up error codes and their meanings." + ) + async def errorcodes(self, context, *, error_code: str = None): + return await errorcodes_command()(self, context, error_code=error_code) + + @commands.hybrid_command( + name="developermode", + description="How to turn on developer mode" + ) + async def developermode(self, context): + return await developermode_command()(self, context) + + @commands.hybrid_command( + name="noapps", + description="Help when apps aren't showing in installed apps view" + ) + async def noapps(self, context): + return await noapps_command()(self, context) + + @commands.hybrid_command( + name="mountddi", + description="How to manually mount DDI" + ) + async def mountddi(self, context): + return await mountddi_command()(self, context) + +async def setup(bot) -> None: + cog = Idevice(bot) + await bot.add_cog(cog) + + bot.logger.info("Loaded extension 'idevice.idevice'") + bot.logger.info("Loaded extension 'idevice.errorcodes'") + bot.logger.info("Loaded extension 'idevice.developermode'") + bot.logger.info("Loaded extension 'idevice.noapps'") + bot.logger.info("Loaded extension 'idevice.mountddi'") diff --git a/cogs/idevice/developermode.py b/cogs/idevice/developermode.py index 1be3ba7..aad0595 100644 --- a/cogs/idevice/developermode.py +++ b/cogs/idevice/developermode.py @@ -5,14 +5,11 @@ from discord.ext.commands import Context import time -class Developermode(commands.Cog, name="developermode"): - def __init__(self, bot) -> None: - self.bot = bot - +def developermode_command(): @commands.hybrid_command( name="developermode", description="How to turn on developer mode" ) - async def developermode(self, context: Context) -> None: + async def developermode(self, context): embed = discord.Embed( color=0xfa8c4a, description=( @@ -40,7 +37,5 @@ class Developermode(commands.Cog, name="developermode"): await context.interaction.response.send_message(embed=embed, view=view) else: await context.send(embed=embed, view=view) - - -async def setup(bot) -> None: - await bot.add_cog(Developermode(bot)) + + return developermode diff --git a/cogs/idevice/error_codes.py b/cogs/idevice/error_codes.py index cc616f2..0a1560f 100644 --- a/cogs/idevice/error_codes.py +++ b/cogs/idevice/error_codes.py @@ -6,54 +6,41 @@ from discord.ext import commands from discord.ext.commands import Context -class ErrorCodes(commands.Cog, name="errorcodes"): - def __init__(self, bot) -> None: - self.bot = bot - self.errors = self.load_errors() - self.key_to_data = {error['name']: (error['description'], error['code']) for error in self.errors} - self.code_to_key = {error['code']: error['name'] for error in self.errors} - - def load_errors(self): - json_path = os.path.join(os.path.dirname(__file__), 'files/errorcodes.json') - try: - with open(json_path, 'r', encoding='utf-8') as f: - return json.load(f) - except FileNotFoundError: - self.bot.logger.error(f"Error codes JSON file not found: {json_path}") - return [] - except json.JSONDecodeError as e: - self.bot.logger.error(f"Error parsing error codes JSON: {e}") - return [] - - async def errorcode_autocomplete(self, interaction: discord.Interaction, current: str): - current_lower = current.lower() - items = [] - for key, (title, code) in self.key_to_data.items(): - if not current or current_lower in key.lower() or current_lower in title.lower() or current_lower in str(code): - items.append(app_commands.Choice(name=f"{key} ยป {title} ({code})", value=key)) - if len(items) >= 25: - break - return items - - @commands.hybrid_command(name="errorcode", description="Look up an idevice error code by name or number") +def errorcodes_command(): + @commands.hybrid_command(name="errorcodes", description="Look up an idevice error code by name or number") @app_commands.describe(name="Start typing to search all error names and codes") - @app_commands.autocomplete(name=errorcode_autocomplete) - async def errorcode(self, context: Context, name: str): + async def errorcodes(self, context, name: str): + def load_errors(): + json_path = os.path.join(os.path.dirname(__file__), 'files/errorcodes.json') + try: + with open(json_path, 'r', encoding='utf-8') as f: + return json.load(f) + except FileNotFoundError: + self.bot.logger.error(f"Error codes JSON file not found: {json_path}") + return [] + except json.JSONDecodeError as e: + self.bot.logger.error(f"Error parsing error codes JSON: {e}") + return [] + + errors = load_errors() + key_to_data = {error['name']: (error['description'], error['code']) for error in errors} + code_to_key = {error['code']: error['name'] for error in errors} + key = name - if key not in self.key_to_data: + if key not in key_to_data: try: num = int(name) - key = self.code_to_key.get(num) + key = code_to_key.get(num) except ValueError: key = None - if key is None or key not in self.key_to_data: + if key is None or key not in key_to_data: if context.interaction: await context.interaction.response.send_message("Error not found.", ephemeral=True) else: await context.send("Error not found.") return - title, code = self.key_to_data[key] + title, code = key_to_data[key] embed = discord.Embed( description=f"## Error Code: {code}\n\n**Name**: `{key}`\n**Description**: {title}", @@ -73,9 +60,7 @@ class ErrorCodes(commands.Cog, name="errorcodes"): await context.interaction.response.send_message(embed=embed, view=view) else: await context.send(embed=embed, view=view) - -async def setup(bot) -> None: - cog = ErrorCodes(bot) - await bot.add_cog(cog) + + return errorcodes diff --git a/cogs/idevice/idevice.py b/cogs/idevice/idevice.py index 75c8390..44caa79 100644 --- a/cogs/idevice/idevice.py +++ b/cogs/idevice/idevice.py @@ -253,14 +253,11 @@ class ideviceView(discord.ui.View): self.add_item(ideviceSelect(bot)) -class idevice(commands.Cog, name="idevice"): - def __init__(self, bot) -> None: - self.bot = bot - +def idevice_command(): @commands.hybrid_command( name="idevice", description="idevice troubleshooting and help" ) - async def idevice(self, context: Context) -> None: + async def idevice(self, context): embed = discord.Embed( title="idevice Commands", description="Choose a command from the dropdown below to get help with specific issues:", @@ -274,8 +271,5 @@ class idevice(commands.Cog, name="idevice"): await context.interaction.response.send_message(embed=embed, view=view, ephemeral=True) else: await context.send(embed=embed, view=view) - - - -async def setup(bot) -> None: - await bot.add_cog(idevice(bot)) \ No newline at end of file + + return idevice \ No newline at end of file diff --git a/cogs/idevice/mountddi.py b/cogs/idevice/mountddi.py index adebf13..505b808 100644 --- a/cogs/idevice/mountddi.py +++ b/cogs/idevice/mountddi.py @@ -4,16 +4,13 @@ from discord.ext.commands import Context import os -class Mountddi(commands.Cog, name="mountddi"): - def __init__(self, bot) -> None: - self.bot = bot - +def mountddi_command(): @commands.hybrid_command( name="mountddi", description="How to manually mount DDI" ) - async def mountddi(self, ctx: Context) -> None: - await ctx.defer() + async def mountddi(self, context): + await context.defer() embed = discord.Embed( color=0xfa8c4a, @@ -46,15 +43,12 @@ class Mountddi(commands.Cog, name="mountddi"): emoji="<:githubicon:1417717356846776340>" )) - ddi_file_path = os.path.join(os.path.dirname(__file__), 'files/DDI.zip') file = discord.File(ddi_file_path, filename='DDI.zip') if os.path.exists(ddi_file_path) else None if file: - await ctx.send(embed=embed, view=view, file=file) + await context.send(embed=embed, view=view, file=file) else: - await ctx.send(embed=embed, view=view) - - -async def setup(bot) -> None: - await bot.add_cog(Mountddi(bot)) + await context.send(embed=embed, view=view) + + return mountddi diff --git a/cogs/idevice/noapps.py b/cogs/idevice/noapps.py index 2e54b72..386c27b 100644 --- a/cogs/idevice/noapps.py +++ b/cogs/idevice/noapps.py @@ -5,14 +5,11 @@ from discord.ext.commands import Context import time -class Noapps(commands.Cog, name="noapps"): - def __init__(self, bot) -> None: - self.bot = bot - +def noapps_command(): @commands.hybrid_command( name="noapps", description="Help when apps aren't showing in installed apps view" ) - async def noapps(self, context: Context) -> None: + async def noapps(self, context): embed = discord.Embed( color=0xfa8c4a, description=( @@ -41,7 +38,5 @@ class Noapps(commands.Cog, name="noapps"): await context.interaction.response.send_message(embed=embed, view=view) else: await context.send(embed=embed, view=view) - - -async def setup(bot) -> None: - await bot.add_cog(Noapps(bot)) + + return noapps