Ejemplo n.º 1
0
        def fmt(prs):
            if verbose:
                s = string.trunc("\n".join(f"**{n}** {d}" for n, d in prs),
                                 1024)
            else:
                s = string.trunc("\n".join(f"- {n}" for n, _ in prs), 1024)

            # Prevents errors for empty bodies.
            return s or "—"
Ejemplo n.º 2
0
    def _format_urban_defn(definition: dict) -> discord.Embed:
        """
        Takes an UrbanDictionary word response and formats an embed
        to represent the output, before returning it.
        """

        # Adds ellipses to the end and truncates if a string is too long.
        def dots(string, limit=1024):
            return string if len(string) < limit else string[: limit - 3] + "..."

        title = definition["word"].title()
        defn = dots(definition["definition"], 2000)

        # Remove embedded URLS to stop Discord following them.
        defn = defn.replace("https://", "").replace("http://", "")
        # [] signify bold phrases
        defn = defn.replace("[", "**").replace("]", "**")

        # Sanitise backticks and place in a code block if applicable.
        example = dots(definition["example"].replace("`", "’"))
        if example:
            example = f"`{string.trunc(example, 1000)}`"

        author = definition["author"]
        yes = definition["thumbs_up"]
        no = definition["thumbs_down"]
        permalink = definition["permalink"]

        embed = discord.Embed(
            title=title, description=string.trunc(defn), colour=0xFFFF00, url=permalink
        )

        embed.set_author(
            name=f"{author} (\N{HEAVY BLACK HEART} {yes} " f"\N{PILE OF POO} {no})"
        )

        if example:
            embed.add_field(name="Example", value=example)

        if "tags" in definition and definition["tags"]:
            tags = ", ".join(sorted({*definition["tags"]}))
            embed.set_footer(text=string.trunc(tags))
        return embed
Ejemplo n.º 3
0
    async def inspect_emoji(self, ctx, *, emoji: discord.Emoji = None):
        """
        Note that this will only work for custom emojis.
        If no emoji name is provided, we list all emojis available in this
        guild.
        """
        if emoji:

            desc = f'Created on {emoji.created_at.strftime("%c")}\n\n'

            if emoji.animated:
                desc += "Animated emoji\n"
            if emoji.require_colons:
                desc += "Must be wrapped in colons\n"
            if emoji.managed:
                desc += "Managed as part of a Twitch integration\n"
            if not emoji.roles:
                desc += "Emoji is usable by everyone here\n"

            rc = emoji.require_colons

            embed = discord.Embed(
                title=rc and f"`:{emoji.name}:`" or f"`{emoji}`",
                description=desc,
                url=emoji.url,
                colour=0xab19cf or emoji.animated and 0xd1851b,
            )

            if emoji.roles:
                embed.add_field(
                    name="Usable by",
                    value=string.trunc(", ".join(map(str, emoji.roles)), 1024),
                )

            embed.set_thumbnail(url=emoji.url)

            embed.set_author(name=f'Emoji in "{emoji.guild}"',
                             icon_url=emoji.url)
            embed.set_footer(text=str(emoji.id), icon_url=emoji.url)
            await ctx.send(embed=embed)
        elif len(ctx.guild.emojis) == 0:
            await ctx.send("This server has no emojis yet...", delete_after=10)
        else:
            binder = bookbinding.StringBookBinder(ctx, max_lines=None)

            def key(e):
                return e.name

            for i, e in enumerate(sorted(ctx.guild.emojis, key=key)):
                binder.add_line(f"`{i + 1:03}`\t{e} \t `{e}`")

            binder.start()
Ejemplo n.º 4
0
        async def fut(reply):
            resp = await destination.send(string.trunc(reply))

            if not bot.debug:
                # Delete after 30s.
                await asyncio.sleep(30)

                futs = [resp.delete()]
                if ctx:
                    futs.append(ctx.message.delete())

                try:
                    await asyncio.gather(*futs)
                except:
                    pass
Ejemplo n.º 5
0
    async def inspect_member(self, ctx, *, member: discord.Member = None):
        """
        If no member is specified, then I will show your profile instead.
        """
        if member is None:
            member = ctx.author

        embed = discord.Embed(title=f"`@{member}`", colour=member.colour)

        desc = "\n".join((
            f"Display name: `{member.display_name}`",
            f'Joined here on: {member.joined_at.strftime("%c")}',
            f'Joined Discord on: {member.created_at.strftime("%c")}',
            f"Top role: {member.top_role}",
            f"Colour: `#{hex(member.colour.value)[2:].zfill(6)}`",
            "Status: " + {
                discord.Status.online: "Online",
                discord.Status.idle: "Away",
                discord.Status.dnd: "Busy",
                discord.Status.invisible: "Hiding",
                discord.Status.offline: "Offline",
            }.get(member.status, "On Mars"),
            f'Account type: {member.bot and "Bot" or "Human"}',
        ))
        embed.description = desc
        embed.set_thumbnail(url=member.avatar_url)
        embed.set_footer(text=str(member.id),
                         icon_url=member.default_avatar_url)

        if member.roles:
            embed.add_field(
                name="Roles",
                value=string.trunc(", ".join(map(str, reversed(member.roles))),
                                   1024),
            )

        role_perms = Permissions.from_discord_type(member.guild_permissions)
        role_perms = {*role_perms.unmask()}

        chn_perms = member.permissions_in(ctx.channel)
        chn_perms = {*Permissions.from_discord_type(chn_perms).unmask()}

        # Calculate any extra perms granted for this channel only.
        chn_perms.difference_update(role_perms)

        if role_perms:
            role_perms = ", ".join(f"`{p}`" for p in role_perms)
        else:
            role_perms = "No role permissions granted (somehow)"

        embed.add_field(name="Role-granted permissions", value=role_perms)

        if member.activity:
            # This design is...not the best imho, but it is confusingly
            # defined in the API:
            # This attr can be a Game, Streaming or Activity, but Activity
            # itself can have a `playing` type which denotes a game, so...
            # how do we know which one to expect? Game is not a subtype
            # of activity nor vice versa!
            if isinstance(member.activity, discord.Activity):
                a = member.activity

                attrs = []
                # Less verbose.
                z = attrs.append

                if a.start:
                    z(f'Since: {a.start.strftime("%c")}')
                if a.end:
                    z(f'Until: {a.end.strftime("%c")}')

                if a.details:
                    z(f"Details: {a.details}")

                if a.small_image_text:
                    z(f"Small tooltip: {a.small_image_text}")
                if a.large_image_text:
                    z(f"Large tooltip: {a.large_image_text}")

                if not attrs:
                    z(a.name)
                else:
                    attrs.insert(0, f"Name: {a.name}")

                t = a.type
                t = "Activity" if t == discord.ActivityType.unknown else t.name.title(
                )

                embed.add_field(name=t, value="\n".join(attrs))
            elif isinstance(member.activity, discord.Game):
                embed.add_field(name="Playing", value=member.activity.name)

            elif isinstance(member.activity, discord.Streaming):
                a = member.activity
                embed.add_field(
                    name="Streaming",
                    value=f"[{a.twitch_name or a.name}]({a.url})\n"
                    f'{a.details or ""}',
                )

        if chn_perms:
            chn_perms = ", ".join(f"`{p}`" for p in chn_perms)
            embed.add_field(name="Additional permissions in this channel",
                            value=chn_perms)

        await ctx.send("Member inspection", embed=embed)
Ejemplo n.º 6
0
    async def inspect_channel(self,
                              ctx,
                              *,
                              channel: GuildChannelConverter = None):
        """
        Inspects a channel in this guild. If no channel is given, we check
        the current channel.
        """
        channel = channel or ctx.channel

        category = channel.category
        category = category and category.name.upper() or None

        if isinstance(channel, discord.TextChannel):
            try:
                wh_count = len(await channel.webhooks())
            except discord.Forbidden:
                wh_count = "I need `MANAGE_WEBHOOKS` first!"

            pin_count = len(await channel.pins())

            try:
                invite_count = len(await channel.invites())
            except discord.Forbidden:
                invite_count = "I need `MANAGE_CHANNELS` first!"

            embed = discord.Embed(
                title=f"`#{channel.name}`",
                colour=alg.rand_colour(),
                description="\n".join([
                    f"Type: Text channel",
                    f'Created on: {channel.created_at.strftime("%c")}',
                    f"Category: `{category}`",
                    f"NSFW: {string.yn(channel.is_nsfw()).lower()}",
                    f"Pin count: {pin_count}",
                    f"Webhook count: {wh_count}",
                    f"Invitations here: {invite_count}",
                ]),
            )

            if channel.topic:
                embed.add_field(name="Topic",
                                value=string.trunc(channel.topic, 1024),
                                inline=False)

            if len(channel.members) == len(ctx.guild.members):
                embed.add_field(
                    name="Accessible by",
                    value="All " +
                    string.plur_simple(len(channel.members), "member"),
                )
            elif len(channel.members) > 10:
                embed.add_field(name="Accessible by",
                                value=f"{len(channel.members)} members")
            elif channel.members:
                embed.add_field(
                    name="Accessible by",
                    value=", ".join(sorted(map(str, channel.members))),
                )
            else:
                embed.add_field(name="Accessible by",
                                value="No one has this role yet!")

            if channel.changed_roles:
                embed.add_field(
                    name="Roles with custom permissions",
                    value=", ".join(
                        str(c)
                        for c in sorted(channel.changed_roles, key=str)),
                )

        else:
            channel: discord.VoiceChannel = channel

            embed = discord.Embed(
                title=f"`#{channel.name}`",
                colour=alg.rand_colour(),
                description="\n".join([
                    f"Type: Text channel",
                    f'Created on: {channel.created_at.strftime("%c")}',
                    f"Category: `{category}`",
                    f"Bitrate: {channel.bitrate / 1000:,.2f}kbps",
                    f"User limit: {channel.user_limit or None}",
                ]),
            )

            if len(channel.members) == len(ctx.guild.members):
                embed.add_field(
                    name="Members in this VC",
                    value="All " +
                    string.plur_simple(len(channel.members), "member"),
                )
            elif len(channel.members) > 10:
                embed.add_field(name="Members in this VC",
                                value=f"{len(channel.members)} members")
            elif channel.members:
                embed.add_field(
                    name="Members in this VC",
                    value=", ".join(sorted(map(str, channel.members))),
                )
            else:
                embed.add_field(name="Members in this VC",
                                value="No one is in this VC yet!")

        embed.set_author(name=f"Channel #{channel.position + 1}")
        embed.set_footer(text=str(channel.id))
        await ctx.send("Channel inspection", embed=embed)
Ejemplo n.º 7
0
    async def info(self, ctx, package):
        """
        Shows a summary for the given package name on PyPI, if there is one.
        """
        url = f"https://pypi.org/pypi/{parse.quote(package)}/json"

        # Seems like aiohttp is screwed up and will not parse these URLS.
        # Requests is fine though. Guess I have to use that...
        with ctx.typing():
            conn = await self.acquire_http()
            resp = await conn.get(url=url)
            result = (await resp.json()) if 200 <= resp.status < 300 else None

        if result:
            data = result["info"]

            name = f'{data["name"]} v{data["version"]}'
            url = data["package_url"]
            summary = data.get("summary", "_No summary was provided_")
            author = data.get("author", "Unknown")
            serial = result.get("last_serial", "No serial")
            if isinstance(serial, int):
                serial = f"Serial #{serial}"

            # Shortens the classifier strings.
            classifiers = data.get("classifiers", [])
            if classifiers:
                fixed_classifiers = []
                for classifier in classifiers:
                    print()
                    if "::" in classifier:
                        _, _, classifier = classifier.rpartition("::")
                    classifier = f"`{classifier.strip()}`"
                    fixed_classifiers.append(classifier)
                classifiers = ", ".join(sorted(fixed_classifiers))

            other_attrs = {
                "License": data.get("license"),
                "Platform": data.get("platform"),
                "Homepage": data.get("home_page"),
                "Requires Python version": data.get("requires_python"),
                "Classifiers": classifiers,
            }

            embed = discord.Embed(
                title=name,
                description=string.trunc(summary, 2048),
                url=url,
                colour=alg.rand_colour(),
            )

            embed.set_author(name=f"{author}")
            embed.set_footer(text=f"{serial}")

            for attr, value in other_attrs.items():
                if not value:
                    continue

                embed.add_field(name=attr, value=value)

            await ctx.send(embed=embed)

        else:
            await ctx.send(f"PyPI said: {resp.reason}", delete_after=10)
Ejemplo n.º 8
0
    async def tldrlegal_logic(self, ctx, query, verbose):
        """
        Helper to prevent code duplication.
        """
        http = await self.acquire_http()

        # Get search results
        async with http.get(f"{base_url}search", params={"q": query}) as resp:
            if resp.status != 200:
                return await ctx.send(f"tldrlegal said {resp.reason!r}")

            results = self.get_results_from_html(await resp.text())

        count = len(results)

        if count == 0:
            return await ctx.send("Nothing was found.", delete_after=15)
        elif count == 1:
            # Get the URL
            page = results[0]
        else:
            page = await option_picker(
                ctx,
                *results,
                option_formatter=lambda o: o[0].replace("*", "∗"))

            if page is None:
                return await ctx.send("Took too long...")

        # Get the info into an object.
        async with http.get(page[1]) as resp:
            if resp.status != 200:
                return await ctx.send(f"tldrlegal said {resp.reason!r}")
            license_info = self.get_license_info(page[1], await resp.text())

        # Generate embed and send.
        embed = discord.Embed(
            title=license_info.name,
            description=string.trunc(license_info.brief),
            colour=alg.rand_colour(),
            url=license_info.url,
        )
        embed.set_footer(text="Disclaimer: This is only a short summary of the"
                         " Full Text. No information on TLDRLegal is"
                         " legal advice.")

        def fmt(prs):
            if verbose:
                s = string.trunc("\n".join(f"**{n}** {d}" for n, d in prs),
                                 1024)
            else:
                s = string.trunc("\n".join(f"- {n}" for n, _ in prs), 1024)

            # Prevents errors for empty bodies.
            return s or "—"

        embed.add_field(name="__CAN__",
                        value=fmt(license_info.can),
                        inline=not verbose)
        embed.add_field(name="__CANNOT__",
                        value=fmt(license_info.cant),
                        inline=not verbose)
        embed.add_field(name="__MUST__",
                        value=fmt(license_info.must),
                        inline=not verbose)

        if not verbose:
            embed.add_field(
                name="\u200b",
                value="_Run again using `tldrlegal more <query>` "
                "to get a longer explanation!_",
            )

        await ctx.send(embed=embed)