aboutsummaryrefslogtreecommitdiffstats
path: root/bot/converters.py
diff options
context:
space:
mode:
Diffstat (limited to 'bot/converters.py')
-rw-r--r--bot/converters.py110
1 files changed, 110 insertions, 0 deletions
diff --git a/bot/converters.py b/bot/converters.py
new file mode 100644
index 000000000..a629768b7
--- /dev/null
+++ b/bot/converters.py
@@ -0,0 +1,110 @@
+import random
+import socket
+
+import discord
+from aiohttp import AsyncResolver, ClientSession, TCPConnector
+from discord.ext.commands import Converter
+from fuzzywuzzy import fuzz
+
+from bot.constants import DEBUG_MODE, SITE_API_KEY, SITE_API_URL
+from bot.utils import disambiguate
+
+NAMES_URL = f"{SITE_API_URL}/bot/snake_names"
+SPECIAL_URL = f"{SITE_API_URL}/bot/special_snakes"
+
+
+class Snake(Converter):
+ snakes = None
+ special_cases = None
+
+ async def convert(self, ctx, name):
+ await self.build_list()
+ name = name.lower()
+
+ if name == 'python':
+ return 'Python (programming language)'
+
+ def get_potential(iterable, *, threshold=80):
+ nonlocal name
+ potential = []
+
+ for item in iterable:
+ original, item = item, item.lower()
+
+ if name == item:
+ return [original]
+
+ a, b = fuzz.ratio(name, item), fuzz.partial_ratio(name, item)
+ if a >= threshold or b >= threshold:
+ potential.append(original)
+
+ return potential
+
+ # Handle special cases
+ if name.lower() in self.special_cases:
+ return self.special_cases.get(name.lower(), name.lower())
+
+ names = {snake['name']: snake['scientific'] for snake in self.snakes}
+ all_names = names.keys() | names.values()
+ timeout = len(all_names) * (3 / 4)
+
+ embed = discord.Embed(title='Found multiple choices. Please choose the correct one.', colour=0x59982F)
+ embed.set_author(name=ctx.author.display_name, icon_url=ctx.author.avatar_url)
+
+ name = await disambiguate(ctx, get_potential(all_names), timeout=timeout, embed=embed)
+ return names.get(name, name)
+
+ @classmethod
+ async def build_list(cls):
+
+ headers = {"X-API-KEY": SITE_API_KEY}
+
+ # Set up the session
+ if DEBUG_MODE:
+ http_session = ClientSession(
+ connector=TCPConnector(
+ resolver=AsyncResolver(),
+ family=socket.AF_INET,
+ verify_ssl=False,
+ )
+ )
+ else:
+ http_session = ClientSession(
+ connector=TCPConnector(
+ resolver=AsyncResolver()
+ )
+ )
+
+ # Get all the snakes
+ if cls.snakes is None:
+ response = await http_session.get(
+ NAMES_URL,
+ params={"get_all": "true"},
+ headers=headers
+ )
+ cls.snakes = await response.json()
+
+ # Get the special cases
+ if cls.special_cases is None:
+ response = await http_session.get(
+ SPECIAL_URL,
+ headers=headers
+ )
+ special_cases = await response.json()
+ cls.special_cases = {snake['name'].lower(): snake for snake in special_cases}
+
+ # Close the session
+ http_session.close()
+
+ @classmethod
+ async def random(cls):
+ """
+ This is stupid. We should find a way to
+ somehow get the global session into a
+ global context, so I can get it from here.
+ :return:
+ """
+
+ await cls.build_list()
+ names = [snake['scientific'] for snake in cls.snakes]
+ return random.choice(names)