mirror of
https://github.com/uhIgnacio/EmoteManager.git
synced 2024-08-15 02:23:13 +00:00
Merge branch 'master' of https://github.com/bmintz/emote-manager-bot
This commit is contained in:
commit
4d336d419f
9 changed files with 213 additions and 45 deletions
34
README.md
Normal file
34
README.md
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
# Emote Manager
|
||||||
|
|
||||||
|
[![Discord Bots](https://discordbots.org/api/widget/status/473370418007244852.svg?noavatar=true)](https://discordbots.org/bot/473370418007244852)
|
||||||
|
|
||||||
|
Need to edit your server's custom emotes from your phone? Just add this simple bot, and use its commands to do it for you!
|
||||||
|
|
||||||
|
**Note:** both you and the bot will need the "Manage Emojis" permission to edit custom server emotes.
|
||||||
|
|
||||||
|
To add the bot to your server, visit https://discordapp.com/oauth2/authorize?client_id=473370418007244852&scope=bot&permissions=1074023488.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
<p>
|
||||||
|
To add an emote:
|
||||||
|
<ul>
|
||||||
|
<li><code>@Emote Manager add <img class="emote" src="https://cdn.discordapp.com/emojis/407347328606011413.png?v=1&size=32" alt=":thonkang:" title=":thonkang:"></code> (if you already have that emote)
|
||||||
|
<li><code>@Emote Manager add rollsafe <https://image.noelshack.com/fichiers/2017/06/1486495269-rollsafe.png></code>
|
||||||
|
<li><code>@Emote Manager add speedtest https://cdn.discordapp.com/emojis/379127000398430219.png</code>
|
||||||
|
</ul>
|
||||||
|
If you invoke <code>@Emote Manager add</code> with an image upload, the image will be used as the emote image, and the filename will be used as the emote name. To choose a different name, simply run it like<br>
|
||||||
|
<code>@Emote Manager add :some_emote:</code> instead.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<code>@Emote Manager list</code> gives you a list of all emotes on this server.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<code>@Emote Manager remove emote</code> will remove :emote:.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<code>@Emote Manager rename old_name new_name</code> will rename :old_name: to :new_name:.
|
||||||
|
</p>
|
18
bot.py
18
bot.py
|
@ -13,14 +13,28 @@ logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
class Bot(commands.AutoShardedBot):
|
class Bot(commands.AutoShardedBot):
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(command_prefix=commands.when_mentioned, **kwargs)
|
|
||||||
|
|
||||||
with open('config.py') as f:
|
with open('config.py') as f:
|
||||||
self.config = eval(f.read(), {})
|
self.config = eval(f.read(), {})
|
||||||
|
|
||||||
|
super().__init__(
|
||||||
|
command_prefix=commands.when_mentioned,
|
||||||
|
description=self.config.get('description', ''),
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
|
self._setup_success_emojis()
|
||||||
|
|
||||||
for cog in self.config['cogs']:
|
for cog in self.config['cogs']:
|
||||||
self.load_extension(cog)
|
self.load_extension(cog)
|
||||||
|
|
||||||
|
def _setup_success_emojis(self):
|
||||||
|
"""Load the emojis from the config to be used when a command fails or succeeds
|
||||||
|
We do it this way so that they can be used anywhere instead of requiring a bot instance.
|
||||||
|
"""
|
||||||
|
import utils.misc
|
||||||
|
default = ('❌', '✅')
|
||||||
|
utils.SUCCESS_EMOJIS = utils.misc.SUCCESS_EMOJIS = (
|
||||||
|
self.config.get('response_emojis', {}).get('success', default))
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
super().run(self.config['tokens'].pop('discord'))
|
super().run(self.config['tokens'].pop('discord'))
|
||||||
|
|
||||||
|
|
105
cogs/emote.py
105
cogs/emote.py
|
@ -8,7 +8,9 @@ import logging
|
||||||
import weakref
|
import weakref
|
||||||
import traceback
|
import traceback
|
||||||
import contextlib
|
import contextlib
|
||||||
|
import urllib.parse
|
||||||
|
|
||||||
|
import aioec
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import discord
|
import discord
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
|
@ -28,11 +30,13 @@ class Emotes:
|
||||||
self.bot.config['user_agent'] + ' '
|
self.bot.config['user_agent'] + ' '
|
||||||
+ self.bot.http.user_agent
|
+ self.bot.http.user_agent
|
||||||
})
|
})
|
||||||
|
self.aioec = aioec.Client(loop=self.bot.loop)
|
||||||
# keep track of paginators so we can end them when the cog is unloaded
|
# keep track of paginators so we can end them when the cog is unloaded
|
||||||
self.paginators = weakref.WeakSet()
|
self.paginators = weakref.WeakSet()
|
||||||
|
|
||||||
def __unload(self):
|
def __unload(self):
|
||||||
self.bot.loop.create_task(self.http.close())
|
self.bot.loop.create_task(self.http.close())
|
||||||
|
self.bot.loop.create_task(self.aioec.close())
|
||||||
|
|
||||||
async def stop_all_paginators():
|
async def stop_all_paginators():
|
||||||
for paginator in self.paginators:
|
for paginator in self.paginators:
|
||||||
|
@ -41,9 +45,11 @@ class Emotes:
|
||||||
self.bot.loop.create_task(stop_all_paginators())
|
self.bot.loop.create_task(stop_all_paginators())
|
||||||
|
|
||||||
async def __local_check(self, context):
|
async def __local_check(self, context):
|
||||||
if not context.guild:
|
if not context.guild or not isinstance(context.author, discord.Member):
|
||||||
raise commands.NoPrivateMessage
|
raise commands.NoPrivateMessage
|
||||||
return False
|
|
||||||
|
if context.command is self.list:
|
||||||
|
return True
|
||||||
|
|
||||||
if context.command is self.list:
|
if context.command is self.list:
|
||||||
return True
|
return True
|
||||||
|
@ -62,9 +68,9 @@ class Emotes:
|
||||||
|
|
||||||
if isinstance(error, commands.NoPrivateMessage):
|
if isinstance(error, commands.NoPrivateMessage):
|
||||||
await context.send(
|
await context.send(
|
||||||
f'{utils.SUCCESS_EMOTES[False]} Sorry, this command may only be used in a server.')
|
f'{utils.SUCCESS_EMOJIS[False]} Sorry, this command may only be used in a server.')
|
||||||
|
|
||||||
@commands.command()
|
@commands.command(usage='[name] <image URL or custom emote>')
|
||||||
async def add(self, context, *args):
|
async def add(self, context, *args):
|
||||||
"""Add a new emote to this server.
|
"""Add a new emote to this server.
|
||||||
|
|
||||||
|
@ -78,11 +84,7 @@ class Emotes:
|
||||||
`add` will upload a new emote using the first attachment as the image,
|
`add` will upload a new emote using the first attachment as the image,
|
||||||
and its filename as the name
|
and its filename as the name
|
||||||
"""
|
"""
|
||||||
try:
|
|
||||||
name, url = self.parse_add_command_args(context, args)
|
name, url = self.parse_add_command_args(context, args)
|
||||||
except commands.BadArgument as exception:
|
|
||||||
return await context.send(exception)
|
|
||||||
|
|
||||||
async with context.typing():
|
async with context.typing():
|
||||||
message = await self.add_safe(context.guild, name, url, context.message.author.id)
|
message = await self.add_safe(context.guild, name, url, context.message.author.id)
|
||||||
await context.send(message)
|
await context.send(message)
|
||||||
|
@ -113,7 +115,7 @@ class Emotes:
|
||||||
if match is None:
|
if match is None:
|
||||||
url = utils.strip_angle_brackets(args[1])
|
url = utils.strip_angle_brackets(args[1])
|
||||||
else:
|
else:
|
||||||
url = utils.emote.url(match.group('id'))
|
url = utils.emote.url(match['id'], animated=match['animated'])
|
||||||
|
|
||||||
return name, url
|
return name, url
|
||||||
|
|
||||||
|
@ -129,10 +131,42 @@ class Emotes:
|
||||||
|
|
||||||
return name, url
|
return name, url
|
||||||
|
|
||||||
async def add_safe(self, guild, name, url, author_id):
|
@commands.command(name='add-from-ec', aliases=['addfromec'])
|
||||||
|
async def add_from_ec(self, context, name, *names):
|
||||||
|
"""Copies one or more emotes from Emote Collector to your server.
|
||||||
|
|
||||||
|
The list of possible emotes you can copy is here:
|
||||||
|
https://emote-collector.python-for.life/list
|
||||||
|
"""
|
||||||
|
if names:
|
||||||
|
for name in (name,) + names:
|
||||||
|
await context.invoke(self.add_from_ec, name)
|
||||||
|
return
|
||||||
|
|
||||||
|
name = name.strip(':')
|
||||||
|
try:
|
||||||
|
emote = await self.aioec.emote(name)
|
||||||
|
except aioec.NotFound:
|
||||||
|
return await context.send("Emote not found in Emote Collector's database.")
|
||||||
|
except aioec.HttpException as exception:
|
||||||
|
return await context.send(
|
||||||
|
f'Error: the Emote Collector API returned status code {exception.status}')
|
||||||
|
|
||||||
|
reason = (
|
||||||
|
f'Added from Emote Collector by {utils.format_user(self.bot, context.author.id)}. '
|
||||||
|
f'Original emote author: {utils.format_user(self.bot, emote.author)}')
|
||||||
|
|
||||||
|
async with context.typing():
|
||||||
|
message = await self.add_safe(context.guild, name, utils.emote.url(
|
||||||
|
emote.id, animated=emote.animated
|
||||||
|
), context.author.id, reason=reason)
|
||||||
|
|
||||||
|
await context.send(message)
|
||||||
|
|
||||||
|
async def add_safe(self, guild, name, url, author_id, *, reason=None):
|
||||||
"""Try to add an emote. Returns a string that should be sent to the user."""
|
"""Try to add an emote. Returns a string that should be sent to the user."""
|
||||||
try:
|
try:
|
||||||
emote = await self.add_from_url(guild, name, url, author_id)
|
emote = await self.add_from_url(guild, name, url, author_id, reason=reason)
|
||||||
except discord.HTTPException as ex:
|
except discord.HTTPException as ex:
|
||||||
return (
|
return (
|
||||||
'An error occurred while creating the emote:\n'
|
'An error occurred while creating the emote:\n'
|
||||||
|
@ -144,9 +178,9 @@ class Emotes:
|
||||||
else:
|
else:
|
||||||
return f'Emote {emote} successfully created.'
|
return f'Emote {emote} successfully created.'
|
||||||
|
|
||||||
async def add_from_url(self, guild, name, url, author_id):
|
async def add_from_url(self, guild, name, url, author_id, *, reason=None):
|
||||||
image_data = await self.fetch_emote(url)
|
image_data = await self.fetch_emote(url)
|
||||||
emote = await self.create_emote_from_bytes(guild, name, author_id, image_data)
|
emote = await self.create_emote_from_bytes(guild, name, author_id, image_data, reason=reason)
|
||||||
|
|
||||||
return emote
|
return emote
|
||||||
|
|
||||||
|
@ -164,38 +198,42 @@ class Emotes:
|
||||||
raise errors.HTTPException(response.status)
|
raise errors.HTTPException(response.status)
|
||||||
return io.BytesIO(await response.read())
|
return io.BytesIO(await response.read())
|
||||||
|
|
||||||
async def create_emote_from_bytes(self, guild, name, author_id, image_data: io.BytesIO):
|
async def create_emote_from_bytes(self, guild, name, author_id, image_data: io.BytesIO, *, reason=None):
|
||||||
# resize_until_small is normally blocking, because wand is.
|
# resize_until_small is normally blocking, because wand is.
|
||||||
# run_in_executor is magic that makes it non blocking somehow.
|
# run_in_executor is magic that makes it non blocking somehow.
|
||||||
# also, None as the executor arg means "use the loop's default executor"
|
# also, None as the executor arg means "use the loop's default executor"
|
||||||
image_data = await self.bot.loop.run_in_executor(None, utils.image.resize_until_small, image_data)
|
image_data = await self.bot.loop.run_in_executor(None, utils.image.resize_until_small, image_data)
|
||||||
|
if reason is None:
|
||||||
|
reason = f'Created by {utils.format_user(self.bot, author_id)}'
|
||||||
return await guild.create_custom_emoji(
|
return await guild.create_custom_emoji(
|
||||||
name=name,
|
name=name,
|
||||||
image=image_data.read(),
|
image=image_data.read(),
|
||||||
reason=f'Created by {utils.format_user(self.bot, author_id)}')
|
reason=reason)
|
||||||
|
|
||||||
@commands.command()
|
@commands.command(aliases=('delete', 'delet', 'rm'))
|
||||||
async def remove(self, context, *names):
|
async def remove(self, context, emote, *emotes):
|
||||||
"""Remove an emote from this server.
|
"""Remove an emote from this server.
|
||||||
|
|
||||||
names: the names of one or more emotes you'd like to remove.
|
emotes: the name of an emote or of one or more emotes you'd like to remove.
|
||||||
"""
|
"""
|
||||||
if len(names) == 1:
|
if not emotes:
|
||||||
emote = await self.disambiguate(context, names[0])
|
emote = await self.parse_emote(context, emote)
|
||||||
await emote.delete(reason=f'Removed by {utils.format_user(self.bot, context.author.id)}')
|
await emote.delete(reason=f'Removed by {utils.format_user(self.bot, context.author.id)}')
|
||||||
await context.send(f'Emote \:{emote.name}: successfully removed.')
|
await context.send(f'Emote \:{emote.name}: successfully removed.')
|
||||||
else:
|
else:
|
||||||
for name in names:
|
for emote in (emote,) + emotes:
|
||||||
await context.invoke(self.remove, name)
|
await context.invoke(self.remove, emote)
|
||||||
|
with contextlib.suppress(discord.HTTPException):
|
||||||
|
await context.message.add_reaction(utils.SUCCESS_EMOJIS[True])
|
||||||
|
|
||||||
@commands.command()
|
@commands.command(aliases=('mv',))
|
||||||
async def rename(self, context, old_name, new_name):
|
async def rename(self, context, old, new_name):
|
||||||
"""Rename an emote on this server.
|
"""Rename an emote on this server.
|
||||||
|
|
||||||
old_name: the name of the emote to rename
|
old: the name of the emote to rename, or the emote itself
|
||||||
new_name: what you'd like to rename it to
|
new_name: what you'd like to rename it to
|
||||||
"""
|
"""
|
||||||
emote = await self.disambiguate(context, old_name)
|
emote = await self.parse_emote(context, old)
|
||||||
try:
|
try:
|
||||||
await emote.edit(
|
await emote.edit(
|
||||||
name=new_name,
|
name=new_name,
|
||||||
|
@ -205,9 +243,9 @@ class Emotes:
|
||||||
'An error occurred while renaming the emote:\n'
|
'An error occurred while renaming the emote:\n'
|
||||||
+ utils.format_http_exception(ex))
|
+ utils.format_http_exception(ex))
|
||||||
|
|
||||||
await context.send(f'Emote \:{old_name}: successfully renamed to \:{new_name}:')
|
await context.send(f'Emote successfully renamed to \:{new_name}:')
|
||||||
|
|
||||||
@commands.command()
|
@commands.command(aliases=('ls', 'dir'))
|
||||||
async def list(self, context, animated=''):
|
async def list(self, context, animated=''):
|
||||||
"""A list of all emotes on this server.
|
"""A list of all emotes on this server.
|
||||||
|
|
||||||
|
@ -239,7 +277,18 @@ class Emotes:
|
||||||
self.paginators.add(paginator)
|
self.paginators.add(paginator)
|
||||||
await paginator.begin()
|
await paginator.begin()
|
||||||
|
|
||||||
|
async def parse_emote(self, context, name_or_emote):
|
||||||
|
match = utils.emote.RE_CUSTOM_EMOTE.match(name_or_emote)
|
||||||
|
if match:
|
||||||
|
id = int(match.group('id'))
|
||||||
|
emote = discord.utils.get(context.guild.emojis, id=id)
|
||||||
|
if emote:
|
||||||
|
return emote
|
||||||
|
name = name_or_emote
|
||||||
|
return await self.disambiguate(context, name)
|
||||||
|
|
||||||
async def disambiguate(self, context, name):
|
async def disambiguate(self, context, name):
|
||||||
|
name = name.strip(':') # in case the user tries :foo: and foo is animated
|
||||||
candidates = [e for e in context.guild.emojis if e.name.lower() == name.lower() and e.require_colons]
|
candidates = [e for e in context.guild.emojis if e.name.lower() == name.lower() and e.require_colons]
|
||||||
if not candidates:
|
if not candidates:
|
||||||
raise errors.EmoteNotFoundError(name)
|
raise errors.EmoteNotFoundError(name)
|
||||||
|
|
45
cogs/meta.py
Normal file
45
cogs/meta.py
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
import contextlib
|
||||||
|
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@commands.command(aliases=['inv'])
|
||||||
|
async def invite(self, context):
|
||||||
|
"""Gives you a link to add me to your server."""
|
||||||
|
permissions = discord.Permissions()
|
||||||
|
permissions.update(**dict.fromkeys((
|
||||||
|
'read_messages',
|
||||||
|
'send_messages',
|
||||||
|
'add_reactions',
|
||||||
|
'external_emojis',
|
||||||
|
'manage_emojis',
|
||||||
|
'embed_links',
|
||||||
|
), True))
|
||||||
|
|
||||||
|
await context.send('<%s>' % discord.utils.oauth_url(self.bot.user.id, permissions))
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
async def support(self, context):
|
||||||
|
"""Directs you to the support server."""
|
||||||
|
try:
|
||||||
|
await context.author.send(self.bot.config['support_server_invite'])
|
||||||
|
with contextlib.suppress(discord.HTTPException):
|
||||||
|
await context.message.add_reaction('📬') # TODO make this emoji configurable too
|
||||||
|
except discord.Forbidden:
|
||||||
|
with contextlib.suppress(discord.HTTPException):
|
||||||
|
await context.message.add_reaction(utils.SUCCESS_EMOJIS[True])
|
||||||
|
await context.send('Unable to send invite in DMs. Please allow DMs from server members.')
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(Meta(bot))
|
||||||
|
|
||||||
|
if not bot.config.get('support_server_invite'):
|
||||||
|
bot.remove_command('support')
|
|
@ -1,6 +1,14 @@
|
||||||
{
|
{
|
||||||
|
'description':
|
||||||
|
'Emote Manager lets you manage custom server emotes from your phone.\n\n'
|
||||||
|
'NOTE: Most commands will be unavailable until both you and the bot have the '
|
||||||
|
'"Manage Emojis" permission.',
|
||||||
|
|
||||||
|
'support_server_invite': 'https://discord.gg/some-invite',
|
||||||
|
|
||||||
'cogs': (
|
'cogs': (
|
||||||
'cogs.emote',
|
'cogs.emote',
|
||||||
|
'cogs.meta',
|
||||||
'ben_cogs.debug',
|
'ben_cogs.debug',
|
||||||
'ben_cogs.misc',
|
'ben_cogs.misc',
|
||||||
'ben_cogs.debug'
|
'ben_cogs.debug'
|
||||||
|
@ -16,5 +24,18 @@
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
'user_agent': 'EmojiManagerBot (https://github.com/bmintz/emoji-manager-bot)',
|
'user_agent': 'EmoteManagerBot (https://github.com/bmintz/emote-manager-bot)',
|
||||||
|
|
||||||
|
# emotes that the bot may use to respond to you
|
||||||
|
# If not provided, the bot will use ('❌', '✅') instead.
|
||||||
|
#
|
||||||
|
# You can obtain these ones from the discordbots.org server under the name "tickNo" and "tickYes"
|
||||||
|
# but I uploaded them to my test server
|
||||||
|
# so that both the staging and the stable versions of the bot can use them
|
||||||
|
'response_emotes': {
|
||||||
|
'success': { # emotes used to indicate success or failure
|
||||||
|
False: '<:error:478164511879069707>',
|
||||||
|
True: '<:success:478164452261363712>'
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
aioec
|
||||||
git+https://github.com/Rapptz/discord.py@rewrite
|
git+https://github.com/Rapptz/discord.py@rewrite
|
||||||
jishaku
|
jishaku
|
||||||
ben_cogs
|
ben_cogs
|
||||||
|
|
|
@ -11,7 +11,7 @@ class MissingManageEmojisPermission(commands.MissingPermissions):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Exception, self).__init__(
|
super(Exception, self).__init__(
|
||||||
f'{utils.SUCCESS_EMOTES[False]} '
|
f'{utils.SUCCESS_EMOJIS[False]} '
|
||||||
"Sorry, you don't have enough permissions to run this command. "
|
"Sorry, you don't have enough permissions to run this command. "
|
||||||
'You and I both need the Manage Emojis permission.')
|
'You and I both need the Manage Emojis permission.')
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,6 @@ import discord
|
||||||
|
|
||||||
"""various utilities for use within the bot"""
|
"""various utilities for use within the bot"""
|
||||||
|
|
||||||
"""Emotes used to indicate success/failure. You can obtain these from the discordbots.org guild,
|
|
||||||
but I uploaded them to my test server
|
|
||||||
so that both the staging and the stable versions of the bot can use them"""
|
|
||||||
SUCCESS_EMOTES = ('<:error:416845770239508512>', '<:success:416845760810844160>')
|
|
||||||
|
|
||||||
def format_user(bot, id, *, mention=False):
|
def format_user(bot, id, *, mention=False):
|
||||||
"""Format a user ID for human readable display."""
|
"""Format a user ID for human readable display."""
|
||||||
user = bot.get_user(id)
|
user = bot.get_user(id)
|
||||||
|
|
|
@ -11,15 +11,12 @@ from discord.ext.commands import Context
|
||||||
|
|
||||||
|
|
||||||
class Paginator:
|
class Paginator:
|
||||||
def __init__(self, ctx: Context, pages: typing.Iterable, *, timeout=300, delete_message=False, predicate=None,
|
def __init__(self, ctx: Context, pages: typing.Iterable, *, timeout=300, delete_message=False,
|
||||||
delete_message_on_timeout=False, text_message=None):
|
delete_message_on_timeout=False, text_message=None):
|
||||||
if predicate is None:
|
|
||||||
def predicate(_, user):
|
|
||||||
return user == ctx.message.author
|
|
||||||
|
|
||||||
self.pages = list(pages)
|
self.pages = list(pages)
|
||||||
self.predicate = predicate
|
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
|
self.author = ctx.author
|
||||||
self.target = ctx.channel
|
self.target = ctx.channel
|
||||||
self.delete_msg = delete_message
|
self.delete_msg = delete_message
|
||||||
self.delete_msg_timeout = delete_message_on_timeout
|
self.delete_msg_timeout = delete_message_on_timeout
|
||||||
|
@ -41,6 +38,15 @@ class Paginator:
|
||||||
|
|
||||||
self._page = None
|
self._page = None
|
||||||
|
|
||||||
|
def react_check(self, reaction, user):
|
||||||
|
if user is None or user != self.author:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if reaction.message.id != self._message.id:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return bool(discord.utils.find(lambda emoji: reaction.emoji == emoji, self.navigation))
|
||||||
|
|
||||||
async def begin(self):
|
async def begin(self):
|
||||||
"""Starts pagination"""
|
"""Starts pagination"""
|
||||||
self._stopped = False
|
self._stopped = False
|
||||||
|
@ -50,7 +56,10 @@ class Paginator:
|
||||||
await self._message.add_reaction(button)
|
await self._message.add_reaction(button)
|
||||||
while not self._stopped:
|
while not self._stopped:
|
||||||
try:
|
try:
|
||||||
reaction, user = await self._client.wait_for('reaction_add', check=self.predicate, timeout=self.timeout)
|
reaction, user = await self._client.wait_for(
|
||||||
|
'reaction_add',
|
||||||
|
check=self.react_check,
|
||||||
|
timeout=self.timeout)
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
await self.stop(delete=self.delete_msg_timeout)
|
await self.stop(delete=self.delete_msg_timeout)
|
||||||
continue
|
continue
|
||||||
|
|
Loading…
Reference in a new issue