miyu-bot/miyu_bot/commands/common/reaction_message.py
2021-01-16 17:00:46 -05:00

135 lines
4.6 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import asyncio
from typing import List, Callable, Awaitable, Union
import discord
from discord import Message, Embed, Emoji
from discord.ext.commands import Context
AnyEmoji = Union[str, Emoji]
async def run_tabbed_message(ctx: Context, emojis: List[AnyEmoji], embeds: List[Embed], files=None, starting_index=0,
timeout=300):
if not files:
files = []
if len(emojis) != len(embeds):
raise ValueError('Emojis and embeds must have the same number of elements.')
message = await ctx.send(files=files, embed=embeds[starting_index])
async def callback(emoji, _ctx, _message):
await message.edit(embed=embeds[emojis.index(emoji)])
await run_reaction_message(ctx, message, emojis, callback, timeout)
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, _ctx, _message):
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)
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:
header = header + '\n'
if max_tabbed_pages > 9:
raise ValueError('max_tabbed_pages must be 9 or less.')
if not content:
embed = base_embed.copy().set_footer(text='Page 0/0')
await ctx.send(embed=embed)
return
page_contents = [content[i:i + page_size] for i in range(0, len(content), page_size)]
item_number = 0
max_item_number_length = len(str(len(content)))
def format_item(item):
nonlocal item_number
item_number += 1
if numbered:
return f'{item_number}.{" " * (max_item_number_length - len(str(item_number)))} {item}'
else:
return str(item)
embeds = [
base_embed.from_dict({
**base_embed.to_dict(),
'description': '```' + header + '\n'.join((format_item(i) for i in page)) + '```',
}).set_footer(text=f'Page {i + 1}/{len(page_contents)}')
for i, page in enumerate(page_contents)]
if len(embeds) == 1:
await ctx.send(embed=embeds[0])
return
if len(embeds) <= max_tabbed_pages:
reaction_emoji = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
await run_tabbed_message(ctx, reaction_emoji[:len(embeds)], embeds, timeout=timeout)
else:
message = await ctx.send(embed=embeds[0], files=files or [])
double_left_arrow = ''
double_right_arrow = ''
left_arrow = ''
right_arrow = ''
arrows = [double_left_arrow, left_arrow, right_arrow, double_right_arrow]
index = 0
async def callback(emoji, _ctx, _message):
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)
async def run_reaction_message(ctx: Context, message: Message, emojis: List[AnyEmoji],
callback: Callable[[AnyEmoji, Context, Message], Awaitable[None]], timeout=300):
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)
await callback(reaction.emoji, ctx, message)
await message.remove_reaction(reaction, user)
except asyncio.TimeoutError:
for emoji in emojis:
await message.remove_reaction(emoji, ctx.bot.user)
break