172 lines
5.5 KiB
Python
172 lines
5.5 KiB
Python
|
"""
|
||
|
Credits to Rapptz/RoboDanny
|
||
|
|
||
|
https://github.com/Rapptz/RoboDanny/blob/0dfa21599da76e84c2f8e7fde0c132ec93c840a8/cogs/utils/paginator.py
|
||
|
"""
|
||
|
import asyncio
|
||
|
import discord
|
||
|
from discord.ext.commands import Paginator as CommandPaginator
|
||
|
from discord.ext import menus
|
||
|
|
||
|
|
||
|
class RoboPages(menus.MenuPages):
|
||
|
def __init__(self, source):
|
||
|
super().__init__(source=source, check_embeds=True)
|
||
|
self.input_lock = asyncio.Lock()
|
||
|
|
||
|
async def finalize(self, timed_out):
|
||
|
try:
|
||
|
if timed_out:
|
||
|
await self.message.clear_reactions()
|
||
|
else:
|
||
|
await self.message.delete()
|
||
|
except discord.HTTPException:
|
||
|
pass
|
||
|
|
||
|
@menus.button("\N{INFORMATION SOURCE}\ufe0f", position=menus.Last(3))
|
||
|
async def show_help(self):
|
||
|
"""shows this message"""
|
||
|
embed = discord.Embed(
|
||
|
title="Paginator help",
|
||
|
description="Hello! Welcome to the help page.",
|
||
|
)
|
||
|
messages = []
|
||
|
for (emoji, button) in self.buttons.items():
|
||
|
messages.append(f"{emoji}: {button.action.__doc__}")
|
||
|
|
||
|
embed.add_field(
|
||
|
name="What are these reactions for?",
|
||
|
value="\n".join(messages),
|
||
|
inline=False,
|
||
|
)
|
||
|
embed.set_footer(
|
||
|
text=f"We were on page {self.current_page + 1} before this message."
|
||
|
)
|
||
|
await self.message.edit(content=None, embed=embed)
|
||
|
|
||
|
async def go_back_to_current_page():
|
||
|
await asyncio.sleep(30.0)
|
||
|
await self.show_page(self.current_page)
|
||
|
|
||
|
self.bot.loop.create_task(go_back_to_current_page())
|
||
|
|
||
|
@menus.button(
|
||
|
"\N{INPUT SYMBOL FOR NUMBERS}", position=menus.Last(1.5), lock=False
|
||
|
)
|
||
|
async def numbered_page(self, payload):
|
||
|
"""lets you type a page number to go to"""
|
||
|
if self.input_lock.locked():
|
||
|
return
|
||
|
|
||
|
async with self.input_lock:
|
||
|
channel = self.message.channel
|
||
|
author_id = payload.user_id
|
||
|
to_delete = []
|
||
|
to_delete.append(
|
||
|
await channel.send("What page do you want to go to?")
|
||
|
)
|
||
|
|
||
|
def message_check(m):
|
||
|
return (
|
||
|
m.author.id == author_id
|
||
|
and channel == m.channel
|
||
|
and m.content.isdigit()
|
||
|
)
|
||
|
|
||
|
try:
|
||
|
msg = await self.bot.wait_for(
|
||
|
"message", check=message_check, timeout=30.0
|
||
|
)
|
||
|
except asyncio.TimeoutError:
|
||
|
to_delete.append(await channel.send("Took too long."))
|
||
|
await asyncio.sleep(5)
|
||
|
else:
|
||
|
page = int(msg.content)
|
||
|
to_delete.append(msg)
|
||
|
await self.show_checked_page(page - 1)
|
||
|
|
||
|
try:
|
||
|
await channel.delete_messages(to_delete)
|
||
|
except Exception:
|
||
|
pass
|
||
|
|
||
|
|
||
|
class FieldPageSource(menus.ListPageSource):
|
||
|
"""A page source that requires (field_name, field_value) tuple items."""
|
||
|
|
||
|
def __init__(self, entries, *, per_page=12):
|
||
|
super().__init__(entries, per_page=per_page)
|
||
|
self.embed = discord.Embed(colour=discord.Colour.blurple())
|
||
|
|
||
|
# pylint: disable=arguments-differ
|
||
|
async def format_page(self, menu, entries):
|
||
|
self.embed.clear_fields()
|
||
|
self.embed.description = discord.Embed.Empty
|
||
|
|
||
|
for key, value in entries:
|
||
|
self.embed.add_field(name=key, value=value, inline=False)
|
||
|
|
||
|
maximum = self.get_max_pages()
|
||
|
if maximum > 1:
|
||
|
text = f"Page {menu.current_page + 1}/{maximum} ({len(self.entries)} entries)"
|
||
|
self.embed.set_footer(text=text)
|
||
|
|
||
|
return self.embed
|
||
|
|
||
|
|
||
|
class TextPageSource(menus.ListPageSource):
|
||
|
def __init__(self, text, *, prefix="```", suffix="```", max_size=2000):
|
||
|
pages = CommandPaginator(
|
||
|
prefix=prefix, suffix=suffix, max_size=max_size - 200
|
||
|
)
|
||
|
for line in text.split("\n"):
|
||
|
pages.add_line(line)
|
||
|
|
||
|
super().__init__(entries=pages.pages, per_page=1)
|
||
|
|
||
|
# pylint: disable=arguments-differ
|
||
|
async def format_page(self, menu, content):
|
||
|
maximum = self.get_max_pages()
|
||
|
if maximum > 1:
|
||
|
return f"{content}\nPage {menu.current_page + 1}/{maximum}"
|
||
|
return content
|
||
|
|
||
|
|
||
|
class SimplePageSource(menus.ListPageSource):
|
||
|
def __init__(self, entries, *, per_page=12):
|
||
|
super().__init__(entries, per_page=per_page)
|
||
|
self.initial_page = True
|
||
|
|
||
|
# pylint: disable=arguments-differ
|
||
|
async def format_page(self, menu, entries):
|
||
|
pages = []
|
||
|
for index, entry in enumerate(
|
||
|
entries, start=menu.current_page * self.per_page
|
||
|
):
|
||
|
pages.append(f"{index + 1}. {entry}")
|
||
|
|
||
|
maximum = self.get_max_pages()
|
||
|
if maximum > 1:
|
||
|
footer = f"Page {menu.current_page + 1}/{maximum} ({len(self.entries)} entries)"
|
||
|
menu.embed.set_footer(text=footer)
|
||
|
|
||
|
if self.initial_page and self.is_paginating():
|
||
|
pages.append("")
|
||
|
pages.append(
|
||
|
"Confused? React with \N{INFORMATION SOURCE} for more info."
|
||
|
)
|
||
|
self.initial_page = False
|
||
|
|
||
|
menu.embed.description = "\n".join(pages)
|
||
|
return menu.embed
|
||
|
|
||
|
|
||
|
class SimplePages(RoboPages):
|
||
|
"""A simple pagination session reminiscent of the old Pages interface.
|
||
|
Basically an embed with some normal formatting.
|
||
|
"""
|
||
|
|
||
|
def __init__(self, entries, *, per_page=12):
|
||
|
super().__init__(SimplePageSource(entries, per_page=per_page))
|
||
|
self.embed = discord.Embed(colour=discord.Colour.blurple())
|