Skip to main content

disnake-super-utils


Documentation Secondary Documentation

A modern python module including many useful features that make discord bot programming extremely easy.
The documentation is not done. if you have any questions, feel free to ask them in our discord server.

Features

  • Very easy to use and user-friendly.
  • Object Oriented.
  • Modern Leveling Manager.
  • Modern Music/Audio playing manager. [Lavalink and FFmpeg support]
  • Modern Async Database Manager (SQLite, MongoDB, PostgreSQL, MySQL, MariaDB).
  • Modern Paginator.
  • Modern Reaction Manager.
  • Modern Economy Manager.
  • Modern Image Manager (PIL).
  • Modern Invite Tracker.
  • Modern Command Hinter.
  • Modern FiveM Server Parser.
  • Modern Birthday Manager.
  • Modern Prefix Manager.
  • Includes easy to use convertors.
  • Modern spotify client that is optimized for player fetching.
  • Modern Punishment Manager (Kick, Ban, Infractions, Mutes)
  • Modern Template Manager.
  • Modern CogManager that supports usage of managers in discord cogs.
  • Modern MessageFilter and AntiSpam.
  • Customizable ModMail Manager
  • Modern Youtube client that is optimized for player fetching.
  • And many more! (MORE COMING SOON!)

Installation

Installing disnakeSuperUtils is very easy.

python -m pip install disnakeSuperUtils

Examples

Leveling Example (With Role Manager)

import disnake
from disnake.ext import commands

import disnakeSuperUtils

bot = commands.Bot(command_prefix="-", intents=discord.Intents.all())
LevelingManager = disnakeSuperUtils.LevelingManager(bot, award_role=True)
ImageManager = (
    disnakeSuperUtils.ImageManager()
)  # LevelingManager uses ImageManager to create the rank command.


@bot.event
async def on_ready():
    database = disnakeSuperUtils.DatabaseManager.connect(...)
    await LevelingManager.connect_to_database(database, ["xp", "roles", "role_list"])

    print("Leveling manager is ready.", bot.user)


@LevelingManager.event()
async def on_level_up(message, member_data, roles):
    await message.reply(
        f"You are now level {await member_data.level()}"
        + (f", you have received the {roles[0]}" f" role." if roles else "")
    )


@bot.command()
async def rank(ctx):
    member_data = await LevelingManager.get_account(ctx.author)

    if not member_data:
        await ctx.send(f"I am still creating your account! please wait a few seconds.")
        return

    guild_leaderboard = await LevelingManager.get_leaderboard(ctx.guild)
    member = [x for x in guild_leaderboard if x.member == ctx.author.id]

    image = await ImageManager.create_leveling_profile(
        ctx.author,
        member_data,
        disnakeSuperUtils.Backgrounds.GALAXY,
        (127, 255, 0),
        guild_leaderboard.index(member[0]) + 1 if member else -1,
        outline=5,
    )
    await ctx.send(file=image)


@bot.command()
async def set_roles(ctx, interval: int, *roles: discord.Role):
    await LevelingManager.set_interval(ctx.guild, interval)
    await LevelingManager.set_roles(ctx.guild, roles)

    await ctx.send(
        f"Successfully set the interval to {interval} and role list to {', '.join(role.name for role in roles)}"
    )


@bot.command()
async def leaderboard(ctx):
    guild_leaderboard = await LevelingManager.get_leaderboard(ctx.guild)
    formatted_leaderboard = [
        f"Member: {x.member}, XP: {await x.xp()}" for x in guild_leaderboard
    ]

    await disnakeSuperUtils.PageManager(
        ctx,
        disnakeSuperUtils.generate_embeds(
            formatted_leaderboard,
            title="Leveling Leaderboard",
            fields=25,
            description=f"Leaderboard of {ctx.guild}",
        ),
    ).run()


bot.run("token")

Leveling Manager Example

Playing Example

from math import floor

from disnake.ext import commands

import disnakeSuperUtils
from disnakeSuperUtils import MusicManager
import disnake

client_id = ""
client_secret = ""

bot = commands.Bot(command_prefix="-", intents=discord.Intents.all())
# MusicManager = MusicManager(bot, spotify_support=False)


MusicManager = MusicManager(
    bot, client_id=client_id, client_secret=client_secret, spotify_support=True
)


# if using spotify support use this instead ^^^


@MusicManager.event()
async def on_music_error(ctx, error):
    raise error  # add your error handling here! Errors are listed in the documentation.


@MusicManager.event()
async def on_queue_end(ctx):
    print(f"The queue has ended in {ctx}")
    # You could wait and check activity, etc...


@MusicManager.event()
async def on_inactivity_disconnect(ctx):
    print(f"I have left {ctx} due to inactivity..")


@MusicManager.event()
async def on_play(ctx, player):
    await ctx.send(f"Playing {player}")


@bot.event
async def on_ready():
    # database = disnakeSuperUtils.DatabaseManager.connect(...)
    # await MusicManager.connect_to_database(database, ["playlists"])

    print("Music manager is ready.", bot.user)


@bot.command()
async def leave(ctx):
    if await MusicManager.leave(ctx):
        await ctx.send("Left Voice Channel")


@bot.command()
async def np(ctx):
    if player := await MusicManager.now_playing(ctx):
        duration_played = await MusicManager.get_player_played_duration(ctx, player)
        # You can format it, of course.

        await ctx.send(
            f"Currently playing: {player}, \n"
            f"Duration: {duration_played}/{player.duration}"
        )


@bot.command()
async def join(ctx):
    if await MusicManager.join(ctx):
        await ctx.send("Joined Voice Channel")


@bot.group(invoke_without_command=True)
async def playlists(ctx, user: discord.User):
    user_playlists = await MusicManager.get_user_playlists(user)

    formatted_playlists = [
        f"ID: '{user_playlist.id}'\nTitle: '{user_playlist.playlist.title}'\nTotal Songs: {len(user_playlist.playlist.songs)}"
        for user_playlist in user_playlists
    ]

    embeds = disnakeSuperUtils.generate_embeds(
        formatted_playlists,
        f"Playlists of {user}",
        f"Shows {user.mention}'s playlists.",
        25,
        string_format="{}",
    )

    page_manager = disnakeSuperUtils.PageManager(ctx, embeds, public=True)
    await page_manager.run()


@playlists.command()
async def add(ctx, url: str):
    added_playlist = await MusicManager.add_playlist(ctx.author, url)

    if not added_playlist:
        await ctx.send("Playlist URL not found!")
        return

    await ctx.send(f"Playlist added with ID {added_playlist.id}")


@playlists.command()
async def play(ctx, playlist_id: str):
    # This command is just an example, and not something you should do.
    # The saved playlist system is supposed to provide fast, easy and simple playing, and the user should not look for
    # the right playlist id before playing, as that defeats the whole point.
    # Instead of playing using a playlist id, I recommend playing using indexes.
    # Please, if you are playing using indexes, find the playlist id you need by getting all the user's playlists
    # and then finding the id from there.
    # Find the user's playlists using MusicManager.get_user_playlists(ctx.author, partial=True).
    # Make sure partial is True to speed up the fetching progress (incase you want to access the playlist data,
    # you can set it to False, of course).
    # Using these playlists, find the id the user wants, and play it (or whatever else you want to do with it).
    # Be creative!

    user_playlist = await MusicManager.get_playlist(ctx.author, playlist_id)

    if not user_playlist:
        await ctx.send("That playlist does not exist!")
        return

    if not ctx.voice_client or not ctx.voice_client.is_connected():
        await MusicManager.join(ctx)

    async with ctx.typing():
        players = await MusicManager.create_playlist_players(
            user_playlist.playlist, ctx.author
        )

    if players:
        if await MusicManager.queue_add(
            players=players, ctx=ctx
        ) and not await MusicManager.play(ctx):
            await ctx.send(f"Added playlist {user_playlist.playlist.title}")

    else:
        await ctx.send("Query not found.")


@playlists.command()
async def remove(ctx, playlist_id: str):
    user_playlist = await MusicManager.get_playlist(ctx.author, playlist_id)

    if not user_playlist:
        await ctx.send(f"Playlist with id {playlist_id} is not found.")
        return

    await user_playlist.delete()
    await ctx.send(f"Playlist {user_playlist.playlist.title} has been deleted")


@bot.command()
async def play(ctx, *, query: str):
    if not ctx.voice_client or not ctx.voice_client.is_connected():
        await MusicManager.join(ctx)

    async with ctx.typing():
        players = await MusicManager.create_player(query, ctx.author)

    if players:
        if await MusicManager.queue_add(
            players=players, ctx=ctx
        ) and not await MusicManager.play(ctx):
            await ctx.send("Added to queue")

    else:
        await ctx.send("Query not found.")


@bot.command()
async def lyrics(ctx, query: str = None):
    if response := await MusicManager.lyrics(ctx, query):
        title, author, query_lyrics = response

        splitted = query_lyrics.split("\n")
        res = []
        current = ""
        for i, split in enumerate(splitted):
            if len(splitted) <= i + 1 or len(current) + len(splitted[i + 1]) > 1024:
                res.append(current)
                current = ""
                continue
            current += split + "\n"

        page_manager = disnakeSuperUtils.PageManager(
            ctx,
            [
                discord.Embed(
                    title=f"Lyrics for '{title}' by '{author}', (Page {i + 1}/{len(res)})",
                    description=x,
                )
                for i, x in enumerate(res)
            ],
            public=True,
        )
        await page_manager.run()
    else:
        await ctx.send("No lyrics found.")


@bot.command()
async def pause(ctx):
    if await MusicManager.pause(ctx):
        await ctx.send("Player paused.")


@bot.command()
async def resume(ctx):
    if await MusicManager.resume(ctx):
        await ctx.send("Player resumed.")


@bot.command()
async def volume(ctx, volume: int):
    await MusicManager.volume(ctx, volume)


@bot.command()
async def loop(ctx):
    is_loop = await MusicManager.loop(ctx)

    if is_loop is not None:
        await ctx.send(f"Looping toggled to {is_loop}")


@bot.command()
async def shuffle(ctx):
    is_shuffle = await MusicManager.shuffle(ctx)

    if is_shuffle is not None:
        await ctx.send(f"Shuffle toggled to {is_shuffle}")


@bot.command()
async def autoplay(ctx):
    is_autoplay = await MusicManager.autoplay(ctx)

    if is_autoplay is not None:
        await ctx.send(f"Autoplay toggled to {is_autoplay}")


@bot.command()
async def queueloop(ctx):
    is_loop = await MusicManager.queueloop(ctx)

    if is_loop is not None:
        await ctx.send(f"Queue looping toggled to {is_loop}")


@bot.command()
async def complete_queue(ctx):
    if ctx_queue := await MusicManager.get_queue(ctx):
        formatted_queue = [
            f"Title: '{x.title}'\nRequester: {x.requester and x.requester.mention}\n"
            f"Position: {i - ctx_queue.pos}"
            for i, x in enumerate(ctx_queue.queue)
        ]

        num_of_fields = 25

        embeds = disnakeSuperUtils.generate_embeds(
            formatted_queue,
            "Complete Song Queue",
            "Shows the complete song queue.",
            num_of_fields,
            string_format="{}",
        )

        page_manager = disnakeSuperUtils.PageManager(
            ctx, embeds, public=True, index=floor(ctx_queue.pos / 25)
        )
        await page_manager.run()


@bot.command()
async def goto(ctx, position: int):
    if ctx_queue := await MusicManager.get_queue(ctx):
        new_pos = ctx_queue.pos + position
        if not 0 <= new_pos < len(ctx_queue.queue):
            await ctx.send("Position is out of bounds.")
            return

        await MusicManager.goto(ctx, new_pos)
        await ctx.send(f"Moved to position {position}")


@bot.command()
async def history(ctx):
    if ctx_queue := await MusicManager.get_queue(ctx):
        formatted_history = [
            f"Title: '{x.title}'\nRequester: {x.requester and x.requester.mention}"
            for x in ctx_queue.history
        ]

        embeds = disnakeSuperUtils.generate_embeds(
            formatted_history,
            "Song History",
            "Shows all played songs",
            25,
            string_format="{}",
        )

        page_manager = disnakeSuperUtils.PageManager(ctx, embeds, public=True)
        await page_manager.run()


@bot.command()
async def skip(ctx, index: int = None):
    await MusicManager.skip(ctx, index)


@bot.command()
async def queue(ctx):
    if ctx_queue := await MusicManager.get_queue(ctx):
        formatted_queue = [
            f"Title: '{x.title}\nRequester: {x.requester and x.requester.mention}"
            for x in ctx_queue.queue[ctx_queue.pos + 1 :]
        ]

        embeds = disnakeSuperUtils.generate_embeds(
            formatted_queue,
            "Queue",
            f"Now Playing: {await MusicManager.now_playing(ctx)}",
            25,
            string_format="{}",
        )

        page_manager = disnakeSuperUtils.PageManager(ctx, embeds, public=True)
        await page_manager.run()


@bot.command()
async def rewind(ctx, index: int = None):
    await MusicManager.previous(ctx, index, no_autoplay=True)


@bot.command()
async def ls(ctx):
    if queue := await MusicManager.get_queue(ctx):
        loop = queue.loop
        loop_status = None

        if loop == disnakeSuperUtils.Loops.LOOP:
            loop_status = "Looping enabled."

        elif loop == disnakeSuperUtils.Loops.QUEUE_LOOP:
            loop_status = "Queue looping enabled."

        elif loop == disnakeSuperUtils.Loops.NO_LOOP:
            loop_status = "No loop enabled."

        if loop_status:
            await ctx.send(loop_status)


@bot.command()
async def move(ctx, player_index: int, index: int):
    await MusicManager.move(ctx, player_index, index)


bot.run("token")

MusicManager Example

More examples are listed in the examples folder.

Known Issues

  • Removing an animated emoji wont be recognized as a reaction role, as it shows up as not animated for some reason, breaking the reaction matcher. (Discord API Related)
  • Leveling might call the on_level_up event multiple times, resulting in duplicate messages, caused by duplicate records in the leveling table. (Fixed)

Support

Metadata

Release files for disnakeSuperUtils 0.9.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for disnakeSuperUtils 0.9.2
File Size Uploaded
disnakeSuperUtils-0.9.2.tar.gz 1.8 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for disnakeSuperUtils 0.9.2
File Interpreter ABI Platform
disnakeSuperUtils-0.9.2-py3-none-any.whl Python 3 none any Details

Total release size: 3.6 MB

Release files / disnakeSuperUtils-0.9.2.tar.gz

Download URL disnakeSuperUtils-0.9.2.tar.gz
Size 1.8 MB
Tags Source
SHA-256 checksum
How to use checksums
6330970a8bc91333d6b119bea5f9549c2f1c2b401ba351d53b8a23973f4b5cec
BLAKE2b-256 checksum
How to use checksums
dc3c2654e5a69de5cea9dd3ef24bef39dadfa25725aeb68870a09fb5684215b5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.8.0 pkginfo/1.8.2 readme-renderer/32.0 requests/2.27.1 requests-toolbelt/0.9.1 urllib3/1.26.8 tqdm/4.62.3 importlib-metadata/4.10.1 keyring/23.5.0 rfc3986/2.0.0 colorama/0.4.4 CPython/3.9.10

Release files / disnakeSuperUtils-0.9.2-py3-none-any.whl

Download URL disnakeSuperUtils-0.9.2-py3-none-any.whl
Size 1.8 MB
Tags Python 3
SHA-256 checksum
How to use checksums
e4c6b9cac0fbd9b94f273b60ba3b9d20c94319248b0609fba08c0fa3ab5d4e1d
BLAKE2b-256 checksum
How to use checksums
c9c042924f87e1d1284cebf289ea9159d01ce96371b33eafab1de173e75a4836
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.8.0 pkginfo/1.8.2 readme-renderer/32.0 requests/2.27.1 requests-toolbelt/0.9.1 urllib3/1.26.8 tqdm/4.62.3 importlib-metadata/4.10.1 keyring/23.5.0 rfc3986/2.0.0 colorama/0.4.4 CPython/3.9.10

Release history Release notifications | RSS feed

This release

0.9.2 This release

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page