Skip to main content

A paginator utility for discord.py with no additional dependencies that makes paginating embeds easier.

Reason this release was yanked:

v1.1.1 contains minor metadata and readme fixes and is more recommended to use instead of this version.

Project description

dpy-paginator

PyPI - Python Version Downloads

Table of contents
Built and tested on discord.py 2.3.2

A discord.py utility with no external dependencies that makes paginating embeds easier.

Quick links

Some of it's features include:

  • 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 a discord.ui.Modal that 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.

Installation

pip install dpy-paginator

or

pip install git+https://github.com/onceyt/dpy-paginator.git@v1.1.0

Usage

Basic usage:
import discord
from dpy_paginator import paginate

embed1 = discord.Embed(title = "This is embed#1")
embed2 = discord.Embed(title = "This is embed#2")
output = paginate(embeds = [embed1, embed2])

# output.embed gives you the first embed of the pagination
# output.view gives you the discord.ui.View that controls the pagination

await Messagable.send(embed = output.embed, view = output.view)

# you want to send both in your Messageable.send
discord.ext.Commands Example:
import discord
from discord.ext import commands
from dpy_paginator import paginate

bot = discord.Bot() # your discord.Bot object

@bot.command()
async def example(ctx: commands.Context):
  embed1 = discord.Embed(title = "This is Embed#1")
  embed2 = discord.Embed(title = "This is Embed#2")
  output = paginate(embeds = [embed1, embed2])
  await ctx.send(embed = output.embed, view = output.view)

This command has the following output:

discord.ext.Commands example image

discord.app_commands Example: (ephemeral)
from discord import app_commands
from dpy_paginator import paginate

@app_commands.command(name='example')
async def example_command(interaction: discord.Interaction):
  await interaction.response.defer(ephemeral = True, thinking = True)
  embed1 = discord.Embed(title = "This is Embed#1")
  embed2 = discord.Embed(title = "This is Embed#2")
  output = paginate(embeds = [embed1, embed2])
  await interaction.followup.send(embed = output.embed, view = output.view)  

This command has the following output:

discord.app_commands (ephemeral) example image

Options and Parameters

Control who can interact: (author_ids: list[int] param)

You can control which user(s) can interact with the view by passing a author_ids list.

...

output = paginate(embeds = [embed1, embed2], author_ids = [#ID1, #ID2])

When anyone except the specified user(s) try to interact, the paginator ignores that interaction:

author_ids error example image

Adding a timeout: (timeout: int param)

By default, the view has a timeout of 90 seconds but this can be changed by passing a timeout parameter.

...

output = paginate(embeds = [embed1, embed2], timeout = 60)

The buttons get automatically disabled after timeout (except when no button is interacted with)[^1]. You can also use timeout = None for no timeout.

Example of a timedout view:

timedout image

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.timedout returns a boolean which we can use to check if the view has timedout.

import asyncio
...
timeout = 60

output = paginate(embeds = [embed1, embed2], timeout = timeout)
message = await Messageable.send(embed = output.embed, view = output.view)

await asyncio.sleep(timeout + 0.5) # add 0.5 to the timeout to account for processing delays
if output.view.timedout: # check if the view is timedout
  await message.edit(view = output.view) # manually edit the buttons if the output is timedout

# the view will automatically timeout incase this check returns False

Note that incase of ephemeral responses (or scenarios where the output will be deleted before the timeout), this extra step is not worth it.

Using custom emojis in buttons: (button_emojis: List[discord.Emoji] param)

You can use custom emojis in the buttons by passing a list of discord.Emoji objects or Unicode emoji strings. The list needs to have exactly 4 elements.

...
output = paginate(embeds = [embed1, embed2, embed3, embed4], button_emojis = ['<:DarkerTan:945570099081920532>', '<:DazzlingRose:945561181467344977>', '<:FluorescentBlue:945561331547914280>', '😮'])

# you can use unicode emojis (😮) directly
# for discord.Emoji objects you can either use them directly in the <:name:id> format or fetch the object using guild.get_emoji(id) or some other functionality

Example of a view using custom emojis:

custom emojis in button example image

Note that the package has no error handling for if you pass a non discord.Emoji object or a non Unicode emoji string in the list. This is because explicitly checking for a discord.Emoji object will not accomodate using an Unicode string. Make sure you are passing the right objects or strings otherwise you will be getting the HTTPException: 400 Bad Request (error code: 50035): Invalid Form Body error.

[^1]: To explain this, the paginateButtons view class receives the discord.Interaction object only when one of the buttons is interacted with which is then used to edit the message with the disabled buttons upon timeout. Only running paginate() 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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dpy_paginator-1.1.0.tar.gz (6.0 kB view details)

Uploaded Source

Built Distribution

dpy_paginator-1.1.0-py2.py3-none-any.whl (6.3 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file dpy_paginator-1.1.0.tar.gz.

File metadata

  • Download URL: dpy_paginator-1.1.0.tar.gz
  • Upload date:
  • Size: 6.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.10.12

File hashes

Hashes for dpy_paginator-1.1.0.tar.gz
Algorithm Hash digest
SHA256 3e38dec7c20510fc4494f74310a1a8082e91523428f0f309766a1f433c0528aa
MD5 d871e85dad6313f23cdc6366d0ee1fd3
BLAKE2b-256 d9e22e0869e719d2d26bbfa8c5cb5c6370af91751245bd94127bab22ae2e292a

See more details on using hashes here.

File details

Details for the file dpy_paginator-1.1.0-py2.py3-none-any.whl.

File metadata

File hashes

Hashes for dpy_paginator-1.1.0-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 32330cdb21c4e6332955a5524bf82950605a504b1cbfc749187b1074af81fc51
MD5 1e85aa479739d256d7f8e3f026b69218
BLAKE2b-256 a34c9325525aa603af7922a614717d2251a1ee69dda21f382188734352238c4e

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page