Package: dpy-paginator
dpy-paginatorTable of contentsOverviewInstallationUsageBasic usagediscord.ext.Commands usagediscord.app_commands usage (ephemeral)Options and ParametersControl who can interactAdd a timeoutBuilt and tested ondiscord.py2.1.1A discord.py utility with no external dependencies that makes paginating embeds easier.Some of it's features are -Easy to use.Supports both ephemeral and non-ephemeral responses.Buttons are enabled/disabled automatically depending on the current page number, number of embeds provided or at timeout.The paginator consists of 4 buttons - ⏪, ◀️, 'Jump To' modal, ▶️, ⏩⏪ - Shows the first embed. Disabled if there are less than 3 embeds or if already on the first embed.◀️ - Shows the previous embed. Disabled if already on the first embed.'Jump To' modal - Triggers adiscord.ui.Modalthat takes you to the page number you input. Disabled if there are less than 4 embeds.▶️ - Shows the next embed. Disabled if already on the last embed.⏩ - Shows the last embed. Disabled if there are less than 3 embeds or if already on the last page.Installationpip install git+https://github.com/onceyt/dpy-paginator.git@v1.0.0UsageBasic usage:importdiscordfromdpy_paginatorimportpaginateembed1=discord.Embed(title="This is embed#1")embed2=discord.Embed(title="This is embed#2")output=awaitpaginate(embeds=[embed1,embed2])# output.embed gives you the first embed of the pagination# output.view gives you the discord.ui.View that controls the paginationawaitMessagable.send(embed=output.embed,view=output.view)# you want to send both in your Messageable.senddiscord.ext.Commands example:importdiscordfromdiscord.extimportcommandsfromdpy_paginatorimportpaginatebot=discord.Bot()# your discord.Bot object@bot.command()asyncdefexample(ctx:commands.Context):embed1=discord.Embed(title="This is Embed#1")embed2=discord.Embed(title="This is Embed#2")output=awaitpaginate(embeds=[embed1,embed2])awaitctx.send(embed=output.embed,view=output.view)This command has the following output:discord.app_commands usage: (ephemeral)fromdiscordimportapp_commandsfromdpy_paginatorimportpaginate@app_commands.command(name='example')asyncdefexample_command(interaction:discord.Interaction):awaitinteraction.response.defer(ephemeral=True,thinking=True)embed1=discord.Embed(title="This is Embed#1")embed2=discord.Embed(title="This is Embed#2")output=awaitpaginate(embeds=[embed1,embed2])awaitinteraction.followup.send(embed=output.embed,view=output.view)This command has the following output:Options and ParametersControl who can interact: (author_ids: list[int]param)You can control which user(s) can interact with the view by passing aauthor_idslist....awaitpaginate(embeds=[embed1,embed2],author_ids=[#ID1, #ID2])When anyone except the specified user(s) try to interact, the paginator ignores that interaction:Adding a timeout: (timeout: intparam)By default, the view has a timeout of 90 seconds but this can be changed by passing atimeoutparameter....awaitpaginate(embeds=[embed1,embed2],timeout=60)The buttons get automatically disabled after timeout (except when no button is interacted with)[^1]. You can also usetimeout = Nonefor no timeout.Example of a timedout view:In the scenario that no button is interacted with and the view gets timedout, the buttons will not be automatically disabled resulting in the need of an extra step.output.view.timedoutreturns a boolean which we can use to check if the view has timedout.importasyncio...timeout=60output=awaitpaginate(embeds=[embed1,embed2],timeout=timeout)message=awaitMessageable.send(embed=output.embed,view=output.view)awaitasyncio.sleep(timeout+0.5)# add 0.5 to the timeout to account for processing delaysifoutput.view.timedout:# check if the view is timedoutawaitmessage.edit(view=output.view)# manually edit the buttons if the output is timedout# the view will automatically timeout incase this check returns FalseNote that incase of ephemeral responses (or scenarios where the output will be deleted before the timeout), this extra step is probably not worth it.[^1]: To explain this, thepaginateButtonsview class receives thediscord.Interactionobject only when one of the buttons is interacted with which is then used to edit the message with the disabled buttons upon timeout. Only runningpaginate()and sending the output does not give the class access to the message sent, thus resulting in the need of an extra step to satisfy this possibility.