Refactor bot into smaller modules

This commit is contained in:
Ev-1 committed 2022-05-29 13:10:48 +02:00
1 parent b8bb2a48da
commit 4c6d15e3e8
28 files changed
+398 -360

No files matched your search

+2 -4
View File
@@ -13,9 +13,7 @@ import aiohttp
import yaml
# Bot Utilities
from cogs.utils.alias import Aliaser
from cogs.utils.context import Context
from cogs.utils.localizer import Localizer, LocalizerWrapper
from cogs.utils.localisation import Aliaser, LocalizedContext, Localizer, LocalizerWrapper
from cogs.utils.logger import BotLogger
from cogs.utils.settingsmanager import Settings
@@ -73,7 +71,7 @@ class Bot(commands.Bot):
await self.process_commands(message)
async def process_commands(self, message):
ctx = await self.get_context(message, cls=Context)
ctx = await self.get_context(message, cls=LocalizedContext)
# Replace aliases with commands
ctx = self.aliaser.get_command(ctx)
+1 -1
View File
@@ -5,7 +5,7 @@ import traceback
# Bot Utilities
from cogs.helpformatter import commandhelper
from cogs.utils.paginator import Scroller
from cogs.utils.userinteraction import Scroller
class CogManager(commands.Cog):
+1 -1
View File
@@ -8,7 +8,7 @@ from cogs.music.music_errors import WrongTextChannelError, WrongVoiceChannelErro
# Bot Utilities
from cogs.helpformatter import commandhelper
from cogs.utils.paginator import Scroller
from cogs.utils.userinteraction import Scroller
class Errors(commands.Cog):
+1 -1
View File
@@ -4,7 +4,7 @@ from discord.ext import commands
import re
# Bot Utilities
from cogs.utils.paginator import HelpPaginator, Scroller
from .utils.userinteraction import HelpPaginator, Scroller
usermention = r"<@!?\d{17,19}>"
+1 -2
View File
@@ -10,8 +10,7 @@ import asyncio
import re
from ..utils import checks, timeformatter
from ..utils.paginator import QueuePaginator, Scroller
from ..utils.selector import Selector
from ..utils.userinteraction import QueuePaginator, Scroller, Selector
from .decorators import require_playing, require_queue, require_voice_connection, voteable
time_rx = re.compile('[0-9]+')
+1 -1
View File
@@ -15,7 +15,7 @@ import urllib
from bs4 import BeautifulSoup
from ..utils import checks
from ..utils.paginator import Scroller, TextPaginator
from ..utils.userinteraction import Scroller, TextPaginator
from .decorators import require_playing, require_voice_connection, voteable
+1 -1
View File
@@ -9,7 +9,7 @@ import yaml
# Bot Utilities
from cogs.helpformatter import commandhelper
from cogs.utils.paginator import Scroller
from cogs.utils.userinteraction import Scroller
from .utils.mixplayer import MixPlayer
+1 -1
View File
@@ -5,7 +5,7 @@ from discord.ext import commands
# Bot Utilities
from cogs.helpformatter import commandhelper
from cogs.utils import checks
from cogs.utils.paginator import Scroller
from cogs.utils.userinteraction import Scroller
class Settings(commands.Cog):
+5
View File
@@ -0,0 +1,5 @@
from .alias import Aliaser
from .localizer import LocalizerWrapper, Localizer
from .localizedcontext import LocalizedContext
__all__ = ['Aliaser', 'LocalizerWrapper', 'Localizer', 'LocalizedContext']
File renamed without changes.
@@ -2,7 +2,7 @@
from discord.ext import commands
class Context(commands.Context):
class LocalizedContext(commands.Context):
def __init__(self, **kwargs):
super().__init__(**kwargs)
if self.message.guild:
@@ -0,0 +1,4 @@
from .localizer import Localizer
from .localizerwrapper import LocalizerWrapper
__all__ = ['LocalizerWrapper', 'Localizer']
File renamed without changes.
@@ -9,7 +9,7 @@ from os import path
import yaml
# Bot Utilities
from cogs.utils.dict_utils import SafeDict, flatten
from .dict_utils import SafeDict, flatten
"""
Localizer for bot
@@ -152,19 +152,3 @@ class Localizer:
def format_embed(self, embed, lang=None, prefix=None, **kvpairs):
raw = embed.to_dict()
return Embed.from_dict(self.format_dict(raw, lang, prefix, **kvpairs))
class LocalizerWrapper:
def __init__(self, localizer, lang=None, prefix=None):
self.localizer = localizer
self.lang = lang
self.prefix = prefix
def format_str(self, s, **kvpairs):
return self.localizer.format_str(s, self.lang, self.prefix, **kvpairs)
def format_dict(self, d, **kvpairs):
return self.localizer.format_dict(d, self.lang, self.prefix, **kvpairs)
def format_embed(self, embed, **kvpairs):
return self.localizer.format_embed(embed, self.lang, self.prefix, **kvpairs)
@@ -0,0 +1,14 @@
class LocalizerWrapper:
def __init__(self, localizer, lang=None, prefix=None):
self.localizer = localizer
self.lang = lang
self.prefix = prefix
def format_str(self, s, **kvpairs):
return self.localizer.format_str(s, self.lang, self.prefix, **kvpairs)
def format_dict(self, d, **kvpairs):
return self.localizer.format_dict(d, self.lang, self.prefix, **kvpairs)
def format_embed(self, embed, **kvpairs):
return self.localizer.format_embed(embed, self.lang, self.prefix, **kvpairs)
-297
View File
@@ -1,297 +0,0 @@
# Discord Packages
import discord
import asyncio
class CantScroll(Exception):
pass
class BasePaginator:
def __init__(self, max_size=2000, max_units=10):
self._pages = []
self._current_page_size = 0
self._current_units = 0
self._max_size = max_size
self._max_units = max_units
def close_page(self):
pass
def add_page_indicator(self, localizer, localizer_str=None, **kvpairs):
self.close_page()
if localizer_str:
for i, page in enumerate(self._pages, start=1):
page.set_footer(text=localizer.format_str(localizer_str, _current=i,
_total=len(self._pages), **kvpairs))
else:
for i, page in enumerate(self._pages, start=1):
page.set_footer(text=f"{i}/{len(self._pages)}")
def append_paginator(self, paginator):
if not isinstance(paginator, BasePaginator):
raise TypeError('Paginator needs to be a subclass of BasePaginator.')
self.close_page()
for page in paginator.pages:
self.pages.append(page)
@property
def pages(self):
if self._current_page_size > 0:
self.close_page()
return self._pages
class TextPaginator(BasePaginator):
def __init__(self, max_size=2000, max_lines=10, **embed_base):
super().__init__(max_size=max_size, max_units=max_lines)
self._current_page = []
self.embed_base = embed_base
def close_page(self):
if self._current_page_size > 0:
embed = discord.Embed(**self.embed_base)
embed.description = '\n'.join(self._current_page)
self._pages.append(embed)
self._current_page_size = 0
self._current_units = 0
self._current_page = []
def add_line(self, line='', *, empty=False):
if len(line) > self._max_size:
raise RuntimeError(f'Line exceeds maximum page size {self._max_size}')
if self._current_page_size + len(line) + 1 > self._max_size:
self.close_page()
if self._current_units >= self._max_units:
self.close_page()
self._current_page_size += len(line) + 1
self._current_units += 1
self._current_page.append(line)
if empty:
self._current_page.append('')
self._current_page_size += 1
class FieldPaginator(BasePaginator):
def __init__(self, max_size=5000, max_fields=8, **embed_base):
super().__init__(max_size=max_size, max_units=max_fields)
self._embed_base = embed_base
self._current_page = discord.Embed(**self._embed_base)
def close_page(self):
if self._current_page_size > 0:
self._pages.append(self._current_page)
self._current_page_size = 0
self._current_units = 0
self._current_page = discord.Embed(**self._embed_base)
def add_field(self, name, value, inline=False):
field = {"name": name, "value": value}
fieldsize = sum([len(val) for _, val in field.items()])
if len(name) > 256 or len(value) > 1024:
raise RuntimeError('Maximum field size exceeded, max name length: 256. max value length: 1024.')
if self._current_page_size + fieldsize > self._max_size:
self.close_page()
if self._current_units >= self._max_units:
self.close_page()
field["inline"] = inline
self._current_page_size += fieldsize
self._current_units += 1
self._current_page.add_field(**field)
class QueuePaginator(TextPaginator):
def __init__(self, localizer, player, color, member: discord.Member = None, include_current: bool = False):
self.localizer = localizer
queue = player.global_queue() if not member else player.user_queue(member.id, dual=True)
duration = player.queue_duration(member=member, include_current=include_current)
if member:
title = localizer.format_str("{queue.userqueue}", _user=member.display_name, _length=len(queue),
_duration=duration)
else:
title = localizer.format_str("{queue.length}", _length=len(queue), _duration=duration)
super().__init__(max_lines=10, **{"color": color, "title": title})
for index, temp in enumerate(queue):
if member is None:
track = temp
queued_track = localizer.format_str("{queue.globaltrack}", _index=index+1, _title=track.title,
_uri=track.uri, _user_id=track.requester)
else:
track, globpos = temp
queued_track = localizer.format_str("{queue.usertrack}", _index=index+1, _globalindex=globpos+1,
_title=track.title, _uri=track.uri)
self.add_line(queued_track)
self.add_page_indicator(self.localizer, "{queue.pageindicator}")
class HelpPaginator(FieldPaginator):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def force_close_page(self):
self._pages.append(self._current_page)
self._current_page_size = 0
self._current_units = 0
self._current_page = discord.Embed(**self._embed_base)
def add_command_field(self, cmd_dict):
if not isinstance(cmd_dict, dict):
return
aliases = cmd_dict.get('aliases', [])
args = cmd_dict.get('args', '')
description = cmd_dict.get('description', '')
cmd = str(aliases[0])
cmd += ' ' + args
self.add_field(name=cmd, value=description, inline=False)
# Maybe slightly very copied from rdanny
# Thanks danny <3
class Scroller:
def __init__(self, ctx, paginator, timeout=120.0, clear_on_timeout=False, clear_on_exit=True, clear_command=True):
if not isinstance(paginator, BasePaginator):
raise TypeError('Paginator needs to be a subclass of BasePaginator.')
self.bot = ctx.bot
self.pages = paginator.pages
self.cmdmsg = ctx.message
self.message = ctx.message
self.channel = ctx.channel
self.author = ctx.author
self.timeout = timeout
self.timeout_delete = clear_on_timeout
self.exit_delete = clear_on_exit
self.clear_command = clear_command
if len(self.pages) > 1:
self.scrolling = True
else:
self.scrolling = False
self.reaction_emojis = [
('\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', self.first_page),
('\N{BLACK LEFT-POINTING TRIANGLE}', self.previous_page),
('\N{BLACK RIGHT-POINTING TRIANGLE}', self.next_page),
('\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', self.last_page),
('❌', self.stop_scrolling),
]
if ctx.guild is not None:
self.permissions = self.channel.permissions_for(ctx.guild.me)
else:
self.permissions = self.channel.permissions_for(ctx.bot.user)
if not self.permissions.embed_links:
raise CantScroll('Bot does not have embed links permission.')
if not self.permissions.send_messages:
raise CantScroll('Bot cannot send messages.')
if self.scrolling:
# verify we can actually use the pagination session
if not self.permissions.add_reactions:
raise CantScroll('Bot does not have add reactions permission.')
if not self.permissions.read_message_history:
raise CantScroll('Bot does not have Read Message History permission.')
async def send(self):
self.current_page = 0
# No embeds to scroll through
if not self.pages:
return
if not self.scrolling:
return await self.channel.send(embed=self.pages[0])
self.message = await self.channel.send(embed=self.pages[0])
for (reaction, _) in self.reaction_emojis:
if len(self.pages) == 2 and reaction in ('\u23ed', '\u23ee'):
continue
await self.message.add_reaction(reaction)
async def scroll(self, page):
if page < 0 or page >= len(self.pages):
return
self.current_page = page
await self.message.edit(embed=self.pages[page])
async def first_page(self):
await self.scroll(0)
async def last_page(self):
await self.scroll(len(self.pages) - 1)
async def next_page(self):
await self.scroll(self.current_page + 1)
async def previous_page(self):
await self.scroll(self.current_page - 1)
async def stop_scrolling(self):
self.scrolling = False
if self.exit_delete:
await self.message.delete()
if self.clear_command:
await self.cmdmsg.delete()
def react_check(self, reaction, user):
if user is None or user.id != self.author.id:
return False
if reaction.message.id != self.message.id:
return False
for (emoji, func) in self.reaction_emojis:
if reaction.emoji == emoji:
self.match = func
return True
return False
async def start_scrolling(self):
if not self.scrolling:
await self.send()
else:
self.bot.loop.create_task(self.send())
while self.scrolling:
try:
reaction, user = await self.bot.wait_for('reaction_add', check=self.react_check, timeout=self.timeout)
except asyncio.TimeoutError:
self.scrolling = False
try:
await self.message.clear_reactions()
if self.timeout_delete:
await self.message.delete()
if self.clear_command:
await self.cmdmsg.delete()
except discord.Forbidden:
pass
finally:
break
try:
await self.message.remove_reaction(reaction, user)
except discord.Forbidden:
pass
await self.match()
+3
View File
@@ -0,0 +1,3 @@
from .settingsmanager import Settings
__all__ = ['Settings']
+37
View File
@@ -0,0 +1,37 @@
class DictMapper:
"""
Base class for interacting with nested dictionaries through lists of keys
E.g. mapping ["a", "b", "c"] to example_dictionary["a"]["b"]["c"]
"""
@staticmethod
def set(d, keys, val):
key = keys[0]
if len(keys) == 1:
if val is None:
try:
d.pop(key)
except KeyError:
pass
else:
d[key] = val
return
if key in d.keys():
if not isinstance(d[key], dict):
d[key] = {}
DictMapper.set(d[key], keys[1:], val)
else:
d[key] = {}
DictMapper.set(d[key], keys[1:], val)
@staticmethod
def get(d, keys):
key = keys[0]
try:
if len(keys) > 1 and isinstance(d[key], dict):
return DictMapper.get(d[key], keys[1:])
else:
return d[key]
except KeyError:
return None
@@ -6,9 +6,10 @@ import locale as localee
import os
import yaml
from .dictmapper import DictMapper
class Settings:
class Settings():
def __init__(self, datadir, **default_settings):
self._DATA_PATH = f"{datadir}/bot/"
self._SETTINGS_PATH = self._DATA_PATH + 'settings.yaml'
@@ -34,35 +35,6 @@ class Settings:
with codecs.open(self._SETTINGS_PATH, "r", encoding='utf8') as f:
self.settings = yaml.load(f, Loader=yaml.SafeLoader)
def _set(self, d, keys, val):
key = keys[0]
if len(keys) == 1:
if val is None:
try:
d.pop(key)
except KeyError:
pass
else:
d[key] = val
return
if key in d.keys():
if not isinstance(d[key], dict):
d[key] = {}
self._set(d[key], keys[1:], val)
else:
d[key] = {}
self._set(d[key], keys[1:], val)
def _get(self, d, keys):
key = keys[0]
try:
if len(keys) > 1 and isinstance(d[key], dict):
return self._get(d[key], keys[1:])
else:
return d[key]
except KeyError:
return None
def set(self, identifier, setting, value):
""" Set value in settings, will overwrite any existing values. """
guild_name = None
@@ -75,7 +47,7 @@ class Settings:
if guild_name:
self.settings[identifier]["_servername"] = guild_name
self._set(self.settings[identifier], setting.split('.'), value)
DictMapper.set(self.settings[identifier], setting.split('.'), value)
with codecs.open(self._SETTINGS_PATH, 'w', encoding='utf8') as f:
yaml.dump(self.settings, f, indent=2)
@@ -95,7 +67,7 @@ class Settings:
if identifier not in self.settings.keys():
return default
value = self._get(self.settings[identifier], setting.split('.'))
value = DictMapper.get(self.settings[identifier], setting.split('.'))
if value is not None:
return value
else:
+6
View File
@@ -0,0 +1,6 @@
from .scroller import Scroller
from .selector import Selector
from .paginators import BasePaginator, TextPaginator, FieldPaginator, HelpPaginator, QueuePaginator, CantScrollException
__all__ = ['Scroller', 'Selector', 'QueuePaginator', 'HelpPaginator',
'TextPaginator', 'FieldPaginator', 'CantScrollException', 'BasePaginator']
@@ -0,0 +1,7 @@
from .queuepaginator import QueuePaginator
from .helppaginator import HelpPaginator
from .textpaginator import TextPaginator
from .fieldpaginator import FieldPaginator
from .basepaginator import CantScrollException, BasePaginator
__all__ = ['QueuePaginator', 'HelpPaginator', 'TextPaginator', 'FieldPaginator', 'CantScrollException', 'BasePaginator']
@@ -0,0 +1,37 @@
class CantScrollException(Exception):
pass
class BasePaginator:
def __init__(self, max_size=2000, max_units=10):
self._pages = []
self._current_page_size = 0
self._current_units = 0
self._max_size = max_size
self._max_units = max_units
def close_page(self):
pass
def add_page_indicator(self, localizer, localizer_str=None, **kvpairs):
self.close_page()
if localizer_str:
for i, page in enumerate(self._pages, start=1):
page.set_footer(text=localizer.format_str(localizer_str, _current=i,
_total=len(self._pages), **kvpairs))
else:
for i, page in enumerate(self._pages, start=1):
page.set_footer(text=f"{i}/{len(self._pages)}")
def append_paginator(self, paginator):
if not isinstance(paginator, BasePaginator):
raise TypeError('Paginator needs to be a subclass of BasePaginator.')
self.close_page()
for page in paginator.pages:
self.pages.append(page)
@property
def pages(self):
if self._current_page_size > 0:
self.close_page()
return self._pages
@@ -0,0 +1,33 @@
import discord
from .basepaginator import BasePaginator
class FieldPaginator(BasePaginator):
def __init__(self, max_size=5000, max_fields=8, **embed_base):
super().__init__(max_size=max_size, max_units=max_fields)
self._embed_base = embed_base
self._current_page = discord.Embed(**self._embed_base)
def close_page(self):
if self._current_page_size > 0:
self._pages.append(self._current_page)
self._current_page_size = 0
self._current_units = 0
self._current_page = discord.Embed(**self._embed_base)
def add_field(self, name, value, inline=False):
field = {"name": name, "value": value}
fieldsize = sum([len(val) for _, val in field.items()])
if len(name) > 256 or len(value) > 1024:
raise RuntimeError('Maximum field size exceeded, max name length: 256. max value length: 1024.')
if self._current_page_size + fieldsize > self._max_size:
self.close_page()
if self._current_units >= self._max_units:
self.close_page()
field["inline"] = inline
self._current_page_size += fieldsize
self._current_units += 1
self._current_page.add_field(**field)
@@ -0,0 +1,25 @@
import discord
from .fieldpaginator import FieldPaginator
class HelpPaginator(FieldPaginator):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def force_close_page(self):
self._pages.append(self._current_page)
self._current_page_size = 0
self._current_units = 0
self._current_page = discord.Embed(**self._embed_base)
def add_command_field(self, cmd_dict):
if not isinstance(cmd_dict, dict):
return
aliases = cmd_dict.get('aliases', [])
args = cmd_dict.get('args', '')
description = cmd_dict.get('description', '')
cmd = str(aliases[0])
cmd += ' ' + args
self.add_field(name=cmd, value=description, inline=False)
@@ -0,0 +1,31 @@
import discord
from .textpaginator import TextPaginator
class QueuePaginator(TextPaginator):
def __init__(self, localizer, player, color, member: discord.Member = None, include_current: bool = False):
self.localizer = localizer
queue = player.global_queue() if not member else player.user_queue(member.id, dual=True)
duration = player.queue_duration(member=member, include_current=include_current)
if member:
title = localizer.format_str("{queue.userqueue}", _user=member.display_name, _length=len(queue),
_duration=duration)
else:
title = localizer.format_str("{queue.length}", _length=len(queue), _duration=duration)
super().__init__(max_lines=10, **{"color": color, "title": title})
for index, temp in enumerate(queue):
if member is None:
track = temp
queued_track = localizer.format_str("{queue.globaltrack}", _index=index+1, _title=track.title,
_uri=track.uri, _user_id=track.requester)
else:
track, globpos = temp
queued_track = localizer.format_str("{queue.usertrack}", _index=index+1, _globalindex=globpos+1,
_title=track.title, _uri=track.uri)
self.add_line(queued_track)
self.add_page_indicator(self.localizer, "{queue.pageindicator}")
@@ -0,0 +1,39 @@
# Discord Packages
import discord
from .basepaginator import BasePaginator
class TextPaginator(BasePaginator):
def __init__(self, max_size=2000, max_lines=10, **embed_base):
super().__init__(max_size=max_size, max_units=max_lines)
self._current_page = []
self.embed_base = embed_base
def close_page(self):
if self._current_page_size > 0:
embed = discord.Embed(**self.embed_base)
embed.description = '\n'.join(self._current_page)
self._pages.append(embed)
self._current_page_size = 0
self._current_units = 0
self._current_page = []
def add_line(self, line='', *, empty=False):
if len(line) > self._max_size:
raise RuntimeError(f'Line exceeds maximum page size {self._max_size}')
if self._current_page_size + len(line) + 1 > self._max_size:
self.close_page()
if self._current_units >= self._max_units:
self.close_page()
self._current_page_size += len(line) + 1
self._current_units += 1
self._current_page.append(line)
if empty:
self._current_page.append('')
self._current_page_size += 1
+141
View File
@@ -0,0 +1,141 @@
# This was at some point *heavliy* inspired by the paginator implementation by Rapptz for r.Danny
# https://github.com/Rapptz/RoboDanny/blob/b0401e046814f42597c6e0280fef2432cc49cc5d/cogs/utils/paginator.py
import discord
import asyncio
from .paginators import BasePaginator, CantScrollException
class Scroller:
def __init__(self, ctx, paginator, timeout=120.0, clear_on_timeout=False, clear_on_exit=True, clear_command=True):
if not isinstance(paginator, BasePaginator):
raise TypeError('Paginator needs to be a subclass of BasePaginator.')
self.bot = ctx.bot
self.pages = paginator.pages
self.cmdmsg = ctx.message
self.message = ctx.message
self.channel = ctx.channel
self.author = ctx.author
self.timeout = timeout
self.timeout_delete = clear_on_timeout
self.exit_delete = clear_on_exit
self.clear_command = clear_command
if len(self.pages) > 1:
self.scrolling = True
else:
self.scrolling = False
self.reaction_emojis = [
('\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', self.first_page),
('\N{BLACK LEFT-POINTING TRIANGLE}', self.previous_page),
('\N{BLACK RIGHT-POINTING TRIANGLE}', self.next_page),
('\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', self.last_page),
('❌', self.stop_scrolling),
]
if ctx.guild is not None:
self.permissions = self.channel.permissions_for(ctx.guild.me)
else:
self.permissions = self.channel.permissions_for(ctx.bot.user)
if not self.permissions.embed_links:
raise CantScrollException('Bot does not have embed links permission.')
if not self.permissions.send_messages:
raise CantScrollException('Bot cannot send messages.')
if self.scrolling:
# verify we can actually use the pagination session
if not self.permissions.add_reactions:
raise CantScrollException('Bot does not have add reactions permission.')
if not self.permissions.read_message_history:
raise CantScrollException('Bot does not have Read Message History permission.')
async def send(self):
self.current_page = 0
# No embeds to scroll through
if not self.pages:
return
if not self.scrolling:
return await self.channel.send(embed=self.pages[0])
self.message = await self.channel.send(embed=self.pages[0])
for (reaction, _) in self.reaction_emojis:
if len(self.pages) == 2 and reaction in ('\u23ed', '\u23ee'):
continue
await self.message.add_reaction(reaction)
async def scroll(self, page):
if page < 0 or page >= len(self.pages):
return
self.current_page = page
await self.message.edit(embed=self.pages[page])
async def first_page(self):
await self.scroll(0)
async def last_page(self):
await self.scroll(len(self.pages) - 1)
async def next_page(self):
await self.scroll(self.current_page + 1)
async def previous_page(self):
await self.scroll(self.current_page - 1)
async def stop_scrolling(self):
self.scrolling = False
if self.exit_delete:
await self.message.delete()
if self.clear_command:
await self.cmdmsg.delete()
def react_check(self, reaction, user):
if user is None or user.id != self.author.id:
return False
if reaction.message.id != self.message.id:
return False
for (emoji, func) in self.reaction_emojis:
if reaction.emoji == emoji:
self.match = func
return True
return False
async def start_scrolling(self):
if not self.scrolling:
await self.send()
else:
self.bot.loop.create_task(self.send())
while self.scrolling:
try:
reaction, user = await self.bot.wait_for('reaction_add', check=self.react_check, timeout=self.timeout)
except asyncio.TimeoutError:
self.scrolling = False
try:
await self.message.clear_reactions()
if self.timeout_delete:
await self.message.delete()
if self.clear_command:
await self.cmdmsg.delete()
except discord.Forbidden:
pass
finally:
break
try:
await self.message.remove_reaction(reaction, user)
except discord.Forbidden:
pass
await self.match()
@@ -4,7 +4,7 @@ import discord
import asyncio
import inspect
from .paginator import TextPaginator
from .paginators import TextPaginator
class Selector(TextPaginator):