{"id":14238579,"url":"https://github.com/OnceYT/dpy-paginator","last_synced_at":"2025-08-11T08:31:19.570Z","repository":{"id":181146298,"uuid":"607577094","full_name":"OnceYT/dpy-paginator","owner":"OnceYT","description":"A discord.py utility with no external dependencies that makes paginating embeds easier.","archived":false,"fork":false,"pushed_at":"2024-04-01T20:59:57.000Z","size":171,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-05-21T18:26:04.424Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OnceYT.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-02-28T08:55:17.000Z","updated_at":"2024-08-21T03:01:38.438Z","dependencies_parsed_at":"2024-04-01T21:42:28.413Z","dependency_job_id":"b48c0d05-209a-4679-ab79-d8f18eb46965","html_url":"https://github.com/OnceYT/dpy-paginator","commit_stats":null,"previous_names":["onceyt/dpy-paginator"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OnceYT%2Fdpy-paginator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OnceYT%2Fdpy-paginator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OnceYT%2Fdpy-paginator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OnceYT%2Fdpy-paginator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OnceYT","download_url":"https://codeload.github.com/OnceYT/dpy-paginator/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":229516970,"owners_count":18085475,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-21T03:00:55.482Z","updated_at":"2024-12-13T08:30:27.892Z","avatar_url":"https://github.com/OnceYT.png","language":"Python","funding_links":[],"categories":["Libraries and Extensions"],"sub_categories":["UI - Pagination, Menus, Embeds and similar"],"readme":"# dpy-paginator\n![PyPI - Python Version](https://img.shields.io/pypi/pyversions/dpy-paginator)\n![Downloads](https://static.pepy.tech/badge/dpy-paginator)\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eTable of contents\u003c/strong\u003e\u003c/summary\u003e\n\n- [Overview](#overview)\n- [Installation](#installation)\n- [Usage](#usage)\n    - [Basic usage](#basic_usage)\n    - [discord.ext.Commands usage](#commands_usage)\n    - [discord.app_commands usage (ephemeral)](#appcommands_usage)\n- [Options and Parameters](#options)\n    - [Control who can interact](#author_ids)\n    - [Adding a timeout](#timeout)\n    - [Using custom emojis in buttons](#button_emojis)\n\u003c/details\u003e\n\n##### \u003ca name='overview'\u003e\u003c/a\u003eBuilt and tested on [discord.py](https://github.com/Rapptz/discord.py) 2.3.2\n[dpy-paginator](https://pypi.org/project/dpy-paginator/) is a discord.py utility with no external dependencies that makes paginating embeds easier.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQuick links\u003c/strong\u003e\u003c/summary\u003e\n\n- [Documentation](https://github.com/OnceYT/dpy-paginator/blob/v1.1.0/README.md)\n- [Security Policy](https://github.com/OnceYT/dpy-paginator/blob/main/.github/SECURITY.md)\n- [Source](https://github.com/OnceYT/dpy-paginator/tree/v1.1.0)\n- [PyPi](https://pypi.org/project/dpy-paginator/)\n- [Support/Contact](https://onceyt.github.io/)\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eChangelog (v1.0.0 -\u003e v1.1.0 and v1.1.1)\u003c/strong\u003e\u003c/summary\u003e\n\n- Added the ability to use [custom emojis in buttons](#button_emojis).\n- Code optimizations.\n- Code cleanup.\n- v1.1.0 -\u003e v1.1.1 contains only readme updates and pyproject.toml changes for metadata.\n\u003c/details\u003e\n\n**Some of it's features include:**\n- Easy to use.\n- Supports both ephemeral and non-ephemeral responses.\n- Buttons are enabled/disabled automatically depending on the current page number, number of embeds provided or at timeout.\n\n**The paginator consists of 4 buttons - ⏪, ◀️, 'Jump To' modal, ▶️, ⏩**\n- ⏪ - Shows the first embed. Disabled if there are less than 3 embeds or if already on the first embed.\n- ◀️ - Shows the previous embed. Disabled if already on the first embed.\n- '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.\n- ▶️ - Shows the next embed. Disabled if already on the last embed.\n- ⏩ - Shows the last embed. Disabled if there are less than 3 embeds or if already on the last page.\n\n# \u003ca name='installation'\u003e\u003c/a\u003eInstallation\n```\npip install dpy-paginator\n```\nor\n```\npip install git+https://github.com/onceyt/dpy-paginator.git@v1.1.1\n```\n\n# \u003ca name='usage'\u003e\u003c/a\u003eUsage\n##### \u003ca name='basic_usage'\u003e\u003c/a\u003eBasic usage:\n```py\nimport discord\nfrom dpy_paginator import paginate\n\nembed1 = discord.Embed(title = \"This is embed#1\")\nembed2 = discord.Embed(title = \"This is embed#2\")\noutput = await paginate(embeds = [embed1, embed2])\n\n# output.embed gives you the first embed of the pagination\n# output.view gives you the discord.ui.View that controls the pagination\n\nawait Messagable.send(embed = output.embed, view = output.view)\n\n# you want to send both in your Messageable.send\n```\n\n##### \u003ca name='commands_usage'\u003e\u003c/a\u003ediscord.ext.Commands Example:\n```py\nimport discord\nfrom discord.ext import commands\nfrom dpy_paginator import paginate\n\nbot = discord.Bot() # your discord.Bot object\n\n@bot.command()\nasync def example(ctx: commands.Context):\n  embed1 = discord.Embed(title = \"This is Embed#1\")\n  embed2 = discord.Embed(title = \"This is Embed#2\")\n  output = await paginate(embeds = [embed1, embed2])\n  await ctx.send(embed = output.embed, view = output.view)\n```\n**This command has the following output:**\n\n![discord.ext.Commands example image](https://i.imgur.com/7aOIIpK.png)\n\n##### \u003ca name='appcommands_usage'\u003e\u003c/a\u003ediscord.app_commands Example: (ephemeral)\n```py\nfrom discord import app_commands\nfrom dpy_paginator import paginate\n\n@app_commands.command(name='example')\nasync def example_command(interaction: discord.Interaction):\n  await interaction.response.defer(ephemeral = True, thinking = True)\n  embed1 = discord.Embed(title = \"This is Embed#1\")\n  embed2 = discord.Embed(title = \"This is Embed#2\")\n  output = await paginate(embeds = [embed1, embed2])\n  await interaction.followup.send(embed = output.embed, view = output.view)  \n```\n**This command has the following output:**\n\n![discord.app_commands (ephemeral) example image](https://i.imgur.com/tA78jy0.png)\n\n# \u003ca name='options'\u003e\u003c/a\u003eOptions and Parameters \n\n##### \u003ca name='author_ids'\u003e\u003c/a\u003eControl who can interact: (`author_ids: list[int]` param)\n\nYou can control which user(s) can interact with the view by passing a `author_ids` list.\n```py\n...\n\noutput = await paginate(embeds = [embed1, embed2], author_ids = [#ID1, #ID2])\n```\nWhen anyone except the specified user(s) try to interact, **the paginator ignores that interaction:**\n\n![author_ids error example image](https://i.imgur.com/QY7dTrw.png)\n\n##### \u003ca name='timeout'\u003e\u003c/a\u003eAdding a timeout: (`timeout: int` param)\n\n\nBy default, the view has a timeout of 90 seconds but this can be changed by passing a `timeout` parameter.\n```py\n...\n\noutput = await paginate(embeds = [embed1, embed2], timeout = 60)\n```\nThe buttons get automatically disabled after timeout (except when no button is interacted with)[^1]. You can also use `timeout = None` for no timeout.\n\n**Example of a timedout view:**\n\n![timedout image](https://i.imgur.com/qzI9eax.png)\n\nIn 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.\n```py\nimport asyncio\n...\ntimeout = 60\n\noutput = await paginate(embeds = [embed1, embed2], timeout = timeout)\nmessage = await Messageable.send(embed = output.embed, view = output.view)\n\nawait asyncio.sleep(timeout + 0.5) # add 0.5 to the timeout to account for processing delays\nif output.view.timedout: # check if the view is timedout\n  await message.edit(view = output.view) # manually edit the buttons if the output is timedout\n\n# the view will automatically timeout incase this check returns False\n```\nNote that incase of ephemeral responses (or scenarios where the output will be deleted before the timeout), this extra step is not worth it.\n\n##### \u003ca name='button_emojis'\u003e\u003c/a\u003eUsing custom emojis in buttons: (`button_emojis: List[discord.Emoji]` param)\n\nYou 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.\n```py\n...\noutput = await paginate(embeds = [embed1, embed2, embed3, embed4], button_emojis = ['\u003c:DarkerTan:945570099081920532\u003e', '\u003c:DazzlingRose:945561181467344977\u003e', '\u003c:FluorescentBlue:945561331547914280\u003e', '😮'])\n\n# you can use unicode emojis (😮) directly\n# for discord.Emoji objects you can either use them directly in the \u003c:name:id\u003e format or fetch the object using guild.get_emoji(id) or some other functionality\n```\n\n**Example of a view using custom emojis:**\n\n![custom emojis in button example image](https://i.imgur.com/h8cDhvZ.png)\n\nNote 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.\n\n[^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.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FOnceYT%2Fdpy-paginator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FOnceYT%2Fdpy-paginator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FOnceYT%2Fdpy-paginator/lists"}