A utility library that she uses for discord.py
This 'library' is still in pre-alpha. This is still actively being develop and major changes may be made :3
Feel free to open an issue if you found any bugs!🌷
Do not use this in production.
pip install git+https://github.com/InterStella0/starlight-dpy
Easily paginate your help command with little effort.
import starlight
import discord
from discord.ext import commands
bot = commands.Bot(
command_prefix="??",
help_command=starlight.MenuHelpCommand(
per_page=10,
accent_color=0xffcccb,
error_color=discord.Color.red()
),
intents=discord.Intents.all(),
description="Demonstration bot"
)Output
You can easily customize your help command by overriding format_* methods!
Format methods:
format_command_brief(cmd: commands.Command)format_cog_page(view: HelpMenuCog, data: List[commands.Command])format_bot_page(view: HelpMenuBot, mapping: Dict[Optional[commands.Cog], List[commands.Command]])format_group_detail(view: HelpMenuGroup)format_command_detail(view: HelpMenuCommand)format_error_detail(view: HelpMenuError)
Note:page suffix meant the View inherits SimplePaginationView
Example:
import starlight
import discord
from discord.ext import commands
class MyMenuHelpCommand(starlight.MenuHelpCommand):
async def format_bot_page(self, view, mapping):
return discord.Embed(
title="Help",
description="Choose a category to display your help command!",
color=self.accent_color
)
bot = commands.Bot(
command_prefix="??",
help_command=MyMenuHelpCommand(
per_page=10,
accent_color=0xffcccb,
error_color=discord.Color.red(),
pagination_buttons={
"start_button": discord.ui.Button(emoji="⏪", row=1),
"previous_button": discord.ui.Button(emoji="◀️", style=discord.ButtonStyle.blurple, row=1),
"stop_button": discord.ui.Button(emoji="⏹️", style=discord.ButtonStyle.red, row=1),
"next_button": discord.ui.Button(emoji="▶️", style=discord.ButtonStyle.blurple, row=1),
"end_button": discord.ui.Button(emoji="⏩", row=1)
}
),
intents=discord.Intents.all(),
description="Demonstration bot"
)Output
Uses buttons for navigation.
import starlight
import discord
from discord.ext import commands
bot = commands.Bot(
command_prefix="??",
help_command=starlight.PaginateHelpCommand(),
intents=discord.Intents.all()
)Output
Hybrid is a term to implement both text and slash command in discord.py.
HelpCommand was explicitly only a text command.
For existing HelpCommand implementation, you can
change it to a hybrid, you can use starlight.convert_help_hybrid.
import starlight
from discord.ext import commands
my_help_command = commands.DefaultHelpCommand()
hybrid_help_command = starlight.convert_help_hybrid(my_help_command)
bot = commands.Bot(..., help_command=hybrid_help_command)Once you sync your command. You can now use help command in slash command.
Note: convert_help_hybrid second argument is directly transfered to
the AppCommand parameters.
For new implementation of helpcommand, you can directly inherits
starlight.HelpHybridCommand. This will have several helpful feature
to integrate with app command. with_app_command should also be
set to True
import starlight
from discord.ext import commands
class MyHelp(starlight.HelpHybridCommand):
async def send_bot_help(self, mapping, /) -> None:
no_command = len([c for cog in mapping.values() for c in cog])
response = f'I have `{no_command:,}` commands!'
await self.get_destination().send(response)
bot = commands.Bot(..., help_command=MyHelp(with_app_command=True))Once you sync your command. You can now use help command in slash command.
Output
A shortcut for view handling.
Create inline view for distinct behaviours with `starlight.inline_view`.import starlight
import discord
@bot.command()
async def my_command(ctx):
view = discord.ui.View()
hi_button = discord.ui.Button(label="hi")
view.add_item(hi_button)
await ctx.send("hi", view=view)
async for interaction, item in starlight.inline_view(view):
if item is hi_button:
response = "hi"
else:
response = "unknown"
await interaction.response.send_message(response, ephemeral=True)You can specify a discord.ui.Item to listen for a single item.
Effective when you're expecting only a single interaction.
result = None
async for interaction, item in starlight.inline_view(view, item=hi_button):
result = await view.get_my_result(interaction)
view.stop() # ensure only a single sequence
print("My Result:", result)Note:
- Interaction callbacks are sequential due to async iterator.
- Always go for View subclasses whenever you can.
A simple pagination interface.
This was designed to not rely on discord.ext.menus due to lack of support
for Interaction. Majority of code that was present in discord.ext.menus
was dedicated for Reaction which has made it not ideal to be inherited.
import starlight
import discord
class MyPagination(starlight.SimplePaginationView):
async def format_page(self, interaction, data):
return discord.Embed(
title=f"Simple display[{self.current_page + 1}/{self.max_pages}]",
description="\n".join(data)
)
@bot.command()
async def my_command(ctx):
my_data = [["1", "2", "3"], ["4", "5", "6"], ["7", "8", "9"]]
view = MyPagination(my_data, cache_page=True)
await view.start(ctx)Note: You're required to chunk your data on your own. Tips:discord.utils.as_chunks
Supports commands.Paginator with .from_paginator classmethod.
Output
Paginating can have distinct formats which could cause boilerplate code. Which leads to the creation of Inline Pagination.
It works similarly with Inline View. With a slight change, `InlinePaginationItem` are yielded for you to respond it to have an effect to the message through `.format()` method.import starlight
import discord
@bot.command()
async def my_command(ctx):
my_data = [["1", "2", "3"], ["4", "5", "6"], ["7", "8", "9"]]
view = starlight.SimplePaginationView(my_data, cache_page=True)
async for item in starlight.inline_pagination(view, context=ctx):
embed = discord.Embed(
title=f"Simple display[{view.current_page + 1}/{view.max_pages}]",
description="\n".join(item.data)
)
item.format(embed=embed) # keyword arguments are passed to `Message.edit`The output of this code is the equivalent of the Pagination View example.
An extended version of discord.utils.get().
However, it is a filter that returns a sequence. This also supports for fuzzy matching as they are relatively common to be used within a discord bot.from starlight import search, Contains
# Contains is alias of ContainsFilter class
items_with_my_value = search(items, my_attr=Contains('my_value'))
# Equivalent of
items_contains_value = [item for item in items if 'my_value' in item.my_attr]Flatten nested iterables.
from starlight import flatten
arr = [[1, 2], [3, [4, 5], 6], 7, [8]]
arr_flatten = flatten(arr)
print(arr_flatten) # -> [1, 2, 3, 4, 5, 6, 7, 8]Greedy behaviour with a separator instead of spaces as delimiter.
By default, this is set to ',' as the delimiter. It can be configured by passing 'separator' keyword argument.from starlight import star_commands
@star_commands.command(bot=bot) # this is required for separators
async def my_command(ctx, colours: star_commands.Separator[discord.Color], *, the_rest: str):
await ctx.send(f"{colours} | '{the_rest}'")Output





