diff --git a/src/pluralkit/bot/commands/__init__.py b/src/pluralkit/bot/commands/__init__.py index d1635c0e..c8583cbd 100644 --- a/src/pluralkit/bot/commands/__init__.py +++ b/src/pluralkit/bot/commands/__init__.py @@ -205,8 +205,10 @@ async def command_root(ctx: CommandContext): await misc_commands.pkfreeze(ctx) elif ctx.match("starstorm"): await misc_commands.pkstarstorm(ctx) + elif ctx.match("commands"): + await misc_commands.command_list(ctx) else: - raise CommandError("Unknown command {}. For a list of commands, type `pk;help commands`.".format(ctx.pop_str())) + raise CommandError("Unknown command {}. For a list of commands, type `pk;commands`.".format(ctx.pop_str())) async def run_command(ctx: CommandContext, func): diff --git a/src/pluralkit/bot/commands/misc_commands.py b/src/pluralkit/bot/commands/misc_commands.py index d8ab6fab..a2259a33 100644 --- a/src/pluralkit/bot/commands/misc_commands.py +++ b/src/pluralkit/bot/commands/misc_commands.py @@ -7,19 +7,81 @@ from pluralkit.bot import help from pluralkit.bot.commands import * from pluralkit.bot.embeds import help_footer_embed +prefix = "pk;" # TODO: configurable + +def make_footer_embed(): + embed = discord.Embed() + embed.set_footer(text=help.helpfile["footer"]) + return embed + +def make_command_embed(command): + embed = make_footer_embed() + embed.title = prefix + command["usage"] + embed.description = (command["description"] + "\n" + command.get("longdesc", "")).strip() + embed.add_field(name="Usage", value=prefix + command["usage"], inline=False) + if "examples" in command: + embed.add_field(name="Examples" if len(command["examples"]) > 1 else "Example", value="\n".join([prefix + cmd for cmd in command["examples"]]), inline=False) + if "subcommands" in command: + embed.add_field(name="Subcommands", value="\n".join([command["name"] + " " + sc["name"] for sc in command["subcommands"]]), inline=False) + return embed + +def find_command(command_list, name): + for command in command_list: + if command["name"].lower().strip() == name.lower().strip(): + return command async def help_root(ctx: CommandContext): - if ctx.match("commands"): - await ctx.reply(help.all_commands, embed=help_footer_embed()) - elif ctx.match("proxy"): - await ctx.reply(help.proxy_guide, embed=help_footer_embed()) - elif ctx.match("system"): - await ctx.reply(help.system_commands, embed=help_footer_embed()) - elif ctx.match("member"): - await ctx.reply(help.member_commands + "\n\n" + help.command_notes, embed=help_footer_embed()) - else: - await ctx.reply(help.root, embed=help_footer_embed()) + for page_name, page_content in help.helpfile["pages"].items(): + if ctx.match(page_name): + return await help_page(ctx, page_content) + + if not ctx.has_next(): + return await help_page(ctx, help.helpfile["pages"]["root"]) + return await help_command(ctx, ctx.remaining()) + +async def help_page(ctx, sections): + msg = "" + for section in sections: + msg += "__**{}**__\n{}\n\n".format(section["name"], section["content"]) + + return await ctx.reply(content=msg, embed=make_footer_embed()) + +async def help_command(ctx, command_name): + name_parts = command_name.replace(prefix, "").split(" ") + command = find_command(help.helpfile["commands"], name_parts[0]) + name_parts = name_parts[1:] + if not command: + raise CommandError("Could not find command '{}'.".format(command_name)) + while len(name_parts) > 0: + found_command = find_command(command["subcommands"], name_parts[0]) + if not found_command: + break + command = found_command + name_parts = name_parts[1:] + + return await ctx.reply(embed=make_command_embed(command)) + +async def command_list(ctx): + cmds = [] + + categories = {} + def make_command_list(lst): + for cmd in lst: + if not cmd["category"] in categories: + categories[cmd["category"]] = [] + categories[cmd["category"]].append("**{}{}** - {}".format(prefix, cmd["usage"], cmd["description"])) + if "subcommands" in cmd: + make_command_list(cmd["subcommands"]) + make_command_list(help.helpfile["commands"]) + + embed = discord.Embed() + embed.title = "PluralKit Commands" + embed.description = "Type `pk;help ` for more information." + for cat_name, cat_cmds in categories.items(): + embed.add_field(name=cat_name, value="\n".join(cat_cmds)) + await ctx.reply(embed=embed) + async def invite_link(ctx: CommandContext): client_id = (await ctx.client.application_info()).id diff --git a/src/pluralkit/bot/help.json b/src/pluralkit/bot/help.json new file mode 100644 index 00000000..0a22ab55 --- /dev/null +++ b/src/pluralkit/bot/help.json @@ -0,0 +1,309 @@ +{ + "commands": [ + { + "name": "system", + "usage": "system [id]", + "description": "Shows information about a system.", + "longdesc": "The given ID can either be a 5-character ID, a Discord account @mention, or a Discord account ID. Leave blank to show your own system.", + "examples": ["system", "system abcde", "system @Foo#1234", "system 102083498529026048"], + "category": "System", + "subcommands": [ + { + "name": "new", + "usage": "system new [name]", + "category": "System", + "description": "Creates a new system registered to your account." + }, + { + "name": "name", + "usage": "system name [name]", + "category": "System", + "description": "Changes the name of your system." + }, + { + "name": "description", + "usage": "system description [description]", + "category": "System", + "description": "Changes the description of your system." + }, + { + "name": "avatar", + "usage": "system avatar [avatar url]", + "category": "System", + "description": "Changes the avatar of your system.", + "longdesc": "**NB:** Avatar URLs must be a *direct* link to an image (ending in .jpg, .gif or .png), AND must be under the size of 1000x1000 (in both dimensions), AND must be smaller than 1 MB. If the avatar doesn't show up properly, it is likely one or more of these rules aren't followed. If you need somewhere to host an image, you can upload it to Discord or Imgur and copy the *direct* link from there.", + "examples": ["system avatar https://i.imgur.com/HmK2Wgo.png"] + }, + { + "name": "tag", + "usage": "system tag [tag]", + "category": "System", + "description": "Changes the system tag of your system.", + "longdesc": "The system tag is a snippet of text added to the end of your member's names when proxying. Many servers require the use of a system tag for identification. Leave blank to clear.\n\n**NB:** You may use standard Discord emojis, but server/Nitro emojis won't work.", + "examples": ["system tag |ABC", "system tag ๐Ÿ’ฎ", "system tag"] + }, + { + "name": "timezone", + "usage": "system timezone [location]", + "category": "System", + "description": "Changes the time zone of your system.", + "longdesc": "This affects all dates or times displayed in PluralKit. Leave blank to clear.\n\n**NB:** You need to specify a location (eg. the nearest major city to you). This allows PluralKit to dynamically adjust for time zone or DST changes.", + "examples": ["system timezone New York", "system timezone Wichita Falls", "system timezone"] + }, + { + "name": "delete", + "usage": "system delete", + "category": "System", + "description": "Deletes your system.", + "longdesc": "The command will ask for confirmation.\n\n**This is irreversible, and will delete all information associated with your system, members, proxied messages, and accounts.**" + }, + { + "name": "fronter", + "usage": "system [id] fronter", + "category": "System", + "description": "Shows the current fronter of a system." + }, + { + "name": "fronthistory", + "usage": "system [id] fronthistory", + "category": "System", + "description": "Shows the last 10 switches of a system." + }, + { + "name": "frontpercent", + "usage": "system [id] fronthistory [timeframe]", + "category": "System", + "description": "Shows the aggregated front history of a system within a given time frame.", + "longdesc": "Percentages may add up to over 100% when multiple members cofront. Time frame will default to 1 month.", + "examples": ["system fronthistory 1 month", "system fronthistory 2 weeks", "system @Foo#1234 fronthistory 4 days"] + }, + { + "name": "list", + "usage": "system [id] list", + "category": "System", + "description": "Shows a paginated list of a system's members." + } + ] + }, + { + "name": "link", + "usage": "link ", + "category": "System", + "description": "Links this system to a different account.", + "longdesc": "This means you can manage the system from both accounts. The other account will need to verify the link by reacting to a message.", + "examples": ["link @Foo#1234", "link 102083498529026048"] + }, + { + "name": "unlink", + "usage": "unlink", + "category": "System", + "description": "Unlinks this account from its system.", + "longdesc": "You can't unlink the only account in a system." + }, + { + "name": "member", + "usage": "member ", + "category": "Member", + "description": "Shows information about a member.", + "longdesc": "The given member name can either be the name of a member in your own system or a 5-character member ID (in any system).", + "examples": ["member John", "member abcde"], + "subcommands": [ + { + "name": "rename", + "usage": "member rename ", + "category": "Member", + "description": "Changes the name of a member.", + "examples": ["member Jack rename Jill"] + }, + { + "name": "description", + "usage": "member description [description]", + "category": "Member", + "description": "Changes the description of a member.", + "examples": ["member Jack description Very cool guy."] + }, + { + "name": "avatar", + "usage": "member avatar [avatarurl]", + "category": "Member", + "description": "Changes the avatar of a member.", + "longdesc": "**NB:** Avatar URLs must be a *direct* link to an image (ending in .jpg, .gif or .png), AND must be under the size of 1000x1000 (in both dimensions), AND must be smaller than 1 MB. If the avatar doesn't show up properly, it is likely one or more of these rules aren't followed. If you need somewhere to host an image, you can upload it to Discord or Imgur and copy the *direct* link from there.", + "examples": ["member Jack avatar https://i.imgur.com/HmK2Wgo.png"] + }, + { + "name": "proxy", + "usage": "member proxy [tags]", + "category": "Member", + "description": "Changes the proxy tags of a member.", + "longdesc": "The proxy tags describe how to proxy this member through Discord. You must pass an \"example proxy\" of the word \"text\", ie. how you'd proxy the word \"text\". For example, if you want square brackets for this member, pass `[text]`. Emojis are allowed.", + "examples": ["member Jack proxy [text]", "member Jill proxy J:text", "member Jones proxy ๐Ÿ’text"] + }, + { + "name": "pronouns", + "usage": "member pronouns [pronouns]", + "category": "Member", + "description": "Changes the pronouns of a member.", + "longdesc": "These will be displayed on their profile. This is a free text field, put whatever you'd like :)", + "examples": ["member Jack pronouns he/him", "member Jill pronouns she/her or they/them", "member Jones pronouns use whatever lol"] + }, + { + "name": "color", + "usage": "member color [color]", + "category": "Member", + "description": "Changes the color of a member.", + "longdesc": "This will displayed on their profile. Colors must be in hex format (eg. #ff0000).\n\n**NB:** Due to a Discord limitation, the colors don't affect proxied message names.", + "examples": ["member Jack color #ff0000", "member Jill color #abcdef"] + }, + { + "name": "birthday", + "usage": "member birthday [birthday]", + "category": "Member", + "description": "Changes the birthday of a member.", + "longdesc": "This must be in YYYY-MM-DD format, or just MM-DD if you don't want to specify a year.", + "examples": ["member Jack birthday 1997-03-27", "member Jill birthday 2018-01-03", "member Jones birthday 12-21"] + }, + { + "name": "delete", + "usage": "member delete", + "category": "Member", + "description": "Deletes a member.", + "longdesc": "This command will ask for confirmation.\n\n**This is irreversible, and will delete all data associated with this member.**" + } + ] + }, + { + "name": "switch", + "usage": "switch [member...]", + "category": "Switching", + "description": "Registers a switch with the given members.", + "longdesc": "You may specify multiple members to indicate cofronting.", + "examples": ["switch Jack", "switch Jack Jill"], + "subcommands": [ + { + "name": "move", + "usage": "switch move