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.
This commit is contained in:
neoarz
2025-09-28 22:57:26 -04:00
parent 72cdd9b403
commit 51393ece85
8 changed files with 110 additions and 98 deletions

2
bot.py
View File

@@ -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}"

View File

@@ -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

59
cogs/idevice/__init__.py Normal file
View File

@@ -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'")

View File

@@ -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

View File

@@ -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

View File

@@ -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))
return idevice

View File

@@ -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

View File

@@ -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