mirror of
https://github.com/uhIgnacio/EmoteManager.git
synced 2024-08-15 02:23:13 +00:00
format and nextcord
This commit is contained in:
parent
3eaac0148d
commit
84c5276076
3 changed files with 679 additions and 645 deletions
20
bot.py
20
bot.py
|
@ -3,6 +3,8 @@
|
||||||
# © lambda#0987 <lambda@lambda.dance>
|
# © lambda#0987 <lambda@lambda.dance>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import asyncio
|
||||||
import base64
|
import base64
|
||||||
import logging
|
import logging
|
||||||
import traceback
|
import traceback
|
||||||
|
@ -17,12 +19,11 @@ logger = logging.getLogger(__name__)
|
||||||
logger.setLevel(logging.INFO)
|
logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
# SelectorEventLoop on windows doesn't support subprocesses lol
|
# SelectorEventLoop on windows doesn't support subprocesses lol
|
||||||
import asyncio
|
|
||||||
import sys
|
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
loop = asyncio.ProactorEventLoop()
|
loop = asyncio.ProactorEventLoop()
|
||||||
asyncio.set_event_loop(loop)
|
asyncio.set_event_loop(loop)
|
||||||
|
|
||||||
|
|
||||||
class Bot(Bot):
|
class Bot(Bot):
|
||||||
startup_extensions = (
|
startup_extensions = (
|
||||||
'cogs.emote',
|
'cogs.emote',
|
||||||
|
@ -39,8 +40,10 @@ class Bot(Bot):
|
||||||
|
|
||||||
super().__init__(config=config, **kwargs)
|
super().__init__(config=config, **kwargs)
|
||||||
# allow use of the bot's user ID before ready()
|
# allow use of the bot's user ID before ready()
|
||||||
token_part0 = self.config['tokens']['discord'].partition('.')[0].encode()
|
token_part0 = self.config['tokens']['discord'].partition('.')[
|
||||||
self.user_id = int(base64.b64decode(token_part0 + b'=' * (3 - len(token_part0) % 3)))
|
0].encode()
|
||||||
|
self.user_id = int(base64.b64decode(
|
||||||
|
token_part0 + b'=' * (3 - len(token_part0) % 3)))
|
||||||
|
|
||||||
def process_config(self):
|
def process_config(self):
|
||||||
"""Load the emojis from the config to be used when a command fails or succeeds
|
"""Load the emojis from the config to be used when a command fails or succeeds
|
||||||
|
@ -52,6 +55,7 @@ class Bot(Bot):
|
||||||
utils.SUCCESS_EMOJIS = utils.misc.SUCCESS_EMOJIS = (
|
utils.SUCCESS_EMOJIS = utils.misc.SUCCESS_EMOJIS = (
|
||||||
self.config.get('response_emojis', {}).get('success', default))
|
self.config.get('response_emojis', {}).get('success', default))
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
@ -59,14 +63,15 @@ def main():
|
||||||
shard_count = None
|
shard_count = None
|
||||||
shard_ids = None
|
shard_ids = None
|
||||||
elif len(sys.argv) < 3:
|
elif len(sys.argv) < 3:
|
||||||
print('Usage:', sys.argv[0], '[<shard count> <hyphen-separated list of shard IDs>]', file=sys.stderr)
|
print(
|
||||||
|
'Usage:', sys.argv[0], '[<shard count> <hyphen-separated list of shard IDs>]', file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
else:
|
else:
|
||||||
shard_count = int(sys.argv[1])
|
shard_count = int(sys.argv[1])
|
||||||
shard_ids = list(map(int, sys.argv[2].split('-')))
|
shard_ids = list(map(int, sys.argv[2].split('-')))
|
||||||
|
|
||||||
Bot(
|
Bot(
|
||||||
intents=discord.Intents(
|
intents=nextcord.Intents(
|
||||||
guilds=True,
|
guilds=True,
|
||||||
# we hardly need DM support but it's helpful to be able to run the help/support commands in DMs
|
# we hardly need DM support but it's helpful to be able to run the help/support commands in DMs
|
||||||
messages=True,
|
messages=True,
|
||||||
|
@ -78,7 +83,7 @@ def main():
|
||||||
|
|
||||||
# the least stateful bot you will ever see 😎
|
# the least stateful bot you will ever see 😎
|
||||||
chunk_guilds_at_startup=False,
|
chunk_guilds_at_startup=False,
|
||||||
member_cache_flags=discord.MemberCacheFlags.none(),
|
member_cache_flags=nextcord.MemberCacheFlags.none(),
|
||||||
# disable message cache
|
# disable message cache
|
||||||
max_messages=None,
|
max_messages=None,
|
||||||
|
|
||||||
|
@ -86,5 +91,6 @@ def main():
|
||||||
shard_ids=shard_ids,
|
shard_ids=shard_ids,
|
||||||
).run()
|
).run()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -18,9 +18,9 @@ import warnings
|
||||||
import weakref
|
import weakref
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import discord
|
import nextcord
|
||||||
import humanize
|
import humanize
|
||||||
from discord.ext import commands
|
from nextcord.ext import commands
|
||||||
|
|
||||||
import utils
|
import utils
|
||||||
import utils.image
|
import utils.image
|
||||||
|
@ -32,16 +32,20 @@ from utils.converter import emote_type_filter_default
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# guilds can have duplicate emotes, so let us create zips to match
|
# guilds can have duplicate emotes, so let us create zips to match
|
||||||
warnings.filterwarnings('ignore', module='zipfile', category=UserWarning, message=r"^Duplicate name: .*$")
|
warnings.filterwarnings('ignore', module='zipfile',
|
||||||
|
category=UserWarning, message=r"^Duplicate name: .*$")
|
||||||
|
|
||||||
|
|
||||||
class UserCancelledError(commands.UserInputError):
|
class UserCancelledError(commands.UserInputError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Emotes(commands.Cog):
|
class Emotes(commands.Cog):
|
||||||
IMAGE_MIMETYPES = {'image/png', 'image/jpeg', 'image/gif', 'image/webp'}
|
IMAGE_MIMETYPES = {'image/png', 'image/jpeg', 'image/gif', 'image/webp'}
|
||||||
# TAR_MIMETYPES = {'application/x-tar', 'application/x-xz', 'application/gzip', 'application/x-bzip2'}
|
# TAR_MIMETYPES = {'application/x-tar', 'application/x-xz', 'application/gzip', 'application/x-bzip2'}
|
||||||
TAR_MIMETYPES = {'application/x-tar'}
|
TAR_MIMETYPES = {'application/x-tar'}
|
||||||
ZIP_MIMETYPES = {'application/zip', 'application/octet-stream', 'application/x-zip-compressed', 'multipart/x-zip'}
|
ZIP_MIMETYPES = {'application/zip', 'application/octet-stream',
|
||||||
|
'application/x-zip-compressed', 'multipart/x-zip'}
|
||||||
ARCHIVE_MIMETYPES = TAR_MIMETYPES | ZIP_MIMETYPES
|
ARCHIVE_MIMETYPES = TAR_MIMETYPES | ZIP_MIMETYPES
|
||||||
ZIP_OVERHEAD_BYTES = 30
|
ZIP_OVERHEAD_BYTES = 30
|
||||||
|
|
||||||
|
@ -57,7 +61,8 @@ class Emotes(commands.Cog):
|
||||||
self.http = aiohttp.ClientSession(
|
self.http = aiohttp.ClientSession(
|
||||||
loop=self.bot.loop,
|
loop=self.bot.loop,
|
||||||
read_timeout=self.bot.config.get('http_read_timeout', 60),
|
read_timeout=self.bot.config.get('http_read_timeout', 60),
|
||||||
connector=connector if self.bot.config.get('use_socks5_for_all_connections') else None,
|
connector=connector if self.bot.config.get(
|
||||||
|
'use_socks5_for_all_connections') else None,
|
||||||
headers={
|
headers={
|
||||||
'User-Agent':
|
'User-Agent':
|
||||||
self.bot.config['user_agent'] + ' '
|
self.bot.config['user_agent'] + ' '
|
||||||
|
@ -83,7 +88,9 @@ class Emotes(commands.Cog):
|
||||||
self.bot.loop.create_task(close())
|
self.bot.loop.create_task(close())
|
||||||
|
|
||||||
public_commands = set()
|
public_commands = set()
|
||||||
def public(command, public_commands=public_commands): # resolve some kinda scope issue that i don't understand
|
|
||||||
|
# resolve some kinda scope issue that i don't understand
|
||||||
|
def public(command, public_commands=public_commands):
|
||||||
public_commands.add(command.qualified_name)
|
public_commands.add(command.qualified_name)
|
||||||
return command
|
return command
|
||||||
|
|
||||||
|
@ -120,7 +127,7 @@ class Emotes(commands.Cog):
|
||||||
You can use it like this:
|
You can use it like this:
|
||||||
`add :thonkang:` (if you already have that emote)
|
`add :thonkang:` (if you already have that emote)
|
||||||
`add rollsafe https://image.noelshack.com/fichiers/2017/06/1486495269-rollsafe.png`
|
`add rollsafe https://image.noelshack.com/fichiers/2017/06/1486495269-rollsafe.png`
|
||||||
`add speedtest <https://cdn.discordapp.com/emojis/379127000398430219.png>`
|
`add speedtest <https://cdn.nextcordapp.com/emojis/379127000398430219.png>`
|
||||||
|
|
||||||
With a file attachment:
|
With a file attachment:
|
||||||
`add name` will upload a new emote using the first attachment as the image and call it `name`
|
`add name` will upload a new emote using the first attachment as the image and call it `name`
|
||||||
|
@ -137,7 +144,7 @@ class Emotes(commands.Cog):
|
||||||
"""Add a bunch of custom emotes."""
|
"""Add a bunch of custom emotes."""
|
||||||
|
|
||||||
ran = False
|
ran = False
|
||||||
# we could use *emotes: discord.PartialEmoji here but that would require spaces between each emote.
|
# we could use *emotes: nextcord.PartialEmoji here but that would require spaces between each emote.
|
||||||
# and would fail if any arguments were not valid emotes
|
# and would fail if any arguments were not valid emotes
|
||||||
for match in re.finditer(utils.emote.RE_CUSTOM_EMOTE, ''.join(emotes)):
|
for match in re.finditer(utils.emote.RE_CUSTOM_EMOTE, ''.join(emotes)):
|
||||||
ran = True
|
ran = True
|
||||||
|
@ -183,19 +190,21 @@ class Emotes(commands.Cog):
|
||||||
return name, url
|
return name, url
|
||||||
|
|
||||||
elif not args:
|
elif not args:
|
||||||
raise commands.BadArgument('Your message had no emotes and no name!')
|
raise commands.BadArgument(
|
||||||
|
'Your message had no emotes and no name!')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def parse_add_command_attachment(cls, context, args):
|
def parse_add_command_attachment(cls, context, args):
|
||||||
attachment = context.message.attachments[0]
|
attachment = context.message.attachments[0]
|
||||||
name = cls.format_emote_filename(''.join(args) if args else attachment.filename)
|
name = cls.format_emote_filename(
|
||||||
|
''.join(args) if args else attachment.filename)
|
||||||
url = attachment.url
|
url = attachment.url
|
||||||
|
|
||||||
return name, url
|
return name, url
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def format_emote_filename(filename):
|
def format_emote_filename(filename):
|
||||||
"""format a filename to an emote name as discord does when you upload an emote image"""
|
"""format a filename to an emote name as nextcord does when you upload an emote image"""
|
||||||
left, sep, right = posixpath.splitext(filename)[0].rpartition('-')
|
left, sep, right = posixpath.splitext(filename)[0].rpartition('-')
|
||||||
return (left or right).replace(' ', '')
|
return (left or right).replace(' ', '')
|
||||||
|
|
||||||
|
@ -238,7 +247,8 @@ class Emotes(commands.Cog):
|
||||||
"""
|
"""
|
||||||
emotes = list(filter(image_type, context.guild.emojis))
|
emotes = list(filter(image_type, context.guild.emojis))
|
||||||
if not emotes:
|
if not emotes:
|
||||||
raise commands.BadArgument('No emotes of that type were found in this server.')
|
raise commands.BadArgument(
|
||||||
|
'No emotes of that type were found in this server.')
|
||||||
|
|
||||||
async with context.typing():
|
async with context.typing():
|
||||||
async for zip_file in self.archive_emotes(context, emotes):
|
async for zip_file in self.archive_emotes(context, emotes):
|
||||||
|
@ -248,6 +258,7 @@ class Emotes(commands.Cog):
|
||||||
filesize_limit = context.guild.filesize_limit
|
filesize_limit = context.guild.filesize_limit
|
||||||
discrims = collections.defaultdict(int)
|
discrims = collections.defaultdict(int)
|
||||||
downloaded = collections.deque()
|
downloaded = collections.deque()
|
||||||
|
|
||||||
async def download(emote):
|
async def download(emote):
|
||||||
# don't put two files in the zip with the same name
|
# don't put two files in the zip with the same name
|
||||||
discrims[emote.name] += 1
|
discrims[emote.name] += 1
|
||||||
|
@ -259,7 +270,7 @@ class Emotes(commands.Cog):
|
||||||
|
|
||||||
name = f'{name}.{"gif" if emote.animated else "png"}'
|
name = f'{name}.{"gif" if emote.animated else "png"}'
|
||||||
|
|
||||||
# place some level of trust on discord's CDN to actually give us images
|
# place some level of trust on nextcord's CDN to actually give us images
|
||||||
data = await self.fetch_safe(str(emote.url), validate_headers=False)
|
data = await self.fetch_safe(str(emote.url), validate_headers=False)
|
||||||
if type(data) is str: # error case
|
if type(data) is str: # error case
|
||||||
await context.send(f'{emote}: {data}')
|
await context.send(f'{emote}: {data}')
|
||||||
|
@ -269,7 +280,8 @@ class Emotes(commands.Cog):
|
||||||
est_size_in_zip = est_zip_overhead + len(data)
|
est_size_in_zip = est_zip_overhead + len(data)
|
||||||
if est_size_in_zip >= filesize_limit:
|
if est_size_in_zip >= filesize_limit:
|
||||||
self.bot.loop.create_task(
|
self.bot.loop.create_task(
|
||||||
context.send(f'{emote} could not be added because it alone would exceed the file size limit.')
|
context.send(
|
||||||
|
f'{emote} could not be added because it alone would exceed the file size limit.')
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -294,7 +306,8 @@ class Emotes(commands.Cog):
|
||||||
downloaded.appendleft(item)
|
downloaded.appendleft(item)
|
||||||
break
|
break
|
||||||
|
|
||||||
zinfo = zipfile.ZipInfo(name, date_time=created_at.timetuple()[:6])
|
zinfo = zipfile.ZipInfo(
|
||||||
|
name, date_time=created_at.timetuple()[:6])
|
||||||
zip.writestr(zinfo, image_data)
|
zip.writestr(zinfo, image_data)
|
||||||
|
|
||||||
if out.tell() == 0:
|
if out.tell() == 0:
|
||||||
|
@ -302,7 +315,7 @@ class Emotes(commands.Cog):
|
||||||
break
|
break
|
||||||
|
|
||||||
out.seek(0)
|
out.seek(0)
|
||||||
yield discord.File(out, f'emotes-{context.guild.id}-{count}.zip')
|
yield nextcord.File(out, f'emotes-{context.guild.id}-{count}.zip')
|
||||||
count += 1
|
count += 1
|
||||||
|
|
||||||
@commands.command(name='import', aliases=['add-zip', 'add-tar', 'add-from-zip', 'add-from-tar'])
|
@commands.command(name='import', aliases=['add-zip', 'add-tar', 'add-from-zip', 'add-from-tar'])
|
||||||
|
@ -314,7 +327,8 @@ class Emotes(commands.Cog):
|
||||||
The rest will be ignored.
|
The rest will be ignored.
|
||||||
"""
|
"""
|
||||||
if url and context.message.attachments:
|
if url and context.message.attachments:
|
||||||
raise commands.BadArgument('Either a URL or an attachment must be given, not both.')
|
raise commands.BadArgument(
|
||||||
|
'Either a URL or an attachment must be given, not both.')
|
||||||
if not url and not context.message.attachments:
|
if not url and not context.message.attachments:
|
||||||
raise commands.BadArgument('A URL or attachment must be given.')
|
raise commands.BadArgument('A URL or attachment must be given.')
|
||||||
|
|
||||||
|
@ -328,7 +342,7 @@ class Emotes(commands.Cog):
|
||||||
return
|
return
|
||||||
|
|
||||||
await self.add_from_archive(context, archive)
|
await self.add_from_archive(context, archive)
|
||||||
with contextlib.suppress(discord.HTTPException):
|
with contextlib.suppress(nextcord.HTTPException):
|
||||||
# so they know when we're done
|
# so they know when we're done
|
||||||
await context.message.add_reaction(utils.SUCCESS_EMOJIS[True])
|
await context.message.add_reaction(utils.SUCCESS_EMOJIS[True])
|
||||||
|
|
||||||
|
@ -383,7 +397,8 @@ class Emotes(commands.Cog):
|
||||||
|
|
||||||
If the image is static and there are not enough free static slots, convert the image to a gif instead.
|
If the image is static and there are not enough free static slots, convert the image to a gif instead.
|
||||||
"""
|
"""
|
||||||
counts = collections.Counter(map(operator.attrgetter('animated'), context.guild.emojis))
|
counts = collections.Counter(
|
||||||
|
map(operator.attrgetter('animated'), context.guild.emojis))
|
||||||
# >= rather than == because there are sneaky ways to exceed the limit
|
# >= rather than == because there are sneaky ways to exceed the limit
|
||||||
if counts[False] >= context.guild.emoji_limit and counts[True] >= context.guild.emoji_limit:
|
if counts[False] >= context.guild.emoji_limit and counts[True] >= context.guild.emoji_limit:
|
||||||
# we raise instead of returning a string in order to abort commands that run this function in a loop
|
# we raise instead of returning a string in order to abort commands that run this function in a loop
|
||||||
|
@ -397,10 +412,10 @@ class Emotes(commands.Cog):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
emote = await self.create_emote_from_bytes(context, name, image_data, reason=reason)
|
emote = await self.create_emote_from_bytes(context, name, image_data, reason=reason)
|
||||||
except discord.InvalidArgument:
|
except nextcord.InvalidArgument:
|
||||||
return discord.utils.escape_mentions(f'{name}: The file supplied was not a valid GIF, PNG, JPEG, or WEBP file.')
|
return nextcord.utils.escape_mentions(f'{name}: The file supplied was not a valid GIF, PNG, JPEG, or WEBP file.')
|
||||||
except discord.HTTPException as ex:
|
except nextcord.HTTPException as ex:
|
||||||
return discord.utils.escape_mentions(
|
return nextcord.utils.escape_mentions(
|
||||||
f'{name}: An error occurred while creating the the emote:\n'
|
f'{name}: An error occurred while creating the the emote:\n'
|
||||||
+ utils.format_http_exception(ex))
|
+ utils.format_http_exception(ex))
|
||||||
s = f'Emote {emote} successfully created'
|
s = f'Emote {emote} successfully created'
|
||||||
|
@ -408,10 +423,12 @@ class Emotes(commands.Cog):
|
||||||
|
|
||||||
async def fetch(self, url, valid_mimetypes=IMAGE_MIMETYPES, *, validate_headers=True):
|
async def fetch(self, url, valid_mimetypes=IMAGE_MIMETYPES, *, validate_headers=True):
|
||||||
valid_mimetypes = valid_mimetypes or self.IMAGE_MIMETYPES
|
valid_mimetypes = valid_mimetypes or self.IMAGE_MIMETYPES
|
||||||
|
|
||||||
def validate_headers(response):
|
def validate_headers(response):
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
# some dumb servers also send '; charset=UTF-8' which we should ignore
|
# some dumb servers also send '; charset=UTF-8' which we should ignore
|
||||||
mimetype, options = cgi.parse_header(response.headers.get('Content-Type', ''))
|
mimetype, options = cgi.parse_header(
|
||||||
|
response.headers.get('Content-Type', ''))
|
||||||
if mimetype not in valid_mimetypes:
|
if mimetype not in valid_mimetypes:
|
||||||
raise errors.InvalidFileError
|
raise errors.InvalidFileError
|
||||||
|
|
||||||
|
@ -423,9 +440,11 @@ class Emotes(commands.Cog):
|
||||||
except aiohttp.ClientResponseError:
|
except aiohttp.ClientResponseError:
|
||||||
raise
|
raise
|
||||||
except aiohttp.ClientError as exc:
|
except aiohttp.ClientError as exc:
|
||||||
raise errors.EmoteManagerError(f'An error occurred while retrieving the file: {exc}')
|
raise errors.EmoteManagerError(
|
||||||
|
f'An error occurred while retrieving the file: {exc}')
|
||||||
|
|
||||||
if validate_headers: await validate(self.http.head(url, timeout=self.bot.config.get('http_head_timeout', 10)))
|
if validate_headers:
|
||||||
|
await validate(self.http.head(url, timeout=self.bot.config.get('http_head_timeout', 10)))
|
||||||
return await validate(self.http.get(url))
|
return await validate(self.http.get(url))
|
||||||
|
|
||||||
async def create_emote_from_bytes(self, context, name, image_data: bytes, *, reason=None):
|
async def create_emote_from_bytes(self, context, name, image_data: bytes, *, reason=None):
|
||||||
|
@ -448,7 +467,7 @@ class Emotes(commands.Cog):
|
||||||
else:
|
else:
|
||||||
for emote in (emote,) + emotes:
|
for emote in (emote,) + emotes:
|
||||||
await context.invoke(self.remove, emote)
|
await context.invoke(self.remove, emote)
|
||||||
with contextlib.suppress(discord.HTTPException):
|
with contextlib.suppress(nextcord.HTTPException):
|
||||||
await context.message.add_reaction(utils.SUCCESS_EMOJIS[True])
|
await context.message.add_reaction(utils.SUCCESS_EMOJIS[True])
|
||||||
|
|
||||||
@commands.command(aliases=('mv',))
|
@commands.command(aliases=('mv',))
|
||||||
|
@ -463,7 +482,7 @@ class Emotes(commands.Cog):
|
||||||
await emote.edit(
|
await emote.edit(
|
||||||
name=new_name,
|
name=new_name,
|
||||||
reason=f'Renamed by {utils.format_user(context.author)}')
|
reason=f'Renamed by {utils.format_user(context.author)}')
|
||||||
except discord.HTTPException as ex:
|
except nextcord.HTTPException as ex:
|
||||||
return await context.send(
|
return await context.send(
|
||||||
'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))
|
||||||
|
@ -539,11 +558,11 @@ class Emotes(commands.Cog):
|
||||||
if match:
|
if match:
|
||||||
id = int(match['id'])
|
id = int(match['id'])
|
||||||
if local:
|
if local:
|
||||||
emote = discord.utils.get(context.guild.emojis, id=id)
|
emote = nextcord.utils.get(context.guild.emojis, id=id)
|
||||||
if emote:
|
if emote:
|
||||||
return emote
|
return emote
|
||||||
else:
|
else:
|
||||||
return discord.PartialEmoji(
|
return nextcord.PartialEmoji(
|
||||||
animated=bool(match['animated']),
|
animated=bool(match['animated']),
|
||||||
name=match['name'],
|
name=match['name'],
|
||||||
id=int(match['id']),
|
id=int(match['id']),
|
||||||
|
@ -552,15 +571,18 @@ class Emotes(commands.Cog):
|
||||||
return await self.disambiguate(context, name)
|
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
|
# 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]
|
name = name.strip(':')
|
||||||
|
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)
|
||||||
|
|
||||||
if len(candidates) == 1:
|
if len(candidates) == 1:
|
||||||
return candidates[0]
|
return candidates[0]
|
||||||
|
|
||||||
message = ['Multiple emotes were found with that name. Which one do you mean?']
|
message = [
|
||||||
|
'Multiple emotes were found with that name. Which one do you mean?']
|
||||||
for i, emote in enumerate(candidates, 1):
|
for i, emote in enumerate(candidates, 1):
|
||||||
message.append(fr'{i}. {emote} (\:{emote.name}:)')
|
message.append(fr'{i}. {emote} (\:{emote.name}:)')
|
||||||
|
|
||||||
|
@ -577,9 +599,11 @@ class Emotes(commands.Cog):
|
||||||
try:
|
try:
|
||||||
message = await self.bot.wait_for('message', check=check, timeout=30)
|
message = await self.bot.wait_for('message', check=check, timeout=30)
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
raise commands.UserInputError('Sorry, you took too long. Try again.')
|
raise commands.UserInputError(
|
||||||
|
'Sorry, you took too long. Try again.')
|
||||||
|
|
||||||
return candidates[int(message.content)-1]
|
return candidates[int(message.content)-1]
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot):
|
||||||
bot.add_cog(Emotes(bot))
|
bot.add_cog(Emotes(bot))
|
||||||
|
|
|
@ -27,11 +27,15 @@
|
||||||
|
|
||||||
'copyright_license_file': 'data/short-license.txt',
|
'copyright_license_file': 'data/short-license.txt',
|
||||||
|
|
||||||
'socks5_proxy_url': None, # required for connecting to the EC API over a Tor onion service
|
# required for connecting to the EC API over a Tor onion service
|
||||||
'use_socks5_for_all_connections': False, # whether to use socks5 for all HTTP operations (other than discord.py)
|
'socks5_proxy_url': None,
|
||||||
|
# whether to use socks5 for all HTTP operations (other than discord.py)
|
||||||
|
'use_socks5_for_all_connections': False,
|
||||||
'user_agent': 'EmoteManagerBot (https://github.com/iomintz/emote-manager-bot)',
|
'user_agent': 'EmoteManagerBot (https://github.com/iomintz/emote-manager-bot)',
|
||||||
'ec_api_base_url': None, # set to None to use the default of https://ec.emote.bot/api/v0
|
# set to None to use the default of https://ec.emote.bot/api/v0
|
||||||
'http_head_timeout': 10, # timeout for the initial HEAD request before retrieving any images (up this if using Tor)
|
'ec_api_base_url': None,
|
||||||
|
# timeout for the initial HEAD request before retrieving any images (up this if using Tor)
|
||||||
|
'http_head_timeout': 10,
|
||||||
'http_read_timeout': 60, # timeout for retrieving an image
|
'http_read_timeout': 60, # timeout for retrieving an image
|
||||||
|
|
||||||
# emotes that the bot may use to respond to you
|
# emotes that the bot may use to respond to you
|
||||||
|
|
Loading…
Reference in a new issue