diff --git a/CHANGELOG.md b/CHANGELOG.md index 237f333..f4188e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] ### Fixed - Fixed issue where HamStudy questions with images would cause an error. +- Added/fixed/removed typing indicators in numerous commands. ## [2.2.1] - 2020-02-20 diff --git a/exts/fun.py b/exts/fun.py index beeab94..b396db8 100644 --- a/exts/fun.py +++ b/exts/fun.py @@ -39,18 +39,17 @@ class FunCog(commands.Cog): @commands.command(name="funetics", aliases=["fun"], category=cmn.cat.fun) async def _funetics_lookup(self, ctx: commands.Context, *, msg: str): """Generates fun/wacky phonetics for a word or phrase.""" - with ctx.typing(): - result = "" - for char in msg.lower(): - if char.isalpha(): - result += random.choice([word for word in self.words if word[0] == char]) - else: - result += char - result += " " - embed = cmn.embed_factory(ctx) - embed.title = f"Funetics for {msg}" - embed.description = result.title() - embed.colour = cmn.colours.good + result = "" + for char in msg.lower(): + if char.isalpha(): + result += random.choice([word for word in self.words if word[0] == char]) + else: + result += char + result += " " + embed = cmn.embed_factory(ctx) + embed.title = f"Funetics for {msg}" + embed.description = result.title() + embed.colour = cmn.colours.good await ctx.send(embed=embed) diff --git a/exts/grid.py b/exts/grid.py index 4d3b5f4..0d07cff 100644 --- a/exts/grid.py +++ b/exts/grid.py @@ -23,93 +23,91 @@ class GridCog(commands.Cog): async def _grid_sq_lookup(self, ctx: commands.Context, lat: str, lon: str): ("""Calculates the grid square for latitude and longitude coordinates, """ """with negative being latitude South and longitude West.""") - with ctx.typing(): - grid = "**" - latf = float(lat) + 90 - lonf = float(lon) + 180 - if 0 <= latf <= 180 and 0 <= lonf <= 360: - grid += chr(ord("A") + int(lonf / 20)) - grid += chr(ord("A") + int(latf / 10)) - grid += chr(ord("0") + int((lonf % 20)/2)) - grid += chr(ord("0") + int((latf % 10)/1)) - grid += chr(ord("a") + int((lonf - (int(lonf/2)*2)) / (5/60))) - grid += chr(ord("a") + int((latf - (int(latf/1)*1)) / (2.5/60))) - grid += "**" - embed = cmn.embed_factory(ctx) - embed.title = f"Maidenhead Grid Locator for {float(lat):.6f}, {float(lon):.6f}" - embed.description = grid - embed.colour = cmn.colours.good - else: - embed = cmn.embed_factory(ctx) - embed.title = f"Error generating grid square for {lat}, {lon}." - embed.description = """Coordinates out of range. - The valid ranges are: - - Latitude: `-90` to `+90` - - Longitude: `-180` to `+180`""" - embed.colour = cmn.colours.bad + grid = "**" + latf = float(lat) + 90 + lonf = float(lon) + 180 + if 0 <= latf <= 180 and 0 <= lonf <= 360: + grid += chr(ord("A") + int(lonf / 20)) + grid += chr(ord("A") + int(latf / 10)) + grid += chr(ord("0") + int((lonf % 20)/2)) + grid += chr(ord("0") + int((latf % 10)/1)) + grid += chr(ord("a") + int((lonf - (int(lonf/2)*2)) / (5/60))) + grid += chr(ord("a") + int((latf - (int(latf/1)*1)) / (2.5/60))) + grid += "**" + embed = cmn.embed_factory(ctx) + embed.title = f"Maidenhead Grid Locator for {float(lat):.6f}, {float(lon):.6f}" + embed.description = grid + embed.colour = cmn.colours.good + else: + embed = cmn.embed_factory(ctx) + embed.title = f"Error generating grid square for {lat}, {lon}." + embed.description = """Coordinates out of range. + The valid ranges are: + - Latitude: `-90` to `+90` + - Longitude: `-180` to `+180`""" + embed.colour = cmn.colours.bad await ctx.send(embed=embed) @commands.command(name="ungrid", aliases=["loc"], category=cmn.cat.maps) async def _location_lookup(self, ctx: commands.Context, grid: str, grid2: str = None): """Calculates the latitude and longitude for the center of a grid square. If two grid squares are given, the distance and azimuth between them is calculated.""" - with ctx.typing(): - if grid2 is None or grid2 == "": - try: - grid = grid.upper() - loc = get_coords(grid) + if grid2 is None or grid2 == "": + try: + grid = grid.upper() + loc = get_coords(grid) - embed = cmn.embed_factory(ctx) - embed.title = f"Latitude and Longitude for {grid}" - embed.colour = cmn.colours.good + embed = cmn.embed_factory(ctx) + embed.title = f"Latitude and Longitude for {grid}" + embed.colour = cmn.colours.good - if len(grid) >= 6: - embed.description = f"**{loc[0]:.5f}, {loc[1]:.5f}**" - embed.url = f"https://www.openstreetmap.org/#map=13/{loc[0]:.5f}/{loc[1]:.5f}" - else: - embed.description = f"**{loc[0]:.1f}, {loc[1]:.1f}**" - embed.url = f"https://www.openstreetmap.org/#map=10/{loc[0]:.1f}/{loc[1]:.1f}" - except Exception as e: - embed = cmn.embed_factory(ctx) - embed.title = f"Error generating latitude and longitude for grid {grid}." - embed.description = str(e) - embed.colour = cmn.colours.bad - else: - radius = 6371 - try: - grid = grid.upper() - grid2 = grid2.upper() - loc = get_coords(grid) - loc2 = get_coords(grid2) - # Haversine formula - d_lat = math.radians(loc2[0] - loc[0]) - d_lon = math.radians(loc2[1] - loc[1]) - a = (math.sin(d_lat/2) ** 2 - + math.cos(math.radians(loc[0])) - * math.cos(math.radians(loc2[0])) - * math.sin(d_lon/2) ** 2) - c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a)) - d = radius * c - d_mi = 0.6213712 * d + if len(grid) >= 6: + embed.description = f"**{loc[0]:.5f}, {loc[1]:.5f}**" + embed.url = f"https://www.openstreetmap.org/#map=13/{loc[0]:.5f}/{loc[1]:.5f}" + else: + embed.description = f"**{loc[0]:.1f}, {loc[1]:.1f}**" + embed.url = f"https://www.openstreetmap.org/#map=10/{loc[0]:.1f}/{loc[1]:.1f}" + except Exception as e: + embed = cmn.embed_factory(ctx) + embed.title = f"Error generating latitude and longitude for grid {grid}." + embed.description = str(e) + embed.colour = cmn.colours.bad + else: + radius = 6371 + try: + grid = grid.upper() + grid2 = grid2.upper() + loc = get_coords(grid) + loc2 = get_coords(grid2) + # Haversine formula + d_lat = math.radians(loc2[0] - loc[0]) + d_lon = math.radians(loc2[1] - loc[1]) + a = (math.sin(d_lat/2) ** 2 + + math.cos(math.radians(loc[0])) + * math.cos(math.radians(loc2[0])) + * math.sin(d_lon/2) ** 2) + c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a)) + d = radius * c + d_mi = 0.6213712 * d - # Bearing - y_dist = math.sin(math.radians(loc2[1]-loc[1])) * math.cos(math.radians(loc2[0])) - x_dist = (math.cos(math.radians(loc[0])) - * math.sin(math.radians(loc2[0])) - - math.sin(math.radians(loc[0])) - * math.cos(math.radians(loc2[0])) - * math.cos(math.radians(loc2[1] - loc[1]))) - bearing = (math.degrees(math.atan2(y_dist, x_dist)) + 360) % 360 + # Bearing + y_dist = math.sin(math.radians(loc2[1]-loc[1])) * math.cos(math.radians(loc2[0])) + x_dist = (math.cos(math.radians(loc[0])) + * math.sin(math.radians(loc2[0])) + - math.sin(math.radians(loc[0])) + * math.cos(math.radians(loc2[0])) + * math.cos(math.radians(loc2[1] - loc[1]))) + bearing = (math.degrees(math.atan2(y_dist, x_dist)) + 360) % 360 - embed = cmn.embed_factory(ctx) - embed.title = f"Great Circle Distance and Bearing from {grid} to {grid2}" - embed.description = f"**Distance:** {d:.1f} km ({d_mi:.1f} mi)\n**Bearing:** {bearing:.1f}°" - embed.colour = cmn.colours.good - except Exception as e: - embed = cmn.embed_factory(ctx) - embed.title = f"Error generating great circle distance and bearing from {grid} and {grid2}." - embed.description = str(e) - embed.colour = cmn.colours.bad + embed = cmn.embed_factory(ctx) + embed.title = f"Great Circle Distance and Bearing from {grid} to {grid2}" + embed.description = f"**Distance:** {d:.1f} km ({d_mi:.1f} mi)\n**Bearing:** {bearing:.1f}°" + embed.colour = cmn.colours.good + except Exception as e: + embed = cmn.embed_factory(ctx) + embed.title = f"Error generating great circle distance and bearing from {grid} and {grid2}." + embed.description = str(e) + embed.colour = cmn.colours.bad await ctx.send(embed=embed) diff --git a/exts/ham.py b/exts/ham.py index 009db1e..d6e0bd5 100644 --- a/exts/ham.py +++ b/exts/ham.py @@ -25,45 +25,42 @@ class HamCog(commands.Cog): @commands.command(name="qcode", aliases=["q"], category=cmn.cat.ref) async def _qcode_lookup(self, ctx: commands.Context, qcode: str): """Looks up the meaning of a Q Code.""" - with ctx.typing(): - qcode = qcode.upper() - embed = cmn.embed_factory(ctx) - if qcode in qcodes.qcodes: - embed.title = qcode - embed.description = qcodes.qcodes[qcode] - embed.colour = cmn.colours.good - else: - embed.title = f"Q Code {qcode} not found" - embed.colour = cmn.colours.bad + qcode = qcode.upper() + embed = cmn.embed_factory(ctx) + if qcode in qcodes.qcodes: + embed.title = qcode + embed.description = qcodes.qcodes[qcode] + embed.colour = cmn.colours.good + else: + embed.title = f"Q Code {qcode} not found" + embed.colour = cmn.colours.bad await ctx.send(embed=embed) @commands.command(name="phonetics", aliases=["ph", "phoneticize", "phoneticise", "phone"], category=cmn.cat.ref) async def _phonetics_lookup(self, ctx: commands.Context, *, msg: str): """Returns NATO phonetics for a word or phrase.""" - with ctx.typing(): - result = "" - for char in msg.lower(): - if char.isalpha(): - result += phonetics.phonetics[char] - else: - result += char - result += " " - embed = cmn.embed_factory(ctx) - embed.title = f"Phonetics for {msg}" - embed.description = result.title() - embed.colour = cmn.colours.good + result = "" + for char in msg.lower(): + if char.isalpha(): + result += phonetics.phonetics[char] + else: + result += char + result += " " + embed = cmn.embed_factory(ctx) + embed.title = f"Phonetics for {msg}" + embed.description = result.title() + embed.colour = cmn.colours.good await ctx.send(embed=embed) @commands.command(name="utc", aliases=["z"], category=cmn.cat.ref) async def _utc_lookup(self, ctx: commands.Context): """Returns the current time in UTC.""" - with ctx.typing(): - now = datetime.utcnow() - result = "**" + now.strftime("%Y-%m-%d %H:%M") + "Z**" - embed = cmn.embed_factory(ctx) - embed.title = "The current time is:" - embed.description = result - embed.colour = cmn.colours.good + now = datetime.utcnow() + result = "**" + now.strftime("%Y-%m-%d %H:%M") + "Z**" + embed = cmn.embed_factory(ctx) + embed.title = "The current time is:" + embed.description = result + embed.colour = cmn.colours.good await ctx.send(embed=embed) @commands.command(name="prefixes", aliases=["vanity", "pfx", "vanities", "prefix"], category=cmn.cat.ref) diff --git a/exts/lookup.py b/exts/lookup.py index ab508d8..e1c585f 100644 --- a/exts/lookup.py +++ b/exts/lookup.py @@ -40,30 +40,29 @@ class LookupCog(commands.Cog): @commands.command(name="dxcc", aliases=["dx"], category=cmn.cat.lookup) async def _dxcc_lookup(self, ctx: commands.Context, query: str): """Gets DXCC info about a callsign prefix.""" - with ctx.typing(): - query = query.upper() - full_query = query - embed = cmn.embed_factory(ctx) - embed.title = "DXCC Info for " - embed.description = f"*Last Updated: {self.cty.formatted_version}*" - embed.colour = cmn.colours.bad - while query: - if query in self.cty.keys(): - data = self.cty[query] - embed.add_field(name="Entity", value=data["entity"]) - embed.add_field(name="CQ Zone", value=data["cq"]) - embed.add_field(name="ITU Zone", value=data["itu"]) - embed.add_field(name="Continent", value=data["continent"]) - embed.add_field(name="Time Zone", - value=f"+{data['tz']}" if data["tz"] > 0 else str(data["tz"])) - embed.title += query - embed.colour = cmn.colours.good - break - else: - query = query[:-1] + query = query.upper() + full_query = query + embed = cmn.embed_factory(ctx) + embed.title = "DXCC Info for " + embed.description = f"*Last Updated: {self.cty.formatted_version}*" + embed.colour = cmn.colours.bad + while query: + if query in self.cty.keys(): + data = self.cty[query] + embed.add_field(name="Entity", value=data["entity"]) + embed.add_field(name="CQ Zone", value=data["cq"]) + embed.add_field(name="ITU Zone", value=data["itu"]) + embed.add_field(name="Continent", value=data["continent"]) + embed.add_field(name="Time Zone", + value=f"+{data['tz']}" if data["tz"] > 0 else str(data["tz"])) + embed.title += query + embed.colour = cmn.colours.good + break else: - embed.title += full_query + " not found" - embed.colour = cmn.colours.bad + query = query[:-1] + else: + embed.title += full_query + " not found" + embed.colour = cmn.colours.bad await ctx.send(embed=embed) @tasks.loop(hours=24) diff --git a/exts/morse.py b/exts/morse.py index 02aa487..9cae058 100644 --- a/exts/morse.py +++ b/exts/morse.py @@ -21,61 +21,58 @@ class MorseCog(commands.Cog): @commands.command(name="morse", aliases=["cw"], category=cmn.cat.ref) async def _morse(self, ctx: commands.Context, *, msg: str): """Converts ASCII to international morse code.""" - with ctx.typing(): - result = "" - for char in msg.upper(): - try: - result += morse.morse[char] - except KeyError: - result += "" - result += " " - embed = cmn.embed_factory(ctx) - embed.title = f"Morse Code for {msg}" - embed.description = "**" + result + "**" - embed.colour = cmn.colours.good + result = "" + for char in msg.upper(): + try: + result += morse.morse[char] + except KeyError: + result += "" + result += " " + embed = cmn.embed_factory(ctx) + embed.title = f"Morse Code for {msg}" + embed.description = "**" + result + "**" + embed.colour = cmn.colours.good await ctx.send(embed=embed) @commands.command(name="unmorse", aliases=["demorse", "uncw", "decw"], category=cmn.cat.ref) async def _unmorse(self, ctx: commands.Context, *, msg: str): """Converts international morse code to ASCII.""" - with ctx.typing(): - result = "" - msg0 = msg - msg = msg.split("/") - msg = [m.split() for m in msg] - for word in msg: - for char in word: - try: - result += morse.ascii[char] - except KeyError: - result += "" - result += " " - embed = cmn.embed_factory(ctx) - embed.title = f"ASCII for {msg0}" - embed.description = result - embed.colour = cmn.colours.good + result = "" + msg0 = msg + msg = msg.split("/") + msg = [m.split() for m in msg] + for word in msg: + for char in word: + try: + result += morse.ascii[char] + except KeyError: + result += "" + result += " " + embed = cmn.embed_factory(ctx) + embed.title = f"ASCII for {msg0}" + embed.description = result + embed.colour = cmn.colours.good await ctx.send(embed=embed) @commands.command(name="cwweight", aliases=["weight", "cww"], category=cmn.cat.ref) async def _weight(self, ctx: commands.Context, *, msg: str): """Calculates the CW weight of a callsign or message.""" embed = cmn.embed_factory(ctx) - with ctx.typing(): - msg = msg.upper() - weight = 0 - for char in msg: - try: - cw_char = morse.morse[char].replace("-", "==") - weight += len(cw_char) * 2 + 2 - except KeyError: - embed.title = "Error in calculation of CW weight" - embed.description = f"Unknown character `{char}` in message" - embed.colour = cmn.colours.bad - await ctx.send(embed=embed) - return - embed.title = f"CW Weight of {msg}" - embed.description = f"The CW weight is **{weight}**" - embed.colour = cmn.colours.good + msg = msg.upper() + weight = 0 + for char in msg: + try: + cw_char = morse.morse[char].replace("-", "==") + weight += len(cw_char) * 2 + 2 + except KeyError: + embed.title = "Error in calculation of CW weight" + embed.description = f"Unknown character `{char}` in message" + embed.colour = cmn.colours.bad + await ctx.send(embed=embed) + return + embed.title = f"CW Weight of {msg}" + embed.description = f"The CW weight is **{weight}**" + embed.colour = cmn.colours.good await ctx.send(embed=embed) diff --git a/exts/qrz.py b/exts/qrz.py index d547a25..2df0395 100644 --- a/exts/qrz.py +++ b/exts/qrz.py @@ -36,50 +36,51 @@ class QRZCog(commands.Cog): await ctx.send(f"http://qrz.com/db/{callsign}") return - try: - await qrz_test_session(self.key, self.session) - except ConnectionError: - await self.get_session() - - url = f"http://xmldata.qrz.com/xml/current/?s={self.key};callsign={callsign}" - async with self.session.get(url) as resp: - if resp.status != 200: - raise ConnectionError(f"Unable to connect to QRZ (HTTP Error {resp.status})") - with BytesIO(await resp.read()) as resp_file: - resp_xml = etree.parse(resp_file).getroot() - - resp_xml_session = resp_xml.xpath("/x:QRZDatabase/x:Session", namespaces={"x": "http://xmldata.qrz.com"}) - resp_session = {el.tag.split("}")[1]: el.text for el in resp_xml_session[0].getiterator()} - if "Error" in resp_session: - if "Session Timeout" in resp_session["Error"]: + async with ctx.typing(): + try: + await qrz_test_session(self.key, self.session) + except ConnectionError: await self.get_session() - await self._qrz_lookup(ctx, callsign) - return - if "Not found" in resp_session["Error"]: - embed = cmn.embed_factory(ctx) - embed.title = f"QRZ Data for {callsign.upper()}" - embed.colour = cmn.colours.bad - embed.description = "No data found!" - await ctx.send(embed=embed) - return - raise ValueError(resp_session["Error"]) - resp_xml_data = resp_xml.xpath("/x:QRZDatabase/x:Callsign", namespaces={"x": "http://xmldata.qrz.com"}) - resp_data = {el.tag.split("}")[1]: el.text for el in resp_xml_data[0].getiterator()} + url = f"http://xmldata.qrz.com/xml/current/?s={self.key};callsign={callsign}" + async with self.session.get(url) as resp: + if resp.status != 200: + raise ConnectionError(f"Unable to connect to QRZ (HTTP Error {resp.status})") + with BytesIO(await resp.read()) as resp_file: + resp_xml = etree.parse(resp_file).getroot() - embed = cmn.embed_factory(ctx) - embed.title = f"QRZ Data for {resp_data['call']}" - embed.colour = cmn.colours.good - embed.url = f"http://www.qrz.com/db/{resp_data['call']}" - if "image" in resp_data: - embed.set_thumbnail(url=resp_data["image"]) + resp_xml_session = resp_xml.xpath("/x:QRZDatabase/x:Session", namespaces={"x": "http://xmldata.qrz.com"}) + resp_session = {el.tag.split("}")[1]: el.text for el in resp_xml_session[0].getiterator()} + if "Error" in resp_session: + if "Session Timeout" in resp_session["Error"]: + await self.get_session() + await self._qrz_lookup(ctx, callsign) + return + if "Not found" in resp_session["Error"]: + embed = cmn.embed_factory(ctx) + embed.title = f"QRZ Data for {callsign.upper()}" + embed.colour = cmn.colours.bad + embed.description = "No data found!" + await ctx.send(embed=embed) + return + raise ValueError(resp_session["Error"]) - data = qrz_process_info(resp_data) + resp_xml_data = resp_xml.xpath("/x:QRZDatabase/x:Callsign", namespaces={"x": "http://xmldata.qrz.com"}) + resp_data = {el.tag.split("}")[1]: el.text for el in resp_xml_data[0].getiterator()} - for title, val in data.items(): - if val is not None: - embed.add_field(name=title, value=val, inline=True) - await ctx.send(embed=embed) + embed = cmn.embed_factory(ctx) + embed.title = f"QRZ Data for {resp_data['call']}" + embed.colour = cmn.colours.good + embed.url = f"http://www.qrz.com/db/{resp_data['call']}" + if "image" in resp_data: + embed.set_thumbnail(url=resp_data["image"]) + + data = qrz_process_info(resp_data) + + for title, val in data.items(): + if val is not None: + embed.add_field(name=title, value=val, inline=True) + await ctx.send(embed=embed) async def get_session(self): """Session creation and caching."""