discord bot (python) "wait_for" "reaction_add" duplicating embed

Viewed 72

I've been having an issue with my attempt to make a embed that reveals a list of characters that a play owns. I basically want to have the :left_arrow: and :right_arrow: emojis as reaction to pan left and right between the long database of characters a user owns.

I did in fact manage to do that however I noticed that if I use the command which shows an embed with all the characters twice before the timeout of one and then i click the left arrow to see the next page it goes to the next page on both embeds instead of just the one i reacted to.

Here's my source code.

@commands.command(aliases=["collection", "c"])
@commands.cooldown(1, 5, commands.BucketType.user)
async def characters(self, ctx):
    if not await bot.check_channel_permissions(ctx.author, ctx.channel): # Checks if the bot can send messages in the channel.
        return

    playerData = await bot.get_player_data(ctx.author, ctx.channel) # Returns the user's data.

    if playerData:

        if len(playerData["Characters"]) > 0: # Checks amount of characters the user owns.

            if len(playerData["Characters"]) > 20: # Player owns 20 so it will create an embed with reactions.

                global pageNumber
                global maxPages
                pageNumber = 1
                maxPages = math.ceil(len(playerData["Characters"]) / 20)

                embed = await characters.setupEmbed(self, playerData, ctx.author, pageNumber)

                currentEmbed = await ctx.channel.send(ctx.author.mention, embed=embed)

                await currentEmbed.add_reaction("⬅")
                await currentEmbed.add_reaction("➡")

                async def listenForRection(self, mainUser): # Waits until the user reacts with the left or right arrow in order to edit the current embed.

                    global pageNumber # the current page (20 characters are shown a page)
                    global maxPages # the max amount of pages the user can pan between.

                    def check(reaction, reactionuser):
                        if reactionuser != mainUser:
                            return False
                        elif str(reaction.emoji) == '⬅' and pageNumber > 1:
                            return True
                        elif str(reaction.emoji) == '➡' and pageNumber < maxPages:
                            return True
                        else:
                            return False

                    try:
                        reaction, reactionuser = await self.client.wait_for(
                            "reaction_add",
                            timeout=60,
                            check=check
                        )
                    except:
                        asyncio.TimeoutError
                        await currentEmbed.edit(content="Timed out.")
                    else:
                        if str(reaction.emoji) == '⬅':
                            pageNumber += -1
                        elif str(reaction.emoji) == "➡":
                            pageNumber += 1
                        newEmbed = await characters.setupEmbed(self, playerData, mainUser, pageNumber) # Returns an embeded list given the page number and info on the user.
                        await currentEmbed.edit(embed=newEmbed) # re-edits the current embed to show the next or previous page.
                        await listenForRection(self, mainUser) # re-runs the function again to listen for the next reaction.

                await listenForRection(self, ctx.author) # runs the listener once so that it can begin detecting and re-running on its own.


            else: # player will get an embeded list with no reactions since they only have 1 page of characters.
                embed = await characters.setupEmbed(self, playerData, ctx.author, 1)
                await ctx.channel.send(ctx.author.mention, embed=embed)
        else:
            await ctx.reply("You don't have any characters.")

What would happen is I run the command once and it works perfectly fine. Then when I run it again before the timeout and click a reaction it either wouldn't work or run both on the new embed and the old. I spent a ton of hours trying multiple things and searching but I didn't manage to do much apart from creating a new bug right after i fix the current.

1 Answers

There is actually an ext library for making paginated menus called discord-ext-menus. It does most of the work for you so you don't have to create your own.

Related