Ejemplo n.º 1
0
 async def show_snipes(self,
                       ctx,
                       amount: int = 5,
                       channel: discord.TextChannel = None):
     """ Select the last N snipes from this channel. """
     if channel:
         if not ctx.author.guild_permissions.manage_messages:
             return await ctx.send(
                 "Sorry, you need to have 'Manage Messages' to view another channel."
             )
         if channel.is_nsfw() and not ctx.channel.is_nsfw():
             return await ctx.send(
                 "No peeping NSFW stuff in here you dirty boi/gurl.")
     channel = channel or ctx.channel
     query = "SELECT * FROM snipe_deletes WHERE guild_id = $2 AND channel_id = $3 ORDER BY id DESC LIMIT $1;"
     results = await self.bot.pool.fetch(query, amount, ctx.guild.id,
                                         channel.id)
     dict_results = [dict(result) for result in results] if results else []
     local_snipes = [
         snipe for snipe in self.snipe_deletes
         if snipe["channel_id"] == channel.id
     ]
     full_results = dict_results + local_snipes
     if not full_results:
         return await ctx.send("No snipes for this channel.")
     full_results = sorted(full_results,
                           key=lambda d: d["delete_time"],
                           reverse=True)[:amount]
     embeds = self._gen_delete_embeds(full_results)
     pages = RoboPages(
         source=SnipePageSource(range(0, len(embeds)), embeds),
         delete_message_after=True,
     )
     await pages.start(ctx)
Ejemplo n.º 2
0
    async def show_edit_snipes(self,
                               ctx,
                               amount: int = 5,
                               channel: discord.TextChannel = None):
        """ Edit snipes, shows the last N from. Must have manage_messages to choose a different channel. """
        # let's check that amount is an int, clear inputs
        if channel:
            if not ctx.author.guild_permissions.manage_messages:
                return await ctx.send(
                    "Sorry, you need to have 'Manage Messages' to view another channel."
                )
        if not 0 < amount < 15:
            raise commands.BadArgument("No more than 15 indexes at once.")

        channel = channel or ctx.channel
        query = "SELECT * FROM snipe_edits WHERE guild_id = $2 AND channel_id = $3 ORDER BY id DESC LIMIT $1;"
        results = await self.bot.pool.fetch(query, amount, ctx.guild.id,
                                            channel.id)
        dict_results = [dict(result) for result in results]
        local_snipes = [
            snipe for snipe in self.snipe_edits
            if snipe["channel_id"] == channel.id
        ]
        full_results = dict_results + local_snipes
        full_results = sorted(full_results,
                              key=lambda d: d["edited_time"],
                              reverse=True)[:amount]
        embeds = await self._gen_edit_embeds(full_results)
        if not embeds:
            return await ctx.send("No edit snipes for this channel.")
        pages = RoboPages(
            source=SnipePageSource(range(0, len(embeds)), embeds),
            delete_message_after=True,
        )
        await pages.start(ctx)
Ejemplo n.º 3
0
    async def words(self, ctx: Context, character: str):
        """ Return the words a Kanji is used in, or in conjuction with. """
        if len(character) > 1:
            raise commands.BadArgument("Only one Kanji please.")
        url = f"{BASE_URL}/words/{character}"

        async with self.bot.session.get(url) as response:
            data = await response.json()

        words_data = [WordsPayload(**payload) for payload in data]
        embeds = [
            KanjiEmbed.from_words(character, kanji) for kanji in words_data
        ]
        real_embeds = [embed for sublist in embeds for embed in sublist]

        fixed_embeds = [
            embed.set_footer(text=(
                f"{embed.footer.text} :: {real_embeds.index(embed) + 1}/{len(real_embeds)}"
                if embed.footer.text else
                f"{real_embeds.index(embed) + 1}/{len(real_embeds)}"))
            for embed in real_embeds
        ]

        menu = RoboPages(
            KanjiAPISource(fixed_embeds),
            delete_message_after=False,
            clear_reactions_after=False,
        )
        await menu.start(ctx)
Ejemplo n.º 4
0
    async def jisho(self, ctx: Context, *, query: str):
        """ Query the Jisho api with your kanji/word. """
        async with self.bot.session.get(JISHO_WORDS_URL,
                                        params={"keyword": query}) as response:
            if response.status == 200:
                data = (await response.json())["data"]
            else:
                raise commands.BadArgument("Not a valid query for Jisho.")
            if not data:
                raise commands.BadArgument("Not a valid query for Jisho.")

            jisho_data = [JishoPayload(**payload) for payload in data]
            embeds = [
                KanjiEmbed.from_jisho(query, item) for item in jisho_data
            ]

            fixed_embeds = [
                embed.set_footer(text=(
                    f"{embed.footer.text} :: {embeds.index(embed) + 1}/{len(embeds)}"
                    if embed.footer.
                    text else f"{embeds.index(embed) + 1}/{len(embeds)}"))
                for embed in embeds
            ]

            menu = RoboPages(
                KanjiAPISource(fixed_embeds),
                delete_message_after=False,
                clear_reactions_after=False,
            )
            await menu.start(ctx)
Ejemplo n.º 5
0
    async def send_cog_help(self, cog: commands.Cog):
        pages = []

        await self.format_commands(
            cog, await self.filter_commands(cog.get_commands(), sort=True), pages=pages
        )

        total = len(pages)
        for i, embed in enumerate(pages, start=1):
            embed.title = f"Page {i}/{total}: {embed.title}"

        pg = RoboPages(HelpSource(range(0, len(pages)), pages))
        await pg.start(self.context)
Ejemplo n.º 6
0
    async def stroke_order(self, ctx: Context, kanji: str) -> None:
        responses = []
        for char in kanji:
            url = quote(f"https://jisho.org/search/{char}#kanji", safe="/:?&")
            data = await ctx.bot.session.get(url)
            soup = bs4.BeautifulSoup(await data.content.read(), "html.parser")
            response = JishoKanji(char, soup, url)
            responses.append(response)

        embeds = self._gen_kanji_embed(responses)
        source = KanjiAPISource(embeds)
        menu = RoboPages(source=source)
        await menu.start(ctx)
Ejemplo n.º 7
0
    async def todo_list(self, ctx: Context) -> None:
        """A list of todos for you."""
        query = """ SELECT * FROM todos WHERE owner_id = $1 ORDER BY id ASC LIMIT 100; """
        records = await self.bot.pool.fetch(query, ctx.author.id)

        if not records:
            await ctx.send(
                "You appear to have no active todos, look at how productive you are."
            )
            return
        embeds = self._gen_todos(records)
        pages = RoboPages(source=SimpleListSource(embeds), ctx=ctx)
        await pages.start()
Ejemplo n.º 8
0
    async def kanji(self, ctx: Context, character: str):
        """ Return data on a single Kanji from the KanjiDev API. """
        if len(character) > 1:
            raise commands.BadArgument("Only one Kanji please.")
        url = f"{BASE_URL}/kanji/{character}"

        async with self.bot.session.get(url) as response:
            data = await response.json()

        kanji_data = KanjiPayload(**data)

        embed = KanjiEmbed.from_kanji(kanji_data)

        menu = RoboPages(KanjiAPISource([embed]))
        await menu.start(ctx)
Ejemplo n.º 9
0
    async def send_bot_help(
        self,
        mapping: Mapping[commands.Cog, List[Union[commands.Group, commands.Command]]],
    ):
        pages = []

        for cog, cmds in mapping.items():
            cmds = await self.filter_commands(cmds, sort=True)
            await self.format_commands(cog, cmds, pages=pages)

        total = len(pages)
        for i, embed in enumerate(pages, start=1):
            embed.title = f"Page {i}/{total}: {embed.title}"

        pg = RoboPages(HelpSource(range(0, len(pages)), pages))
        await pg.start(self.context)
Ejemplo n.º 10
0
    async def stroke_order(self, ctx: Context, kanji: str) -> None:
        """
        Returns an animation of the stroke order of the provided kana/kanji.
        """
        responses = []
        for char in kanji:
            url = quote(f"https://jisho.org/search/{char}#kanji", safe="/:?&")
            data = await ctx.bot.session.get(url)
            soup = bs4.BeautifulSoup(await data.content.read(), "html.parser")
            response = JishoKanji(char, soup, url)
            responses.append(response)

        embeds = self._gen_kanji_embed(responses)
        source = SimpleListSource(embeds)
        menu = RoboPages(source=source, ctx=ctx)
        await menu.start()
Ejemplo n.º 11
0
 async def _reddit(self,
                   ctx: commands.Context,
                   subreddit: str,
                   sort_by: str = "hot"):
     """ Main Reddit command, subcommands to be added. """
     sub_re = re.compile(r"(/?(r/)?(?P<subname>.*))")
     sub_search = sub_re.search(subreddit)
     if sub_search.group("subname"):
         subreddit = sub_search["subname"]
     embeds = await self._perform_search(str(ctx.author), ctx.channel,
                                         subreddit, sort_by)
     if not embeds:
         raise commands.BadArgument("Bad subreddit.", subreddit)
     pages = RoboPages(source=SubredditPageSource(embeds),
                       delete_message_after=True)
     await pages.start(ctx)
Ejemplo n.º 12
0
    async def todo_list(self, ctx):
        """ A list of todos for you. """
        query = (
            """ SELECT * FROM todos WHERE owner_id = $1 ORDER BY id ASC LIMIT 100; """
        )
        records = await self.bot.pool.fetch(query, ctx.author.id)

        if not records:
            return await ctx.send(
                "You appear to have no active todos, look at how productive you are."
            )
        embeds = self._gen_todos(records)
        pages = RoboPages(
            source=TodoPageSource(range(0, len(embeds)), embeds),
            delete_message_after=True,
        )
        await pages.start(ctx)
Ejemplo n.º 13
0
    async def _urban(self, ctx, *, word):
        """Searches urban dictionary."""

        url = "http://api.urbandictionary.com/v0/define"
        async with ctx.session.get(url, params={"term": word}) as resp:
            if resp.status != 200:
                return await ctx.send(
                    f"An error occurred: {resp.status} {resp.reason}")

            js = await resp.json()
            data = js.get("list", [])
            if not data:
                return await ctx.send("No results found, sorry.")

        pages = RoboPages(UrbanDictionaryPageSource(data))
        try:
            await pages.start(ctx)
        except menus.MenuError as e:
            await ctx.send(e)
Ejemplo n.º 14
0
    async def danbooru(self, ctx: Context, *, params: str) -> None:
        """Danbooru command. Access danbooru commands.
        This command uses a flag style syntax.
        The following options are valid.

        `*` denotes it is a mandatory argument.

        `+t | ++tags`: The tags to search Gelbooru for. `*` (uses logical AND per tag)
        `+l | ++limit`: The maximum amount of posts to show. Cannot be higher than 30.

        Examples:
        ```
        !gelbooru ++tags lemon
            - search for the 'lemon' tag.
            - NOTE: if your tag has a space in it, replace it with '_'

        !danbooru ++tags melon -rating:explicit
            - search for the 'melon' tag, removing posts marked as 'explicit`

        !danbooru ++tags apple orange rating:safe
            - Search for the 'apple' AND 'orange' tags, with only 'safe' results.
        ```
        """
        aiohttp_params = {}
        parser = argparse.ArgumentParser(add_help=False,
                                         allow_abbrev=False,
                                         prefix_chars="+")
        parser.add_argument("+t", "++tags", nargs="+", required=True)
        parser.add_argument("+l", "++limit", type=int, default=40)
        try:
            real_args = parser.parse_args(shlex.split(params))
        except SystemExit as f**k:
            raise commands.BadArgument(
                "Your flags could not be parsed.") from f**k
        except Exception as err:
            await ctx.send(f"Parsing your args failed: {err}.")
            return

        current_config = await self.get_booru_config(
            getattr(ctx.guild, "id", -1))

        if real_args.limit:
            limit = real_args.limit
            if not 1 < real_args.limit <= 30:
                limit = 30
            aiohttp_params.update({"limit": limit})
        lowered_tags = [tag.lower() for tag in real_args.tags]
        tags = set(lowered_tags)
        common_elems = tags & current_config.blacklist
        if common_elems:
            raise BlacklistedBooru(common_elems)
        aiohttp_params.update({"tags": " ".join(lowered_tags)})

        async with ctx.typing():
            async with self.bot.session.get(
                    self.danbooru_config.endpoint,
                    params=aiohttp_params,
                    auth=self.danbooru_config.auth,
            ) as resp:
                data = await resp.text()
                if not data:
                    ctx.command.reset_cooldown(ctx)
                    raise commands.BadArgument(
                        "Got an empty response... bad search?")
                json_data = json.loads(data)

            if not json_data:
                ctx.command.reset_cooldown(ctx)
                raise commands.BadArgument(
                    "The specified query returned no results.")

            embeds = self._gen_danbooru_embeds(json_data, current_config)
            if not embeds:
                fmt = "Your search had results but all of them contained blacklisted tags"
                if "loli" in lowered_tags:
                    fmt += "\nPlease note that Danbooru does not support 'loli'."
                raise commands.BadArgument(fmt)

            pages = RoboPages(source=SimpleListSource(embeds[:30]), ctx=ctx)
            await pages.start()
Ejemplo n.º 15
0
    async def gelbooru(self, ctx: Context, *, params: str):
        """This command uses a flag style syntax.
        The following options are valid.

        `*` denotes it is a mandatory argument.

        `+t | ++tags`: The tags to search Gelbooru for. `*` (uses logical AND per tag)
        `+l | ++limit`: The maximum amount of posts to show. Cannot be higher than 30.
        `+p | ++pid`: Page ID to search. Handy when posts begin to repeat.
        `+c | ++cid`: Change ID of the post to search for(?)

        Examples:
        ```
        !gelbooru ++tags lemon
            - search for the 'lemon' tag.
            - NOTE: if your tag has a space in it, replace it with '_'

        !gelbooru ++tags melon -rating:explicit
            - search for the 'melon' tag, removing posts marked as 'explicit`

        !gelbooru ++tags apple orange rating:safe ++pid 2
            - Search for the 'apple' AND 'orange' tags, with only 'safe' results, but on Page 2.
            - NOTE: if not enough searches are returned, page 2 will cause an empty response.
        ```
        """
        aiohttp_params = {}
        aiohttp_params.update({"json": 1})
        parser = argparse.ArgumentParser(add_help=False,
                                         allow_abbrev=False,
                                         prefix_chars="+")
        parser.add_argument("+l", "++limit", type=int, default=40)
        parser.add_argument("+p", "++pid", type=int)
        parser.add_argument("+t", "++tags", nargs="+", required=True)
        parser.add_argument("+c", "++cid", type=int)
        try:
            real_args = parser.parse_args(shlex.split(params))
        except SystemExit as f**k:
            raise commands.BadArgument(
                "Your flags could not be parsed.") from f**k
        except Exception as err:
            await ctx.send(f"Parsing your args failed: {err}")
            return

        current_config = await self.get_booru_config(
            getattr(ctx.guild, "id", -1))

        if real_args.limit:
            aiohttp_params.update({"limit": int(real_args.limit)})
        if real_args.pid:
            aiohttp_params.update({"pid": real_args.pid})
        if real_args.cid:
            aiohttp_params.update({"cid", real_args.cid})
        lowered_tags = [tag.lower() for tag in real_args.tags]
        tags_set = set(lowered_tags)
        common_elems = tags_set & current_config.blacklist
        if common_elems:
            raise BlacklistedBooru(common_elems)
        aiohttp_params.update({"tags": " ".join(lowered_tags)})

        async with ctx.typing():
            async with self.bot.session.get(
                    self.gelbooru_config.endpoint,
                    params=aiohttp_params,
                    auth=self.gelbooru_config.auth,
            ) as resp:
                data = await resp.text()
                if not data:
                    ctx.command.reset_cooldown(ctx)
                    raise commands.BadArgument(
                        "Got an empty response... bad search?")
                json_data = json.loads(data)

            if not json_data:
                ctx.command.reset_cooldown(ctx)
                raise commands.BadArgument(
                    "The specified query returned no results.")

            embeds = self._gen_gelbooru_embeds(json_data, current_config)
            if not embeds:
                raise commands.BadArgument(
                    "Your search had results but all of them contain blacklisted tags."
                )
            pages = RoboPages(
                source=LewdPageSource(embeds[:30]),
                delete_message_after=False,
                clear_reactions_after=True,
            )
            await pages.start(ctx)