Beispiel #1
0
    def at_everyone_filter(content, author, force_remove=False):
        # See if the user is allowed to do @everyone
        # Removes mentions if user doesn't have the permission to mention
        filter_stuff = not (author.guild_permissions.mention_everyone
                            or force_remove)

        return filter_text(content,
                           mass_mentions=filter_stuff,
                           user_mention=filter_stuff)
Beispiel #2
0
    async def on_message(self, message, **kwargs):
        trans = self.trans

        prefix = kwargs.get("prefix")
        lang = kwargs.get("lang")

        # Check if this is a valid command
        if not is_valid_command(message.content, commands, prefix):
            return
        else:
            self.stats.add(MESSAGE)

        def startswith(*matches):
            for match in matches:
                if message.content.startswith(match):
                    return True

            return False

        # !imdb
        if startswith(prefix + "imdb"):
            # The process can take some time so we show that something is happening
            await message.channel.trigger_typing()

            cut = message.content[len(prefix + "imdb "):]

            try:
                subcommand, argument = cut.split(" ", maxsplit=1)
            # In case there are no parameters
            except ValueError:
                # Check if no subcommand - valid
                # If there's a subcommand, but no argument, fail
                if not cut.strip(" "):
                    await message.channel.send(trans.get("MSG_IMDB_INVALID_USAGE", lang).format(prefix))
                    return

                else:
                    subcommand, argument = cut, ""

            # !imdb plot
            if subcommand == "plot":
                data = await self._imdb_search(argument, message, lang)

                # Check type
                if data.media_type not in ["tv", "movie"]:
                    await message.channel.send(trans.get("MSG_IMDB_CANTPERSON", lang))
                    return

                # Try to send
                try:
                    info = trans.get("MSG_IMDB_PLOT", lang).format(data.title, data.overview)

                    await message.channel.send(filter_text(info))
                except AttributeError:
                    await message.channel.send(trans.get("MSG_IMDB_PLOT_MISSING", lang))


            # !imdb trailer
            elif subcommand == "trailer":
                data = await self._imdb_search(argument, message, lang)

                try:
                    title, trailer = filter_text(data.title), filter_text(data.trailer)
                    await message.channel.send(trans.get("MSG_IMDB_TRAILER", lang).format(title, trailer))
                except (AttributeError, KeyError):
                    await message.channel.send(trans.get("MSG_IMDB_TRAILER_MISSING", lang))

            # !imdb rating
            elif subcommand == "rating":
                data = await self._imdb_search(argument, message, lang)

                try:
                    title, vote_avg = filter_text(data.title), filter_text(data.vote_average)
                    content = trans.get("MSG_IMDB_RATINGS", lang).format(title, vote_avg)
                    await message.channel.send(content)
                except AttributeError:
                    await message.channel.send(trans.get("MSG_IMDB_RATINGS_MISSING", lang))

            # !imdb help
            elif subcommand == "help":
                await message.channel.send(trans.get("MSG_IMDB_HELP", lang).replace("_", prefix))

            # !imdb search
            else:
                # Parse arguments
                if subcommand == "search":
                    # !imdb search the hunger games
                    query = argument
                else:
                    # !imdb the hunger games
                    query = " ".join((subcommand, argument))

                data = await self._imdb_search(query, message, lang)

                # Check type
                if data.media_type in ["tv", "movie"]:
                    info = []

                    # Step-by-step adding - some data might be missing
                    try:
                        media_type = trans.get("MSG_IMDB_SERIES", lang) if data.media_type == "tv" else ""

                        info.append("**{}** {}\n".format(data.title, media_type))
                    except AttributeError:
                        pass

                    try:
                        genres = "`{}`".format("`, `".join(data.genres))
                        info.append(trans.get("MSG_IMDB_GENRES", lang).format(genres))
                    except AttributeError:
                        pass

                    try:
                        info.append(trans.get("MSG_IMDB_AVGRATING", lang).format(data.vote_average))
                    except AttributeError:
                        pass

                    if data.media_type == "tv":
                        try:
                            info.append(trans.get("MSG_IMDB_SEASONS", lang).format(len(data.seasons)))
                        except AttributeError:
                            pass

                    try:
                        info.append(trans.get("MSG_IMDB_SUMMARY", lang).format(data.overview))
                    except AttributeError:
                        pass

                    try:
                        if data.poster:
                            info.append(trans.get("MSG_IMDB_POSTER", lang).format(data.poster))
                    except AttributeError:
                        pass

                    # Compile together info that is available
                    media_info = filter_text("\n".join(info))

                else:
                    await message.channel.send(trans.get("MSG_IMDB_PERSON_NOT_SUPPORTED", lang))
                    return

                # Send the details
                try:
                    await message.channel.send(media_info)
                except errors.HTTPException:
                    await message.channel.send(trans.get("MSG_IMDB_ERROR", lang))
Beispiel #3
0
 def _prepare_channel(self, content, lang):
     return self.trans.get("MSG_REMINDER_CHANNEL", lang).format(
         filter_text(content, user_mention=False))
Beispiel #4
0
 def _prepare_private(self, content, lang):
     return self.trans.get("MSG_REMINDER_PRIVATE", lang).format(
         filter_text(content, user_mention=False))
Beispiel #5
0
    async def on_message(self, message, **kwargs):
        prefix = kwargs.get("prefix")

        trans = self.trans
        lang = kwargs.get("lang")

        if not is_valid_command(message.content, commands, prefix=prefix):
            return
        else:
            self.stats.add(MESSAGE)

        def startswith(*msg):
            for a in msg:
                if message.content.startswith(a):
                    return True

            return False

        if startswith(prefix + "steam"):
            await message.channel.trigger_typing()

            cut = message.content[len(prefix + "steam "):].strip(" ")

            try:
                subcommand, argument = cut.split(" ", maxsplit=1)
            # In case there are no parameters
            except ValueError:
                # Check if no subcommand - valid
                # If there's a subcommand, but no argument, fail
                if not cut.strip(" "):
                    await message.channel.send(
                        trans.get("MSG_STEAM_INVALID_PARAMS",
                                  lang).format(prefix))
                    return

                subcommand, argument = cut, ""

            # !steam games
            if subcommand == "games":
                if not argument:
                    await message.channel.send(
                        trans.get("MSG_STEAM_NEED_URL", lang))
                    return

                # Game search
                try:
                    username, games = await self.steam.get_owned_games(argument
                                                                       )
                except ValueError:
                    await message.channel.send(
                        trans.get("MSG_STEAM_INVALID_URL", lang))
                    return
                except (steamapi.errors.APIFailure,
                        steamapi.errors.APIException,
                        steamapi.errors.AccessException):
                    await message.channel.send(
                        trans.get("MSG_STEAM_PRIVATE", lang))
                    raise

                if not username:
                    await message.channel.send(
                        trans.get("ERROR_NO_USER2", lang))
                    self.stats.add(WRONG_ARG)
                    return

                if not games:
                    await message.channel.send(
                        trans.get("MSG_STEAM_PRIVATE_GAMES", lang))
                    self.stats.add(WRONG_ARG)
                    return

                games = ["`{}`".format(game) for game in games]

                try:
                    await message.channel.send(
                        trans.get("MSG_STEAM_GAMES",
                                  lang).format(username,
                                               filter_text(", ".join(games))))
                except HTTPException:
                    await message.channel.send(
                        trans.get("MSG_STEAM_GAMES_TOO_MANY", lang))

            elif subcommand == "user":
                if not argument:
                    await message.channel.send(
                        trans.get("MSG_STEAM_NEED_URL", lang))
                    return

                # Basic search
                try:
                    steam_user = await self.steam.get_user(argument)
                except ValueError:
                    await message.channel.send(
                        trans.get("MSG_STEAM_INVALID_URL", lang))
                    return
                except (steamapi.errors.APIFailure,
                        steamapi.errors.APIException):
                    await message.channel.send(
                        trans.get("MSG_STEAM_PRIVATE", lang))
                    raise

                if not steam_user:
                    await message.channel.send(
                        trans.get("ERROR_NO_USER2", lang))
                    self.stats.add(WRONG_ARG)
                    return

                state = trans.get("MSG_STEAM_ONLINE",
                                  lang) if steam_user.state else trans.get(
                                      "MSG_STEAM_OFFLINE", lang)

                try:
                    info = trans.get("MSG_STEAM_USER_INFO",
                                     lang).format(steam_user.name, state,
                                                  steam_user.level,
                                                  len(steam_user.games),
                                                  len(steam_user.friends),
                                                  argument)
                except AttributeError:
                    await message.channel.send(
                        trans.get("MSG_STEAM_PRIVATE", lang))
                    return

                if len(info) > 2000:
                    await message.channel.send(
                        trans.get("MSG_STEAM_FRIENDS_TOO_MANY", lang))

                else:
                    await message.channel.send(filter_text(info))

            elif subcommand == "help":
                await message.channel.send(
                    trans.get("MSG_STEAM_HELP", lang).replace("!", prefix))
Beispiel #6
0
    async def on_message(self, message, **kwargs):
        assert isinstance(message, Message)

        prefix = kwargs.get("prefix")

        trans = self.trans
        lang = kwargs.get("lang")

        if not is_valid_command(message.content, commands, prefix=prefix):
            return
        else:
            self.stats.add(MESSAGE)

        def startswith(*msg):
            for a in msg:
                if message.content.startswith(a):
                    return True

            return False

        if startswith(prefix + "wiki", prefix + "define"):
            if startswith(prefix + "wiki"):
                search = str(message.content)[len(prefix +
                                                  "wiki "):].strip(" ")
            elif startswith(prefix + "define"):
                search = str(message.content)[len(prefix +
                                                  "define "):].strip(" ")
            else:
                # Not possible, but k
                return

            if not search:
                await message.channel.send(trans.get("MSG_WIKI_NO_QUERY",
                                                     lang))
                return

            summary = filter_text(await self.wiki.get_definition(search))

            if not summary:
                await message.channel.send(trans.get("MSG_WIKI_NO_DEF", lang))
                return

            await message.channel.send(
                trans.get("MSG_WIKI_DEFINITION", lang).format(
                    search, add_dots(summary, max_len=MAX_WIKI_LENGTH)))

        elif startswith(prefix + "urban"):
            search = str(message.content)[len(prefix + "urban "):].strip(" ")

            if not search:
                await message.channel.send(
                    trans.get("MSG_URBAN_NO_QUERY", lang))
                return

            description = filter_text(await
                                      self.urban.urban_dictionary(search))

            if not description:
                await message.channel.send(trans.get("MSG_URBAN_NO_DEF", lang))
                return

            await message.channel.send(
                trans.get("MSG_URBAN_DEFINITION", lang).format(
                    search, add_dots(description, max_len=MAX_URBAN_LENGTH)))
Beispiel #7
0
    async def on_message(self, message, **kwargs):
        trans = self.trans

        prefix = kwargs.get("prefix")
        lang = kwargs.get("lang")

        simple_commands = {
            "( ͡° ͜ʖ ͡°)": trans.get("MSG_WHOKNOWS", lang)
        }

        # Loop over simple commands
        for k, v in simple_commands.items():
            if message.content.startswith(k):
                await message.channel.send(v)
                self.stats.add(MESSAGE)
                return

        # Check if this is a valid command
        if not is_valid_command(message.content, commands, prefix):
            return
        else:
            self.stats.add(MESSAGE)

        def startswith(*matches):
            for match in matches:
                if message.content.startswith(match):
                    return True

            return False

        # Other commands
        if startswith(prefix + "kappa"):
            await message.channel.send(file=File(KAPPA_LOCATION, "kappa.png"))

            self.stats.add(IMAGE_SENT)

        # !randomgif (optional_tag)
        elif startswith(prefix + "randomgif"):
            tags = message.content[len(prefix + "randomgif "):]

            gif = await self.gif.get_random_gif(tags or None)
            nonexistent = False

            if gif == -1:
                await message.channel.send(trans.get("MSG_GIPHY_TOOFAST", lang))
                return

            # Gif with such tag does not exist, fall back to random one
            if gif is None:
                gif = await self.gif.get_random_gif()
                nonexistent = True

            embed = Embed(colour=Colour(GIPHY_GREEN))
            embed.set_image(url=gif)

            if not nonexistent:
                embed.set_footer(text=trans.get("MSG_GIPHY_POWEREDBY", lang))
            else:
                that_text = trans.get("MSG_GIPHY_POWEREDBY", lang) + " | " + trans.get("MSG_GIPHY_NOSUCHTAG", lang).format(add_dots(tags, 20))
                embed.set_footer(text=that_text)

            await message.channel.send(embed=embed)

            self.stats.add(IMAGE_SENT)

        # !meme [meme name]|[top text]|[bottom text]
        elif startswith(prefix + "meme"):
            query = message.content[len(prefix + "meme "):]

            if not query:
                await message.channel.send(trans.get("ERROR_INVALID_CMD_ARGUMENTS", lang))
                return

            middle = [a.strip(" ") for a in query.split("|")]

            # If only two arguments are passed, assume no bottom text
            if len(middle) == 2:
                name = middle[0]
                top = middle[1]
                bottom = ""

            # 0, 1 or more than 3 arguments - error
            elif len(middle) < 2 or len(middle) > 3:
                await message.channel.send(trans.get("MSG_MEME_USAGE", lang).format(prefix=prefix))
                return

            # Normal
            else:
                name = middle[0]
                top = middle[1]
                bottom = middle[2]

            meme = await self.generator.caption_meme(name, top, bottom)

            if not meme:
                await message.channel.send(trans.get("MSG_MEME_NONEXISTENT", lang))
            else:
                embed = Embed(colour=Colour(0x607D8B))
                embed.set_image(url=meme)
                embed.set_footer(text=trans.get("MSG_MEME_FOOTER", lang))

                await message.channel.send(embed=embed)

        elif startswith(prefix + "rip"):
            if len(message.mentions) == 1:
                rip_text = " " + message.mentions[0].name
            elif len(message.mentions) == 0:
                rip_text = " " + message.content[len(prefix + "rip "):]
            else:
                rip_text = ""

            rip_text = filter_text(rip_text)

            prays = self.stats.get_amount(PRAYER)
            await message.channel.send(trans.get("MSG_RIP", lang).format(rip_text, prays))

            self.stats.add(PRAYER)

        elif startswith(prefix + "achievement"):
            text = message.content[len(prefix + "achievement "):].strip(" ")

            if not text:
                await message.channel.send(trans.get("MSG_ACHIEVMENT_NOTEXT", lang))
                return

            img = self.achievement.create_image(text)
            img_filename = "Achievement_{}.png".format(gen_id(4))

            await message.channel.send(file=File(img, img_filename))
            # Just in case GC fails
            del img
Beispiel #8
0
    async def on_message(self, message, **kwargs):
        trans = self.trans

        prefix = kwargs.get("prefix")
        lang = kwargs.get("lang")

        # Check if this is a valid command
        if not is_valid_command(message.content, commands, prefix):
            return
        else:
            self.stats.add(MESSAGE)

        def startswith(*matches):
            for match in matches:
                if message.content.startswith(match):
                    return True

            return False

        # !cat gif/jpg/png
        if startswith(prefix + "cat"):
            fmt = str(message.content[len(prefix + "cat"):]).strip(" ")

            # GIF is the default type!
            if fmt == "jpg":
                type_ = "jpg"
            elif fmt == "png":
                type_ = "png"
            else:
                type_ = "gif"

            pic = await self.cats.random_cat(type_)

            if pic:
                # Teal (blue-ish)
                embed = Embed(colour=Colour(0x00796b))
                embed.set_image(url=pic)
                embed.set_footer(text=trans.get("MSG_CAT_FOOTER", lang))

                await message.channel.send(embed=embed)
            else:
                await message.channel.send(trans.get("MSG_CAT_FAILED", lang))

            self.stats.add(IMAGE_SENT)

        # !xkcd random/number/latest
        elif startswith(prefix + "xkcd"):
            fmt = str(message.content[len(prefix + "xkcd"):]).strip(" ")

            # Decides mode
            fetch = "random"
            if fmt:
                if is_number(fmt):
                    # Check if number is valid
                    if int(fmt) > self.xkcd.last_num:
                        await message.channel.send(
                            trans.get("MSG_XKCD_NO_SUCH", lang))
                        return
                    else:
                        fetch = "number"
                elif fmt == trans.get("INFO_RANDOM", lang) or fmt == "random":
                    fetch = "random"
                # Any other argument means latest
                else:
                    fetch = "latest"
            # Default: random
            else:
                fetch == "random"

            if fetch == "random":
                xkcd = await self.xkcd.get_random_xkcd()
            elif fetch == "number":
                xkcd = await self.xkcd.get_xkcd_by_number(fmt)
            # Can only mean latest
            else:
                xkcd = await self.xkcd.get_latest_xkcd()

            # In case something went wrong
            if not xkcd:
                await message.channel.send(trans.get("MSG_XKCD_FAILED", lang))
                log_to_file("XKCD: string {}, fetch: {}, got None".format(
                    fmt, fetch))

            xkcd_link = self.xkcd.make_link(xkcd["num"])

            embed = Embed(title=trans.get("MSG_XKCD",
                                          lang).format(xkcd["num"]),
                          description=filter_text(xkcd["safe_title"]))
            embed.set_image(url=xkcd["img"])
            embed.set_footer(
                text=trans.get("MSG_XKCD_SOURCE", lang).format(xkcd_link))

            await message.channel.send(embed=embed)

        # !joke (yo mama/chuck norris)
        elif startswith(prefix + "joke"):
            content = filter_text(self.joke.random_joke())

            embed = Embed(description=content)
            await message.channel.send(embed=embed)
Beispiel #9
0
    async def on_message(self, message, **kwargs):
        assert isinstance(message, Message)

        prefix = kwargs.get("prefix")

        trans = self.trans
        lang = kwargs.get("lang")

        if not is_valid_command(message.content, commands, prefix=prefix):
            return
        else:
            self.stats.add(MESSAGE)

        def startswith(*msg):
            for a in msg:
                if message.content.startswith(a):
                    return True

            return False

        if startswith(prefix + "wiki", prefix + "define"):
            if startswith(prefix + "wiki"):
                search = str(message.content)[len(prefix +
                                                  "wiki "):].strip(" ")
            elif startswith(prefix + "define"):
                search = str(message.content)[len(prefix +
                                                  "define "):].strip(" ")
            else:
                # Shouldn't happen, RuntimeError means startswith() is not working properly
                raise RuntimeError

            # filter mentions
            search = filter_text(search)

            if not search:
                await message.channel.send(trans.get("MSG_WIKI_NO_QUERY",
                                                     lang))
                return

            summary = await self.wiki.get_definition(search)

            if not summary:
                await message.channel.send(trans.get("MSG_WIKI_NO_DEF", lang))
                return

            await message.channel.send(
                trans.get("MSG_WIKI_DEFINITION", lang).format(
                    search,
                    add_dots(filter_text(summary), max_len=MAX_WIKI_LENGTH)))

        elif startswith(prefix + "urban"):
            search = str(message.content)[len(prefix + "urban "):].strip(" ")

            if not search:
                await message.channel.send(
                    trans.get("MSG_URBAN_NO_QUERY", lang))
                return

            # filter mentions
            search = filter_text(search)

            description = await self.urban.urban_dictionary(search)

            if not description:
                await message.channel.send(trans.get("MSG_URBAN_NO_DEF", lang))
                return

            await message.channel.send(
                trans.get("MSG_URBAN_DEFINITION", lang).format(
                    search,
                    add_dots(filter_text(description),
                             max_len=MAX_URBAN_LENGTH)))
Beispiel #10
0
    async def on_message(self, message, **kwargs):
        trans = self.trans

        prefix = kwargs.get("prefix")
        lang = kwargs.get("lang")

        # Check if this is a valid command
        if not is_valid_command(message.content, commands, prefix):
            return
        else:
            self.stats.add(MESSAGE)

        def startswith(*matches):
            for match in matches:
                if message.content.startswith(match):
                    return True

            return False

        # !poll start
        # Arguments: "[title]" [option1]|(option2)|...
        # OR       : "[title]" [option1],(option2),...
        if startswith(prefix + "poll start"):
            if not self.handler.is_admin(message.author, message.guild):
                await message.channel.send(trans.get("PERM_ADMIN", lang))
                self.stats.add(WRONG_PERMS)
                return

            if self.vote.in_progress(message.guild.id):
                await message.channel.send(trans.get("MSG_VOTING_IN_PROGRESS", lang))
                return

            arguments = message.content[len(prefix + "poll start "):].strip(" ")
            if not arguments:
                await message.channel.send(trans.get("MSG_VOTING_I_USAGE", lang).format(prefix))
                return

            # TITLE
            # Handle short_title, "longer title", 'also like this'
            if arguments[0] == "\"":
                _, title, arguments = arguments.split("\"", maxsplit=3)
            elif arguments[0] == "'":
                _, title, arguments = arguments.split("'", maxsplit=3)
            else:
                title, arguments = arguments.split(" ", maxsplit=1)

            arguments = arguments.lstrip(" ")


            # CHOICES
            # | as separator
            if "|" in arguments:
                items = [a.strip(" ") for a in arguments.split("|") if a]
            # , used as separator
            else:
                items = [a.strip(" ") for a in arguments.split(",") if a]

            # Send an error if there's only a title
            if len(items) < 2:
                await message.channel.send(trans.get("MSG_VOTING_NEED_OPTIONS", lang).format(prefix))
                return
            # END OF ARGUMENT PARSING


            # Check item amount
            if len(items) > VOTE_ITEM_LIMIT:
                await message.channel.send(trans.get("MSG_VOTING_OPTIONS_TM", lang).format(VOTE_ITEM_LIMIT, len(items)))
                return

            # Check total length
            if (len(title) + sum([len(a) for a in items])) > VOTE_ITEM_MAX_LENGTH:
                await message.channel.send(trans.get("MSG_VOTING_OPTIONS_TL ", lang).format(VOTE_ITEM_MAX_LENGTH, sum([len(a) for a in items])))
                return

            # Check if any option is empty
            if any(e == "" for e in items):
                await message.channel.send(trans.get("MSG_VOTING_EMPTY_ITEM", lang))
                return

            # Filter text (remove @ everyone, etc)
            title, items = filter_text(title), [filter_text(i) for i in items]

            self.vote.start_vote(message.author.id, message.guild.id, title, items)

            # Generates a list of options to show
            choices = "\n\n".join(["[{}]\n{}".format(en + 1, ch) for en, ch in
                                   enumerate(self.vote.get_choices(message.guild.id))])

            await message.channel.send(trans.get("MSG_VOTING_STARTED", lang).format(title, choices))

        # !poll end
        elif startswith(prefix + "poll end"):
            if not self.handler.is_admin(message.author, message.guild):
                await message.channel.send(trans.get("PERM_ADMIN", lang))
                self.stats.add(WRONG_PERMS)
                return

            if not self.vote.in_progress(message.guild.id):
                await message.channel.send(trans.get("MSG_VOTING_NO_PROGRESS", lang))
                return

            # Wait for confirmation
            msg = await message.channel.send(trans.get("MSG_VOTING_END_CONFIRMATION", lang).format(OK_EMOJI))
            await msg.add_reaction(OK_EMOJI)

            def check(reaction, user):
                return user == message.author and str(reaction.emoji) == OK_EMOJI

            try:
                await self.client.wait_for('reaction_add', timeout=45, check=check)
            except asyncio.TimeoutError:
                await message.channel.send(trans.get("MSG_VOTING_END_ABORT", lang))
                return

            await msg.delete()

            votes = self.vote.get_votes(message.guild.id)
            title = self.vote.get_title(message.guild.id)

            total_votes = sum(votes.values())

            embed = Embed(title="**{}**".format(title), colour=Colour(0x303F9F), description=trans.get("MSG_VOTING_AMOUNT", lang).format(total_votes))

            for name, val in votes.items():
                # Zero-width space
                dotted = add_dots(name, max_len=240) or "\u200B"
                embed.add_field(name=dotted, value=trans.get("MSG_VOTING_AMOUNT2", lang).format(val))

            # Actually end the voting
            self.vote.end_voting(message.guild.id)

            try:
                await message.channel.send(trans.get("MSG_VOTING_ENDED", lang) + "\n", embed=embed)
            except errors.HTTPException as e:
                await message.channel.send(trans.get("MSG_VOTING_ERROR", lang))
                log_to_file("VOTING ({}): {}".format(e, embed.to_dict()), "bug")

        # !poll status
        elif startswith(prefix + "poll status"):
            if not self.vote.in_progress(message.guild.id):
                await message.channel.send(trans.get("MSG_VOTING_NO_PROGRESS", lang))
                return

            header = filter_text(self.vote.get_title(message.guild.id))
            votes = sum(self.vote.get_votes(message.guild.id).values())

            if votes == 0:
                vote_disp = trans.get("MSG_VOTING_S_NONE", lang)
            elif votes == 1:
                vote_disp = trans.get("MSG_VOTING_S_ONE", lang)
            else:
                vote_disp = trans.get("MSG_VOTING_S_MULTI", lang).format(votes)

            await message.channel.send(trans.get("MSG_VOTING_STATUS", lang).format(header, vote_disp))

        # !vote
        elif startswith(prefix + "vote"):
            # Ignore if there is no vote going on instead of getting an exception
            if not self.vote.in_progress(message.guild.id):
                await message.add_reaction(X_EMOJI)

                msg = await message.channel.send(trans.get("MSG_VOTING_NO_PROGRESS", lang))
                await asyncio.sleep(2)
                await msg.delete()

                return

            # Get the choice, but tell the author if he/she didn't supply a number
            try:
                choice = int(message.content[len(prefix + "vote "):]) - 1
            # Cannot convert to int
            except ValueError:
                await message.add_reaction(BLOCK_EMOJI)

                m = await message.channel.send(trans.get("MSG_VOTING_NOT_NUMBER", lang))
                await asyncio.sleep(2)
                await m.delete()
                return

            res = self.vote.plus_one(choice, message.author.id, message.guild.id)

            # User already voted
            if res == -1:
                await message.add_reaction(BLOCK_EMOJI)

                msg = await message.channel.send(trans.get("MSG_VOTING_CHEATER", lang))
                await asyncio.sleep(2)
                await msg.delete()

            # No such option
            elif not res:
                await message.add_reaction(X_EMOJI)

                msg = await message.channel.send(trans.get("MSG_VOTING_INVALID_NUMBER", lang))
                await asyncio.sleep(2)
                await msg.delete()

            # Everything ok, was added
            else:
                await message.add_reaction(OK_EMOJI)

            self.stats.add(VOTE)
Beispiel #11
0
    async def on_message(self, message, **kwargs):
        client = self.client
        trans = self.trans

        prefix = kwargs.get("prefix")
        lang = kwargs.get("lang")

        # Custom commands registered for the server
        server_commands = self.handler.get_custom_commands_keys(
            message.guild.id)

        if server_commands:
            # According to tests, .startswith is faster than slicing, m8pls
            for k in server_commands:
                k = str(k)

                if message.content.startswith(k):
                    # raw_resp = self.handler.get_custom_command_by_key(message.guild.id, k)
                    # response = self.parser.parse(raw_resp, message)
                    response = self.handler.get_custom_command_by_key(
                        message.guild.id, k)

                    await message.channel.send(response)
                    return

        # Check if this is a valid command
        if not is_valid_command(message.content, commands, prefix):
            return
        else:
            self.stats.add(MESSAGE)

        def startswith(*matches):
            for match in matches:
                if message.content.startswith(match):
                    return True

            return False

        # COMMANDS

        # !hello
        if startswith(prefix + "hello"):
            argument = message.content[len(prefix + "hello "):]

            # Parse mentions or name
            if argument:
                if len(message.mentions) > 0:
                    mention = message.mentions[0].mention
                else:
                    # Find user
                    usr = utils.find(lambda a: a.name == argument,
                                     message.guild.members)
                    if not usr:
                        mention = message.author.mention
                    else:
                        mention = usr.mention
            else:
                mention = message.author.mention

            if len(message.mentions) >= 1:
                await message.channel.send(
                    trans.get("INFO_HI", lang).format(mention))
            elif len(message.mentions) == 0:
                await message.channel.send(
                    trans.get("INFO_HI", lang).format(mention))

        # !uptime
        elif startswith(prefix + "uptime"):
            d = datetime(
                1, 1, 1) + timedelta(seconds=time.time() - self.nano.boot_time)
            uptime = trans.get("MSG_UPTIME",
                               lang).format(d.day - 1, d.hour, d.minute,
                                            d.second)

            await message.channel.send(uptime)

        # !nano, nano.info
        elif startswith((prefix + "nano", "nano.info")):
            await message.channel.send(
                trans.get("INFO_GENERAL", lang).format(p=prefix,
                                                       ver=self.nano.version))

        # !github
        elif startswith(prefix + "github"):
            await message.channel.send(trans.get("INFO_GITHUB", lang))

        # !roll [number]
        elif startswith(prefix + "roll", prefix + "rng "):
            if startswith(prefix + "roll"):
                num = message.content[len(prefix + "roll "):]
            else:
                num = message.content[len(prefix + "rng "):]

            if not num.isnumeric():
                await message.channel.send(trans.get("ERROR_NOT_NUMBER", lang))
                return

            rn = randint(0, int(num))
            result = "**{}**. {}".format(rn,
                                         "**GG**" if rn == int(num) else "")

            await message.channel.send(
                trans.get("MSG_ROLL", lang).format(message.author.mention,
                                                   result))

        # !dice [dice expression: 5d6 + 1d8]
        elif startswith(prefix + "dice"):
            cut = message.content[len(prefix + "dice "):]

            # Defaults to a normal dice
            if not cut:
                dice_types = ["1d6"]
            else:
                dice_types = [a.strip(" ") for a in cut.split("+")]

            # To prevent lag
            if len(dice_types) > MAX_DICE_EXPR:
                await message.channel.send(
                    trans.get("MSG_DICE_TOO_MANY", lang).format(MAX_DICE_EXPR))
                return

            results = []
            tt = 0
            for dice in dice_types:
                try:
                    times, sides = dice.split("d")
                    times, sides = int(times), int(sides)

                    if sides <= 0 or times <= 0:
                        raise ValueError("can't roll 0 sides/times")

                except ValueError:
                    await message.channel.send(
                        trans.get("MSG_DICE_INVALID",
                                  lang).format(prefix=prefix))
                    return

                if times > MAX_DICE or sides > MAX_DICE:
                    await message.channel.send(
                        trans.get("MSG_DICE_TOO_BIG", lang).format(MAX_DICE))
                    return

                total = 0
                for _ in range(times):
                    total += randint(1, sides)

                tt += total

                results.append(
                    trans.get("MSG_DICE_ENTRY", lang).format(dice, total))

            await message.channel.send(
                trans.get("MSG_DICE_RESULTS",
                          lang).format(message.author.mention,
                                       "\n".join(results), tt))

        # !ping
        elif startswith(prefix + "ping"):
            base_time = datetime.now() - message.created_at
            base_taken = int(divmod(base_time.total_seconds(), 60)[1] * 1000)

            a = await message.channel.send(
                trans.get("MSG_PING_MEASURING", lang))
            self.pings[a.id] = [time.monotonic(), a, base_taken]

            # Thumbs up
            await a.add_reaction("\U0001F44D")
            self.stats.add(PING)

        # !decide [item1]|[item2]|etc...
        elif startswith(prefix + "decide"):
            cut = str(message.content)[len(prefix + "decide "):].strip(" ")

            if not cut:
                await message.channel.send(
                    trans.get("MSG_DECIDE_NO_ARGS", lang))
                return

            # If | is not used, try spaces
            options = cut.split("|")
            if len(options) == 1:
                options = cut.split(" ")

            if len(options) == 1:
                await message.channel.send(
                    trans.get("MSG_DECIDE_SPECIAL", lang).format(cut))

            else:
                rn = randint(0, len(options) - 1)
                await message.channel.send(
                    trans.get("MSG_DECIDE_NORMAL", lang).format(options[rn]))

        # !8ball
        elif startswith(prefix + "8ball"):
            eight_ball = [
                a.strip(" ")
                for a in trans.get("MSG_8BALL_STRINGS", lang).split("|")
            ]
            answer = eight_ball[randint(0, len(eight_ball) - 1)]

            await message.channel.send(
                trans.get("MSG_8BALL", lang).format(answer))

        # !quote
        elif startswith(prefix + "quote"):
            chosen = str(quotes[randint(0, len(quotes) - 1)])

            # Find the part where the author is mentioned
            place = chosen.rfind("–")
            await message.channel.send("{}\n- __{}__".format(
                chosen[:place], chosen[place + 1:]))

        # !invite
        elif startswith(prefix + "invite", "nano.invite"):
            # ONLY FOR TESTING - if nano beta is active
            if startswith("nano.invite.make_real"):
                application = await client.application_info()

                # Most of the permissions that Nano uses
                perms = "1543765079"
                url = "<https://discordapp.com/oauth2/" \
                      "authorize?client_id={}&scope=bot&permissions={}>".format(application.id, perms)

                await message.channel.send(
                    trans.get("INFO_INVITE", lang).replace("<link>", url))
                return

            await message.channel.send(
                trans.get("INFO_INVITE",
                          lang).replace("<link>",
                                        "<http://invite.nanobot.pw>"))

        # !avatar
        elif startswith(prefix + "avatar"):
            name = message.content[len(prefix + "avatar "):]

            if not name:
                member = message.author
            else:
                member = await self.resolve_user(name, message, lang)

            url = member.avatar_url

            if url:
                await message.channel.send(
                    trans.get("MSG_AVATAR_OWNERSHIP",
                              lang).format(filter_text(member.name), url))
            else:
                await message.channel.send(
                    trans.get("MSG_AVATAR_NONE",
                              lang).format(filter_text(member.name)))

        # !say (#channel) [message]
        elif startswith(prefix + "say"):
            if not self.handler.is_mod(message.author, message.guild):
                await message.channel.send(trans.get("PERM_MOD", lang))
                return "return"

            content = str(message.content[len(prefix + "say "):]).strip(" ")

            if not content:
                await message.channel.send(
                    trans.get("ERROR_INVALID_CMD_ARGUMENTS", lang))
                return

            if len(message.channel_mentions) != 0:
                channel = message.channel_mentions[0]
                content = content.replace(channel.mention, "").strip(" ")
            else:
                channel = message.channel

            content = self.at_everyone_filter(content, message.author)

            try:
                await channel.send(content)
                await self.log_say_command(message, content, prefix, lang)
            except Forbidden:
                await message.channel.send(
                    trans.get("MSG_SAY_NOPERM", lang).format(channel.id))