Exemplo n.º 1
0
    async def code(self, ctx):
        """
        code command

        Parameters
        ------------
        ctx : discord.context
            The message context object
        """
        try:
            (arguments, message) = parse.args(ctx.message.content)

            # Explain all the arguments to the user
            if "help" in arguments or (len(message) == 0
                                       and len(arguments) == 0):
                title = "!code - User Guide"
                description = (
                    "Remote code execution. Allows users to write code and submit it to the bot for "
                    +
                    "remote execution, after which the bot prints out the results, any error codes, "
                    +
                    "the execution time, and memory consumption. The command supports 65 different "
                    +
                    "languages, including Java, Python 2/3, PHP, Swift, C++, Rust, and Go.\n\nTo invoke "
                    +
                    "execution, include a block of code using the multi-line Discord code format "
                    +
                    "( https://support.discordapp.com/hc/en-us/articles/210298617-Markdown-Text-101-Chat-"
                    +
                    "Formatting-Bold-Italic-Underline- ). To use this formatting, use three backticks "
                    +
                    "(`, the key above the tab key), followed immediately (no spaces!) by the language "
                    +
                    "tag, followed by a linebreak, followed by your code. Close off the code block with "
                    +
                    "three more backticks. It's a little complicated, I apologize. It's Discord's "
                    +
                    "formatting rules, not mine.\n\n**Be advised**\nRemote execution will time out after "
                    +
                    "5 seconds and does not support external libraries or access to the internet."
                )

                helpdict = {
                    "-help":
                    "Shows this user guide",
                    "-full":
                    "Shows the full list of supported languages",
                    "-lang":
                    "Shows the common languages supported by this command",
                }
                await self.bot.say(embed=utils.embedfromdict(
                    helpdict,
                    title=title,
                    description=description,
                    thumbnail_url=COMMAND_THUMBNAILS["code"]))
                return

            if "ls" in arguments or "full" in arguments:
                message = "`Name` (`compiler version`) - `tag`\n---------"
                for langname in self.langs.keys():
                    name = self.langs[langname][0]  # Name
                    message += "\n**" + name + "** : " + langname
                if "full" in arguments:
                    message += "\n---------"
                    for langname in self.esolangs.keys():
                        name = self.esolangs[langname][0]  # Name
                        message += "\n**" + name + "** : " + langname
                await self.bot.say(utils.trimtolength(message, 2000))
                return

            if "dev" in arguments:
                [json, resp_code
                 ] = await utils.get_json_with_post(url=self.credits_check_url,
                                                    json={
                                                        "clientId":
                                                        self.JDOODLE_ID,
                                                        "clientSecret":
                                                        self.JDOODLE_SECRET
                                                    })
                if resp_code != 200:
                    await utils.report(self.bot,
                                       "Failed to check credits\n" + str(json),
                                       source="!code dev",
                                       ctx=ctx)
                    return
                if "used" not in json.keys():
                    await utils.report(
                        self.bot,
                        json,
                        "Failed to get credit count for JDOODLE account",
                        ctx=ctx)
                    await self.bot.say(
                        "Forces external to your request have caused this command to fail."
                    )
                    return
                await self.bot.say(json['used'])
                return

            if "```" in message:
                trimmedmessage = message[message.find("```") + 3:]
                if "```" in trimmedmessage:
                    trimmedmessage = trimmedmessage[:trimmedmessage.find("```"
                                                                         )]
                    splitmessage = trimmedmessage.split("\n", maxsplit=1)
                    if len(trimmedmessage) == 0:
                        await self.bot.say(
                            "You need to put code inside the backticks")
                        return
                    if trimmedmessage[0] not in [" ", "\n"
                                                 ] and len(splitmessage) > 1:
                        [language, script] = splitmessage
                        language = language.strip()
                        for key in self.esolangs.keys():
                            self.langs[key] = self.esolangs[key]
                        if language.lower() in self.langs.keys():
                            response = await utils.get_json_with_post(
                                url=self.execute_url,
                                json={
                                    "clientId": self.JDOODLE_ID,
                                    "clientSecret": self.JDOODLE_SECRET,
                                    "script": script,
                                    "language":
                                    self.langs[language.lower()][1],
                                    "versionIndex":
                                    self.langs[language.lower()][2]
                                })
                            [json, resp_code] = response
                            if resp_code == 429:
                                await utils.report(
                                    self.bot,
                                    json,
                                    "Bot has reached its JDOODLE execution limit",
                                    ctx=ctx)
                                await self.bot.say(
                                    "The bot has reached its code execution limit for the day."
                                )
                                return
                            output_embed = Embed()
                            if "error" in json.keys():
                                output_embed.description = json['error']
                                output_embed.title = "ERROR"
                                output_embed.colour = EMBED_COLORS["error"]
                                await self.bot.say(embed=output_embed)
                                return
                            output_embed.title = "Output"
                            output_embed.colour = EMBED_COLORS["code"]
                            output_embed.add_field(name="CPU Time",
                                                   value=str(json['cpuTime']) +
                                                   " seconds")
                            output_embed.add_field(name="Memory Usage",
                                                   value=json['memory'])
                            if len(json['output']) > 2046:
                                output_embed.description = "``` " + utils.trimtolength(
                                    json['output'], 2040) + "```"
                            else:
                                output_embed.description = "``` " + json[
                                    'output'] + "```"
                            await self.bot.say(embed=output_embed)
                        else:
                            await self.bot.say(
                                "I don't know the language '" + language +
                                "'. Type `!code -full` " +
                                "to see the list of languages I support, or type `!code -ls` to see "
                                + "the most popular ones")
                    else:
                        await self.bot.say(
                            "There was no language tag. Remember to include the language tag "
                            +
                            "immediately after the opening backticks. Type `!code -ls` or "
                            + "`!code -full` to find your language's tag")
                else:
                    await self.bot.say("You didn't close your triple backticks"
                                       )
            else:
                await self.bot.say("I don't see any code")
        except Exception as e:
            await utils.report(self.bot,
                               str(e),
                               source="!code command",
                               ctx=ctx)
Exemplo n.º 2
0
    async def tag(self, ctx):
        """
        Tag command

        Parameters
        ------------
        ctx : discord.context
            The message context object
        """
        try:
            # -------------------------------- SET-UP

            # Makes the apostrophe types consistent
            # (See function documentation for explanation)
            parsed_ctx = parse.apos(ctx.message.content)
            # Parses CLI arguments
            (arguments, message) = parse.args(parsed_ctx)

            # -------------------------------- ARGUMENTS

            # Acting on arguments
            if "help" in arguments or (len(message) == 0 and len(arguments) == 0):
                title = "!tag - User Guide"
                description = (
                            "Bot call and response. Allows the user to pair a message or attached image with a tag. " +
                            "These tags can then be used to have the bot respond with the associated content. By " +
                            "default, these tags are server wide, but by using the user list argument (`-u`, e.g. " +
                            "`!tag -u [base] All your base are belong to us`) the user can specify personal tags. " +
                            "This allows a user to store a different value for a key than the server value and to " +
                            "make tags that will be available for that user across servers and in DMs.")
                helpdict = {
                    "-ap [<key>] <value>": "If the tag entered already exists, the " +
                                           "new text will be appended to the end after a space",
                    "-apnl [<key>] <value>": "If the tag entered already exists, " +
                                             "the new text will be appended to the end after a line break",
                    "-edit [<key>] <value>": "If the tag entered already exists, " +
                                             "the existing tag will be overwritten",
                    "-help": "Show this guide",
                    "-ls": "Lists the tags within the selected group. Overrides any " +
                           "other argument",
                    "-rm <key>": "removes a tag from the group",
                    "-u": "Selects your specific tag group instead of the server " +
                          "tags for the following command"}
                await self.bot.say(embed=utils.embedfromdict(helpdict,
                                                             title=title,
                                                             description=description,
                                                             thumbnail_url=COMMAND_THUMBNAILS["tag"]))
                return

            # Rejects ambiguous argument pairs
            if "rm" in arguments and "edit" in arguments:
                await self.bot.say("`-rm` and `-edit` are incompatible arguments")
                return
            elif ("apnl" in arguments or "ap" in arguments) and ("edit" in arguments or "rm" in arguments):
                await self.bot.say("`ap` or `apnl` are incompatible with the arguments `-rm` or `-edit`")
                return
            elif "ap" in arguments and "apnl" in arguments:
                await self.bot.say("`-ap` and `-apnl` is an ambiguous argument pair")
                return

            # flag for if the user is overwriting an existing tag
            edit = False
            # flag for if the user is appending to an existing tag
            append = False
            # flag for if the user wants a line break before their append is added
            newline = False
            # String specifying tag domain
            domain = "server"

            if ctx.message.server is None or "u" in arguments:
                domain = "user"
                # MySQL parameter to specify owner of the tag
                tagowner = ctx.message.author.id
                # if user does not have a user tag group
                if ctx.message.author.id not in self.tags["user"].keys():
                    # Creates a user tag group
                    self.tags["user"][ctx.message.author.id] = {}
                # Changes the selected tag group to the user's tags
                selected_tags = self.tags["user"][ctx.message.author.id]
            else:
                # Selecting tag group (default is 'server')
                if ctx.message.server.id not in self.tags["server"].keys():
                    self.tags["server"][ctx.message.server.id] = {}
                # Gets domain tag group
                selected_tags = self.tags["server"][ctx.message.server.id]
                # MySQL parameter to specify owner of the tag
                tagowner = ctx.message.server.id

            # Adds global tags to server tag group
            for key in self.tags["global"].keys():
                selected_tags[key] = self.tags["global"][key]

            # List the saved tags in the selected tag group
            if "ls" in arguments:
                taglist = ""
                for tagkey in sorted(selected_tags.keys()):
                    if tagkey in self.tags["global"].keys():
                        taglist += ", `" + tagkey + "`"
                    else:
                        taglist += ", " + tagkey
                if taglist == "":
                    if domain == "user":
                        await self.bot.say("You do not have any saved tags")
                    else:
                        await self.bot.say("This server does not have any saved tags")
                    return
                taglist = taglist[2:]  # pulls the extraneous comma off
                await self.bot.say("**The tags I know are**\n" + taglist + "")
                return

            # Reject empty messages (`-ls` calls have already been handled)
            if len(message) == 0:
                await self.bot.say("I see some arguments `` " + str(arguments) +
                                   " ``, but no key or value to work with :/")
                return

            # Deletes a saved tag
            if "rm" in arguments:
                key = message.lower()
                if key in selected_tags.keys():
                    del selected_tags[key]
                    await self.bot.say("Okay. I deleted it")
                    self.update_tag_remove(key, tagowner, domain)
                else:  # If that tag didn't exist
                    await self.bot.say("Hmmm, that's funny. I didn't see the tag `` " + message +
                                       " `` in the saved tags list.")
                return

            # ------ Set or Get ------

            # Check for modification flags
            if any(edit_arg in arguments for edit_arg in ["edit", "apnl", "ap"]):
                edit = True  # Allows modification of existing tag
            if any(append_arg in arguments for append_arg in ["apnl", "ap"]):
                append = True  # Adds new text to end of existing tag
            if "apnl" in arguments:
                newline = True  # Adds a new line before appending text

            # Setting
            if message[0] is "[":
                tag_keyvalue = parse.key_value(message, ctx.message.attachments)
                if tag_keyvalue[0] is None:
                    error_messages = {"EMPTY KEY": "There was no key to store",
                                      "UNCLOSED KEY": "You didn't close your brackets",
                                      "NO VALUE": "There was no text to save for the key provided",
                                      "WHITESPACE KEY": "Just because this bot is written in Python " +
                                                        "does not mean whitespace is an acceptable tag",
                                      "KEY STARTS WITH -": "The `-` character denotes the start of " +
                                                           "an argument and cannot be used in tag keys"}
                    await self.bot.say(error_messages[tag_keyvalue[1]])
                    return
                else:
                    tagkey = tag_keyvalue[0].lower()
                    tagvalue = tag_keyvalue[1]
                    if tagkey in selected_tags.keys():
                        if tagkey in self.tags["global"].keys():
                            await self.bot.say(
                                "I'm sorry, but the key `` " + tagkey +
                                " `` has already been reserved for a global tag")
                            return
                        elif edit is False:
                            await self.bot.say("I already have a value stored for the tag `` " + tagkey +
                                               " ``. Add `-edit` to overwrite existing  self.tags")
                            return
                        elif append is True:
                            if newline is True:
                                selected_tags[tagkey] = selected_tags[tagkey] + "\n" + tagvalue
                            else:
                                selected_tags[tagkey] = selected_tags[tagkey] + " " + tagvalue
                            self.update_tag_edit(tagkey, selected_tags[tagkey], tagowner, domain)
                            await self.bot.say("Edited!")
                            return
                        else:
                            selected_tags[tagkey] = tagvalue
                            self.update_tag_edit(tagkey, tagvalue, tagowner, domain)
                            await self.bot.say("Edited!")
                            return
                    selected_tags[tagkey] = tagvalue
                    self.update_tag_add(tagkey, tagvalue, tagowner, domain)
                    await self.bot.say("Saved!")
            # Getting
            else:
                key = message.lower()
                if key in selected_tags.keys():
                    await self.bot.say(utils.trimtolength(selected_tags[key], 2000))
                elif domain == "user":
                    await self.bot.say("I don't think I have a tag `" + key +
                                       "` stored for you. Type `!tag -u -ls` to see the  self.tags I have " +
                                       "saved for you")
                else:
                    await self.bot.say("I don't think I have a tag `" + key + "`. Type `!tag -ls` to see the tags " +
                                       "I have saved for this server")
        except Exception as e:
            await utils.report(self.bot, str(e), source="Tag command", ctx=ctx)
Exemplo n.º 3
0
async def dev(ctx):
    global currently_playing
    try:
        if ctx.message.author.id not in AUTHORIZED_IDS:
            await bot.say("You are not authorized to use these commands")
            return

        [func, parameter] = parse.func_param(ctx.message.content)

        if func in ["help", ""]:
            title = "`!dev` User Guide"
            description = "A list of features useful for "
            helpdict = {
                "channelid":
                "Posts the ID of the current channel",
                "colton":
                "Check the `!colton` data",
                "dump":
                "A debug command for the bot to dump a variable into chat",
                "flag":
                "Tests the `flag` function",
                "load":
                "Loads an extension",
                "playing":
                "Sets the presence of the bot (what the bot says it's currently playing)",
                "reload":
                "Reloads an extension",
                "report":
                "Tests the `report` function",
                "serverid":
                "Posts the ID of the current channel",
                "swears":
                "Find out who swears the most",
                "test":
                "A catch-all command for inserting code into the bot to test",
            }
            await bot.say("`!dev` User Guide",
                          embed=embedfromdict(helpdict,
                                              title=title,
                                              description=description))

        elif func == "channelid":
            await bot.say("Channel ID: " + ctx.message.channel.id)

        elif func == "colton":
            await bot.say(
                "Colton has mentioned being forever alone {} times.\n"
                "The last time he mentioned being forever alone was **{}**".
                format(total_colton, last_colton.strftime("%c")))

        elif func == "dump":
            await bot.say("AT THE DUMP")

        elif func == "flag":
            await bot.say("Triggering flag...")
            await utils.flag(bot,
                             "Test",
                             description="This is a test of the flag ability",
                             ctx=ctx)

        elif func == "load":
            """Loads an extension."""
            try:
                bot.load_extension("cogs." + parameter)
            except (AttributeError, ImportError) as e:
                await utils.report(bot,
                                   "```py\n{}: {}\n```".format(
                                       type(e).__name__, str(e)),
                                   source="Loading extension (!dev)",
                                   ctx=ctx)
                return
            await bot.say("`` {} `` loaded.".format(parameter))

        elif func == "nick":
            try:
                if ctx.message.server is None:
                    await bot.say("I can't do that here")
                    return
                newnick = parameter
                if newnick == "":
                    newnick = None
                botmember = ctx.message.server.get_member(
                    "340287898433748993")  # Gets the bot's own member object
                await bot.change_nickname(botmember, newnick)
            except Exception as e:
                await utils.report(bot, str(e), source="!dev nick", ctx=ctx)

        elif func == "playing":
            try:
                currently_playing = parameter
                await bot.change_presence(game=discord.Game(
                    name=currently_playing))
                utils.update_cache(bot.dbconn, "currPlaying",
                                   currently_playing)
                await bot.say("I'm now playing `" + parameter + "`")
            except discord.InvalidArgument as e:
                await utils.report(bot,
                                   "Failed to change presence to `" +
                                   parameter + "`\n" + str(e),
                                   source="dev playing",
                                   ctx=ctx)

        elif func == "serverid":
            await bot.say("Server ID: " + ctx.message.server.id)

        elif func == "swears":
            sortedlist = sorted(list(swear_tally.items()),
                                key=lambda user_tally: user_tally[1][2],
                                reverse=True)
            message = ""
            for i, user in enumerate(sortedlist):
                message += ("**" + str(i + 1) + ".** " + bot.users[user[0]] +
                            " - " + str(round(user[1][2] * 100, 2)) + "%\n")
            if len(message) > 0:
                await bot.say(utils.trimtolength(message, 2000))

        elif func == "reload":
            bot.unload_extension(parameter)
            await bot.say("`` {} `` unloaded.".format(parameter))
            try:
                bot.load_extension("cogs." + parameter)
            except (AttributeError, ImportError) as e:
                await utils.report(bot,
                                   "```py\n{}: {}\n```".format(
                                       type(e).__name__, str(e)),
                                   source="Loading extension (!dev)",
                                   ctx=ctx)
                return
            await bot.say("`` {} `` loaded.".format(parameter))

        elif func == "report":
            await bot.say("Triggering report...")
            await utils.report(bot,
                               "This is a test of the report system",
                               source="dev report command",
                               ctx=ctx)

        elif func == "test":
            try:
                await bot.say("hello")
            except Exception as e:
                await utils.report(bot, str(e), source="dev test", ctx=ctx)

        elif func == "unload":
            """ Unoads an extension """
            bot.unload_extension(parameter)
            await bot.say("`` {} `` unloaded.".format(parameter))

        else:
            await bot.say("I don't recognize the command `" + func +
                          "`. You can type `!dev` for a list of " +
                          "available functions")
    except Exception as e:
        await utils.report(bot, str(e), source="dev command", ctx=ctx)
Exemplo n.º 4
0
    async def wiki(self, ctx):
        # ---------------------------------------------------- HELPER METHODS

        # Find an article with a matching title
        async def search_for_term(term):
            wiki_search_url = (
                "http://en.wikipedia.org/w/api.php?action=query&format=json" +
                "&prop=&list=search&titles=&srsearch=" + quote(term))
            # Looks for articles matching the search term
            wiki_search_json = await utils.get_json_with_get(wiki_search_url)
            if wiki_search_json[0]['query']['searchinfo']['totalhits'] == 0:
                return None
            return wiki_search_json[0]['query']['search'][0]['title']

        # Gets the details of an article with an exact URL title (not always the same as the article title)
        # Returns a tuple of the article's title, its extract, and a brief description of the subject
        # Returns None if no article was found or the result has no extract
        async def query_article(querytitle):
            # Makes the title URL friendly
            quoted_article_title = quote(querytitle)
            wiki_query_url = (
                "http://en.wikipedia.org/w/api.php?action=query&format=json" +
                "&prop=info%7Cextracts%7Cdescription&titles=" +
                quoted_article_title +
                "&exlimit=max&explaintext=1&exsectionformat=plain")
            # Gets the article details
            response = await utils.get_json_with_get(wiki_query_url)
            # If Wikipedia found nothing
            if "-1" in response[0]['query']['pages'].keys():
                return None
            # Gets the first result
            response = list(response[0]['query']['pages'].values())[0]
            # If the returned result isn't usable
            if "extract" not in response.keys():
                await utils.report(
                    self.bot,
                    utils.trimtolength(response, 2000),
                    source="Wiki command found no useful article",
                    ctx=ctx)
                return None
            response_title = response['title']
            response_extract = response['extract']
            if 'description' in response.keys():
                response_description = response['description']
            else:
                response_description = None
            return response_title, response_extract, response_description

        # ---------------------------------------------------- COMMAND LOGIC

        try:
            # WIKI -------------------------------- SET-UP

            (arguments, search_term) = parse.args(ctx.message.content)

            # WIKI -------------------------------- ARGUMENTS

            # Act on arguments
            if "help" in arguments:  # provides help using this command
                title = "`!wiki` User Guide"
                description = "Wikipedia search engine. Searches wikipedia for an article with the title provided " \
                              "and returns the opening section or the full article text. Additionally, it can " \
                              "return the sections of an article or the text of a designated section."
                helpdict = {
                    "-help":
                    "Displays this user guide. Gives instructions on how to use the command and its features",
                    "-full <title>":
                    "Displays the full extract of the article, up to the embed character limit"
                }
                await self.bot.say(embed=utils.embedfromdict(
                    helpdict,
                    title=title,
                    description=description,
                    thumbnail_url=COMMAND_THUMBNAILS["wiki"]))
                return

            # Performs article search
            if search_term == "":
                await self.bot.say("I need a term to search")
                return
            article_title = await search_for_term(search_term)
            if article_title is None:
                await self.bot.say("I found no articles matching the term '" +
                                   search_term + "'")
                return

            # Shows the text of the article searched for
            [title, extract, summary] = await query_article(article_title)
            wiki_embed = Embed()
            wiki_embed.title = title
            wiki_embed.set_footer(
                text="Wikipedia",
                icon_url=
                "https://upload.wikimedia.org/wikipedia/commons/thumb/8/80/"
                "Wikipedia-logo-v2.svg/800px-Wikipedia-logo-v2.svg.png")
            if "full" in arguments or "f" in arguments:
                description = utils.trimtolength(extract, 2048)
            else:
                description = utils.trimtolength(extract[:extract.find("\n")],
                                                 2048)
            wiki_embed.description = description
            wiki_embed.add_field(name="Summary", value=summary, inline=False)
            wiki_embed.add_field(name="Full Article",
                                 value="http://en.wikipedia.org/wiki/" +
                                 quote(title),
                                 inline=False)
            wiki_embed.colour = EMBED_COLORS['wiki']  # Make the embed white
            await self.bot.say(embed=wiki_embed)
        except Exception as e:
            await utils.report(self.bot,
                               str(e),
                               source="Wiki command",
                               ctx=ctx)
Exemplo n.º 5
0
async def dev(ctx):
    global currently_playing
    try:
        if ctx.message.author.id not in AUTHORIZED_IDS:
            await bot.say("You are not authorized to use these commands")
            return

        [func, parameter] = parse.func_param(ctx.message.content)

        if func in ["help", ""]:
            title = "`!dev` User Guide"
            description = "A list of features useful for "
            helpdict = {
                "channelid":
                "Posts the ID of the current channel",
                "dump":
                "A debug command for the bot to dump a variable into chat",
                "flag":
                "Tests the `flag` function",
                "load":
                "Loads an extension",
                "playing":
                "Sets the presence of the bot (what the bot says it's currently playing)",
                "reload":
                "Reloads an extension",
                "report":
                "Tests the `report` function",
                "serverid":
                "Posts the ID of the current channel",
                "test":
                "A catch-all command for inserting code into the bot to test",
            }
            await bot.say("`!dev` User Guide",
                          embed=embedfromdict(helpdict,
                                              title=title,
                                              description=description))

        elif func == "channelid":
            await bot.say("Channel ID: " + ctx.message.channel.id)

        elif func == "dump":
            await bot.say("hello")

        elif func == "flag":
            await bot.say("Triggering flag...")
            await utils.flag(bot,
                             "Test",
                             description="This is a test of the flag ability",
                             ctx=ctx)

        elif func == "load":
            """Loads an extension."""
            try:
                bot.load_extension("cogs." + parameter)
            except (AttributeError, ImportError) as e:
                await utils.report(bot,
                                   "```py\n{}: {}\n```".format(
                                       type(e).__name__, str(e)),
                                   source="Loading extension (!dev)",
                                   ctx=ctx)
                return
            await bot.say("`` {} `` loaded.".format(parameter))

        elif func == "nick":
            try:
                if ctx.message.server is None:
                    await bot.say("I can't do that here")
                    return
                new_nick = parameter
                if new_nick == "":
                    new_nick = None
                bot_member = ctx.message.server.get_member(tokens["CLIENT_ID"])
                await bot.change_nickname(bot_member, new_nick)
            except Exception as e:
                await utils.report(bot, str(e), source="!dev nick", ctx=ctx)

        elif func == "playing":
            try:
                currently_playing = parameter
                await bot.change_presence(game=discord.Game(
                    name=currently_playing))
                utils.update_cache(bot.dbconn, "currPlaying",
                                   currently_playing)
                await bot.say("I'm now playing `" + parameter + "`")
            except discord.InvalidArgument as e:
                await utils.report(bot,
                                   "Failed to change presence to `" +
                                   parameter + "`\n" + str(e),
                                   source="dev playing",
                                   ctx=ctx)

        elif func == "serverid":
            await bot.say("Server ID: " + ctx.message.server.id)

        elif func == "reload":
            bot.unload_extension(parameter)
            await bot.say("`` {} `` unloaded.".format(parameter))
            try:
                bot.load_extension("cogs." + parameter)
            except (AttributeError, ImportError) as e:
                await utils.report(bot,
                                   "```py\n{}: {}\n```".format(
                                       type(e).__name__, str(e)),
                                   source="Loading extension (!dev)",
                                   ctx=ctx)
                return
            await bot.say("`` {} `` loaded.".format(parameter))

        elif func == "report":
            await bot.say("Triggering report...")
            await utils.report(bot,
                               "This is a test of the report system",
                               source="dev report command",
                               ctx=ctx)

        elif func == "test":
            try:
                await bot.say("hello")
            except Exception as e:
                await utils.report(bot, str(e), source="dev test", ctx=ctx)

        elif func == "unload":
            """ Unoads an extension """
            bot.unload_extension(parameter)
            await bot.say("`` {} `` unloaded.".format(parameter))

        else:
            await bot.say("I don't recognize the command `" + func +
                          "`. You can type `!dev` for a list of " +
                          "available functions")
    except Exception as e:
        await utils.report(bot, str(e), source="dev command", ctx=ctx)
Exemplo n.º 6
0
    async def anime(self, ctx):
        """
        anime command

        Parameters
        ------------
        ctx : discord.context
            The message context object
        """

        try:
            # Gets the arguments from the message
            (arguments, searchterm) = parse.args(ctx.message.content)

            if "dev" in arguments:
                await self.bot.say(self.character_synonyms)
                return

            # Explain all the arguments to the user
            if "help" in arguments or searchterm == "help":
                title = "!anime - User Guide"
                description = (
                    "A search tool for anime shows and characters. This command uses the AniList.co API to "
                    +
                    "return details on the search term provided for the show/character whose name is provide "
                    +
                    "with the command (e.g. `!anime Kill la Kill`). For shows, information like a show "
                    +
                    "description, air date, rating, and genre information will be returned. For characters, "
                    +
                    "the bot provides a description, their nicknames, and the media they've been in.\n\nThe "
                    +
                    "bot uses a synonym engine to make it easier to find popular characters and allow for "
                    +
                    "searching for entries using unofficial nicknames (e.g. `!anime klk` redirects to "
                    +
                    "`!anime Kill la Kill`). The bot's synonym table can be modified by users to allow for a "
                    + "more complete table of synonyms")
                helpdict = {
                    "<search>":
                    "Searches the database for an anime",
                    "-help":
                    "Displays this message",
                    "-add [<Synonym>] <Value>":
                    ("Adds a synonym to the list. Will search for " +
                     "`Value` when a user types `Synonym`. Can be used " +
                     "with the `-char` command to create character " +
                     "synonyms. `<Synonym>` also supports semicolon-" +
                     "delineated lists"),
                    "-char <search>":
                    "Searches the database for a character page",
                    "-info <search>":
                    ("Shows the complete details for an anime. Has no effect on "
                     + "`-char` searches"),
                    "-ls":
                    ("Lists the anime synonym table. If used with the `-char` command, it "
                     + "lists the character synonym table"),
                    "-raw <search>":
                    "Disables synonym correction for search terms",
                    "-remove <Search Value>":
                    ("Removes a synonym from the list. Can be used with " +
                     "the `-char` command to remove character synonyms")
                }
                await self.bot.say(embed=utils.embedfromdict(
                    helpdict,
                    title=title,
                    description=description,
                    thumbnail_url=COMMAND_THUMBNAILS["anime"]))
                return

            if "ls" in arguments:
                if "char" in arguments:
                    searchdict = self.character_synonyms
                    title = "Character name synonyms"
                else:
                    searchdict = self.anime_synonyms
                    title = "Anime title synonyms"
                message = ""
                for changeto in sorted(list(searchdict.keys())):
                    message += "**" + changeto + "** <- " + ", ".join(
                        searchdict[changeto]) + "\n"
                embed = Embed()
                embed.title = title
                embed.description = utils.trimtolength(message, 2040)
                embed.colour = EMBED_COLORS["anime"]
                await self.bot.say(embed=embed)
                return

            if "add" in arguments and "remove" in arguments:
                await self.bot.say(
                    "I don't know how you possibly expect me to both add and "
                    + "remove a synonym in the same command")

            if "char" in arguments:
                synonymdict = self.character_synonyms
                searchtype = "character"
            else:
                synonymdict = self.anime_synonyms
                searchtype = "anime"

            # Add search synonym
            if "add" in arguments:
                tag_kv = parse.key_value(searchterm)
                if tag_kv[0] is None:
                    errormessages = {
                        "EMPTY KEY":
                        "There was no synonym for the search value",
                        "UNCLOSED KEY":
                        "You didn't close your brackets",
                        "NO VALUE":
                        "There was no search value to save for the synonym",
                        "WHITESPACE KEY":
                        ("Just because this bot is written in Python does not mean whitespace is an "
                         + "acceptable synonym"),
                        "KEY STARTS WITH -":
                        ("The `-` character denotes the start of an argument and cannot be used to "
                         + "start a synonym")
                    }
                    await self.bot.say(errormessages[tag_kv[1]])
                    return
                changefrom = tag_kv[0].lower()
                changeto = tag_kv[1]
                collision = checkforexistingsynonym(changefrom, synonymdict)
                if collision is None:
                    if changeto not in synonymdict.keys():
                        synonymdict[changeto] = list()
                    changefromlist = changefrom.split(";")
                    for element in changefromlist:
                        synonymdict[changeto].append(element.strip())
                        self.add_synonym(searchtype.upper(), changeto, element)
                    await self.bot.say("All " + searchtype +
                                       " searches for `" +
                                       "` or `".join(changefromlist) +
                                       "` will now correct to `" + changeto +
                                       "`")
                else:
                    await self.bot.say(
                        "The synonym `` {} `` already corrects to `` {} ``. Pick a different "
                        +
                        "word/phrase or remove the existing synonym with the command "
                        + "``!anime -remove {} ``".format(
                            changefrom, collision, changefrom))
                return

            # Remove search synonym
            if "remove" in arguments:
                correction = checkforexistingsynonym(searchterm, synonymdict)
                if correction is not None:
                    synonymdict[correction].remove(searchterm)
                    if len(synonymdict[correction]) == 0:
                        del synonymdict[correction]
                    self.remove_synonym(searchtype.upper(), searchterm)
                    await self.bot.say("Alright, `" + searchterm +
                                       "` will no longer correct to `" +
                                       correction + "` for " + searchtype +
                                       " searches")
                else:
                    await self.bot.say((
                        "The synonym you searched for does not exist. Check your use "
                        +
                        "(or lack thereof) of the `-char` command, or use the `-ls` command to check "
                        + "that everything is spelled correctly"))
                return

            if searchterm == "":
                await self.bot.say(
                    "I don't see a search term to look up. Type `!anime -help` for a user guide"
                )
                return

            embedgenerator = None
            if "char" in arguments:
                if "raw" not in arguments:
                    for key in self.character_synonyms.keys():
                        if searchterm.lower() in self.character_synonyms[key]:
                            searchterm = key
                char_var = {'name': searchterm}
                [json,
                 status] = await utils.get_json_with_post(self.api_url,
                                                          json={
                                                              'query':
                                                              self.char_query,
                                                              'variables':
                                                              char_var
                                                          })
                if "json" in arguments:
                    await self.bot.say(utils.trimtolength(json, 2000))
                if status == 200:
                    embedgenerator = Character(json['data']['Character'])
            else:
                if "raw" not in arguments:
                    for key in self.anime_synonyms.keys():
                        if searchterm.lower() in self.anime_synonyms[key]:
                            searchterm = key
                anime_var = {'title': searchterm}
                [json,
                 status] = await utils.get_json_with_post(self.api_url,
                                                          json={
                                                              'query':
                                                              self.anime_query,
                                                              'variables':
                                                              anime_var
                                                          })
                if "json" in arguments:
                    await self.bot.say(utils.trimtolength(json, 2000))
                if status == 200:
                    embedgenerator = Anime(json['data']['Media'])

            if status != 200:
                if status == 500:
                    await utils.flag(self.bot,
                                     "500 Server Error on search term " +
                                     searchterm,
                                     description=str(json),
                                     ctx=ctx)
                    await self.bot.say(
                        "`500 Server Error`. The AniList servers had a brief hiccup. Try again in a little bit"
                    )
                elif status == 404:
                    await utils.flag(self.bot,
                                     "Failed to find result for search term " +
                                     searchterm,
                                     description=str(json),
                                     ctx=ctx)
                    await self.bot.say("I found no results for `" +
                                       searchterm + "`")
                elif status == 400:
                    await utils.report(
                        self.bot,
                        str(json),
                        source="Error in `!anime` search for term " +
                        searchterm,
                        ctx=ctx)
                    await self.bot.say(
                        "The bot made an error. My bad. A bug report has been automatically submitted"
                    )
                else:
                    await utils.report(self.bot,
                                       str(json),
                                       source="Unknown Error Type",
                                       ctx=ctx)
                    await self.bot.say(
                        "Something went wrong and I don't know why")
                return

            if "info" in arguments:
                await self.bot.say(embed=embedgenerator.info_embed())
            else:
                await self.bot.say(embed=embedgenerator.embed())
        except Exception as e:
            await utils.report(self.bot,
                               str(e),
                               source="!anime command",
                               ctx=ctx)
Exemplo n.º 7
0
    async def say(self, ctx):
        """
        Makes SuitsBot say a stored audio clip in voice via a tag system. (e.g. `!say anthem`)
        The command also supports several CLI arguments for different tasks

        "-help": Shows the command's help embed
        "-ls": Lists all audio clip tags
        "-stop": Stops the current audio clip

        Parameters
        ------------
        ctx : discord.context
            The message context object
        """

        # List of quote files
        quotes = {
            "ah f**k":
            ["Ah f**k. I can't believe you've done this", "ah-f**k.mp3"],
            "anthem": [
                "**SOYUZ NERUSHIMY RESPUBLIK SVOBODNYKH SPLOTILA NAVEKI VELIKAYA RUS'!**",
                "anthem.mp3"
            ],
            "austin": ["IT'S ME, AUSTIN!", "itsMeAustin.mp3"],
            "beat my dick": [
                "Good evening Twitter, it's ya boi EatDatPussy445.",
                "beatTheFuck.wav"
            ],
            "boi": ["B O I", "boi.mp3"],
            "bold strategy": [
                "It's a bold strategy cotton, let's see if it pays off for 'em",
                "bold-strategy-cotton.mp3"
            ],
            "careless whisper":
            ["*sexy sax solo intensifies*", "careless_whispers.mp3"],
            "cavalry": ["*britishness intensifies*", "cheersLove.ogg"],
            "deja vu": ["Ever get that feeling of deja vu?", "dejaVu.ogg"],
            "disco": [
                "Reminder: You can stop media using the `!say -stop` command",
                "platinumDisco.mp3"
            ],
            "do it": ["*Do it*", "doIt.mp3"],
            "everybody": ["Se *no*!", "everybody.wav"],
            "ftsio": ["F**k this shit I'm out", "f**k-this-shit-im-out.mp3"],
            "f**k you": ["**F**k yoooooou!**", "fuckYou.mp3"],
            "gfd": ["God *f*****g* dammit!", "gfd.mp3"],
            "hentai":
            ["It's called hentai, and it's *art*", "itsCalledHentai.mp3"],
            "hello darkness":
            ["*Hello darkness my old friend...*", "helloDarkness.mp3"],
            "hello there": ["**GENERAL KENOBI**", "hello_there_obi.mp3"],
            "heroes never die": ["Heroes never die!", "heroesNeverDie.ogg"],
            "high noon": ["It's hiiiiiigh nooooooon...", "itsHighNoon.ogg"],
            "how": ["**I MADE MY MISTAKES**", "howCould.mp3"],
            "i tried so hard":
            ["Woah there, don't cut yourself on that edge", "inTheEnd.mp3"],
            "it was me": ["Ko! No! Dio! Da!", "itWasMeDio.mp3"],
            "laser sights":
            ["*Fooking laser sights*", "fookin-laser-sights.mp3"],
            "leroy": ["LEEEEEEROOOOOOOOOOOOOY", "leroy.mp3"],
            "love": [
                "AND IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...",
                "iWillAlwaysLoveYou.mp3"
            ],
            "my power": [
                "*You underestimate my power!*",
                "you-underestimate-my-power.mp3"
            ],
            "nerf this": ["It's nerf or nothing", "nerfThis.ogg"],
            "nani": ["NANI SORE!?", "nani-sore.mp3"],
            "nico":
            [("Nico Nico-nii~ Anata no Heart ni Nico Nico-nii, Egao todokeru Yazawa "
              + "Nico Nico~ Nico-nii te oboeteru Love Nico~ XD"),
             "nico_nico_nii.mp3"],
            "nyan": [("Naname nanajyuunana-do no narabi de nakunaku inanaku " +
                      "nanahan nanadai nannaku narabete naganagame.\nOwO"),
                     "nyan.mp3"],
            "omg": ["OH MY GOD!", "omg.mp3"],
            "oof": ["OOF!", "oof.mp3"],
            "over 9000": ["It's over **9000!!!**", "over9000.mp3"],
            "pingas": ["Pingas.", "pingas.mp3"],
            "rimshot": ["Badum, tiss", "rimshot.mp3"],
            "roundabout": ["To be continued...", "roundabout.mp3"],
            "sanic": ["goTtA gO faSt!", "sanic.mp3"],
            "satania": ["BWAHAHAHA!", "sataniaLaugh.mp3"],
            "sob": ["SON OF A BITCH!", "sob.mp3"],
            "somebody":
            ["What are you doing in my swamp?!", "somebodyClipping.wav"],
            "star destroyers":
            ["**IT BROKE NEW GROUND**", "starDestroyers.mp3"],
            "stop": ["It's time to stop!", "stop.mp3"],
            "take a sip": ["Take a f****n' sip, babes...", "takeASip.mp3"],
            "tea": ["I've got f*****g tea, ya dickhead!", "gotTea.wav"],
            "trash": ["**Endless trash**", "Endless Trash.mp3"],
            "tuturu": ["TUTURUUUUUUUU", "tuturu.mp3"],
            "violin": ["*sadness intensifies*", "sadViolin.mp3"],
            "wake me up": ["**I CAN'T WAKE UP**", "wakeMeUp.mp3"],
            "winky face": [":wink:", "winkyFace.ogg"],
            "woomy": ["Woomy!", "woomy.mp3"],
            "wow": ["Wow", "wow.mp3"],
            "wtf": ["**Hey Todd?!**", "whatTheFuck.mp3"],
            "yeah": ["*Puts on sunglasses*", "yeah.mp3"],
            "yes": ["YES YES YES YES... **YES**!", "yes.mp3"],
            "your way":
            ["Don't lose your waaaaaaaaay!", "dontloseyourway.mp3"],
            "zaworldo": ["ZA WARLDO!", "za_warudo.mp3"]
        }
        try:
            (arguments, key) = parse.args(ctx.message.content)

            # ------------------------------ NO AUDIO ARGUMENTS

            # Acting on arguments
            if "help" in arguments:  # provides help using this command
                title = "`!say` User Guide"
                description = (
                    "Plays an audio clip in voice. If not already in the user's voice channel, the bot "
                    +
                    "will automatically join the voice channel of the user issuing the command. The bot "
                    +
                    "holds a list of stored audio files which can be summoned using predefined tags "
                    +
                    "(the list of tags can be viewed using the `!say -ls` command). If an audio clip is "
                    +
                    "currently playing, another tag cannot be started. If all users leave the audio "
                    +
                    "channel the bot is in, the bot will leave as well. If the user is not in a voice "
                    + "channel, the command will be rejected")
                helpdict = {
                    "<tag>":
                    ("Plays the predetermined audio clip for that tag. Tags are case-insensitive, but make "
                     + "sure your spelling is right!"),
                    "-help":
                    "Shows this list",
                    "-ls":
                    "Lists the tags for all the available audio clips",
                    "-stop":
                    "Stops the current voice clip"
                }
                await self.bot.say(embed=utils.embedfromdict(
                    helpdict,
                    title=title,
                    description=description,
                    thumbnail_url=COMMAND_THUMBNAILS["say"]))
                return
            if "ls" in arguments:
                message = "The audio clips I know are: \n"
                for quoteKey in quotes.keys():
                    message += quoteKey + ", "
                await self.bot.say(message[:-2])
                return
            if "stop" in arguments:
                if not self.bot.player.is_playing():
                    await self.bot.say("I'm not saying anything...")
                else:
                    self.bot.player.stop()
                    await self.bot.say("Shutting up.")
                return

            # ------------------------------ VALIDATING KEY

            if key == "":
                await self.bot.say(
                    "You need to type the name of an audio clip for me to say. Type `!say -ls` for "
                    +
                    "a list of my audio clips or type `!say -help` for a full list of my arguments"
                )
                return

            if key not in quotes.keys():
                await self.bot.say("I don't see an audio clip tagged '" + key +
                                   "'. Type `!say -ls` for a list of tags")
                return

            # ------------------------------ AUDIO INITIALIZATION

            # Gets the voice channel the author is in
            author_voice_channel = ctx.message.author.voice_channel
            if author_voice_channel is None:  # Ignores the command if the author is not in voice
                await self.bot.say("You are not in a voice channel right now")
                return

            # If the bot is connected to voice,
            if self.bot.is_voice_connected(ctx.message.server):
                voice_channel = self.bot.voice_client_in(
                    ctx.message.server).channel
                # Does nothing if the bot is already in the author's voice channel
                if voice_channel != author_voice_channel:
                    # Stops any active voice clip
                    self.bot.player.stop()
                    voice = self.bot.voice_client_in(ctx.message.server)
                    # Moves the bot to the new channel
                    await voice.move_to(author_voice_channel)
            else:
                await self.bot.join_voice_channel(author_voice_channel)

            # ------------------------------ PLAYING AUDIO

            # Ignores command if bot is already playing a voice clip
            if self.bot.player is not None and self.bot.player.is_playing():
                await self.bot.say("Currently processing other voice command")
                return

            await self.bot.say(quotes[key][0]
                               )  # Responds with the text of the voice clip
            voice = self.bot.voice_client_in(
                ctx.message.server)  # Gets the active voice client
            player = voice.create_ffmpeg_player(
                self.quote_folder + quotes[key][1]
            )  # Gets the voice clip and creates a ffmpeg player
            self.bot.player = player  # Assigns the player to the bot
            player.start()  # Plays the voice clip
        except Exception as e:
            await utils.report(self.bot, str(e), source="Say command", ctx=ctx)
Exemplo n.º 8
0
    async def rand(self, ctx):
        try:
            # Extracts the function and parameter from the message
            [func, parameter] = parse.func_param(ctx.message.content)

            # !rand help
            if func in ["help", ""]:
                title = "!rand - User Guide"
                description = "Randomizer. This command is used for randomization in several circumstances. From " \
                              "coin flips and dice rolls to random numbers and picking from lists, let the bot " \
                              "generate random numbers for you.\n\n**WARNING**\nThis command is only pseudorandom " \
                              "and not cryptographically secure"
                helpdict = {
                    "!rand":
                    "No function. Will present this help list",
                    "!rand help":
                    "This command. Shows user guide",
                    "!rand coin":
                    "Flips a coin",
                    "!rand item <A>, <B>, <C>...":
                    "Returns a random item from a comma delineated list",
                    "!rand num":
                    "Returns a random decimal",
                    "!rand num <A>":
                    "Returns a random integer from 0 to A",
                    "!rand num <A> <B>":
                    "Returns a random integer between A and B",
                    "!rand roll <num>d<sides>,...":
                    "Rolls the number of n-sided dice presented. "
                    "Multiple dice types can be rolled with a comma separated "
                    "list"
                }
                await self.bot.say(embed=utils.embedfromdict(
                    helpdict,
                    title=title,
                    description=description,
                    thumbnail_url=COMMAND_THUMBNAILS["rand"]))
                return

            # !rand coin
            if func == "coin":
                await self.bot.say(utils.random_element(["Heads!", "Tails!"]))
                return

            # !rand item <item>, <item>, <item>
            if func == "item":
                if len(parameter) == 0:
                    await self.bot.say(
                        "I need a comma delineated list (e.g. '!random item A, B, C, D, E' etc.) "
                        "to pick from")
                    return
                itemlist = list(filter(None, parameter.split(",")))
                if len(itemlist) == 0:
                    await self.bot.say(
                        "There aren't any items here for me to choose from!")
                    return
                elif len(itemlist) == 1:
                    await self.bot.say(
                        "There's only one item. That's an easy choice: " +
                        itemlist[0])
                    return
                await self.bot.say("I choose... " +
                                   utils.random_element(itemlist).strip())
                return

            # rand num
            # rand num <num>
            # rand num <num> <num>
            if func == "num" or func == "number":
                if len(parameter) == 0:
                    await self.bot.say(str(random.random()))
                    return
                numbers = parameter.split(" ")
                if len(numbers) == 1:
                    try:
                        bound = int(numbers[0])
                    except ValueError:
                        await self.bot.say("I can't seem to parse '" +
                                           numbers[0] + "'")
                        return
                    await self.bot.say(str(random.randint(0, bound)))
                else:
                    try:
                        lowerbound = int(numbers[0])
                    except ValueError:
                        await self.bot.say("I can't seem to parse '" +
                                           numbers[0] + "'")
                        return
                    try:
                        upperbound = int(numbers[1])
                    except ValueError:
                        await self.bot.say("I can't seem to parse '" +
                                           numbers[1] + "'")
                        return
                    if upperbound < lowerbound:
                        temp = upperbound
                        upperbound = lowerbound
                        lowerbound = temp
                    message = str(random.randint(lowerbound, upperbound))
                    if len(numbers) > 2:
                        message += "\n\nFYI, this function takes a maximum of two only arguments"
                    await self.bot.say(message)
                return

            # !rand roll <num>d<sides>, <num>d<sides>
            if func == "roll":
                dice = list(filter(None, parameter.split(",")))
                total = 0
                message = ""
                for die in dice:
                    die = die.strip()
                    dloc = die.find("d")
                    # if there is no "d"
                    if dloc == -1:
                        await self.bot.say(
                            "I don't see a 'd' in the argument '" + die + "'.")
                        return

                    # if there is no number in front of the "d", it is assumed to be one
                    if dloc == 0:
                        count = "1"
                        sides = die[1:]
                    # if there is no number after the "d", the bot rejects it
                    elif (dloc + 1) == len(die):
                        await self.bot.say(
                            "I don't see a number after 'd' in the argument '"
                            + die + "'. I need to know a number of sides")
                        return
                    else:
                        count = die[0:dloc]
                        sides = die[dloc + 1:]

                    try:
                        sides = int(sides)
                    except ValueError:
                        await self.bot.say("I'm sorry, but '" + sides +
                                           "' isn't a parsable integer...")
                        return
                    try:
                        count = int(count)
                    except ValueError:
                        await self.bot.say("I'm sorry, but '" + count +
                                           "' isn't a parsable integer...")
                        return

                    if count > 100000:
                        await self.bot.say(
                            str(count) +
                            " dice is a *lot*. I think rolling that many would hurt "
                            "my head :confounded:\nPlease don't make me do it."
                        )
                        return
                    dicesum = 0
                    for i in range(0, count):
                        dicesum += random.randint(1, sides)
                    total += dicesum
                    message += str(count) + " d" + str(
                        sides) + ": I rolled " + str(dicesum) + "\n"
                if len(dice) > 1:
                    await self.bot.say(message + "Total: " + str(total))
                else:
                    await self.bot.say(message)
                return

            await self.bot.say(
                "I don't recognize the function `" + func +
                "`. Type `!rand help` for information on this command")

        except Exception as e:
            await utils.report(self.bot,
                               str(e),
                               source="Rand command",
                               ctx=ctx)
Exemplo n.º 9
0
    async def handle_rss_feed(self, feed, ctx):
        """
        The universal rss feed handler. Takes in an RSSFeed object
        then does all the magic
        :param feed: The RSSFeed
        :param ctx: The ctx object of the inciting message
        """
        try:
            message = parse.stripcommand(ctx.message.content)

            # Update feed
            feed.refresh_if_stale()

            # Show most recent episode
            if message == "":
                episode = feed.items[0]
                await self.bot.say(embed=feed.get_embed(episode))
                return

            # check for subcommand and parse it out
            subcommand = ""
            parameter = message
            if message[0] == "-":
                whitespace = utils.first_whitespace(message)
                if whitespace == -1:
                    subcommand = message[1:]
                    parameter = ""
                else:
                    subcommand = message[1:whitespace]
                    parameter = message[whitespace:].strip()

            # Teach the person how to use this thing
            if subcommand == "help":
                command_name = ctx.invoked_with
                title = f"!{command_name} - User Guide"
                description = f"Searches the RSS feed for {feed.title}"
                helpdict = {
                    f"!{command_name}": "Post the most recent item in the feed",
                    f"!{command_name} <word>": "Post the most recent item whose title contains the whole word <word>",
                    f"!{command_name} -help": "Posts this message",
                    f"!{command_name} -reg <regex>": "Perform a regular expression search for the most "
                                                     "recent item title matching <regex>",
                    f"!{command_name} -refresh": "Force the bot to refresh its cache"}
                thumbnail = feed.image if feed.image is not None else COMMAND_THUMBNAILS["rssfeed"]
                await self.bot.say(embed=utils.embedfromdict(helpdict,
                                                             title=title,
                                                             description=description,
                                                             thumbnail_url=thumbnail))
                return

            # Dump all the info about the feed
            if subcommand == "details":
                await self.bot.say(feed.to_string())
                return

            # Test an embed for a given feed
            if subcommand == "embed":
                await self.bot.say(embed=feed.get_embed(feed.items[0]))
                return

            # Test an embed for a given feed
            if subcommand == "image":
                embed = Embed()
                embed.set_image(url=feed.image)
                await self.bot.say(embed=embed)
                return

            # If some nerd like Kris or Pat wants to do regex search
            if subcommand == "reg":
                episode = feed.search(parameter, regex=True)
                if episode:
                    await self.bot.say(embed=feed.get_embed(episode))
                    return
                await self.bot.say(f"I couldn't find any results for the regex string `{parameter}`")

            # Force a refresh on the feed
            if subcommand == "refresh":
                feed.refresh()
                await self.bot.say(f"Alright, I have refreshed the feed `{feed.feed_id}`")
                return

            # Returns search results that the user can select
            if subcommand == "search":
                await self.bot.say("This has not been implemented yet :sad:")
                return

            # If there was a subcommand but it was unrecognized
            if subcommand != "":
                await self.bot.say(f"I'm sorry, I don't understand the subcommand `{subcommand}`. " +
                                   f"Please consult `-help` for more information")
                return

            # Search for the term
            episode = feed.search(parameter)
            if episode:
                await self.bot.say(embed=feed.get_embed(episode))
                return
            await self.bot.say(f"I couldn't find any results in the {feed.title} feed "
                               f"for the term `{parameter}` :worried:")

        except Exception as e:
            await utils.report(self.bot, str(e), source=f"handle_rss_feed() for '{feed.feed_id}'", ctx=ctx)