import discord from discord.ext import commands from discord import ButtonStyle, Embed, Interaction from discord.ui import Button, View class Bot(commands.Bot): def __init__(self): super().__init__( command_prefix=commands.when_mentioned_or("$"), intents=discord.Intents(guilds=True, messages=True) ) async def on_ready(self): print(f"Logged in as {self.user} (ID: {self.user.id})") print("------") # Define 3 View subclasses that we will switch between depending on if we are viewing the first page, a page in the middle, or the last page. # The first page has the "left" button disabled, because there is no left page to go to class FirstPageComps(View): def __init__( self, author_id: int, ): super().__init__() self.value = None self.author_id = author_id async def interaction_check( self, interaction: Interaction, ): return interaction.user.id == self.author_id @discord.ui.button( style=ButtonStyle.primary, disabled=True, label="Left", ) async def left( self, button: discord.ui.Button, interaction: Interaction, ): self.value = "left" self.stop() @discord.ui.button( style=ButtonStyle.primary, label="Right", ) async def right( self, button: discord.ui.Button, interaction: Interaction, ): self.value = "right" self.stop() # The middle pages have both left and right buttons available class MiddlePageComps(View): def __init__( self, author_id: int, ): super().__init__() self.value = None self.author_id = author_id async def interaction_check( self, interaction: Interaction, ): return interaction.user.id == self.author_id @discord.ui.button( style=ButtonStyle.primary, label="Left", ) async def left( self, button: discord.ui.Button, interaction: Interaction, ): self.value = "left" self.stop() @discord.ui.button( style=ButtonStyle.primary, label="Right", ) async def right( self, button: discord.ui.Button, interaction: Interaction, ): self.value = "right" self.stop() # The last page has the right button disabled, because there's no right page to go to class LastPageComps(View): def __init__( self, author_id: int, ): super().__init__() self.value = None self.author_id = author_id async def interaction_check( self, interaction: Interaction, ): return interaction.user.id == self.author_id @discord.ui.button( style=ButtonStyle.primary, label="Left", ) async def left( self, button: discord.ui.Button, interaction: Interaction, ): self.value = "left" self.stop() @discord.ui.button( style=ButtonStyle.primary, label="Right", disabled=True, ) async def right( self, button: discord.ui.Button, interaction: Interaction, ): self.value = "right" self.stop() # Now we define the function that will take care of the pagination for us. It will take a list of Embeds and allow the user to cycle between them using left/right buttons # There is also an optional title parameter in case you want to give your paginator a title, it will display in the embed title, for example if the title is Book # then the title will look like "Book | Page 1/2". This is very optional and can be removed async def paginate( ctx, pages: list, title: str = None, ): total_pages = len(pages) first_page = pages[0] last_page = pages[-1] current_page = first_page index = 0 embed = first_page if title: embed.title = f"{title} | Page {index+1}/{total_pages}" view = FirstPageComps(ctx.author.id) # Here we send the message with the view of the first page and the FirstPageComps buttons msg = await ctx.send( embed=embed, view=view, ) # The default timeout for Views is 3 minutes, but if a user selects to scroll between pages the timer will be reset. # If the timer reaches 0, though, the loop will just silently stop. while True: wait = await view.wait() if wait: return if view.value == "right": index += 1 current_page = pages[index] view = MiddlePageComps(ctx.author.id) if current_page != last_page else LastPageComps(ctx.author.id) embed = current_page if title: embed.title = f"{title} | Page {index+1}/{total_pages}" elif view.value == "left": index -= 1 current_page = pages[index] view = MiddlePageComps(ctx.author.id) if current_page != first_page else FirstPageComps(ctx.author.id) embed = current_page if title: embed.title = f"{title} | Page {index+1}/{total_pages}" await msg.edit( embed=embed, view=view, ) bot = Bot() # To test our new function, let's create a list of a couple Embeds and let our paginator deal with the sending and buttons @bot.command() async def sendpages(ctx): page1 = Embed(description="This is page 1") page2 = Embed(description="This is page 2") page3 = Embed(description="This is page 3") await paginate(ctx, [page1, page2, page3]) bot.run("token")