Example #1
0
    async def warn(self, ctx: Context, member: Member, *, reason: str):
        """Warn someone

        Warns do not give any punishments apart fron an entry in the warn list.
        """

        guild, _ = await Guild.get_or_create(id=ctx.guild.id)
        user, _ = await User.get_or_create(id=member.id)
        warn = await Warn.create(moderator=ctx.author.id,
                                 guild=guild,
                                 user=user,
                                 reason=reason)

        embed = Embed(ctx, title=f"Warn [{warn.id}]", color=member.color)
        embed.description = t(ctx,
                              "message",
                              member=member.mention,
                              reason=reason)

        await ctx.send(embed=embed)

        try:
            await member.send(
                t(ctx, "dm_message", guild=ctx.guild, reason=reason))
        except (Forbidden, HTTPException, AttributeError):
            pass
Example #2
0
    async def mutes_active(self, ctx: Context):
        """See active mutes"""

        embed = Embed(ctx, title="Active mutes")
        await ctx.trigger_typing()

        mutes = Mute.filter(guild__id=ctx.guild.id, active=True)
        if not await mutes.count():
            return await ctx.send(
                f"There are no active mutes in **{ctx.guild.name}**.")

        # TODO: Split active mutes into different embeds when more than 10
        #       and add scrolling (◀️ ▶️)
        async for i in mutes.prefetch_related("user"):
            moderator = ctx.guild.get_member(i.moderator)
            user = ctx.guild.get_member(i.user.id)

            description = (
                f"**Given at**: {str(i.start.time())[:-10]} {str(i.start.date())[5:]}\n"
                f"**Duration**: {str(i.end - i.start)[:-7]}\n"
                f"**Moderator**: {moderator.mention}")
            if i.reason:
                description += f"\n**Reason**: *{i.reason}*"

            embed.add_field(name=f"{user} [{i.id}]",
                            value=description,
                            inline=False)

        await ctx.send(embed=embed)
Example #3
0
    async def mute(self,
                   ctx: Context,
                   member: Member,
                   time: Timedelta,
                   *,
                   reason: str = None):
        """Mute someone

        Muting someone gives them the mute role specified by the muterole command and removes the role after the specified time has passed.
        Note: Mutes are checked every 10 seconds, so times are not perfect.
        """

        mute = await Mute.filter(user__id=member.id,
                                 guild__id=ctx.guild.id,
                                 active=True).first()
        if mute:
            mute.end += time
            await mute.save()
            return await ctx.send(
                t(ctx, "message_extended", member=member, time=time))
            # NOTE: Extensions don't add a mute entry, they just make the
            # active mute longer.
            # return await ctx.send(f"{member.name} is already muted.")

        user, _ = await User.get_or_create(id=member.id)
        guild, _ = await Guild.get_or_create(id=ctx.guild.id)
        if not guild.mute_role:
            return await ctx.send(t(ctx, "no_mute_role", guild=ctx.guild))
        mute = await Mute.create(
            moderator=ctx.author.id,
            user=user,
            guild=guild,
            reason=reason,
            end=datetime.utcnow() + time,
        )

        mute_role = ctx.guild.get_role(guild.mute_role)
        # TODO: Check if member has lower permissions required to mute them
        await member.add_roles(
            mute_role,
            reason=f"Muted by {ctx.author} for {time}, reason: {reason}")

        embed = Embed(ctx, title=f"Mute [{mute.id}]", color=member.color)
        embed.set_thumbnail(url=member.avatar_url)
        embed.description = t(ctx,
                              "message",
                              member=member.mention,
                              time=time,
                              reason=reason)

        await ctx.send(embed=embed)

        try:
            await member.send(
                t(ctx, "dm_message", guild=ctx.guild, time=time,
                  reason=reason))
        except (Forbidden, HTTPException, AttributeError):
            pass
Example #4
0
    async def avatar(self, ctx: Context, *, user: User = None):
        """Shows an user's avatar"""

        if not user:
            user = ctx.author

        embed = Embed(ctx, title=t(ctx, "title", user=user.name))
        embed.set_image(url=user.avatar_url_as(size=2048))
        await ctx.send(embed=embed)
Example #5
0
    async def pay(self, ctx: Context, amount: int, *, member: Member):
        """Give coins to someone

        You can't give money to yourself or any bots.
        Transfer amount should be more than 0.
        """

        if member == ctx.author or member.bot:
            return await ctx.send(t(ctx, "other_users_only"))
        if amount <= 0:
            return await ctx.send(t(ctx, "at_least_one"))

        user, _ = await User.get_or_create(id=ctx.author.id)

        if user.balance < amount:
            return await ctx.send(
                t(
                    ctx,
                    "not_enough_funds",
                    coins=user.balance,
                    missing=amount - user.balance,
                )
            )

        embed = Embed(
            ctx,
            title=t(ctx, "title"),
            description=t(ctx, "confirmation", amount=amount, member=member.mention),
        )
        message = await ctx.send(embed=embed)
        await message.add_reaction("✅")

        try:
            await self.bot.wait_for(
                "reaction_add",
                timeout=30,
                check=lambda r, u: u == ctx.message.author and str(r.emoji) == "✅",
            )
        except TimeoutError:
            embed.description = t(ctx, "cancelled")
            return await message.edit(embed=embed)

        target_user, _ = await User.get_or_create(id=member.id)
        user.balance -= amount
        target_user.balance += amount
        await user.save()
        await target_user.save()

        try:
            await message.clear_reactions()
        except Forbidden:
            pass

        embed.description = t(ctx, "success", amount=amount, member=member.mention)
        await message.edit(embed=embed)
Example #6
0
    async def manga(self, ctx: Context, *, title: str):
        """Manga info from AniList"""

        query = """
        query ($title: String) {
            Media (search: $title, type: MANGA) {
                title {romaji}
                coverImage {extraLarge color}
                description (asHtml: false)
                siteUrl
                rankings {rank allTime type context}
                status
                chapters
                volumes
                format
                averageScore
                genres
            }
        }
        """
        manga = (await anilist(query, {"title": title}))["data"]["Media"]

        embed = Embed(
            ctx,
            title=manga["title"]["romaji"],
            description="",
            url=manga["siteUrl"],
            footer="Via AniList",
        )

        embed.set_thumbnail(url=manga["coverImage"]["extraLarge"])

        for i in manga["rankings"]:
            if not i["allTime"]:
                continue

            if i["type"] == "RATED":
                embed.description += "⭐"
            elif i["type"] == "POPULAR":
                embed.description += "❤️"

            embed.description += f" #{i['rank']} {i['context'].title()}\n"
        embed.description += "\n"

        if manga["description"]:
            description = clean_description(manga["description"])
            embed.description += (
                t(ctx, "synopsis_ellipsis", synopsis=description[:250])
                if len(description) >= 250
                else t(ctx, "synopsis", synopsis=description)
            )

        if color_hex := manga["coverImage"]["color"]:
            embed.color = Color(int(color_hex.replace("#", ""), 16))
Example #7
0
    async def anime(self, ctx: Context, *, title: str):
        """Anime info from AniList"""

        query = """
        query ($title: String) {
            Media (search: $title, type: ANIME) {
                title {romaji}
                coverImage {extraLarge color}
                description (asHtml: false)
                siteUrl
                rankings {rank allTime type context}
                status
                episodes
                duration
                season
                seasonYear
                format
                averageScore
                genres
                studios (isMain: true) {nodes {name}}
            }
        }
        """
        anime = (await anilist(query, {"title": title}))["data"]["Media"]

        embed = Embed(
            ctx,
            title=anime["title"]["romaji"],
            description="",
            url=anime["siteUrl"],
            footer="Via AniList",
        )

        embed.set_thumbnail(url=anime["coverImage"]["extraLarge"])

        for i in anime["rankings"]:
            if not i["allTime"]:
                continue

            if i["type"] == "RATED":
                embed.description += "⭐"
            elif i["type"] == "POPULAR":
                embed.description += "❤️"

            embed.description += f" #{i['rank']} {i['context'].title()}\n"
        embed.description += "\n"

        if description := clean_description(anime["description"]):
            embed.description += (
                t(ctx, "synopsis_ellipsis", synopsis=description[:250])
                if len(description) >= 250
                else t(ctx, "synopsis", synopsis=description)
            )
Example #8
0
    async def pay(self, ctx: Context, amount: int, *, member: Member):
        """Give coins to someone

        You can't give money to yourself or any bots.
        Transfer amount should be more than 0.
        """

        if member == ctx.author or member.bot:
            return await ctx.send("You can give money to other users only.")
        if amount <= 0:
            return await ctx.send("You need to pay at least 1 coin.")

        user, _ = await User.get_or_create(id=ctx.author.id)

        if user.balance < amount:
            return await ctx.send(
                f"Not enough funds, you have "
                f"{user.balance} coins ({amount - user.balance} missing).")

        embed = Embed(
            ctx,
            title="Transfer",
            description=f"You are about to give **{amount}** "
            f"coin(s) to {member.mention}, are you sure?",
        )
        message = await ctx.send(embed=embed)
        await message.add_reaction("✅")

        try:
            await self.bot.wait_for(
                "reaction_add",
                timeout=30,
                check=lambda r, u: u == ctx.message.author and str(r.emoji) ==
                "✅",
            )
        except TimeoutError:
            embed.description = "Transfer cancelled."
            return await message.edit(embed=embed)

        target_user, _ = await User.get_or_create(id=member.id)
        user.balance -= amount
        target_user.balance += amount
        await user.save()
        await target_user.save()

        try:
            await message.clear_reactions()
        except Forbidden:
            pass

        embed.description = f"Transferred **{amount}** coin(s) " f"to {member.mention}"
        await message.edit(embed=embed)
Example #9
0
    async def profile(self, ctx: Context, *, member: Member = None):
        """User's profile"""

        if not member:
            member = ctx.author

        user, _ = await User.get_or_create(id=member.id)
        # Calculate current level progress:
        # (exp - curr lvl req) * 100 / (curr lvl req - next lvl req)
        current_level_exp = (user.level * 4)**2
        next_level_exp = ((user.level + 1) * 4)**2
        progress = round((user.exp - current_level_exp) * 100 /
                         (next_level_exp - current_level_exp))
        # Find position of profile in global user ranking
        rank = (await User.all().order_by("-exp")).index(user)

        embed = Embed(ctx,
                      title=f"{member.name}'s profile",
                      color=member.color)
        embed.set_thumbnail(url=member.avatar_url)

        embed.add_fields(
            ("Rank", str(rank + 1)),
            ("Level", f"{user.level}"),
            ("Experience", f"{user.exp}/{next_level_exp} ({progress}%)"),
            ("Balance", f"{user.balance} coins"),
        )

        if mutes := await Mute.filter(guild__id=ctx.guild.id,
                                      user__id=member.id).count():
            embed.add_field(name="Mutes", value=str(mutes))
Example #10
0
    async def send_group_help(self, group):
        ctx = self.context
        embed = Embed(
            ctx,
            title=f"`{self.get_command_signature(group)}`",
            description=group.help,
            color=Color.blue(),
        )

        commands = self.get_formatted_commands(await self.filter_commands(
            group.commands))
        embed.add_field(name="Commands", value="\n".join(commands))

        await ctx.send(embed=embed)
Example #11
0
    async def send_cog_help(self, cog):
        ctx = self.context
        embed = Embed(
            ctx,
            title=f"{cog.qualified_name} Commands",
            description=cog.description,
            color=Color.blue(),
        )

        commands = self.get_formatted_commands(await self.filter_commands(
            cog.get_commands()))
        embed.add_field(name="Commands", value="\n".join(commands))

        await ctx.send(embed=embed)
Example #12
0
    async def mutes(self, ctx: Context, *, member: Member = None):
        """See someone's mutes

        If no member specified, this shows Your mutes.
        """

        if not member:
            member = ctx.author

        embed = Embed(
            ctx,
            title=t(ctx, "title", member=member),
            description="",
            color=member.color,
        )
        await ctx.trigger_typing()

        mutes = Mute.filter(user__id=member.id, guild__id=ctx.guild.id)
        if not await mutes.count():
            return await ctx.send(t(ctx, "no_mutes", member=member))

        async for i in mutes:
            moderator = await self.bot.fetch_user(i.moderator)
            embed.description += (
                f"`{i.id}` {str(i.start.time())[:-10]} "
                f"{i.start.date()} ({str(i.end - i.start)[:-7]}) "
                f"**{moderator}**: *{i.reason or t(ctx, 'no_reason')}* ")
            # TODO: Format time and use timezones
            if i.active:
                embed.description += "🔴"
            embed.description += "\n"

        await ctx.send(embed=embed)
Example #13
0
    async def warns(self, ctx: Context, *, member: Member = None):
        """See someone's warns

        If no member specified, this shows Your warns.
        """

        if not member:
            member = ctx.author

        embed = Embed(
            ctx,
            title=t(ctx, "title", member=member),
            description="",
            color=member.color,
        )

        await ctx.trigger_typing()
        warns = Warn.filter(user__id=member.id, guild__id=ctx.guild.id)

        if not await warns.count():
            return await ctx.send(t(ctx, "no_mutes", member=member))

        async for i in warns:
            moderator = ctx.bot.get_user(i.moderator)
            # TODO: Format time and use timezones (settings)
            embed.description += (
                f"`{i.id}` {str(i.when.time())[:-10]} "
                f"{i.when.date()} **{moderator}**: *{i.reason}*\n")

        await ctx.send(embed=embed)
Example #14
0
    async def uptime(self, ctx: Context):
        """Bot uptime"""

        timestamp_difference = round(time() - self.bot.start_timestamp)
        uptime = timedelta(seconds=timestamp_difference)
        embed = Embed(ctx, title=t(ctx, "title"), description=str(uptime))

        await ctx.send(embed=embed)
Example #15
0
    async def bug(self, ctx: Context):
        """Where to report bugs and feature requests"""

        embed = Embed(
            ctx,
            title=t(ctx, "title"),
            description=t(ctx, "message"),
        )

        await ctx.send(embed=embed)
Example #16
0
    async def ping(self, ctx: Context):
        """Bot connection latency

        This isn't very accurate, and mainly used as a "is this bot alive?" command.
        """

        ping = round(self.bot.latency * 1000)
        embed = Embed(ctx, title="Ping", description=f":ping_pong:‎‎{ping}ms")

        await ctx.send(embed=embed)
Example #17
0
    async def send_command_help(self, command):
        ctx = self.context
        embed = Embed(
            ctx,
            title=f"`{self.get_command_signature(command)}`",
            description=command.help,
            color=Color.blue(),
        )

        await ctx.send(embed=embed)
Example #18
0
    async def invite(self, ctx: Context):
        """Nagatoro's bot invite link"""

        embed = Embed(
            ctx,
            title=t(ctx, "title"),
            url=t(ctx, "invite_url"),
            description=t(ctx, "message"),
        )

        await ctx.send(embed=embed)
Example #19
0
    async def mutes_active(self, ctx: Context):
        """See active mutes"""

        embed = Embed(ctx, title=t(ctx, "title"))
        await ctx.trigger_typing()

        mutes = Mute.filter(guild__id=ctx.guild.id, active=True)
        if not await mutes.count():
            return await ctx.send(t(ctx, "no_mutes", guild=ctx.guild))

        # TODO: Split active mutes into different embeds when more than 10
        #       and add scrolling (◀️ ▶️)
        async for i in mutes.prefetch_related("user"):
            moderator = ctx.guild.get_member(i.moderator)
            user = ctx.guild.get_member(i.user.id)

            if i.reason:
                description = t(
                    ctx,
                    "entry_with_reason",
                    given_at=
                    f"{str(i.start.time())[:-10]} {str(i.start.date())[5:]}",
                    duration=i.end - i.start,
                    moderator=moderator.mention,
                    reason=i.reason,
                )
            else:
                description = t(
                    ctx,
                    "entry",
                    given_at=
                    f"{str(i.start.time())[:-10]} {str(i.start.date())[5:]}",
                    duration=i.end - i.start,
                    moderator=moderator.mention,
                )

            embed.add_field(name=f"{user} [{i.id}]",
                            value=description,
                            inline=False)

        await ctx.send(embed=embed)
Example #20
0
    async def ranking_level(self, ctx: Context):
        """User ranking, by level"""

        embed = Embed(ctx, title=t(ctx, "title"), description="", color=Color.blue())

        await ctx.trigger_typing()
        async for pos, i in aenumerate(User.all().order_by("-exp").limit(10), start=1):
            user = await self.bot.fetch_user(i.id)
            embed.description += t(
                ctx, "ranking_entry", pos=pos, user=user, lvl=i.level, exp=i.exp
            )

        await ctx.send(embed=embed)
Example #21
0
    async def ping(self, ctx: Context):
        """Bot connection latency

        This isn't very accurate, and mainly used as a "is this bot alive?" command.
        """

        embed = Embed(
            ctx,
            title=t(ctx, "title"),
            description=t(ctx, "message", ping=round(self.bot.latency * 1000)),
        )

        await ctx.send(embed=embed)
Example #22
0
    async def bug(self, ctx: Context):
        """Where to report bugs and feature requests"""

        embed = Embed(
            ctx,
            title="Bug reporting",
            description="You can report bugs directly to me (@Predator#xxxx) "
            "or preferrably, if you are familiar with GitHub, on the "
            "[issues page](https://github.com/stefankar1000/nagatoro/issues)"
            "\n\nPlease, provide any errors and context while reporting bugs "
            "and clearly explain the issue.",
        )

        await ctx.send(embed=embed)
Example #23
0
    async def warn(self, ctx: Context, member: Member, *, reason: str):
        """Warn someone

        Warns do not give any punishments apart fron an entry in the warn list.
        """

        guild, _ = await Guild.get_or_create(id=ctx.guild.id)
        user, _ = await User.get_or_create(id=member.id)
        warn = await Warn.create(moderator=ctx.author.id,
                                 guild=guild,
                                 user=user,
                                 reason=reason)

        embed = Embed(ctx, title=f"Warn [{warn.id}]", color=member.color)
        embed.description = f"Warned {member.mention}, reason: *{reason}*"

        await ctx.send(embed=embed)

        try:
            await member.send(f"You have been warned in **{ctx.guild.name}**, "
                              f"reason: *{warn.reason}*")
        except (Forbidden, HTTPException, AttributeError):
            pass
Example #24
0
    async def prefix(self, ctx: Context):
        """Custom bot prefix"""

        embed = Embed(
            ctx,
            title=t(ctx, "title", guild=ctx.guild.name),
            description="",
            color=Color.blue(),
        )

        for i in (await ctx.bot.command_prefix(ctx.bot, ctx.message))[1:]:
            embed.description += f"- **{i}**\n"

        return await ctx.send(embed=embed)
Example #25
0
    async def character(self, ctx: Context, *, name: str):
        """Character info from AniList"""

        query = """
        query ($name: String) {
            Character (search: $name) {
                name {full}
                image {large}
                description (asHtml: false)
                siteUrl
                favourites
                media (perPage: 10) {
                    edges {
                        node {
                            title {romaji}
                            siteUrl
                        }
                        characterRole
                    }
                }
            }
        }
        """

        character = (await anilist(query, {"name": name}))["data"]["Character"]

        embed = Embed(ctx,
                      title=character["name"]["full"],
                      description="",
                      url=character["siteUrl"],
                      footer="Via AniList",
                      color=Color.blue())

        embed.set_thumbnail(url=character["image"]["large"])

        if character["favourites"]:
            embed.description += f"❤️ {character['favourites']} favorites \n\n"

        if character["description"]:
            description = clean_description(character["description"])
            embed.description += f"Description: ||{description[:250]}...||" \
                if len(description) >= 250 \
                else f"Description: ||{description}||"

        appears_in = ["Main 🌕 Supporting 🌗 Background 🌑"]
        for i in character["media"]["edges"]:
            role = i["characterRole"] \
                .replace("MAIN", "🌕") \
                .replace("SUPPORTING", "🌗") \
                .replace("BACKGROUND", "🌑")

            appears_in.append(f"{role} [{i['node']['title']['romaji']}]"
                              f"({i['node']['siteUrl']})")

        embed.add_field(name="Appears in", value="\n".join(appears_in))

        await ctx.send(embed=embed)
Example #26
0
    async def studio(self, ctx: Context, *, name: str):
        """Studio info from AniList"""

        query = """
        query ($name: String) {
            Studio (search: $name, sort: SEARCH_MATCH) {
                name
                siteUrl
                isAnimationStudio
                media (sort: POPULARITY_DESC, perPage: 10) {
                    nodes {
                        title {romaji}
                        coverImage {extraLarge}
                        siteUrl
                        popularity
                        favourites
                    }
                }
            }
        }
        """
        studio = (await anilist(query, {"name": name}))["data"]["Studio"]

        embed = Embed(
            ctx, title=studio["name"], url=studio["siteUrl"], footer="Via AniList"
        )

        embed.set_thumbnail(url=studio["media"]["nodes"][0]["coverImage"]["extraLarge"])

        if studio["isAnimationStudio"]:
            embed.description = t(ctx, "animation_studio")

        # TODO: Observe, if this breaks when isAnimationStudio=False.
        most_popular = [t(ctx, "most_popular_header")]
        for i in studio["media"]["nodes"]:
            most_popular.append(
                t(
                    ctx,
                    "most_popular_item",
                    popularity=i["popularity"],
                    favorites=i["favourites"],
                    title=i["title"]["romaji"],
                    url=i["siteUrl"],
                )
            )

        embed.add_field(
            name=t(ctx, "most_popular_title"), value="\n".join(most_popular)
        )

        await ctx.send(embed=embed)
Example #27
0
    async def send_bot_help(self, mapping):
        ctx = self.context
        embed = Embed(
            ctx,
            title="Commands",
            description=self.get_opening_note(),
            color=Color.blue(),
        )

        for cog, commands in mapping.items():
            if not cog:
                # Don't show commands without a cog (e.g. the help command)
                continue

            category_name = cog.qualified_name
            filtered_commands = await self.filter_commands(commands)

            embed.add_field(
                name=category_name,
                value=", ".join(i.name for i in filtered_commands),
                inline=False,
            )

        await ctx.send(embed=embed)
Example #28
0
    async def ranking_level(self, ctx: Context):
        """User ranking, by level"""

        embed = Embed(ctx,
                      title="Level Ranking",
                      description="",
                      color=Color.blue())

        await ctx.trigger_typing()
        async for pos, i in aenumerate(User.all().order_by("-exp").limit(10),
                                       start=1):
            user = await self.bot.fetch_user(i.id)
            embed.description += f"{pos}. **{user}**: {i.level} ({i.exp} exp)\n"

        await ctx.send(embed=embed)
Example #29
0
    async def ranking_balance(self, ctx: Context):
        """User ranking, sorted by balance"""

        embed = Embed(ctx,
                      title="Balance Ranking",
                      description="",
                      color=Color.blue())

        await ctx.trigger_typing()
        async for pos, i in aenumerate(
                User.all().order_by("-balance").limit(10), start=1):
            user = await self.bot.fetch_user(i.id)
            embed.description += f"{pos}. **{user}**: {i.balance} coins\n"

        await ctx.send(embed=embed)
Example #30
0
    async def user(self, ctx: Context, *, user: Union[Member, User] = None):
        """Shows info about an user or a member"""

        if not user:
            user = ctx.author

        title = str(user) if not user.bot else f"{user} :robot:"
        embed = Embed(ctx, title=title, color=user.color)
        embed.set_thumbnail(url=user.avatar_url)
        embed.add_fields(("ID", user.id), ("Created at", user.created_at))

        await ctx.send(embed=embed)