0
votes

I'm making a command that acts a manga reader, and I want to use wait_for to wait for reactions from the user and then go forwards or backwards accordingly. However, I'm confused on how to implement it.

@commands.command()
    async def read_manga(self, ctx, page=1):
        page -= 1
        image_urls = ['image1.url', 'image2.url', 'image3.url', 'etc.urls']

        message = await ctx.send(image_urls[page])

        def backward_check(reaction, user):
            return user == ctx.message.author and str(reaction.emoji) == '◀️'

        def forward_check(reaction, user):
            return user == ctx.message.author and str(reaction.emoji) == '▶️'
        
        try:
            reaction, user = await self.bot.wait_for('reaction_add', timeout=60.0, check=forward_check)
        except asyncio.TimeoutError:
            print('Timed Out')
        else:
            await message.edit(content=image_urls[page+1])

        try:
            reaction, user = await self.bot.wait_for('reaction_add', timeout=60.0, check=backward_check)
        except asyncio.TimeoutError:
            print('Timed Out')
        else:
            await message.edit(content=image_urls[page-1])

As it is right now, the bot will only respond to the forward check and not the backward check. In addition, the bot will not detect if I react with ▶️, unreact, and then react with ▶️ again. How can I fix these issues?

3
Looks like you're trying to implement a menu, you can use this menu extension and save yourself some hassleCeres

3 Answers

1
votes

Your bot is waiting for a reaction and after that command is ending. You can use a while loop to avoid from this.

import asyncio
BUTTONS = ["◀️", "⏹", "▶️"]

@commands.command(name="read-manga")
async def read_manga(self, ctx):
  urls = ["url1.png", "url2.png"] #Your image urls
  index = 0
  msg = await ctx.send(urls[index])
  for b in BUTTONS:
    await msg.add_reaction(b)
  
  while True:
    try:
      react, user = await self.bot.wait_for("reaction_add", timeout=60.0, check=lambda r, u: r.message.id == msg.id and u.id == ctx.author.id and r.emoji in BUTTONS)
      await msg.remove_reaction(react.emoji, user) #Removes the user reaction after he/she reacts the message
    
    except asyncio.TimeoutError:
      return await msg.delete()

    else:
      if react.emoji == BUTTONS[0] and index > 0: #if current page is the first page this will not work
        index -= 1
      elif react.emoji == BUTTONS[1]:
        return await msg.delete()
      elif react.emoji == BUTTONS[2] and index < len(urls) - 1: #checking if current page is not the last one
        index += 1
      await msg.edit(content=urls[index]) #editing message content
0
votes

It is possible to wait_for 2 emojis at the same time with a list and by using lambda function instead of basic function:

reaction, user = await self.bot.wait_for('reaction_add', timeout=60.0, check=lambda reaction, user: reaction.emoji in ['◀️','▶️'] and user == ctx.message.author)

You can use some condition after the else like:

else:
    if reaction == '◀️':
        ...
    else:
        ...

Instead of else: you can put elif reaction == '▶️':, it will be the same thing.

0
votes

Credit to Ceres for providing me with a link to a menu extension, and I agree this is probably the a better way to get what I'm trying to achieve.