Exemple #1
0
    async def on_member_remove(self, member: discord.Member):
        if chan := member.guild.get_channel_or_thread(
                self.bot.config.getattr(member.guild.id,
                                        "join_leave_chan_id")):
            role_names = ", ".join(
                tuple(r.name for r in member.roles if not r.is_default()))
            if not role_names:
                role_names = "None"

            leave_embed = discord.Embed(
                color=discord.Color.red(),
                description=f"{member} left",
                timestamp=discord.utils.utcnow(),
            )
            leave_embed.add_field(
                name="User Information",
                value=f"{member} ({member.id}) {member.mention}",
                inline=False,
            )
            leave_embed.add_field(name="Roles", value=role_names, inline=False)
            if member.joined_at:
                leave_embed.add_field(
                    name="Joined At",
                    value=
                    (f"{discord.utils.format_dt(member.joined_at, style='F')} ({discord.utils.format_dt(member.joined_at, 'R')})"
                     ),
                    inline=False,
                )
            leave_embed.add_field(
                name="Created At",
                value=
                (f"{discord.utils.format_dt(member.created_at, style='F')} ({discord.utils.format_dt(member.created_at, 'R')})"
                 ),
                inline=False,
            )
            leave_embed.add_field(name="ID",
                                  value=f"```ini\nUser = {member.id}\n```",
                                  inline=False)

            leave_embed.set_author(
                name=str(member),
                icon_url=utils.get_icon_url(member._user.display_avatar),
            )
            leave_embed.set_footer(
                text=str(self.bot.user),
                icon_url=utils.get_icon_url(member.guild.me.display_avatar),
            )

            await chan.send(embed=leave_embed)
Exemple #2
0
    def embed_gen(self, ctx, description):
        selection_embed = discord.Embed(colour=discord.Colour(0x4378FC),
                                        description="\n".join(description))
        selection_embed.set_author(
            name=f"{ctx.guild.me.name}",
            icon_url=utils.get_icon_url(ctx.guild.me.display_avatar),
        )

        return selection_embed
Exemple #3
0
    async def run(self, ctx: utils.SeraContextBase):
        def check(m: discord.Message):
            return m.author == ctx.author and m.channel == ctx.channel

        wizard_embed = discord.Embed(title=self.embed_title, colour=self.color)
        wizard_embed.set_author(
            name=f"{ctx.bot.user.name}",
            icon_url=utils.get_icon_url(ctx.guild.me.display_avatar),
        )
        wizard_embed.set_footer(
            text=
            "If you wish to stop this setup at any time, just type in 'exit'.")

        for question in self.questions:
            wizard_embed.description = question.question

            if not self.ori_mes:
                self.ori_mes = await ctx.reply(embed=wizard_embed)
            else:
                await self.ori_mes.edit(embed=wizard_embed)

            try:
                reply: discord.Message = await ctx.bot.wait_for(
                    "message", check=check, timeout=self.timeout)
            except asyncio.TimeoutError:
                wizard_embed.description = "Failed to reply. Exiting..."
                wizard_embed.set_footer(text=None)
                await self.ori_mes.edit(embed=wizard_embed)
                return
            else:
                if reply.content.lower() == "exit":
                    wizard_embed.description = "Exiting..."
                    wizard_embed.set_footer(text=None)
                    await self.ori_mes.edit(embed=wizard_embed)
                    return

            try:
                converted = await discord.utils.maybe_coroutine(
                    question.converter, ctx, reply.content)
            except Exception as e:  # base exceptions really shouldn't be caught
                wizard_embed.description = (
                    f"Invalid input. Exiting...\n\nError: {str(e)}")
                wizard_embed.set_footer(text=None)
                await self.ori_mes.edit(embed=wizard_embed)
                return

            if not self.pass_self:
                await discord.utils.maybe_coroutine(question.action, ctx,
                                                    converted)
            else:
                await discord.utils.maybe_coroutine(question.action, ctx,
                                                    converted, self)

        wizard_embed.description = self.final_text
        wizard_embed.set_footer(text=None)
        await self.ori_mes.edit(embed=wizard_embed)
Exemple #4
0
    async def about(self, ctx):
        """Gives information about the bot."""

        msg_list = (
            collections.deque()
        )  # is this pointless? yeah, mostly (there's a slight performance boost), but why not

        msg_list.append("Hi! I'm Seraphim, Astrea's personal bot!")
        msg_list.append(
            "I was created initially as a starboard bot as other starboard bots had"
            " poor uptime, "
            + "but I've since been expanded to other functions, too."
        )
        msg_list.append(
            "I tend to have features that are either done poorly by other bots, or"
            " features of bots "
            + "that tend to be offline/unresponsive for a decent amount of time."
        )
        msg_list.append(
            "If you want to invite me, you're in luck. The link is:"
            " https://discord.com/api/oauth2/authorize?client_id=700857077672706120&permissions=8&scope=bot%20applications.commands"
        )
        msg_list.append(
            "If you need support for me, maybe take a look at the support server"
            " here:\nhttps://discord.gg/NSdetwGjpK"
        )

        about_embed = discord.Embed(
            title="About",
            colour=discord.Colour(0x4378FC),
            description="\n\n".join(msg_list),
        )
        about_embed.set_author(
            name=f"{self.bot.user.name}",
            icon_url=utils.get_icon_url(ctx.guild.me.display_avatar),
        )

        source_list = collections.deque()
        source_list.append(
            "My source code is [here!](https://github.com/Astrea49/Seraphim-Bot)"
        )
        source_list.append(
            "This code might not be the best code out there, but you may have some use"
            " for it."
        )

        about_embed.add_field(
            name="Source Code", value="\n".join(source_list), inline=False
        )

        await ctx.reply(embed=about_embed)
Exemple #5
0
    async def pos(
        self,
        ctx: commands.Context,
        *,
        user: typing.Optional[fuzzys.FuzzyMemberConverter],
    ):
        """Allows you to get either your or whoever you mentioned’s position in the star leaderboard (like the top command, but only for one person).
        The user can be mentioned, searched up by ID, or you can say their name and the bot will attempt to search for that person."""

        await ctx.trigger_typing()

        member = ctx.author if not user else user
        user_star_list = await self.get_star_rankings(f"guild_id = {ctx.guild.id}")

        if user_star_list:
            if user:
                placing = (
                    f"{member.display_name}'s"
                    f" {self.get_user_placing(user_star_list, member.id)}"
                )
            else:
                placing = f"Your {self.get_user_placing(user_star_list, member.id)}"

            place_embed = discord.Embed(
                colour=discord.Colour(0xCFCA76),
                description=placing,
                timestamp=discord.utils.utcnow(),
            )
            place_embed.set_author(
                name=f"{self.bot.user.name}",
                icon_url=utils.get_icon_url(ctx.guild.me.display_avatar),
            )
            place_embed.set_footer(text="Sent")

            await ctx.reply(embed=place_embed)
        else:
            raise utils.CustomCheckFailure(
                "There are no starboard entries for this server!"
            )
Exemple #6
0
    async def avatar(
        self,
        ctx: commands.Context,
        user: typing.Union[fuzzys.FuzzyMemberConverter, discord.User, None],
        *,
        flags: AvatarFlags,
    ):
        """Gets the avatar of the user.
        As Seraphim (or, well, me) is kept constatly up to date, this means you can get guild-specific \
        avatars with this command.
        Defaults to getting the avatar of the user who ran the command if no user is provided.
        Due to limitations, if you wish to provide an input for the user you wish to get an icon of and \
        it has spaces, you will need to wrap it with quotes.

        Optional flags:
        guild: <true/false> - whether to get the guild-specific avatar of a user or not. Defaults to getting \
        the guild specific avatar.
        animated: <true/false> - whether to get the animated version or not, if it exists. Defaults to getting \
        the animated version.
        size: <power of two between 16 and 4096> - the size of the image. Defaults to 4096 (or whatever the max \
        size of the avatar is).
        """

        if not user:
            user = ctx.author

        avatar_asset = user.display_avatar if flags.guild else user.avatar
        if not flags.animated:
            avatar_url = str(avatar_asset.replace(format="png", size=flags.size))
        else:
            avatar_url = utils.get_icon_url(avatar_asset, size=flags.size)

        await ctx.reply(
            f"{user.mention}'s avatar: {avatar_url}",
            allowed_mentions=utils.deny_mentions(ctx.author),
        )
Exemple #7
0
async def base_generate(bot: utils.SeraphimBase,
                        mes: discord.Message,
                        no_attachments: bool = False):
    # sourcery no-metrics
    # generates core of star messages
    image_url = ""

    if (mes.embeds and mes.author.id == bot.user.id
            and mes.embeds[0].author.name != bot.user.name
            and mes.embeds[0].fields and mes.embeds[0].footer.text
            and mes.embeds[0].footer.text.startswith("ID:")
        ):  # all of this... for pinboard support
        send_embed = mes.embeds[0].copy(
        )  # it's using the same internal gen, so why not just copy it

        for x in range(len(send_embed.fields)):
            if send_embed.fields[x].name == "Original":
                send_embed.remove_field(x)
                break

        # next pieces of code make the embed more how a normally generated embed would be like
        send_embed.color = discord.Colour(0xCFCA76)
        send_embed.timestamp = mes.created_at
        send_embed.set_footer()  # will set footer to default, aka none

    elif (mes.embeds != [] and mes.embeds[0].type == "rich"
          and mes.embeds[0].author.name != bot.user.name
          and isinstance(mes.embeds[0].author.icon_url, str)
          and "&userid=" in mes.embeds[0].author.icon_url
          ):  # if message is sniped message that's supported
        snipe_embed = mes.embeds[0]

        entry = await bot.starboard.get(mes.id)

        if entry:
            author = await utils.user_from_id(bot, mes.guild, entry.author_id)
        else:
            author_id = star_utils.get_author_id(mes, bot)
            author = await utils.user_from_id(bot, mes.guild, author_id)

        author_str = ""
        if author is None or author.id == bot.user.id:
            author_str = mes.embeds[0].author.name
        else:
            author_str = f"{author.display_name} ({author})"

        icon = (snipe_embed.author.icon_url if author is None or author.id
                == bot.user.id else utils.get_icon_url(author.display_avatar))

        content = snipe_embed.description

        send_embed = discord.Embed(
            title="Sniped:",
            colour=discord.Colour(0xCFCA76),
            description=content,
            timestamp=mes.created_at,
        )
        send_embed.set_author(name=author_str, icon_url=icon)

    elif (mes.author.bot and mes.embeds != [] and mes.embeds[0].description
          and mes.embeds[0].type == "rich"
          and (mes.embeds[0].footer.url !=
               "https://abs.twimg.com/icons/apple-touch-icon-192x192.png"
               and mes.embeds[0].footer.text != "Twitter")):

        author = f"{mes.author.display_name} ({mes.author})"
        icon = utils.get_icon_url(mes.author.display_avatar)

        send_embed = discord.Embed(
            colour=discord.Colour(0xCFCA76),
            description=mes.embeds[0].description,
            timestamp=mes.created_at,
        )
        send_embed.set_author(name=author, icon_url=icon)

    else:
        content = utils.get_content(mes)
        author = f"{mes.author.display_name} ({mes.author})"
        icon = utils.get_icon_url(mes.author.display_avatar)

        if content:
            send_embed = discord.Embed(
                colour=discord.Colour(0xCFCA76),
                description=content,
                timestamp=mes.created_at,
            )
        else:
            send_embed = discord.Embed(
                colour=discord.Colour(0xCFCA76),
                description=None,
                timestamp=mes.created_at,
            )
        send_embed.set_author(name=author, icon_url=icon)

        if mes.type == discord.MessageType.reply:
            # checks if message has inline reply

            ref_mes_url = mes.reference.jump_url  # type: ignore

            reply_msg = await utils.resolve_reply(bot, mes)
            ref_author = reply_msg.author if reply_msg else None
            ref_auth_str = ref_author.display_name if ref_author else "a message"

            send_embed.title = f"Replying to {ref_auth_str}:"
            send_embed.url = ref_mes_url

        if (mes.embeds != [] and mes.embeds[0].type == "image"
                and mes.embeds[0].thumbnail.url):
            image_url = mes.embeds[0].thumbnail.url

            if not no_attachments and mes.attachments:
                send_embed = cant_display(send_embed, mes.attachments, 0)
        elif not no_attachments and mes.attachments != []:
            if (mes.attachments[0].proxy_url.lower().endswith(
                    bot.image_extensions)
                    and not mes.attachments[0].is_spoiler()):
                image_url = mes.attachments[0].proxy_url

                if len(mes.attachments) > 1:
                    send_embed = cant_display(send_embed, mes.attachments, 1)
            else:
                send_embed = cant_display(send_embed, mes.attachments, 0)
        else:
            if not mes.flags.suppress_embeds:  # would suppress images too
                # http://urlregex.com/
                urls = re.findall(
                    r"http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+",
                    content,
                )
                if urls != []:
                    first_url = urls[0]

                    possible_url = await image_utils.get_image_url(first_url)
                    if possible_url != None:
                        image_url = possible_url

                # if the image url is still blank and the message has a gifv embed
                if (image_url == "" and mes.embeds != [] and mes.embeds[0].type
                        == "gifv") and (mes.embeds[0].thumbnail.url
                                        ):  # if there is a thumbnail url
                    image_url = mes.embeds[0].thumbnail.url

                # if the image url is STILL blank and there's a youtube video
                if (image_url == "" and mes.embeds
                        and mes.embeds[0].type == "video"
                        and mes.embeds[0].provider
                        and mes.embeds[0].provider.name
                        and mes.embeds[0].provider.name == "YouTube"):
                    image_url = mes.embeds[0].thumbnail.url
                    send_embed.add_field(
                        name="YouTube:",
                        value=(
                            f"{mes.embeds[0].author.name}:"
                            f" [{mes.embeds[0].title}]({mes.embeds[0].url})"),
                        inline=False,
                    )

            # if the image url is STILL blank and the message has a sticker
            if image_url == "" and mes.stickers:
                if mes.stickers[0].format != discord.StickerFormatType.lottie:
                    image_url = str(mes.stickers[0].url)
                else:  # as of right now, you cannot send content with a sticker, so we might as well
                    send_embed.description = (
                        "*This message has a sticker that I cannot display. Please view"
                        " the original message to see it.*")

            if not no_attachments and mes.attachments:
                send_embed = cant_display(send_embed, mes.attachments, 0)

    if image_url != "":
        send_embed.set_image(url=image_url)

    if utils.embed_check(send_embed):
        return send_embed
    else:
        # unlikely to happen, but who knows
        raise ValueError(f"Embed was too big to process for {mes.jump_url}!")
Exemple #8
0
    async def top(self, ctx: commands.Context, *, flags: TopFlags):
        """Allows you to view the top 10 people with the most stars on a server. Cooldown of once every 5 seconds per user.
        Flags: --role <role>: allows you to filter by the role specified, only counting those who have that role.
        --bots <true/false>: if bot messages will be on the leaderboard."""

        await ctx.trigger_typing()

        optional_role = flags.role
        if optional_role:
            role_members = frozenset(str(r.id) for r in optional_role.members)
            user_star_list = await self.get_star_rankings(
                f"guild_id = {ctx.guild.id} AND author_id IN ({','.join(role_members)})"
            )
        else:
            user_star_list = await self.get_star_rankings(f"guild_id = {ctx.guild.id}")

        if not user_star_list:
            raise utils.CustomCheckFailure(
                "There are no starboard entries for this server/role!"
            )

        top_embed = discord.Embed(
            title=f"Star Leaderboard for {ctx.guild.name}",
            colour=discord.Colour(0xCFCA76),
            timestamp=discord.utils.utcnow(),
        )
        top_embed.set_author(
            name=f"{self.bot.user.name}",
            icon_url=utils.get_icon_url(ctx.guild.me.display_avatar),
        )

        actual_entry_count = 0
        filtered_star_list = []

        for entry in user_star_list:
            if actual_entry_count > 9 and flags.bots:
                break

            member = await utils.user_from_id(self.bot, ctx.guild, entry.author_id)

            if flags.bots or not member or not member.bot:
                filtered_star_list.append(entry)

                if actual_entry_count < 10:
                    num_stars = entry.stars
                    author_str = (
                        f"{member.display_name} ({member})"
                        if member != None
                        else f"User ID: {entry.author_id}"
                    )

                    top_embed.add_field(
                        name=f"#{actual_entry_count+1}: {author_str}",
                        value=f"{num_stars} ⭐\n",
                        inline=False,
                    )
                    actual_entry_count += 1

        if not top_embed.fields:
            raise utils.CustomCheckFailure(
                "There are no non-bot starboard entries for this server!"
            )
        elif not flags.bots or optional_role:
            top_embed.set_footer(
                text=(
                    "Your filtered"
                    f" {self.get_user_placing(filtered_star_list, ctx.author.id)}"
                )
            )
        else:
            top_embed.set_footer(
                text=f"Your {self.get_user_placing(filtered_star_list, ctx.author.id)}"
            )
        await ctx.reply(embed=top_embed)
Exemple #9
0
    async def msgtop(self, ctx: utils.SeraContextBase, *, flags: MsgTopFlags):
        """Allows you to view the top 10 starred messages on a server. Cooldown of once every 5 seconds per user.
        Optional flags:
        user: <user> - allows you to view the top starred messages by the user specified.
        role: <role> - allows you to view the top starred messages by users who have the role specified.
        bots: <true/false> - if bot messages will be on the leaderboard."""

        if flags.role:
            role_members = frozenset(str(r.id) for r in flags.role.members)

        if flags.user and flags.user.bot and not flags.bots:
            raise commands.BadArgument(
                "You can't just specify a user who is a bot and then filter out bots."
            )
        if flags.user and flags.role and str(flags.user.id) not in role_members:
            raise commands.BadArgument(
                "You can't just specify both a user and a role and have that user not"
                " have that role."
            )

        await ctx.trigger_typing()

        conditions = ""

        if flags.user:
            conditions = f"guild_id = {ctx.guild.id} AND author_id = {flags.user.id}"
        elif flags.role:
            conditions = (
                f"guild_id = {ctx.guild.id} AND author_id IN ({','.join(role_members)})"
            )
        else:
            conditions = f"guild_id = {ctx.guild.id}"

        guild_entries = await self.bot.starboard.select_query(
            f"{conditions} AND star_var_id IS NOT NULL AND NOT (ori_reactors = '{{}}'"
            " AND var_reactors = '{}') ORDER BY cardinality(ori_reactors ||"
            " var_reactors) DESC"
        )

        if not guild_entries:
            raise utils.CustomCheckFailure(
                "There are no starboard entries for this server, role, and/or for this"
                " user!"
            )

        if flags.user:
            top_embed = discord.Embed(
                title=(
                    f"Top starred messages in {ctx.guild.name} by"
                    f" {flags.user.display_name} ({flags.user})"
                ),
                colour=discord.Colour(0xCFCA76),
                timestamp=discord.utils.utcnow(),
            )

        else:
            top_embed = discord.Embed(
                title=f"Top starred messages in {ctx.guild.name}",
                colour=discord.Colour(0xCFCA76),
                timestamp=discord.utils.utcnow(),
            )
        top_embed.set_author(
            name=f"{self.bot.user.name}",
            icon_url=utils.get_icon_url(ctx.guild.me.display_avatar),
        )
        top_embed.set_footer(text="As of")

        actual_entry_count = 0
        for entry in guild_entries:
            if actual_entry_count > 9:
                break

            starboard_id = entry.starboard_id

            url = f"https://discordapp.com/channels/{ctx.guild.id}/{starboard_id}/{entry.star_var_id}"
            num_stars = entry.num_reactors

            if flags.role:
                member = (
                    ctx.guild.get_member(entry.author_id)
                    if not flags.user
                    else flags.user
                )
            else:
                member = (
                    await utils.user_from_id(self.bot, ctx.guild, entry.author_id)
                    if not flags.user
                    else flags.user
                )

            if flags.bots or (not member or not member.bot):
                author_str = (
                    f"{member.display_name} ({member})"
                    if member
                    else f"User ID: {entry.author_id}"
                )

                top_embed.add_field(
                    name=f"#{actual_entry_count+1}: {num_stars} ⭐ from {author_str}",
                    value=f"[Message]({url})\n",
                    inline=False,
                )
                actual_entry_count += 1

        if not top_embed.fields:
            raise utils.CustomCheckFailure(
                "There are no non-bot starboard entries for this server/role!"
            )
        await ctx.reply(embed=top_embed)