Beispiel #1
0
async def summary(message: discord.Message, *options, phrase: Annotate.LowerContent=None):
    """ Perform a summary! """
    # This dict stores all parsed options as keywords
    member, channel, num = [], None, None
    for value in options:
        num_match = valid_num.match(value)
        if num_match:
            assert not num
            num = int(num_match.group("num"))

            # Assign limits
            if num > max_summaries:
                num = max_summaries
            elif num < 1:
                num = 1
            continue

        member_match = valid_member.match(value)
        if member_match:
            member.append(utils.find_member(message.server, member_match.group()))
            continue

        channel_match = valid_channel.match(value)
        if channel_match:
            assert not channel
            channel = utils.find_channel(message.server, channel_match.group())
            assert channel.permissions_for(message.server.me).read_message_history, "**I can't see this channel.**"
            continue

    # Assign defaults
    if not num:
        num = 1
    if not channel:
        channel = message.channel

    await client.send_typing(message.channel)
    await update_task.wait()
    await update_messages(channel)

    # Split the messages into content and filter member and phrase
    if member:
        message_content = [m.clean_content for m in stored_messages[channel.id] if m.author in member]
    else:
        message_content = [m.clean_content for m in stored_messages[channel.id]]
    if phrase:
        message_content = [s for s in message_content if phrase.lower() in s.lower()]

    # Clean up by removing all commands from the summaries
    if phrase is None or not phrase.startswith(config.command_prefix):
        message_content = [s for s in message_content if not s.startswith(config.command_prefix)]

    # Check if we even have any messages
    assert message_content, on_no_messages.format(message)

    # Generate the summary, or num summaries
    for i in range(num):
        sentence = markov_messages(message_content)
        await client.say(message, sentence or on_fail.format(message))
Beispiel #2
0
async def summary(message: discord.Message,
                  *options,
                  phrase: Annotate.Content = None):
    """ Run a markov chain through the past 5000 messages + up to another 5000
    messages after first use. This command needs some time after the plugin reloads
    as it downloads the past 5000 messages in the given channel. """
    # This dict stores all parsed options as keywords
    member, channel, num = [], None, None
    regex, case, tts, coherent, strict = False, False, False, False, False
    bots = not summary_options.data["no_bot"]

    for value in options:
        num_match = valid_num.match(value)
        if num_match:
            assert not num
            num = int(num_match.group("num"))
            continue

        member_match = valid_member.match(value)
        if member_match:
            member.append(message.server.get_member(member_match.group("id")))
            continue

        member_match = valid_member_silent.match(value)
        if member_match:
            member.append(
                utils.find_member(message.server, member_match.group("name")))
            continue

        role_match = valid_role.match(value)
        if role_match:
            role = discord.utils.get(message.server.roles,
                                     id=role_match.group("id"))
            member.extend(m for m in message.server.members if role in m.roles)
            continue

        channel_match = valid_channel.match(value)
        if channel_match:
            assert not channel
            channel = utils.find_channel(message.server, channel_match.group())
            continue

        if value in valid_options:
            if value == "+re" or value == "+regex":
                regex = True
            if value == "+case":
                case = True
            if value == "+tts":
                tts = True
            if value == "+coherent":
                coherent = True
            if value == "+strict":
                strict = True

            bots = False if value == "+nobot" else True if value == "+bot" else bots
Beispiel #3
0
async def summary(message: discord.Message, *options, phrase: Annotate.Content=None):
    """ Perform a summary! """
    # This dict stores all parsed options as keywords
    member, channel, num = [], None, None
    regex, case, tts = False, False, False
    bots = not summary_options.data["no_bot"]

    for value in options:
        num_match = valid_num.match(value)
        if num_match:
            assert not num
            num = int(num_match.group("num"))

            # Assign limits
            if num > max_summaries:
                num = max_summaries
            elif num < 1:
                num = 1
            continue

        member_match = valid_member.match(value)
        if member_match:
            member.append(utils.find_member(message.server, member_match.group()))
            continue

        member_match = valid_member_silent.match(value)
        if member_match:
            member.append(utils.find_member(message.server, member_match.group("name")))
            continue

        channel_match = valid_channel.match(value)
        if channel_match:
            assert not channel
            channel = utils.find_channel(message.server, channel_match.group())
            assert channel.permissions_for(message.server.me).read_message_history, "**I can't see this channel.**"
            continue

        if value in valid_options:
            if value == "+re" or value == "+regex":
                regex = True
            if value == "+case":
                case = True
            if value == "+tts":
                assert message.author.permissions_in(message.channel).send_tts_messages, \
                    "**You don't have permissions to send tts messages in this channel.**"
                tts = True
            bots = False if value == "+nobot" else True if value == "+bot" else bots
Beispiel #4
0
def parse_annotation(param: inspect.Parameter, default, arg: str, index: int, message: discord.Message):
    """ Parse annotations and return the command to use.

    index is basically the arg's index in shelx.split(message.content) """
    if default is param.empty:
        default = None

    if param.annotation is not param.empty:  # Any annotation is a function or Annotation enum
        anno = param.annotation

        # Valid enum checks
        if isinstance(anno, utils.Annotate):
            content = lambda s: utils.split(s, maxsplit=index)[-1].strip("\" ")

            if anno is utils.Annotate.Content:  # Split and get raw content from this point
                return content(message.content) or default
            elif anno is utils.Annotate.LowerContent:  # Lowercase of above check
                return content(message.content).lower() or default
            elif anno is utils.Annotate.CleanContent:  # Split and get clean raw content from this point
                return content(message.clean_content) or default
            elif anno is utils.Annotate.LowerCleanContent:  # Lowercase of above check
                return content(message.clean_content).lower() or default
            elif anno is utils.Annotate.Member:  # Checks member names or mentions
                return utils.find_member(message.server, arg) or default_self(anno, default, message)
            elif anno is utils.Annotate.Channel:  # Checks channel names or mentions
                return utils.find_channel(message.server, arg) or default_self(anno, default, message)
            elif anno is utils.Annotate.Code:  # Works like Content but extracts code
                return utils.get_formatted_code(utils.split(message.content, maxsplit=index)[-1]) or default

        try:  # Try running as a method
            result = anno(arg)
            return result if result is not None else default
        except TypeError:
            raise TypeError("Command parameter annotation must be either pcbot.utils.Annotate or a callable")
        except:  # On error, eg when annotation is int and given argument is str
            return None

    return str(arg) or default  # Return str of arg if there was no annotation
Beispiel #5
0
Datei: bot.py Projekt: stoz/PCBOT
async def parse_annotation(param: inspect.Parameter, default, arg: str,
                           index: int, message: discord.Message):
    """ Parse annotations and return the command to use.

    index is basically the arg's index in shelx.split(message.content) """
    if default is param.empty:
        default = None

    if param.annotation is not param.empty:  # Any annotation is a function or Annotation enum
        anno = override_annotation(param.annotation)
        content = lambda s: utils.split(s, maxsplit=index)[-1].strip("\" ")

        # Valid enum checks
        if isinstance(anno, utils.Annotate):
            if anno is utils.Annotate.Content:  # Split and get raw content from this point
                return content(message.content) or default
            elif anno is utils.Annotate.LowerContent:  # Lowercase of above check
                return content(message.content).lower() or default
            elif anno is utils.Annotate.CleanContent:  # Split and get clean raw content from this point
                return content(message.clean_content) or default
            elif anno is utils.Annotate.LowerCleanContent:  # Lowercase of above check
                return content(message.clean_content).lower() or default
            elif anno is utils.Annotate.Member:  # Checks member names or mentions
                return utils.find_member(message.server, arg) or default_self(
                    anno, default, message)
            elif anno is utils.Annotate.Channel:  # Checks text channel names or mentions
                return utils.find_channel(message.server, arg) or default_self(
                    anno, default, message)
            elif anno is utils.Annotate.VoiceChannel:  # Checks voice channel names or mentions
                return utils.find_channel(message.server,
                                          arg,
                                          channel_type="voice")
            elif anno is utils.Annotate.Code:  # Works like Content but extracts code
                return utils.get_formatted_code(
                    utils.split(message.content,
                                maxsplit=index)[-1]) or default

        try:  # Try running as a method
            if getattr(anno, "allow_spaces", False):
                arg = content(message.content)

            # Pass the message if the argument has this specified
            if getattr(anno, "pass_message", False):
                result = anno(message, arg)
            else:
                result = anno(arg)

            # The function can be a coroutine
            if inspect.isawaitable(result):
                result = await result

            return result if result is not None else default
        except TypeError:
            raise TypeError(
                "Command parameter annotation must be either pcbot.utils.Annotate, a callable or a coroutine"
            )
        except AssertionError as e:  # raise the error in order to catch it at a lower level
            raise AssertionError(e)
        except:  # On error, eg when annotation is int and given argument is str
            return None

    return str(arg) or default  # Return str of arg if there was no annotation
Beispiel #6
0
def members_and_channels(message: discord.Message, arg: str):
    """ Look for both members and channel mentions. """
    if utils.channel_mention_pattern.match(arg):
        return utils.find_channel(message.server, arg)

    return utils.find_member(message.server, arg)
Beispiel #7
0
async def summary(message: discord.Message,
                  *options,
                  phrase: Annotate.Content = None):
    """ Run a markov chain through the past 5000 messages + up to another 5000
    messages after first use. This command needs some time after the plugin reloads
    as it downloads the past 5000 messages in the given channel. """
    # This dict stores all parsed options as keywords
    member, channel, num = [], None, None
    regex, case, tts, coherent, strict = False, False, False, False, True
    bots = not summary_options.data["no_bot"]

    async with message.channel.typing():
        for value in options:
            num_match = valid_num.match(value)
            if num_match:
                assert not num
                num = int(num_match.group("num"))
                continue

            member_match = valid_member.match(value)
            if member_match:
                member.append(
                    message.guild.get_member(int(member_match.group("id"))))
                continue

            member_match = valid_member_silent.match(value)
            if member_match:
                member.append(
                    utils.find_member(message.guild,
                                      member_match.group("name")))
                continue

            role_match = valid_role.match(value)
            if role_match:
                role = discord.utils.get(message.guild.roles,
                                         id=int(role_match.group("id")))
                member.extend(m for m in message.guild.members
                              if role in m.roles)
                continue

            channel_match = valid_channel.match(value)
            if channel_match:
                assert not channel
                channel = utils.find_channel(message.guild,
                                             channel_match.group())
                continue

            if value in valid_options:
                if value == "+re" or value == "+regex":
                    regex = True
                if value == "+case":
                    case = True
                if value == "+tts":
                    tts = True
                if value == "+coherent":
                    coherent = True
                if value == "+loose":
                    strict = False

                bots = False if value == "+nobot" else True if value == "+bot" else bots

        # Assign defaults and number of summaries limit
        is_privileged = message.author.permissions_in(
            message.channel).manage_messages

        if num is None or num < 1:
            num = 1
        elif num > max_admin_summaries and is_privileged:
            num = max_admin_summaries
        elif num > max_summaries:
            num = max_summaries if not is_privileged else num

        if not channel:
            channel = message.channel

        # Check channel permissions after the given channel has been decided
        assert channel.permissions_for(
            message.guild.me
        ).read_message_history, "**I can't see this channel.**"
        assert not tts or message.author.permissions_in(message.channel).send_tts_messages, \
            "**You don't have permissions to send tts messages in this channel.**"

        if str(channel.id) in summary_options.data["persistent_channels"]:
            messages = summary_data.data["channels"][str(channel.id)]
        else:
            await update_task.wait()
            await update_messages(channel)
            messages = stored_messages[str(channel.id)]

        message_content = filter_messages_by_arguments(messages, channel,
                                                       member, bots)

        # Replace new lines with text to make them persist through splitting
        message_content = (s.replace("\n", NEW_LINE_IDENTIFIER)
                           for s in message_content)

        # Filter looking for phrases if specified
        if phrase and not is_endswith(phrase):
            message_content = list(
                filter_messages(message_content, phrase, regex, case))

        command_prefix = config.guild_command_prefix(message.guild)
        # Clean up by removing all commands from the summaries
        if phrase is None or not phrase.startswith(command_prefix):
            message_content = [
                s for s in message_content if not s.startswith(command_prefix)
            ]

        # Check if we even have any messages
        assert message_content, on_no_messages.format(message)

        markovify_model = None
        if strict:
            try:
                markovify_model = markovify.Text(message_content)
            except NameError:
                logging.warning(
                    "+strict was used but markovify is not imported")
                strict = False
            except KeyError:
                markovify_model = None

        # Generate the summary, or num summaries
        for i in range(num):
            if strict and markovify_model:
                if phrase and is_endswith(phrase):
                    try:
                        sentence = markovify_model.make_sentence_with_start(
                            phrase[:-3])
                    except KeyError:
                        sentence = markovify_model.make_sentence(tries=1000)

                else:
                    sentence = markovify_model.make_sentence(tries=1000)
            else:
                sentence = markov_messages(message_content, coherent)

            if not sentence:
                sentence = markov_messages(message_content, coherent)

            assert sentence, on_fail.format(message)

            # Convert new line identifiers back to characters
            sentence = sentence.replace(NEW_LINE_IDENTIFIER.strip(" "), "\n")

            await client.send_message(message.channel, sentence, tts=tts)