107 lines
3.5 KiB
Python
107 lines
3.5 KiB
Python
import logging
|
|
from discord.ext import commands
|
|
import os
|
|
import json
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
CONFIG_FILE = 'config.json'
|
|
REQUIRED_MESSAGES = ['upper_desc', 'footer', 'pfx_message']
|
|
|
|
class HelpCog(commands.Cog):
|
|
def __init__(self, bot: commands.Bot):
|
|
self.bot = bot
|
|
self.help_config = self._load_and_validate_config()
|
|
self.cogs_dir = os.path.join(
|
|
os.path.dirname(__file__),
|
|
self.help_config["settings"]["cogs_dir"]
|
|
)
|
|
|
|
def _load_and_validate_config(self) -> dict:
|
|
path = os.path.join(os.path.dirname(__file__), CONFIG_FILE)
|
|
|
|
if not os.path.exists(path):
|
|
raise FileNotFoundError(f"Help cog config not found at {path}")
|
|
|
|
with open(path, 'r', encoding='utf-8') as f:
|
|
config = json.load(f)
|
|
|
|
messages = config.get("messages", {})
|
|
missing_msgs = [key for key in REQUIRED_MESSAGES if key not in messages]
|
|
if missing_msgs:
|
|
raise KeyError(f"Help config 'messages' is missing required keys: {missing_msgs}")
|
|
|
|
settings = config.get("settings", {})
|
|
settings.setdefault("cogs_dir", "..")
|
|
settings.setdefault("column_width", 20)
|
|
settings.setdefault("command_pfx", "!")
|
|
|
|
config["messages"] = messages
|
|
config["settings"] = settings
|
|
|
|
logger.info("Help cog config loaded successfully")
|
|
return config
|
|
|
|
def _build_help_text(self, prefix: str) -> list[str]:
|
|
settings = self.help_config["settings"]
|
|
column_width = settings["column_width"]
|
|
lines = []
|
|
|
|
if not os.path.exists(self.cogs_dir):
|
|
logger.error(f"Cogs directory not found at: {self.cogs_dir}")
|
|
return lines
|
|
|
|
for item in sorted(os.listdir(self.cogs_dir)):
|
|
cog_dir = os.path.join(self.cogs_dir, item)
|
|
if not os.path.isdir(cog_dir):
|
|
continue
|
|
|
|
config_path = os.path.join(cog_dir, CONFIG_FILE)
|
|
if not os.path.exists(config_path):
|
|
continue
|
|
|
|
try:
|
|
with open(config_path, 'r', encoding='utf-8') as f:
|
|
cog_config = json.load(f)
|
|
except (json.JSONDecodeError, OSError) as e:
|
|
logger.warning(f"Failed to load config for cog '{item}': {e}")
|
|
continue
|
|
|
|
description = cog_config.get('description', '')
|
|
usages = cog_config.get('usages', [])
|
|
hidden = cog_config.get('hidden', False)
|
|
|
|
if not usages or hidden:
|
|
continue
|
|
|
|
for usage in usages:
|
|
usage_text = usage if usage.startswith(prefix) else f"{prefix}{usage}"
|
|
lines.append(f"{usage_text:<{column_width}} : {description}")
|
|
|
|
return lines
|
|
|
|
@commands.command(name="help")
|
|
async def help(self, ctx: commands.Context):
|
|
cfg_msgs = self.help_config["messages"]
|
|
cfg_sets = self.help_config["settings"]
|
|
|
|
prefix = ctx.prefix or cfg_sets['command_pfx']
|
|
lines = self._build_help_text(prefix)
|
|
|
|
if not lines:
|
|
await ctx.send("No commands available.")
|
|
return
|
|
|
|
help_text = (
|
|
f"{cfg_msgs['upper_desc']}\n"
|
|
f"```\n"
|
|
f"{chr(10).join(lines)}\n"
|
|
f"```\n"
|
|
f"{cfg_msgs['pfx_message']} `{cfg_sets['command_pfx']}`\n"
|
|
f"{cfg_msgs['footer']}"
|
|
)
|
|
|
|
await ctx.send(help_text)
|
|
|
|
async def setup(bot: commands.Bot):
|
|
await bot.add_cog(HelpCog(bot)) |