miyu-bot/miyu_bot/commands/common/reaction_message.py

147 lines
4.9 KiB
Python
Raw Normal View History

import asyncio
from typing import List, Callable, Awaitable, Union
import discord
from discord import Message, Embed, Emoji
from discord.ext.commands import Context
2020-12-27 00:59:11 -05:00
AnyEmoji = Union[str, Emoji]
2021-01-16 16:55:13 -05:00
async def run_tabbed_message(ctx: Context, emojis: List[AnyEmoji], embeds: List[Embed], files=None, starting_index=0,
timeout=300):
if len(emojis) != len(embeds):
raise ValueError('Emojis and embeds must have the same number of elements.')
2021-01-15 13:11:57 -05:00
message = await ctx.send(files=files, embed=embeds[starting_index])
async def callback(emoji):
await message.edit(embed=embeds[emojis.index(emoji)])
await run_reaction_message(ctx, message, emojis, callback, timeout)
2021-01-16 16:55:13 -05:00
async def run_dynamically_paged_message(ctx: Context, embed_generator: Callable[[int], discord.Embed], timeout=300):
left_arrow = ''
right_arrow = ''
arrows = [left_arrow, right_arrow]
message = await ctx.send(embed=embed_generator(0))
async def callback(emoji):
2021-01-16 16:55:13 -05:00
if emoji == left_arrow:
new_embed = embed_generator(-1)
elif emoji == right_arrow:
new_embed = embed_generator(1)
else:
return
if new_embed:
await message.edit(embed=new_embed)
await run_reaction_message(ctx, message, arrows, callback, timeout)
2021-01-13 09:33:17 -05:00
async def run_paged_message(ctx: Context, base_embed: discord.Embed, content: List[str], page_size: int = 15,
header='', numbered: bool = True, timeout=300, max_tabbed_pages=4, files=None):
if header:
2021-01-18 15:14:50 -05:00
header = f'`{header}`\n'
2021-01-13 09:33:17 -05:00
if max_tabbed_pages > 9:
raise ValueError('max_tabbed_pages must be 9 or less.')
2020-12-27 00:59:11 -05:00
if not content:
2021-01-13 09:33:17 -05:00
embed = base_embed.copy().set_footer(text='Page 0/0')
message = await ctx.send(embed=embed)
await run_deletable_message(ctx, message, timeout)
2020-12-27 00:59:11 -05:00
return
page_contents = [content[i:i + page_size] for i in range(0, len(content), page_size)]
item_number = 0
2021-01-11 12:18:28 -05:00
max_item_number_length = len(str(len(content)))
2020-12-27 00:59:11 -05:00
def format_item(item):
nonlocal item_number
item_number += 1
2021-01-11 12:18:28 -05:00
if numbered:
return f'`{item_number}.{" " * (max_item_number_length - len(str(item_number)))} {item}`'
2021-01-11 12:18:28 -05:00
else:
return f'`{item}`'
2020-12-27 00:59:11 -05:00
embeds = [
2021-01-13 09:33:17 -05:00
base_embed.from_dict({
**base_embed.to_dict(),
2021-01-18 15:14:50 -05:00
'description': header + '\n'.join((format_item(i) for i in page)),
2021-01-13 09:33:17 -05:00
}).set_footer(text=f'Page {i + 1}/{len(page_contents)}')
2020-12-27 00:59:11 -05:00
for i, page in enumerate(page_contents)]
if len(embeds) == 1:
message = await ctx.send(embed=embeds[0])
await run_deletable_message(ctx, message, timeout)
2020-12-27 00:59:11 -05:00
return
if len(embeds) <= max_tabbed_pages:
reaction_emoji = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
2021-01-16 16:55:13 -05:00
await run_tabbed_message(ctx, reaction_emoji[:len(embeds)], embeds, timeout=timeout)
2020-12-27 00:59:11 -05:00
else:
2021-01-16 16:55:13 -05:00
message = await ctx.send(embed=embeds[0], files=files or [])
double_left_arrow = ''
double_right_arrow = ''
left_arrow = ''
right_arrow = ''
2020-12-27 00:59:11 -05:00
arrows = [double_left_arrow, left_arrow, right_arrow, double_right_arrow]
2020-12-27 00:59:11 -05:00
index = 0
async def callback(emoji):
nonlocal index
start_index = index
if emoji == double_left_arrow:
index = 0
elif emoji == left_arrow:
index -= 1
elif emoji == right_arrow:
index += 1
elif emoji == double_right_arrow:
index = len(embeds) - 1
index = min(len(embeds) - 1, max(0, index))
if index != start_index:
await message.edit(embed=embeds[index])
await run_reaction_message(ctx, message, arrows, callback, timeout)
2020-12-27 00:59:11 -05:00
2021-01-23 23:34:13 -05:00
async def run_deletable_message(ctx: Context, message: Message, timeout=300):
await run_reaction_message(ctx, message, [], _noop, timeout=timeout)
async def _noop(n):
return None
2020-12-27 00:59:11 -05:00
async def run_reaction_message(ctx: Context, message: Message, emojis: List[AnyEmoji],
callback: Callable[[AnyEmoji], Awaitable[None]], timeout=300):
2021-01-23 23:34:13 -05:00
emojis.append('')
for emoji in emojis:
await message.add_reaction(emoji)
def check(rxn, usr):
return usr == ctx.author and rxn.emoji in emojis and rxn.message.id == message.id
while True:
try:
reaction, user = await ctx.bot.wait_for('reaction_add', timeout=timeout, check=check)
2021-01-23 23:34:13 -05:00
if reaction.emoji == '':
await message.delete()
return
await callback(reaction.emoji)
await message.remove_reaction(reaction, user)
except asyncio.TimeoutError:
for emoji in emojis:
2020-12-27 00:59:11 -05:00
await message.remove_reaction(emoji, ctx.bot.user)
break