mirror of
				https://github.com/miaowware/qrm2.git
				synced 2025-10-30 19:00:22 -04:00 
			
		
		
		
	Normalised string quote type
- "" instead of '', except for dictionary lookups in f-strings Element of #142 New year lint removal
This commit is contained in:
		
							parent
							
								
									29e75c38e1
								
							
						
					
					
						commit
						29d0440d3d
					
				
							
								
								
									
										38
									
								
								common.py
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								common.py
									
									
									
									
									
								
							| @ -34,24 +34,24 @@ colours = SimpleNamespace(good=0x43B581, | ||||
|                           neutral=0x7289DA, | ||||
|                           bad=0xF04747) | ||||
| # meow | ||||
| cat = SimpleNamespace(lookup='Information Lookup', | ||||
|                       fun='Fun', | ||||
|                       maps='Mapping', | ||||
|                       ref='Reference', | ||||
|                       study='Exam Study', | ||||
|                       weather='Land and Space Weather', | ||||
|                       admin='Bot Control') | ||||
| cat = SimpleNamespace(lookup="Information Lookup", | ||||
|                       fun="Fun", | ||||
|                       maps="Mapping", | ||||
|                       ref="Reference", | ||||
|                       study="Exam Study", | ||||
|                       weather="Land and Space Weather", | ||||
|                       admin="Bot Control") | ||||
| 
 | ||||
| emojis = SimpleNamespace(check_mark='✅', | ||||
|                          x='❌', | ||||
|                          warning='⚠️', | ||||
|                          question='❓', | ||||
|                          no_entry='⛔', | ||||
|                          bangbang='‼️', | ||||
|                          a='🇦', | ||||
|                          b='🇧', | ||||
|                          c='🇨', | ||||
|                          d='🇩') | ||||
| emojis = SimpleNamespace(check_mark="✅", | ||||
|                          x="❌", | ||||
|                          warning="⚠️", | ||||
|                          question="❓", | ||||
|                          no_entry="⛔", | ||||
|                          bangbang="‼️", | ||||
|                          a="🇦", | ||||
|                          b="🇧", | ||||
|                          c="🇨", | ||||
|                          d="🇩") | ||||
| 
 | ||||
| paths = SimpleNamespace(data=Path("./data/"), | ||||
|                         resources=Path("./resources/"), | ||||
| @ -117,7 +117,7 @@ class GlobalChannelConverter(commands.IDConverter): | ||||
|     async def convert(self, ctx: commands.Context, argument: str): | ||||
|         bot = ctx.bot | ||||
|         guild = ctx.guild | ||||
|         match = self._get_id_match(argument) or re.match(r'<#([0-9]+)>$', argument) | ||||
|         match = self._get_id_match(argument) or re.match(r"<#([0-9]+)>$", argument) | ||||
|         result = None | ||||
|         if match is None: | ||||
|             # not a mention/ID | ||||
| @ -150,7 +150,7 @@ def error_embed_factory(ctx: commands.Context, exception: Exception, debug_mode: | ||||
|         fmtd_ex = traceback.format_exception_only(exception.__class__, exception) | ||||
|     embed = embed_factory(ctx) | ||||
|     embed.title = "⚠️ Error" | ||||
|     embed.description = "```\n" + '\n'.join(fmtd_ex) + "```" | ||||
|     embed.description = "```\n" + "\n".join(fmtd_ex) + "```" | ||||
|     embed.colour = colours.bad | ||||
|     return embed | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										156
									
								
								exts/ae7q.py
									
									
									
									
									
								
							
							
						
						
									
										156
									
								
								exts/ae7q.py
									
									
									
									
									
								
							| @ -29,16 +29,16 @@ class AE7QCog(commands.Cog): | ||||
| 
 | ||||
|     @commands.group(name="ae7q", aliases=["ae"], category=cmn.cat.lookup) | ||||
|     async def _ae7q_lookup(self, ctx: commands.Context): | ||||
|         '''Look up a callsign, FRN, or Licensee ID on [ae7q.com](http://ae7q.com/).''' | ||||
|         """Look up a callsign, FRN, or Licensee ID on [ae7q.com](http://ae7q.com/).""" | ||||
|         if ctx.invoked_subcommand is None: | ||||
|             await ctx.send_help(ctx.command) | ||||
| 
 | ||||
|     @_ae7q_lookup.command(name="call", aliases=["c"], category=cmn.cat.lookup) | ||||
|     async def _ae7q_call(self, ctx: commands.Context, callsign: str): | ||||
|         '''Look up the history of a callsign on [ae7q.com](http://ae7q.com/).''' | ||||
|         """Look up the history of a callsign on [ae7q.com](http://ae7q.com/).""" | ||||
|         with ctx.typing(): | ||||
|             callsign = callsign.upper() | ||||
|             desc = '' | ||||
|             desc = "" | ||||
|             base_url = "http://ae7q.com/query/data/CallHistory.php?CALL=" | ||||
|             embed = cmn.embed_factory(ctx) | ||||
| 
 | ||||
| @ -56,20 +56,20 @@ class AE7QCog(commands.Cog): | ||||
|             if len(table[0]) == 1: | ||||
|                 for row in table: | ||||
|                     desc += " ".join(row.getText().split()) | ||||
|                     desc += '\n' | ||||
|                 desc = desc.replace(callsign, f'`{callsign}`') | ||||
|                     desc += "\n" | ||||
|                 desc = desc.replace(callsign, f"`{callsign}`") | ||||
|                 table = tables[1] | ||||
| 
 | ||||
|             table_headers = table[0].find_all("th") | ||||
|             first_header = ''.join(table_headers[0].strings) if len(table_headers) > 0 else None | ||||
|             first_header = "".join(table_headers[0].strings) if len(table_headers) > 0 else None | ||||
| 
 | ||||
|             # catch if the wrong table was selected | ||||
|             if first_header is None or first_header != 'Entity Name': | ||||
|             if first_header is None or first_header != "Entity Name": | ||||
|                 embed.title = f"AE7Q History for {callsign}" | ||||
|                 embed.colour = cmn.colours.bad | ||||
|                 embed.url = base_url + callsign | ||||
|                 embed.description = desc | ||||
|                 embed.description += f'\nNo records found for `{callsign}`' | ||||
|                 embed.description += f"\nNo records found for `{callsign}`" | ||||
|                 await ctx.send(embed=embed) | ||||
|                 return | ||||
| 
 | ||||
| @ -82,18 +82,18 @@ class AE7QCog(commands.Cog): | ||||
| 
 | ||||
|             # add the first three rows of the table to the embed | ||||
|             for row in table[0:3]: | ||||
|                 header = f'**{row[0]}** ({row[1]})'     # **Name** (Applicant Type) | ||||
|                 body = (f'Class: *{row[2]}*\n' | ||||
|                         f'Region: *{row[3]}*\n' | ||||
|                         f'Status: *{row[4]}*\n' | ||||
|                         f'Granted: *{row[5]}*\n' | ||||
|                         f'Effective: *{row[6]}*\n' | ||||
|                         f'Cancelled: *{row[7]}*\n' | ||||
|                         f'Expires: *{row[8]}*') | ||||
|                 header = f"**{row[0]}** ({row[1]})"     # **Name** (Applicant Type) | ||||
|                 body = (f"Class: *{row[2]}*\n" | ||||
|                         f"Region: *{row[3]}*\n" | ||||
|                         f"Status: *{row[4]}*\n" | ||||
|                         f"Granted: *{row[5]}*\n" | ||||
|                         f"Effective: *{row[6]}*\n" | ||||
|                         f"Cancelled: *{row[7]}*\n" | ||||
|                         f"Expires: *{row[8]}*") | ||||
|                 embed.add_field(name=header, value=body, inline=False) | ||||
| 
 | ||||
|             if len(table) > 3: | ||||
|                 desc += f'\nRecords 1 to 3 of {len(table)}. See ae7q.com for more...' | ||||
|                 desc += f"\nRecords 1 to 3 of {len(table)}. See ae7q.com for more..." | ||||
| 
 | ||||
|             embed.description = desc | ||||
| 
 | ||||
| @ -101,10 +101,10 @@ class AE7QCog(commands.Cog): | ||||
| 
 | ||||
|     @_ae7q_lookup.command(name="trustee", aliases=["t"], category=cmn.cat.lookup) | ||||
|     async def _ae7q_trustee(self, ctx: commands.Context, callsign: str): | ||||
|         '''Look up the licenses for which a licensee is trustee on [ae7q.com](http://ae7q.com/).''' | ||||
|         """Look up the licenses for which a licensee is trustee on [ae7q.com](http://ae7q.com/).""" | ||||
|         with ctx.typing(): | ||||
|             callsign = callsign.upper() | ||||
|             desc = '' | ||||
|             desc = "" | ||||
|             base_url = "http://ae7q.com/query/data/CallHistory.php?CALL=" | ||||
|             embed = cmn.embed_factory(ctx) | ||||
| 
 | ||||
| @ -123,12 +123,12 @@ class AE7QCog(commands.Cog): | ||||
|                 embed.colour = cmn.colours.bad | ||||
|                 embed.url = base_url + callsign | ||||
|                 embed.description = desc | ||||
|                 embed.description += f'\nNo records found for `{callsign}`' | ||||
|                 embed.description += f"\nNo records found for `{callsign}`" | ||||
|                 await ctx.send(embed=embed) | ||||
|                 return | ||||
| 
 | ||||
|             table_headers = table[0].find_all("th") | ||||
|             first_header = ''.join(table_headers[0].strings) if len(table_headers) > 0 else None | ||||
|             first_header = "".join(table_headers[0].strings) if len(table_headers) > 0 else None | ||||
| 
 | ||||
|             # catch if the wrong table was selected | ||||
|             if first_header is None or not first_header.startswith("With"): | ||||
| @ -136,7 +136,7 @@ class AE7QCog(commands.Cog): | ||||
|                 embed.colour = cmn.colours.bad | ||||
|                 embed.url = base_url + callsign | ||||
|                 embed.description = desc | ||||
|                 embed.description += f'\nNo records found for `{callsign}`' | ||||
|                 embed.description += f"\nNo records found for `{callsign}`" | ||||
|                 await ctx.send(embed=embed) | ||||
|                 return | ||||
| 
 | ||||
| @ -149,18 +149,18 @@ class AE7QCog(commands.Cog): | ||||
| 
 | ||||
|             # add the first three rows of the table to the embed | ||||
|             for row in table[0:3]: | ||||
|                 header = f'**{row[0]}** ({row[3]})'     # **Name** (Applicant Type) | ||||
|                 body = (f'Name: *{row[2]}*\n' | ||||
|                         f'Region: *{row[1]}*\n' | ||||
|                         f'Status: *{row[4]}*\n' | ||||
|                         f'Granted: *{row[5]}*\n' | ||||
|                         f'Effective: *{row[6]}*\n' | ||||
|                         f'Cancelled: *{row[7]}*\n' | ||||
|                         f'Expires: *{row[8]}*') | ||||
|                 header = f"**{row[0]}** ({row[3]})"     # **Name** (Applicant Type) | ||||
|                 body = (f"Name: *{row[2]}*\n" | ||||
|                         f"Region: *{row[1]}*\n" | ||||
|                         f"Status: *{row[4]}*\n" | ||||
|                         f"Granted: *{row[5]}*\n" | ||||
|                         f"Effective: *{row[6]}*\n" | ||||
|                         f"Cancelled: *{row[7]}*\n" | ||||
|                         f"Expires: *{row[8]}*") | ||||
|                 embed.add_field(name=header, value=body, inline=False) | ||||
| 
 | ||||
|             if len(table) > 3: | ||||
|                 desc += f'\nRecords 1 to 3 of {len(table)}. See ae7q.com for more...' | ||||
|                 desc += f"\nRecords 1 to 3 of {len(table)}. See ae7q.com for more..." | ||||
| 
 | ||||
|             embed.description = desc | ||||
| 
 | ||||
| @ -168,11 +168,11 @@ class AE7QCog(commands.Cog): | ||||
| 
 | ||||
|     @_ae7q_lookup.command(name="applications", aliases=["a"], category=cmn.cat.lookup) | ||||
|     async def _ae7q_applications(self, ctx: commands.Context, callsign: str): | ||||
|         '''Look up the application history for a callsign on [ae7q.com](http://ae7q.com/).''' | ||||
|         """Look up the application history for a callsign on [ae7q.com](http://ae7q.com/).""" | ||||
|         """ | ||||
|         with ctx.typing(): | ||||
|             callsign = callsign.upper() | ||||
|             desc = '' | ||||
|             desc = "" | ||||
|             base_url = "http://ae7q.com/query/data/CallHistory.php?CALL=" | ||||
|             embed = cmn.embed_factory(ctx) | ||||
| 
 | ||||
| @ -190,14 +190,14 @@ class AE7QCog(commands.Cog): | ||||
|             if len(table[0]) == 1: | ||||
|                 for row in table: | ||||
|                     desc += " ".join(row.getText().split()) | ||||
|                     desc += '\n' | ||||
|                 desc = desc.replace(callsign, f'`{callsign}`') | ||||
|                     desc += "\n" | ||||
|                 desc = desc.replace(callsign, f"`{callsign}`") | ||||
| 
 | ||||
|             # select the last table to get applications | ||||
|             table = tables[-1] | ||||
| 
 | ||||
|             table_headers = table[0].find_all("th") | ||||
|             first_header = ''.join(table_headers[0].strings) if len(table_headers) > 0 else None | ||||
|             first_header = "".join(table_headers[0].strings) if len(table_headers) > 0 else None | ||||
| 
 | ||||
|             # catch if the wrong table was selected | ||||
|             if first_header is None or not first_header.startswith("Receipt"): | ||||
| @ -205,7 +205,7 @@ class AE7QCog(commands.Cog): | ||||
|                 embed.colour = cmn.colours.bad | ||||
|                 embed.url = base_url + callsign | ||||
|                 embed.description = desc | ||||
|                 embed.description += f'\nNo records found for `{callsign}`' | ||||
|                 embed.description += f"\nNo records found for `{callsign}`" | ||||
|                 await ctx.send(embed=embed) | ||||
|                 return | ||||
| 
 | ||||
| @ -218,16 +218,16 @@ class AE7QCog(commands.Cog): | ||||
| 
 | ||||
|             # add the first three rows of the table to the embed | ||||
|             for row in table[0:3]: | ||||
|                 header = f'**{row[1]}** ({row[3]})'     # **Name** (Callsign) | ||||
|                 body = (f'Received: *{row[0]}*\n' | ||||
|                         f'Region: *{row[2]}*\n' | ||||
|                         f'Purpose: *{row[5]}*\n' | ||||
|                         f'Last Action: *{row[7]}*\n' | ||||
|                         f'Application Status: *{row[8]}*\n') | ||||
|                 header = f"**{row[1]}** ({row[3]})"     # **Name** (Callsign) | ||||
|                 body = (f"Received: *{row[0]}*\n" | ||||
|                         f"Region: *{row[2]}*\n" | ||||
|                         f"Purpose: *{row[5]}*\n" | ||||
|                         f"Last Action: *{row[7]}*\n" | ||||
|                         f"Application Status: *{row[8]}*\n") | ||||
|                 embed.add_field(name=header, value=body, inline=False) | ||||
| 
 | ||||
|             if len(table) > 3: | ||||
|                 desc += f'\nRecords 1 to 3 of {len(table)}. See ae7q.com for more...' | ||||
|                 desc += f"\nRecords 1 to 3 of {len(table)}. See ae7q.com for more..." | ||||
| 
 | ||||
|             embed.description = desc | ||||
| 
 | ||||
| @ -238,7 +238,7 @@ class AE7QCog(commands.Cog): | ||||
| 
 | ||||
|     @_ae7q_lookup.command(name="frn", aliases=["f"], category=cmn.cat.lookup) | ||||
|     async def _ae7q_frn(self, ctx: commands.Context, frn: str): | ||||
|         '''Look up the history of an FRN on [ae7q.com](http://ae7q.com/).''' | ||||
|         """Look up the history of an FRN on [ae7q.com](http://ae7q.com/).""" | ||||
|         """ | ||||
|         NOTES: | ||||
|         - 2 tables: callsign history and application history | ||||
| @ -260,21 +260,21 @@ class AE7QCog(commands.Cog): | ||||
|                 embed.title = f"AE7Q History for FRN {frn}" | ||||
|                 embed.colour = cmn.colours.bad | ||||
|                 embed.url = base_url + frn | ||||
|                 embed.description = f'No records found for FRN `{frn}`' | ||||
|                 embed.description = f"No records found for FRN `{frn}`" | ||||
|                 await ctx.send(embed=embed) | ||||
|                 return | ||||
| 
 | ||||
|             table = tables[0] | ||||
| 
 | ||||
|             table_headers = table[0].find_all("th") | ||||
|             first_header = ''.join(table_headers[0].strings) if len(table_headers) > 0 else None | ||||
|             first_header = "".join(table_headers[0].strings) if len(table_headers) > 0 else None | ||||
| 
 | ||||
|             # catch if the wrong table was selected | ||||
|             if first_header is None or not first_header.startswith('With Licensee'): | ||||
|             if first_header is None or not first_header.startswith("With Licensee"): | ||||
|                 embed.title = f"AE7Q History for FRN {frn}" | ||||
|                 embed.colour = cmn.colours.bad | ||||
|                 embed.url = base_url + frn | ||||
|                 embed.description = f'No records found for FRN `{frn}`' | ||||
|                 embed.description = f"No records found for FRN `{frn}`" | ||||
|                 await ctx.send(embed=embed) | ||||
|                 return | ||||
| 
 | ||||
| @ -287,25 +287,25 @@ class AE7QCog(commands.Cog): | ||||
| 
 | ||||
|             # add the first three rows of the table to the embed | ||||
|             for row in table[0:3]: | ||||
|                 header = f'**{row[0]}** ({row[3]})'     # **Callsign** (Applicant Type) | ||||
|                 body = (f'Name: *{row[2]}*\n' | ||||
|                         f'Class: *{row[4]}*\n' | ||||
|                         f'Region: *{row[1]}*\n' | ||||
|                         f'Status: *{row[5]}*\n' | ||||
|                         f'Granted: *{row[6]}*\n' | ||||
|                         f'Effective: *{row[7]}*\n' | ||||
|                         f'Cancelled: *{row[8]}*\n' | ||||
|                         f'Expires: *{row[9]}*') | ||||
|                 header = f"**{row[0]}** ({row[3]})"     # **Callsign** (Applicant Type) | ||||
|                 body = (f"Name: *{row[2]}*\n" | ||||
|                         f"Class: *{row[4]}*\n" | ||||
|                         f"Region: *{row[1]}*\n" | ||||
|                         f"Status: *{row[5]}*\n" | ||||
|                         f"Granted: *{row[6]}*\n" | ||||
|                         f"Effective: *{row[7]}*\n" | ||||
|                         f"Cancelled: *{row[8]}*\n" | ||||
|                         f"Expires: *{row[9]}*") | ||||
|                 embed.add_field(name=header, value=body, inline=False) | ||||
| 
 | ||||
|             if len(table) > 3: | ||||
|                 embed.description = f'Records 1 to 3 of {len(table)}. See ae7q.com for more...' | ||||
|                 embed.description = f"Records 1 to 3 of {len(table)}. See ae7q.com for more..." | ||||
| 
 | ||||
|             await ctx.send(embed=embed) | ||||
| 
 | ||||
|     @_ae7q_lookup.command(name="licensee", aliases=["l"], category=cmn.cat.lookup) | ||||
|     async def _ae7q_licensee(self, ctx: commands.Context, licensee_id: str): | ||||
|         '''Look up the history of a licensee ID on [ae7q.com](http://ae7q.com/).''' | ||||
|         """Look up the history of a licensee ID on [ae7q.com](http://ae7q.com/).""" | ||||
|         with ctx.typing(): | ||||
|             licensee_id = licensee_id.upper() | ||||
|             base_url = "http://ae7q.com/query/data/LicenseeIdHistory.php?ID=" | ||||
| @ -323,21 +323,21 @@ class AE7QCog(commands.Cog): | ||||
|                 embed.title = f"AE7Q History for Licensee {licensee_id}" | ||||
|                 embed.colour = cmn.colours.bad | ||||
|                 embed.url = base_url + licensee_id | ||||
|                 embed.description = f'No records found for Licensee `{licensee_id}`' | ||||
|                 embed.description = f"No records found for Licensee `{licensee_id}`" | ||||
|                 await ctx.send(embed=embed) | ||||
|                 return | ||||
| 
 | ||||
|             table = tables[0] | ||||
| 
 | ||||
|             table_headers = table[0].find_all("th") | ||||
|             first_header = ''.join(table_headers[0].strings) if len(table_headers) > 0 else None | ||||
|             first_header = "".join(table_headers[0].strings) if len(table_headers) > 0 else None | ||||
| 
 | ||||
|             # catch if the wrong table was selected | ||||
|             if first_header is None or not first_header.startswith('With FCC'): | ||||
|             if first_header is None or not first_header.startswith("With FCC"): | ||||
|                 embed.title = f"AE7Q History for Licensee {licensee_id}" | ||||
|                 embed.colour = cmn.colours.bad | ||||
|                 embed.url = base_url + licensee_id | ||||
|                 embed.description = f'No records found for Licensee `{licensee_id}`' | ||||
|                 embed.description = f"No records found for Licensee `{licensee_id}`" | ||||
|                 await ctx.send(embed=embed) | ||||
|                 return | ||||
| 
 | ||||
| @ -350,19 +350,19 @@ class AE7QCog(commands.Cog): | ||||
| 
 | ||||
|             # add the first three rows of the table to the embed | ||||
|             for row in table[0:3]: | ||||
|                 header = f'**{row[0]}** ({row[3]})'     # **Callsign** (Applicant Type) | ||||
|                 body = (f'Name: *{row[2]}*\n' | ||||
|                         f'Class: *{row[4]}*\n' | ||||
|                         f'Region: *{row[1]}*\n' | ||||
|                         f'Status: *{row[5]}*\n' | ||||
|                         f'Granted: *{row[6]}*\n' | ||||
|                         f'Effective: *{row[7]}*\n' | ||||
|                         f'Cancelled: *{row[8]}*\n' | ||||
|                         f'Expires: *{row[9]}*') | ||||
|                 header = f"**{row[0]}** ({row[3]})"     # **Callsign** (Applicant Type) | ||||
|                 body = (f"Name: *{row[2]}*\n" | ||||
|                         f"Class: *{row[4]}*\n" | ||||
|                         f"Region: *{row[1]}*\n" | ||||
|                         f"Status: *{row[5]}*\n" | ||||
|                         f"Granted: *{row[6]}*\n" | ||||
|                         f"Effective: *{row[7]}*\n" | ||||
|                         f"Cancelled: *{row[8]}*\n" | ||||
|                         f"Expires: *{row[9]}*") | ||||
|                 embed.add_field(name=header, value=body, inline=False) | ||||
| 
 | ||||
|             if len(table) > 3: | ||||
|                 embed.description = f'Records 1 to 3 of {len(table)}. See ae7q.com for more...' | ||||
|                 embed.description = f"Records 1 to 3 of {len(table)}. See ae7q.com for more..." | ||||
| 
 | ||||
|             await ctx.send(embed=embed) | ||||
| 
 | ||||
| @ -372,13 +372,13 @@ async def process_table(table: list): | ||||
|     table_contents = [] | ||||
|     for tr in table: | ||||
|         row = [] | ||||
|         for td in tr.find_all('td'): | ||||
|         for td in tr.find_all("td"): | ||||
|             cell_val = td.getText().strip() | ||||
|             row.append(cell_val if cell_val else '-') | ||||
|             row.append(cell_val if cell_val else "-") | ||||
| 
 | ||||
|             # take care of columns that span multiple rows by copying the contents rightward | ||||
|             if 'colspan' in td.attrs and int(td.attrs['colspan']) > 1: | ||||
|                 for i in range(int(td.attrs['colspan']) - 1): | ||||
|             if "colspan" in td.attrs and int(td.attrs["colspan"]) > 1: | ||||
|                 for i in range(int(td.attrs["colspan"]) - 1): | ||||
|                     row.append(row[-1]) | ||||
| 
 | ||||
|         # get rid of ditto marks by copying the contents from the previous row | ||||
|  | ||||
							
								
								
									
										86
									
								
								exts/base.py
									
									
									
									
									
								
							
							
						
						
									
										86
									
								
								exts/base.py
									
									
									
									
									
								
							| @ -24,7 +24,7 @@ import data.options as opt | ||||
| 
 | ||||
| class QrmHelpCommand(commands.HelpCommand): | ||||
|     def __init__(self): | ||||
|         super().__init__(command_attrs={'help': 'Shows help about qrm or a command', 'aliases': ['h']}) | ||||
|         super().__init__(command_attrs={"help": "Shows help about qrm or a command", "aliases": ["h"]}) | ||||
|         self.verify_checks = True | ||||
| 
 | ||||
|     async def get_bot_mapping(self): | ||||
| @ -32,7 +32,7 @@ class QrmHelpCommand(commands.HelpCommand): | ||||
|         mapping = {} | ||||
| 
 | ||||
|         for cmd in await self.filter_commands(bot.commands, sort=True): | ||||
|             cat = cmd.__original_kwargs__.get('category', None) | ||||
|             cat = cmd.__original_kwargs__.get("category", None) | ||||
|             if cat in mapping: | ||||
|                 mapping[cat].append(cmd) | ||||
|             else: | ||||
| @ -42,27 +42,27 @@ class QrmHelpCommand(commands.HelpCommand): | ||||
|     async def get_command_signature(self, command): | ||||
|         parent = command.full_parent_name | ||||
|         if command.aliases != []: | ||||
|             aliases = ', '.join(command.aliases) | ||||
|             aliases = ", ".join(command.aliases) | ||||
|             fmt = command.name | ||||
|             if parent: | ||||
|                 fmt = f'{parent} {fmt}' | ||||
|                 fmt = f"{parent} {fmt}" | ||||
|             alias = fmt | ||||
|             return f'{opt.prefix}{alias} {command.signature}\n    *Aliases:* {aliases}' | ||||
|         alias = command.name if not parent else f'{parent} {command.name}' | ||||
|         return f'{opt.prefix}{alias} {command.signature}' | ||||
|             return f"{opt.prefix}{alias} {command.signature}\n    *Aliases:* {aliases}" | ||||
|         alias = command.name if not parent else f"{parent} {command.name}" | ||||
|         return f"{opt.prefix}{alias} {command.signature}" | ||||
| 
 | ||||
|     async def send_error_message(self, error): | ||||
|         embed = cmn.embed_factory(self.context) | ||||
|         embed.title = 'qrm Help Error' | ||||
|         embed.title = "qrm Help Error" | ||||
|         embed.description = error | ||||
|         embed.colour = cmn.colours.bad | ||||
|         await self.context.send(embed=embed) | ||||
| 
 | ||||
|     async def send_bot_help(self, mapping): | ||||
|         embed = cmn.embed_factory(self.context) | ||||
|         embed.title = 'qrm Help' | ||||
|         embed.description = (f'For command-specific help and usage, use `{opt.prefix}help [command name]`' | ||||
|                              '. Many commands have shorter aliases.') | ||||
|         embed.title = "qrm Help" | ||||
|         embed.description = (f"For command-specific help and usage, use `{opt.prefix}help [command name]`." | ||||
|                              " Many commands have shorter aliases.") | ||||
|         mapping = await mapping | ||||
| 
 | ||||
|         for cat, cmds in mapping.items(): | ||||
| @ -70,9 +70,9 @@ class QrmHelpCommand(commands.HelpCommand): | ||||
|                 continue | ||||
|             names = sorted([cmd.name for cmd in cmds]) | ||||
|             if cat is not None: | ||||
|                 embed.add_field(name=cat.title(), value=', '.join(names), inline=False) | ||||
|                 embed.add_field(name=cat.title(), value=", ".join(names), inline=False) | ||||
|             else: | ||||
|                 embed.add_field(name='Other', value=', '.join(names), inline=False) | ||||
|                 embed.add_field(name="Other", value=", ".join(names), inline=False) | ||||
|         await self.context.send(embed=embed) | ||||
| 
 | ||||
|     async def send_command_help(self, command): | ||||
| @ -112,27 +112,27 @@ class BaseCog(commands.Cog): | ||||
| 
 | ||||
|         embed.add_field(name="Authors", value=", ".join(info.authors)) | ||||
|         embed.add_field(name="License", value=info.license) | ||||
|         embed.add_field(name="Version", value=f'v{info.release}') | ||||
|         embed.add_field(name="Version", value=f"v{info.release}") | ||||
|         embed.add_field(name="Contributing", value=info.contributing, inline=False) | ||||
|         embed.add_field(name="Official Server", value=info.bot_server, inline=False) | ||||
|         embed.set_thumbnail(url=str(self.bot.user.avatar_url)) | ||||
|         await ctx.send(embed=embed) | ||||
| 
 | ||||
|     @commands.command(name="ping", aliases=['beep']) | ||||
|     @commands.command(name="ping", aliases=["beep"]) | ||||
|     async def _ping(self, ctx: commands.Context): | ||||
|         """Show the current latency to the discord endpoint.""" | ||||
|         embed = cmn.embed_factory(ctx) | ||||
|         content = '' | ||||
|         content = "" | ||||
|         if ctx.invoked_with == "beep": | ||||
|             embed.title = "**Boop!**" | ||||
|         else: | ||||
|             content = ctx.message.author.mention if random.random() < 0.05 else '' | ||||
|             content = ctx.message.author.mention if random.random() < 0.05 else "" | ||||
|             embed.title = "🏓 **Pong!**" | ||||
|         embed.description = f'Current ping is {self.bot.latency*1000:.1f} ms' | ||||
|         embed.description = f"Current ping is {self.bot.latency*1000:.1f} ms" | ||||
|         await ctx.send(content, embed=embed) | ||||
| 
 | ||||
|     @commands.command(name="changelog", aliases=["clog"]) | ||||
|     async def _changelog(self, ctx: commands.Context, version: str = 'latest'): | ||||
|     async def _changelog(self, ctx: commands.Context, version: str = "latest"): | ||||
|         """Show what has changed in a bot version.""" | ||||
|         embed = cmn.embed_factory(ctx) | ||||
|         embed.title = "qrm Changelog" | ||||
| @ -144,25 +144,25 @@ class BaseCog(commands.Cog): | ||||
| 
 | ||||
|         version = version.lower() | ||||
| 
 | ||||
|         if version == 'latest': | ||||
|         if version == "latest": | ||||
|             version = info.release | ||||
|         if version == 'unreleased': | ||||
|             version = 'Unreleased' | ||||
|         if version == "unreleased": | ||||
|             version = "Unreleased" | ||||
| 
 | ||||
|         try: | ||||
|             log = changelog[version] | ||||
|         except KeyError: | ||||
|             embed.title += ": Version Not Found" | ||||
|             embed.description += '\n\n**Valid versions:** latest, ' | ||||
|             embed.description += ', '.join(vers) | ||||
|             embed.description += "\n\n**Valid versions:** latest, " | ||||
|             embed.description += ", ".join(vers) | ||||
|             embed.colour = cmn.colours.bad | ||||
|             await ctx.send(embed=embed) | ||||
|             return | ||||
| 
 | ||||
|         if 'date' in log: | ||||
|             embed.description += f'\n\n**v{version}** ({log["date"]})' | ||||
|         if "date" in log: | ||||
|             embed.description += f"\n\n**v{version}** ({log['date']})" | ||||
|         else: | ||||
|             embed.description += f'\n\n**v{version}**' | ||||
|             embed.description += f"\n\n**v{version}**" | ||||
|         embed = await format_changelog(log, embed) | ||||
| 
 | ||||
|         await ctx.send(embed=embed) | ||||
| @ -190,36 +190,36 @@ class BaseCog(commands.Cog): | ||||
| 
 | ||||
| def parse_changelog(): | ||||
|     changelog = OrderedDict() | ||||
|     ver = '' | ||||
|     heading = '' | ||||
|     ver = "" | ||||
|     heading = "" | ||||
| 
 | ||||
|     with open('CHANGELOG.md') as changelog_file: | ||||
|     with open("CHANGELOG.md") as changelog_file: | ||||
|         for line in changelog_file.readlines(): | ||||
|             if line.strip() == '': | ||||
|             if line.strip() == "": | ||||
|                 continue | ||||
|             if re.match(r'##[^#]', line): | ||||
|                 ver_match = re.match(r'\[(.+)\](?: - )?(\d{4}-\d{2}-\d{2})?', line.lstrip('#').strip()) | ||||
|             if re.match(r"##[^#]", line): | ||||
|                 ver_match = re.match(r"\[(.+)\](?: - )?(\d{4}-\d{2}-\d{2})?", line.lstrip("#").strip()) | ||||
|                 if ver_match is not None: | ||||
|                     ver = ver_match.group(1) | ||||
|                     changelog[ver] = dict() | ||||
|                     if ver_match.group(2): | ||||
|                         changelog[ver]['date'] = ver_match.group(2) | ||||
|             elif re.match(r'###[^#]', line): | ||||
|                 heading = line.lstrip('#').strip() | ||||
|                         changelog[ver]["date"] = ver_match.group(2) | ||||
|             elif re.match(r"###[^#]", line): | ||||
|                 heading = line.lstrip("#").strip() | ||||
|                 changelog[ver][heading] = [] | ||||
|             elif ver != '' and heading != '': | ||||
|                 if line.startswith('-'): | ||||
|                     changelog[ver][heading].append(line.lstrip('-').strip()) | ||||
|             elif ver != "" and heading != "": | ||||
|                 if line.startswith("-"): | ||||
|                     changelog[ver][heading].append(line.lstrip("-").strip()) | ||||
|     return changelog | ||||
| 
 | ||||
| 
 | ||||
| async def format_changelog(log: dict, embed: discord.Embed): | ||||
|     for header, lines in log.items(): | ||||
|         formatted = '' | ||||
|         if header != 'date': | ||||
|         formatted = "" | ||||
|         if header != "date": | ||||
|             for line in lines: | ||||
|                 formatted += f'- {line}\n' | ||||
|             embed.add_field(name=f'**{header}**', value=formatted, inline=False) | ||||
|                 formatted += f"- {line}\n" | ||||
|             embed.add_field(name=f"**{header}**", value=formatted, inline=False) | ||||
|     return embed | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										26
									
								
								exts/fun.py
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								exts/fun.py
									
									
									
									
									
								
							| @ -17,37 +17,37 @@ import common as cmn | ||||
| class FunCog(commands.Cog): | ||||
|     def __init__(self, bot: commands.Bot): | ||||
|         self.bot = bot | ||||
|         with open('resources/words') as words_file: | ||||
|         with open("resources/words") as words_file: | ||||
|             self.words = words_file.read().lower().splitlines() | ||||
| 
 | ||||
|     @commands.command(name="xkcd", aliases=['x'], category=cmn.cat.fun) | ||||
|     @commands.command(name="xkcd", aliases=["x"], category=cmn.cat.fun) | ||||
|     async def _xkcd(self, ctx: commands.Context, number: str): | ||||
|         '''Look up an xkcd by number.''' | ||||
|         await ctx.send('http://xkcd.com/' + number) | ||||
|         """Look up an xkcd by number.""" | ||||
|         await ctx.send("http://xkcd.com/" + number) | ||||
| 
 | ||||
|     @commands.command(name="tar", category=cmn.cat.fun) | ||||
|     async def _tar(self, ctx: commands.Context): | ||||
|         '''Returns an xkcd about tar.''' | ||||
|         await ctx.send('http://xkcd.com/1168') | ||||
|         """Returns an xkcd about tar.""" | ||||
|         await ctx.send("http://xkcd.com/1168") | ||||
| 
 | ||||
|     @commands.command(name="xd", hidden=True, category=cmn.cat.fun) | ||||
|     async def _xd(self, ctx: commands.Context): | ||||
|         '''ecks dee''' | ||||
|         await ctx.send('ECKS DEE :smirk:') | ||||
|         """ecks dee""" | ||||
|         await ctx.send("ECKS DEE :smirk:") | ||||
| 
 | ||||
|     @commands.command(name="funetics", aliases=['fun'], category=cmn.cat.fun) | ||||
|     @commands.command(name="funetics", aliases=["fun"], category=cmn.cat.fun) | ||||
|     async def _funetics_lookup(self, ctx: commands.Context, *, msg: str): | ||||
|         '''Get fun phonetics for a word or phrase.''' | ||||
|         """Get fun phonetics for a word or phrase.""" | ||||
|         with ctx.typing(): | ||||
|             result = '' | ||||
|             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 += ' ' | ||||
|                 result += " " | ||||
|             embed = cmn.embed_factory(ctx) | ||||
|             embed.title = f'Funetics for {msg}' | ||||
|             embed.title = f"Funetics for {msg}" | ||||
|             embed.description = result.title() | ||||
|             embed.colour = cmn.colours.good | ||||
|         await ctx.send(embed=embed) | ||||
|  | ||||
							
								
								
									
										64
									
								
								exts/grid.py
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								exts/grid.py
									
									
									
									
									
								
							| @ -20,27 +20,27 @@ class GridCog(commands.Cog): | ||||
| 
 | ||||
|     @commands.command(name="grid", category=cmn.cat.maps) | ||||
|     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.''' | ||||
|         """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 += 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.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.title = f"Error generating grid square for {lat}, {lon}." | ||||
|                 embed.description = ("Coordinates out of range.\n" | ||||
|                                      "The valid ranges are:\n" | ||||
|                                      "- Latitude: `-90` to `+90`\n" | ||||
| @ -48,29 +48,29 @@ with negative being latitude South and longitude West.''' | ||||
|                 embed.colour = cmn.colours.bad | ||||
|         await ctx.send(embed=embed) | ||||
| 
 | ||||
|     @commands.command(name="ungrid", aliases=['loc'], category=cmn.cat.maps) | ||||
|     @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.''' | ||||
|         """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 == '': | ||||
|             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.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}' | ||||
|                         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}' | ||||
|                         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.title = f"Error generating latitude and longitude for grid {grid}." | ||||
|                     embed.description = str(e) | ||||
|                     embed.colour = cmn.colours.bad | ||||
|             else: | ||||
| @ -101,12 +101,12 @@ If two grid squares are given, the distance and azimuth between them is calculat | ||||
|                     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.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.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) | ||||
| @ -114,23 +114,23 @@ If two grid squares are given, the distance and azimuth between them is calculat | ||||
| 
 | ||||
| def get_coords(grid: str): | ||||
|     if len(grid) < 3: | ||||
|         raise ValueError('The grid locator must be at least 4 characters long.') | ||||
|         raise ValueError("The grid locator must be at least 4 characters long.") | ||||
| 
 | ||||
|     if not grid[0:2].isalpha() or not grid[2:4].isdigit(): | ||||
|         if len(grid) <= 4: | ||||
|             raise ValueError('The grid locator must be of the form AA##.') | ||||
|             raise ValueError("The grid locator must be of the form AA##.") | ||||
|         if len(grid) >= 6 and not grid[5:7].isalpha(): | ||||
|             raise ValueError('The grid locator must be of the form AA##AA.') | ||||
|             raise ValueError("The grid locator must be of the form AA##AA.") | ||||
| 
 | ||||
|     lon = ((ord(grid[0]) - ord('A')) * 20) - 180 | ||||
|     lat = ((ord(grid[1]) - ord('A')) * 10) - 90 | ||||
|     lon += ((ord(grid[2]) - ord('0')) * 2) | ||||
|     lat += ((ord(grid[3]) - ord('0')) * 1) | ||||
|     lon = ((ord(grid[0]) - ord("A")) * 20) - 180 | ||||
|     lat = ((ord(grid[1]) - ord("A")) * 10) - 90 | ||||
|     lon += ((ord(grid[2]) - ord("0")) * 2) | ||||
|     lat += ((ord(grid[3]) - ord("0")) * 1) | ||||
| 
 | ||||
|     if len(grid) >= 6: | ||||
|         # have subsquares | ||||
|         lon += ((ord(grid[4])) - ord('A')) * (5/60) | ||||
|         lat += ((ord(grid[5])) - ord('A')) * (2.5/60) | ||||
|         lon += ((ord(grid[4])) - ord("A")) * (5/60) | ||||
|         lat += ((ord(grid[5])) - ord("A")) * (2.5/60) | ||||
|         # move to center of subsquare | ||||
|         lon += (2.5/60) | ||||
|         lat += (1.25/60) | ||||
|  | ||||
							
								
								
									
										30
									
								
								exts/ham.py
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								exts/ham.py
									
									
									
									
									
								
							| @ -21,9 +21,9 @@ class HamCog(commands.Cog): | ||||
|     def __init__(self, bot: commands.Bot): | ||||
|         self.bot = bot | ||||
| 
 | ||||
|     @commands.command(name="qcode", aliases=['q'], category=cmn.cat.ref) | ||||
|     @commands.command(name="qcode", aliases=["q"], category=cmn.cat.ref) | ||||
|     async def _qcode_lookup(self, ctx: commands.Context, qcode: str): | ||||
|         '''Look up a Q Code.''' | ||||
|         """Look up a Q Code.""" | ||||
|         with ctx.typing(): | ||||
|             qcode = qcode.upper() | ||||
|             embed = cmn.embed_factory(ctx) | ||||
| @ -32,49 +32,49 @@ class HamCog(commands.Cog): | ||||
|                 embed.description = qcodes.qcodes[qcode] | ||||
|                 embed.colour = cmn.colours.good | ||||
|             else: | ||||
|                 embed.title = f'Q Code {qcode} not found' | ||||
|                 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) | ||||
|     @commands.command(name="phonetics", aliases=["ph", "phoneticize", "phoneticise", "phone"], category=cmn.cat.ref) | ||||
|     async def _phonetics_lookup(self, ctx: commands.Context, *, msg: str): | ||||
|         '''Get phonetics for a word or phrase.''' | ||||
|         """Get phonetics for a word or phrase.""" | ||||
|         with ctx.typing(): | ||||
|             result = '' | ||||
|             result = "" | ||||
|             for char in msg.lower(): | ||||
|                 if char.isalpha(): | ||||
|                     result += phonetics.phonetics[char] | ||||
|                 else: | ||||
|                     result += char | ||||
|                 result += ' ' | ||||
|                 result += " " | ||||
|             embed = cmn.embed_factory(ctx) | ||||
|             embed.title = f'Phonetics for {msg}' | ||||
|             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) | ||||
|     @commands.command(name="utc", aliases=["z"], category=cmn.cat.ref) | ||||
|     async def _utc_lookup(self, ctx: commands.Context): | ||||
|         '''Gets the current time in UTC.''' | ||||
|         """Gets the current time in UTC.""" | ||||
|         with ctx.typing(): | ||||
|             now = datetime.utcnow() | ||||
|             result = '**' + now.strftime('%Y-%m-%d %H:%M') + 'Z**' | ||||
|             result = "**" + now.strftime("%Y-%m-%d %H:%M") + "Z**" | ||||
|             embed = cmn.embed_factory(ctx) | ||||
|             embed.title = 'The current time is:' | ||||
|             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) | ||||
|     async def _vanity_prefixes(self, ctx: commands.Context, country: str = None): | ||||
|         '''Lists valid prefixes for countries.''' | ||||
|         """Lists valid prefixes for countries.""" | ||||
|         if country is None: | ||||
|             await ctx.send_help(ctx.command) | ||||
|             return | ||||
|         embed = cmn.embed_factory(ctx) | ||||
|         if country.lower() not in callsign_info.options: | ||||
|             embed.title = f'{country} not found!', | ||||
|             embed.description = f'Valid countries: {", ".join(callsign_info.options.keys())}', | ||||
|             embed.title = f"{country} not found!", | ||||
|             embed.description = f"Valid countries: {', '.join(callsign_info.options.keys())}", | ||||
|             embed.colour = cmn.colours.bad | ||||
|         else: | ||||
|             embed.title = callsign_info.options[country.lower()][0] | ||||
|  | ||||
| @ -18,8 +18,8 @@ import common as cmn | ||||
| 
 | ||||
| 
 | ||||
| class ImageCog(commands.Cog): | ||||
|     gl_url = ('http://www.fourmilab.ch/cgi-bin/uncgi/Earth?img=NOAAtopo.evif' | ||||
|               '&imgsize=320&dynimg=y&opt=-p&lat=&lon=&alt=&tle=&date=0&utc=&jd=') | ||||
|     gl_url = ("http://www.fourmilab.ch/cgi-bin/uncgi/Earth?img=NOAAtopo.evif" | ||||
|               "&imgsize=320&dynimg=y&opt=-p&lat=&lon=&alt=&tle=&date=0&utc=&jd=") | ||||
| 
 | ||||
|     def __init__(self, bot: commands.Bot): | ||||
|         self.bot = bot | ||||
| @ -27,17 +27,17 @@ class ImageCog(commands.Cog): | ||||
|         self.maps = cmn.ImagesGroup(cmn.paths.maps / "meta.json") | ||||
|         self.session = aiohttp.ClientSession(connector=bot.qrm.connector) | ||||
| 
 | ||||
|     @commands.command(name="bandplan", aliases=['plan', 'bands'], category=cmn.cat.ref) | ||||
|     async def _bandplan(self, ctx: commands.Context, region: str = ''): | ||||
|         '''Posts an image of Frequency Allocations.''' | ||||
|     @commands.command(name="bandplan", aliases=["plan", "bands"], category=cmn.cat.ref) | ||||
|     async def _bandplan(self, ctx: commands.Context, region: str = ""): | ||||
|         """Posts an image of Frequency Allocations.""" | ||||
|         async with ctx.typing(): | ||||
|             arg = region.lower() | ||||
|             embed = cmn.embed_factory(ctx) | ||||
|             if arg not in self.bandcharts: | ||||
|                 desc = 'Possible arguments are:\n' | ||||
|                 desc = "Possible arguments are:\n" | ||||
|                 for key, img in self.bandcharts.items(): | ||||
|                     desc += f'`{key}`: {img.name}{("  " + img.emoji if img.emoji else "")}\n' | ||||
|                 embed.title = f'Bandplan Not Found!' | ||||
|                     desc += f"`{key}`: {img.name}{('  ' + img.emoji if img.emoji else '')}\n" | ||||
|                 embed.title = f"Bandplan Not Found!" | ||||
|                 embed.description = desc | ||||
|                 embed.colour = cmn.colours.bad | ||||
|                 await ctx.send(embed=embed) | ||||
| @ -51,20 +51,20 @@ class ImageCog(commands.Cog): | ||||
|                 embed.add_field(name="Source", value=metadata.source) | ||||
|             embed.title = metadata.long_name + ("  " + metadata.emoji if metadata.emoji else "") | ||||
|             embed.colour = cmn.colours.good | ||||
|             embed.set_image(url='attachment://' + metadata.filename) | ||||
|             embed.set_image(url="attachment://" + metadata.filename) | ||||
|             await ctx.send(embed=embed, file=img) | ||||
| 
 | ||||
|     @commands.command(name="map", category=cmn.cat.maps) | ||||
|     async def _map(self, ctx: commands.Context, map_id: str = ''): | ||||
|         '''Posts an image of a ham-relevant map.''' | ||||
|     async def _map(self, ctx: commands.Context, map_id: str = ""): | ||||
|         """Posts an image of a ham-relevant map.""" | ||||
|         async with ctx.typing(): | ||||
|             arg = map_id.lower() | ||||
|             embed = cmn.embed_factory(ctx) | ||||
|             if arg not in self.maps: | ||||
|                 desc = 'Possible arguments are:\n' | ||||
|                 desc = "Possible arguments are:\n" | ||||
|                 for key, img in self.maps.items(): | ||||
|                     desc += f'`{key}`: {img.name}{("  " + img.emoji if img.emoji else "")}\n' | ||||
|                 embed.title = 'Map Not Found!' | ||||
|                     desc += f"`{key}`: {img.name}{('  ' + img.emoji if img.emoji else '')}\n" | ||||
|                 embed.title = "Map Not Found!" | ||||
|                 embed.description = desc | ||||
|                 embed.colour = cmn.colours.bad | ||||
|                 await ctx.send(embed=embed) | ||||
| @ -78,22 +78,22 @@ class ImageCog(commands.Cog): | ||||
|                 embed.add_field(name="Source", value=metadata.source) | ||||
|             embed.title = metadata.long_name + ("  " + metadata.emoji if metadata.emoji else "") | ||||
|             embed.colour = cmn.colours.good | ||||
|             embed.set_image(url='attachment://' + metadata.filename) | ||||
|             embed.set_image(url="attachment://" + metadata.filename) | ||||
|             await ctx.send(embed=embed, file=img) | ||||
| 
 | ||||
|     @commands.command(name="grayline", aliases=['greyline', 'grey', 'gray', 'gl'], category=cmn.cat.maps) | ||||
|     @commands.command(name="grayline", aliases=["greyline", "grey", "gray", "gl"], category=cmn.cat.maps) | ||||
|     async def _grayline(self, ctx: commands.Context): | ||||
|         '''Posts a map of the current greyline, where HF propagation is the best.''' | ||||
|         """Posts a map of the current greyline, where HF propagation is the best.""" | ||||
|         async with ctx.typing(): | ||||
|             embed = cmn.embed_factory(ctx) | ||||
|             embed.title = 'Current Greyline Conditions' | ||||
|             embed.title = "Current Greyline Conditions" | ||||
|             embed.colour = cmn.colours.good | ||||
|             async with self.session.get(self.gl_url) as resp: | ||||
|                 if resp.status != 200: | ||||
|                     raise cmn.BotHTTPError(resp) | ||||
|                 data = io.BytesIO(await resp.read()) | ||||
|             embed.set_image(url=f'attachment://greyline.jpg') | ||||
|             await ctx.send(embed=embed, file=discord.File(data, 'greyline.jpg')) | ||||
|             embed.set_image(url=f"attachment://greyline.jpg") | ||||
|             await ctx.send(embed=embed, file=discord.File(data, "greyline.jpg")) | ||||
| 
 | ||||
| 
 | ||||
| def setup(bot: commands.Bot): | ||||
|  | ||||
| @ -19,48 +19,48 @@ class LookupCog(commands.Cog): | ||||
|     def __init__(self, bot): | ||||
|         self.bot = bot | ||||
|         try: | ||||
|             self.cty = BigCty('./data/cty.json') | ||||
|             self.cty = BigCty("./data/cty.json") | ||||
|         except OSError: | ||||
|             self.cty = BigCty() | ||||
| 
 | ||||
|     # TODO: See #107 | ||||
|     # @commands.command(name="sat", category=cmn.cat.lookup) | ||||
|     # async def _sat_lookup(self, ctx: commands.Context, sat_name: str, grid1: str, grid2: str = None): | ||||
|     #     '''Links to info about satellite passes on satmatch.com.''' | ||||
|     #     now = datetime.utcnow().strftime('%Y-%m-%d%%20%H:%M') | ||||
|     #     if grid2 is None or grid2 == '': | ||||
|     #         await ctx.send(f'http://www.satmatch.com/satellite/{sat_name}/obs1/{grid1}' | ||||
|     #                        f'?search_start_time={now}&duration_hrs=24') | ||||
|     #     """Links to info about satellite passes on satmatch.com.""" | ||||
|     #     now = datetime.utcnow().strftime("%Y-%m-%d%%20%H:%M") | ||||
|     #     if grid2 is None or grid2 == "": | ||||
|     #         await ctx.send(f"http://www.satmatch.com/satellite/{sat_name}/obs1/{grid1}" | ||||
|     #                        f"?search_start_time={now}&duration_hrs=24") | ||||
|     #     else: | ||||
|     #         await ctx.send(f'http://www.satmatch.com/satellite/{sat_name}/obs1/{grid1}' | ||||
|     #                        f'/obs2/{grid2}?search_start_time={now}&duration_hrs=24') | ||||
|     #         await ctx.send(f"http://www.satmatch.com/satellite/{sat_name}/obs1/{grid1}" | ||||
|     #                        f"/obs2/{grid2}?search_start_time={now}&duration_hrs=24") | ||||
| 
 | ||||
|     @commands.command(name="dxcc", aliases=['dx'], category=cmn.cat.lookup) | ||||
|     @commands.command(name="dxcc", aliases=["dx"], category=cmn.cat.lookup) | ||||
|     async def _dxcc_lookup(self, ctx: commands.Context, query: str): | ||||
|         '''Gets info about a DXCC prefix.''' | ||||
|         """Gets info about a DXCC prefix.""" | ||||
|         with ctx.typing(): | ||||
|             query = query.upper() | ||||
|             full_query = query | ||||
|             embed = cmn.embed_factory(ctx) | ||||
|             embed.title = f'DXCC Info for ' | ||||
|             embed.description = f'*Last Updated: {self.cty.formatted_version}*' | ||||
|             embed.title = f"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="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'])) | ||||
|                                     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] | ||||
|             else: | ||||
|                 embed.title += full_query + ' not found' | ||||
|                 embed.title += full_query + " not found" | ||||
|                 embed.colour = cmn.colours.bad | ||||
|         await ctx.send(embed=embed) | ||||
| 
 | ||||
|  | ||||
| @ -17,63 +17,63 @@ class MorseCog(commands.Cog): | ||||
|     def __init__(self, bot: commands.Bot): | ||||
|         self.bot = bot | ||||
| 
 | ||||
|     @commands.command(name="morse", aliases=['cw'], category=cmn.cat.ref) | ||||
|     @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 = '' | ||||
|             result = "" | ||||
|             for char in msg.upper(): | ||||
|                 try: | ||||
|                     result += morse.morse[char] | ||||
|                 except KeyError: | ||||
|                     result += '<?>' | ||||
|                 result += ' ' | ||||
|                     result += "<?>" | ||||
|                 result += " " | ||||
|             embed = cmn.embed_factory(ctx) | ||||
|             embed.title = f'Morse Code for {msg}' | ||||
|             embed.description = '**' + result + '**' | ||||
|             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) | ||||
|     @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.''' | ||||
|         """Converts international morse code to ASCII.""" | ||||
|         with ctx.typing(): | ||||
|             result = '' | ||||
|             result = "" | ||||
|             msg0 = msg | ||||
|             msg = msg.split('/') | ||||
|             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 += ' ' | ||||
|                         result += "<?>" | ||||
|                 result += " " | ||||
|             embed = cmn.embed_factory(ctx) | ||||
|             embed.title = f'ASCII for {msg0}' | ||||
|             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) | ||||
|     @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.''' | ||||
|         """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('-', '==') | ||||
|                     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.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.title = f"CW Weight of {msg}" | ||||
|             embed.description = f"The CW weight is **{weight}**" | ||||
|             embed.colour = cmn.colours.good | ||||
|         await ctx.send(embed=embed) | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										146
									
								
								exts/qrz.py
									
									
									
									
									
								
							
							
						
						
									
										146
									
								
								exts/qrz.py
									
									
									
									
									
								
							| @ -26,11 +26,11 @@ class QRZCog(commands.Cog): | ||||
| 
 | ||||
|     @commands.command(name="call", aliases=["qrz"], category=cmn.cat.lookup) | ||||
|     async def _qrz_lookup(self, ctx: commands.Context, callsign: str, *flags): | ||||
|         '''Look up a callsign on [QRZ.com](https://www.qrz.com/). Add `--link` to only link the QRZ page.''' | ||||
|         """Look up a callsign on [QRZ.com](https://www.qrz.com/). Add `--link` to only link the QRZ page.""" | ||||
|         flags = [f.lower() for f in flags] | ||||
| 
 | ||||
|         if keys.qrz_user == '' or keys.qrz_pass == '' or '--link' in flags: | ||||
|             await ctx.send(f'http://qrz.com/db/{callsign}') | ||||
|         if keys.qrz_user == "" or keys.qrz_pass == "" or "--link" in flags: | ||||
|             await ctx.send(f"http://qrz.com/db/{callsign}") | ||||
|             return | ||||
| 
 | ||||
|         try: | ||||
| @ -38,38 +38,38 @@ class QRZCog(commands.Cog): | ||||
|         except ConnectionError: | ||||
|             await self.get_session() | ||||
| 
 | ||||
|         url = f'http://xmldata.qrz.com/xml/current/?s={self.key};callsign={callsign}' | ||||
|         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})') | ||||
|                 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']: | ||||
|         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']: | ||||
|             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!' | ||||
|                 embed.description = "No data found!" | ||||
|                 await ctx.send(embed=embed) | ||||
|                 return | ||||
|             raise ValueError(resp_session['Error']) | ||||
|             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()} | ||||
|         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()} | ||||
| 
 | ||||
|         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']) | ||||
|         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) | ||||
| 
 | ||||
| @ -81,14 +81,14 @@ class QRZCog(commands.Cog): | ||||
|     async def get_session(self): | ||||
|         """Session creation and caching.""" | ||||
|         self.key = await qrz_login(keys.qrz_user, keys.qrz_pass, self.session) | ||||
|         with open('data/qrz_session', 'w') as qrz_file: | ||||
|         with open("data/qrz_session", "w") as qrz_file: | ||||
|             qrz_file.write(self.key) | ||||
| 
 | ||||
|     @tasks.loop(count=1) | ||||
|     async def _qrz_session_init(self): | ||||
|         """Helper task to allow obtaining a session at cog instantiation.""" | ||||
|         try: | ||||
|             with open('data/qrz_session') as qrz_file: | ||||
|             with open("data/qrz_session") as qrz_file: | ||||
|                 self.key = qrz_file.readline().strip() | ||||
|             await qrz_test_session(self.key, self.session) | ||||
|         except (FileNotFoundError, ConnectionError): | ||||
| @ -96,86 +96,86 @@ class QRZCog(commands.Cog): | ||||
| 
 | ||||
| 
 | ||||
| async def qrz_login(user: str, passwd: str, session: aiohttp.ClientSession): | ||||
|     url = f'http://xmldata.qrz.com/xml/current/?username={user};password={passwd};agent=discord-qrm2' | ||||
|     url = f"http://xmldata.qrz.com/xml/current/?username={user};password={passwd};agent=discord-qrm2" | ||||
|     async with session.get(url) as resp: | ||||
|         if resp.status != 200: | ||||
|             raise ConnectionError(f'Unable to connect to QRZ (HTTP Error {resp.status})') | ||||
|             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: | ||||
|         raise ConnectionError(resp_session['Error']) | ||||
|     if resp_session['SubExp'] == 'non-subscriber': | ||||
|         raise ConnectionError('Invalid QRZ Subscription') | ||||
|     return resp_session['Key'] | ||||
|     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: | ||||
|         raise ConnectionError(resp_session["Error"]) | ||||
|     if resp_session["SubExp"] == "non-subscriber": | ||||
|         raise ConnectionError("Invalid QRZ Subscription") | ||||
|     return resp_session["Key"] | ||||
| 
 | ||||
| 
 | ||||
| async def qrz_test_session(key: str, session: aiohttp.ClientSession): | ||||
|     url = f'http://xmldata.qrz.com/xml/current/?s={key}' | ||||
|     url = f"http://xmldata.qrz.com/xml/current/?s={key}" | ||||
|     async with session.get(url) as resp: | ||||
|         if resp.status != 200: | ||||
|             raise ConnectionError(f'Unable to connect to QRZ (HTTP Error {resp.status})') | ||||
|             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: | ||||
|         raise ConnectionError(resp_session['Error']) | ||||
|     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: | ||||
|         raise ConnectionError(resp_session["Error"]) | ||||
| 
 | ||||
| 
 | ||||
| def qrz_process_info(data: dict): | ||||
|     if 'name' in data: | ||||
|         if 'fname' in data: | ||||
|             name = data['fname'] + ' ' + data['name'] | ||||
|     if "name" in data: | ||||
|         if "fname" in data: | ||||
|             name = data["fname"] + " " + data["name"] | ||||
|         else: | ||||
|             name = data['name'] | ||||
|             name = data["name"] | ||||
|     else: | ||||
|         name = None | ||||
|     if 'state' in data: | ||||
|         state = f', {data["state"]}' | ||||
|     if "state" in data: | ||||
|         state = f", {data['state']}" | ||||
|     else: | ||||
|         state = '' | ||||
|     address = data.get('addr1', '') + '\n' + data.get('addr2', '') + state + ' ' + data.get('zip', '') | ||||
|         state = "" | ||||
|     address = data.get("addr1", "") + "\n" + data.get("addr2", "") + state + " " + data.get("zip", "") | ||||
|     address = address.strip() | ||||
|     if address == '': | ||||
|     if address == "": | ||||
|         address = None | ||||
|     if 'eqsl' in data: | ||||
|         eqsl = 'Yes' if data['eqsl'] == 1 else 'No' | ||||
|     if "eqsl" in data: | ||||
|         eqsl = "Yes" if data["eqsl"] == 1 else "No" | ||||
|     else: | ||||
|         eqsl = 'Unknown' | ||||
|     if 'mqsl' in data: | ||||
|         mqsl = 'Yes' if data['mqsl'] == 1 else 'No' | ||||
|         eqsl = "Unknown" | ||||
|     if "mqsl" in data: | ||||
|         mqsl = "Yes" if data["mqsl"] == 1 else "No" | ||||
|     else: | ||||
|         mqsl = 'Unknown' | ||||
|     if 'lotw' in data: | ||||
|         lotw = 'Yes' if data['lotw'] == 1 else 'No' | ||||
|         mqsl = "Unknown" | ||||
|     if "lotw" in data: | ||||
|         lotw = "Yes" if data["lotw"] == 1 else "No" | ||||
|     else: | ||||
|         lotw = 'Unknown' | ||||
|         lotw = "Unknown" | ||||
| 
 | ||||
|     return OrderedDict([('Name', name), | ||||
|                         ('Country', data.get('country', None)), | ||||
|                         ('Address', address), | ||||
|                         ('Grid Square', data.get('grid', None)), | ||||
|                         ('County', data.get('county', None)), | ||||
|                         ('CQ Zone', data.get('cqzone', None)), | ||||
|                         ('ITU Zone', data.get('ituzone', None)), | ||||
|                         ('IOTA Designator', data.get('iota', None)), | ||||
|                         ('Expires', data.get('expdate', None)), | ||||
|                         ('Aliases', data.get('aliases', None)), | ||||
|                         ('Previous Callsign', data.get('p_call', None)), | ||||
|                         ('License Class', data.get('class', None)), | ||||
|                         ('Trustee', data.get('trustee', None)), | ||||
|                         ('eQSL?', eqsl), | ||||
|                         ('Paper QSL?', mqsl), | ||||
|                         ('LotW?', lotw), | ||||
|                         ('QSL Info', data.get('qslmgr', None)), | ||||
|                         ('CQ Zone', data.get('cqzone', None)), | ||||
|                         ('ITU Zone', data.get('ituzone', None)), | ||||
|                         ('IOTA Designator', data.get('iota', None)), | ||||
|                         ('Born', data.get('born', None))]) | ||||
|     return OrderedDict([("Name", name), | ||||
|                         ("Country", data.get("country", None)), | ||||
|                         ("Address", address), | ||||
|                         ("Grid Square", data.get("grid", None)), | ||||
|                         ("County", data.get("county", None)), | ||||
|                         ("CQ Zone", data.get("cqzone", None)), | ||||
|                         ("ITU Zone", data.get("ituzone", None)), | ||||
|                         ("IOTA Designator", data.get("iota", None)), | ||||
|                         ("Expires", data.get("expdate", None)), | ||||
|                         ("Aliases", data.get("aliases", None)), | ||||
|                         ("Previous Callsign", data.get("p_call", None)), | ||||
|                         ("License Class", data.get("class", None)), | ||||
|                         ("Trustee", data.get("trustee", None)), | ||||
|                         ("eQSL?", eqsl), | ||||
|                         ("Paper QSL?", mqsl), | ||||
|                         ("LotW?", lotw), | ||||
|                         ("QSL Info", data.get("qslmgr", None)), | ||||
|                         ("CQ Zone", data.get("cqzone", None)), | ||||
|                         ("ITU Zone", data.get("ituzone", None)), | ||||
|                         ("IOTA Designator", data.get("iota", None)), | ||||
|                         ("Born", data.get("born", None))]) | ||||
| 
 | ||||
| 
 | ||||
| def setup(bot): | ||||
|  | ||||
| @ -21,17 +21,17 @@ from resources import study | ||||
| 
 | ||||
| 
 | ||||
| class StudyCog(commands.Cog): | ||||
|     choices = {cmn.emojis.a: 'A', cmn.emojis.b: 'B', cmn.emojis.c: 'C', cmn.emojis.d: 'D'} | ||||
|     choices = {cmn.emojis.a: "A", cmn.emojis.b: "B", cmn.emojis.c: "C", cmn.emojis.d: "D"} | ||||
| 
 | ||||
|     def __init__(self, bot: commands.Bot): | ||||
|         self.bot = bot | ||||
|         self.lastq = dict() | ||||
|         self.source = 'Data courtesy of [HamStudy.org](https://hamstudy.org/)' | ||||
|         self.source = "Data courtesy of [HamStudy.org](https://hamstudy.org/)" | ||||
|         self.session = aiohttp.ClientSession(connector=bot.qrm.connector) | ||||
| 
 | ||||
|     @commands.command(name="hamstudy", aliases=['rq', 'randomquestion', 'randomq'], category=cmn.cat.study) | ||||
|     async def _random_question(self, ctx: commands.Context, country: str = '', level: str = ''): | ||||
|         '''Gets a random question from [HamStudy's](https://hamstudy.org) question pools.''' | ||||
|     @commands.command(name="hamstudy", aliases=["rq", "randomquestion", "randomq"], category=cmn.cat.study) | ||||
|     async def _random_question(self, ctx: commands.Context, country: str = "", level: str = ""): | ||||
|         """Gets a random question from [HamStudy's](https://hamstudy.org) question pools.""" | ||||
|         with ctx.typing(): | ||||
|             embed = cmn.embed_factory(ctx) | ||||
| 
 | ||||
| @ -52,7 +52,7 @@ class StudyCog(commands.Cog): | ||||
|                     embed.description = "Possible arguments are:" | ||||
|                     embed.colour = cmn.colours.bad | ||||
|                     for cty in study.pool_names: | ||||
|                         levels = '`, `'.join(study.pool_names[cty].keys()) | ||||
|                         levels = "`, `".join(study.pool_names[cty].keys()) | ||||
|                         embed.add_field(name=f"**Country: `{cty}` {study.pool_emojis[cty]}**", | ||||
|                                         value=f"Levels: `{levels}`", inline=False) | ||||
|                     embed.add_field(name="**Random**", value="To select a random pool or country, use `random` or `r`") | ||||
| @ -70,7 +70,7 @@ class StudyCog(commands.Cog): | ||||
|                 embed.description = "Possible arguments are:" | ||||
|                 embed.colour = cmn.colours.bad | ||||
|                 for cty in study.pool_names: | ||||
|                     levels = '`, `'.join(study.pool_names[cty].keys()) | ||||
|                     levels = "`, `".join(study.pool_names[cty].keys()) | ||||
|                     embed.add_field(name=f"**Country: `{cty}` {study.pool_emojis[cty]}**", | ||||
|                                     value=f"Levels: `{levels}`", inline=False) | ||||
|                 embed.add_field(name="**Random**", value="To select a random pool or country, use `random` or `r`") | ||||
| @ -99,7 +99,7 @@ class StudyCog(commands.Cog): | ||||
|                 embed.description = "Possible arguments are:" | ||||
|                 embed.colour = cmn.colours.bad | ||||
|                 for cty in study.pool_names: | ||||
|                     levels = '`, `'.join(study.pool_names[cty].keys()) | ||||
|                     levels = "`, `".join(study.pool_names[cty].keys()) | ||||
|                     embed.add_field(name=f"**Country: `{cty}` {study.pool_emojis[cty]}**", | ||||
|                                     value=f"Levels: `{levels}`", inline=False) | ||||
|                 embed.add_field(name="**Random**", value="To select a random pool or country, use `random` or `r`") | ||||
| @ -108,31 +108,31 @@ class StudyCog(commands.Cog): | ||||
| 
 | ||||
|             pool_meta = pools[pool] | ||||
| 
 | ||||
|             async with self.session.get(f'https://hamstudy.org/pools/{pool}') as resp: | ||||
|             async with self.session.get(f"https://hamstudy.org/pools/{pool}") as resp: | ||||
|                 if resp.status != 200: | ||||
|                     raise cmn.BotHTTPError(resp) | ||||
|                 pool = json.loads(await resp.read())['pool'] | ||||
|                 pool = json.loads(await resp.read())["pool"] | ||||
| 
 | ||||
|             # Select a question | ||||
|             pool_section = random.choice(pool)['sections'] | ||||
|             pool_questions = random.choice(pool_section)['questions'] | ||||
|             pool_section = random.choice(pool)["sections"] | ||||
|             pool_questions = random.choice(pool_section)["questions"] | ||||
|             question = random.choice(pool_questions) | ||||
| 
 | ||||
|             embed.title = f"{study.pool_emojis[country]} {pool_meta['class']} {question['id']}" | ||||
|             embed.description = self.source | ||||
|             embed.add_field(name='Question:', value=question['text'], inline=False) | ||||
|             embed.add_field(name='Answers:', | ||||
|             embed.add_field(name="Question:", value=question["text"], inline=False) | ||||
|             embed.add_field(name="Answers:", | ||||
|                             value=(f"**{cmn.emojis.a}** {question['answers']['A']}" | ||||
|                                    f"\n**{cmn.emojis.b}** {question['answers']['B']}" | ||||
|                                    f"\n**{cmn.emojis.c}** {question['answers']['C']}" | ||||
|                                    f"\n**{cmn.emojis.d}** {question['answers']['D']}"), | ||||
|                             inline=False) | ||||
|             embed.add_field(name='To Answer:', | ||||
|                             value=('Answer with reactions below. If not answered within 10 minutes,' | ||||
|                                    ' the answer will be revealed.'), | ||||
|             embed.add_field(name="To Answer:", | ||||
|                             value=("Answer with reactions below. If not answered within 10 minutes," | ||||
|                                    " the answer will be revealed."), | ||||
|                             inline=False) | ||||
|             if 'image' in question: | ||||
|                 image_url = f'https://hamstudy.org/_1330011/images/{pool.split("_",1)[1]}/{question["image"]}' | ||||
|             if "image" in question: | ||||
|                 image_url = f"https://hamstudy.org/_1330011/images/{pool.split('_',1)[1]}/{question['image']}" | ||||
|                 embed.set_image(url=image_url) | ||||
| 
 | ||||
|         q_msg = await ctx.send(embed=embed) | ||||
| @ -148,13 +148,13 @@ class StudyCog(commands.Cog): | ||||
|                     and str(reaction.emoji) in self.choices.keys()) | ||||
| 
 | ||||
|         try: | ||||
|             reaction, user = await self.bot.wait_for('reaction_add', timeout=600.0, check=check) | ||||
|             reaction, user = await self.bot.wait_for("reaction_add", timeout=600.0, check=check) | ||||
|         except asyncio.TimeoutError: | ||||
|             embed.remove_field(2) | ||||
|             embed.add_field(name="Answer:", value=f"Timed out! The correct answer was **{question['answer']}**.") | ||||
|             await q_msg.edit(embed=embed) | ||||
|         else: | ||||
|             if self.choices[str(reaction.emoji)] == question['answer']: | ||||
|             if self.choices[str(reaction.emoji)] == question["answer"]: | ||||
|                 embed.remove_field(2) | ||||
|                 embed.add_field(name="Answer:", value=f"Correct! The answer was **{question['answer']}**.") | ||||
|                 embed.colour = cmn.colours.good | ||||
| @ -166,7 +166,7 @@ class StudyCog(commands.Cog): | ||||
|                 await q_msg.edit(embed=embed) | ||||
| 
 | ||||
|     async def hamstudy_get_pools(self): | ||||
|         async with self.session.get('https://hamstudy.org/pools/') as resp: | ||||
|         async with self.session.get("https://hamstudy.org/pools/") as resp: | ||||
|             if resp.status != 200: | ||||
|                 raise cmn.BotHTTPError(resp) | ||||
|             else: | ||||
|  | ||||
| @ -25,23 +25,23 @@ class WeatherCog(commands.Cog): | ||||
|         self.bot = bot | ||||
|         self.session = aiohttp.ClientSession(connector=bot.qrm.connector) | ||||
| 
 | ||||
|     @commands.command(name="bandconditions", aliases=['cond', 'condx', 'conditions'], category=cmn.cat.weather) | ||||
|     @commands.command(name="bandconditions", aliases=["cond", "condx", "conditions"], category=cmn.cat.weather) | ||||
|     async def _band_conditions(self, ctx: commands.Context): | ||||
|         '''Posts an image of HF Band Conditions.''' | ||||
|         """Posts an image of HF Band Conditions.""" | ||||
|         async with ctx.typing(): | ||||
|             embed = cmn.embed_factory(ctx) | ||||
|             embed.title = 'Current Solar Conditions' | ||||
|             embed.title = "Current Solar Conditions" | ||||
|             embed.colour = cmn.colours.good | ||||
|             async with self.session.get('http://www.hamqsl.com/solarsun.php') as resp: | ||||
|             async with self.session.get("http://www.hamqsl.com/solarsun.php") as resp: | ||||
|                 if resp.status != 200: | ||||
|                     raise cmn.BotHTTPError(resp) | ||||
|                 data = io.BytesIO(await resp.read()) | ||||
|             embed.set_image(url=f'attachment://condx.png') | ||||
|             await ctx.send(embed=embed, file=discord.File(data, 'condx.png')) | ||||
|             embed.set_image(url=f"attachment://condx.png") | ||||
|             await ctx.send(embed=embed, file=discord.File(data, "condx.png")) | ||||
| 
 | ||||
|     @commands.group(name="weather", aliases=['wttr'], category=cmn.cat.weather) | ||||
|     @commands.group(name="weather", aliases=["wttr"], category=cmn.cat.weather) | ||||
|     async def _weather_conditions(self, ctx: commands.Context): | ||||
|         '''Posts an image of Local Weather Conditions from [wttr.in](http://wttr.in/). | ||||
|         """Posts an image of Local Weather Conditions from [wttr.in](http://wttr.in/). | ||||
| 
 | ||||
| *Supported location types:* | ||||
|     city name: `paris` | ||||
| @ -51,71 +51,71 @@ class WeatherCog(commands.Cog): | ||||
|     domain name `@stackoverflow.com` | ||||
|     area codes: `12345` | ||||
|     GPS coordinates: `-78.46,106.79` | ||||
|         ''' | ||||
|         """ | ||||
|         if ctx.invoked_subcommand is None: | ||||
|             await ctx.send_help(ctx.command) | ||||
| 
 | ||||
|     @_weather_conditions.command(name='forecast', aliases=['fc', 'future'], category=cmn.cat.weather) | ||||
|     @_weather_conditions.command(name="forecast", aliases=["fc", "future"], category=cmn.cat.weather) | ||||
|     async def _weather_conditions_forecast(self, ctx: commands.Context, *, location: str): | ||||
|         '''Posts an image of Local Weather Conditions for the next three days from [wttr.in](http://wttr.in/). | ||||
| See help for weather command for possible location types. Add a `-c` or `-f` to use Celcius or Fahrenheit.''' | ||||
|         """Posts an image of Local Weather Conditions for the next three days from [wttr.in](http://wttr.in/). | ||||
| See help for weather command for possible location types. Add a `-c` or `-f` to use Celcius or Fahrenheit.""" | ||||
|         async with ctx.typing(): | ||||
|             try: | ||||
|                 units_arg = re.search(self.wttr_units_regex, location).group(1) | ||||
|             except AttributeError: | ||||
|                 units_arg = '' | ||||
|             if units_arg.lower() == 'f': | ||||
|                 units = 'u' | ||||
|             elif units_arg.lower() == 'c': | ||||
|                 units = 'm' | ||||
|                 units_arg = "" | ||||
|             if units_arg.lower() == "f": | ||||
|                 units = "u" | ||||
|             elif units_arg.lower() == "c": | ||||
|                 units = "m" | ||||
|             else: | ||||
|                 units = '' | ||||
|                 units = "" | ||||
| 
 | ||||
|             loc = self.wttr_units_regex.sub('', location).strip() | ||||
|             loc = self.wttr_units_regex.sub("", location).strip() | ||||
| 
 | ||||
|             embed = cmn.embed_factory(ctx) | ||||
|             embed.title = f'Weather Forecast for {loc}' | ||||
|             embed.description = 'Data from [wttr.in](http://wttr.in/).' | ||||
|             embed.title = f"Weather Forecast for {loc}" | ||||
|             embed.description = "Data from [wttr.in](http://wttr.in/)." | ||||
|             embed.colour = cmn.colours.good | ||||
| 
 | ||||
|             loc = loc.replace(' ', '+') | ||||
|             async with self.session.get(f'http://wttr.in/{loc}_{units}pnFQ.png') as resp: | ||||
|             loc = loc.replace(" ", "+") | ||||
|             async with self.session.get(f"http://wttr.in/{loc}_{units}pnFQ.png") as resp: | ||||
|                 if resp.status != 200: | ||||
|                     raise cmn.BotHTTPError(resp) | ||||
|                 data = io.BytesIO(await resp.read()) | ||||
|             embed.set_image(url=f'attachment://wttr_forecast.png') | ||||
|             await ctx.send(embed=embed, file=discord.File(data, 'wttr_forecast.png')) | ||||
|             embed.set_image(url=f"attachment://wttr_forecast.png") | ||||
|             await ctx.send(embed=embed, file=discord.File(data, "wttr_forecast.png")) | ||||
| 
 | ||||
|     @_weather_conditions.command(name='now', aliases=['n'], category=cmn.cat.weather) | ||||
|     @_weather_conditions.command(name="now", aliases=["n"], category=cmn.cat.weather) | ||||
|     async def _weather_conditions_now(self, ctx: commands.Context, *, location: str): | ||||
|         '''Posts an image of current Local Weather Conditions from [wttr.in](http://wttr.in/). | ||||
| See help for weather command for possible location types. Add a `-c` or `-f` to use Celcius or Fahrenheit.''' | ||||
|         """Posts an image of current Local Weather Conditions from [wttr.in](http://wttr.in/). | ||||
| See help for weather command for possible location types. Add a `-c` or `-f` to use Celcius or Fahrenheit.""" | ||||
|         async with ctx.typing(): | ||||
|             try: | ||||
|                 units_arg = re.search(self.wttr_units_regex, location).group(1) | ||||
|             except AttributeError: | ||||
|                 units_arg = '' | ||||
|             if units_arg.lower() == 'f': | ||||
|                 units = 'u' | ||||
|             elif units_arg.lower() == 'c': | ||||
|                 units = 'm' | ||||
|                 units_arg = "" | ||||
|             if units_arg.lower() == "f": | ||||
|                 units = "u" | ||||
|             elif units_arg.lower() == "c": | ||||
|                 units = "m" | ||||
|             else: | ||||
|                 units = '' | ||||
|                 units = "" | ||||
| 
 | ||||
|             loc = self.wttr_units_regex.sub('', location).strip() | ||||
|             loc = self.wttr_units_regex.sub("", location).strip() | ||||
| 
 | ||||
|             embed = cmn.embed_factory(ctx) | ||||
|             embed.title = f'Current Weather for {loc}' | ||||
|             embed.description = 'Data from [wttr.in](http://wttr.in/).' | ||||
|             embed.title = f"Current Weather for {loc}" | ||||
|             embed.description = "Data from [wttr.in](http://wttr.in/)." | ||||
|             embed.colour = cmn.colours.good | ||||
| 
 | ||||
|             loc = loc.replace(' ', '+') | ||||
|             async with self.session.get(f'http://wttr.in/{loc}_0{units}pnFQ.png') as resp: | ||||
|             loc = loc.replace(" ", "+") | ||||
|             async with self.session.get(f"http://wttr.in/{loc}_0{units}pnFQ.png") as resp: | ||||
|                 if resp.status != 200: | ||||
|                     raise cmn.BotHTTPError(resp) | ||||
|                 data = io.BytesIO(await resp.read()) | ||||
|             embed.set_image(url=f'attachment://wttr_now.png') | ||||
|             await ctx.send(embed=embed, file=discord.File(data, 'wttr_now.png')) | ||||
|             embed.set_image(url=f"attachment://wttr_now.png") | ||||
|             await ctx.send(embed=embed, file=discord.File(data, "wttr_now.png")) | ||||
| 
 | ||||
| 
 | ||||
| def setup(bot: commands.Bot): | ||||
|  | ||||
							
								
								
									
										4
									
								
								info.py
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								info.py
									
									
									
									
									
								
							| @ -24,5 +24,5 @@ authors = ("@ClassAbbyAmplifier#2229", "@0x5c#0639") | ||||
| description = """A bot with various useful ham radio-related functions, written in Python.""" | ||||
| license = "Released under the GNU General Public License v2" | ||||
| contributing = "Check out the source on GitHub, contributions welcome: https://github.com/classabbyamp/discord-qrm2" | ||||
| release = '2.1.0' | ||||
| bot_server = 'https://discord.gg/Ntbg3J4' | ||||
| release = "2.1.0" | ||||
| bot_server = "https://discord.gg/Ntbg3J4" | ||||
|  | ||||
							
								
								
									
										6
									
								
								main.py
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								main.py
									
									
									
									
									
								
							| @ -167,7 +167,7 @@ async def on_command_error(ctx: commands.Context, err: commands.CommandError): | ||||
|         await cmn.add_react(ctx.message, cmn.emojis.bangbang) | ||||
|     elif isinstance(err, (commands.CommandInvokeError, commands.ConversionError)): | ||||
|         # Emulating discord.py's default beaviour. | ||||
|         print('Ignoring exception in command {}:'.format(ctx.command), file=sys.stderr) | ||||
|         print("Ignoring exception in command {}:".format(ctx.command), file=sys.stderr) | ||||
|         traceback.print_exception(type(err), err, err.__traceback__, file=sys.stderr) | ||||
| 
 | ||||
|         embed = cmn.error_embed_factory(ctx, err.original, bot.qrm.debug_mode) | ||||
| @ -176,7 +176,7 @@ async def on_command_error(ctx: commands.Context, err: commands.CommandError): | ||||
|         await ctx.send(embed=embed) | ||||
|     else: | ||||
|         # Emulating discord.py's default beaviour. (safest bet) | ||||
|         print('Ignoring exception in command {}:'.format(ctx.command), file=sys.stderr) | ||||
|         print("Ignoring exception in command {}:".format(ctx.command), file=sys.stderr) | ||||
|         traceback.print_exception(type(err), err, err.__traceback__, file=sys.stderr) | ||||
|         await cmn.add_react(ctx.message, cmn.emojis.warning) | ||||
| 
 | ||||
| @ -221,7 +221,7 @@ async def _ensure_activity_fixed(): | ||||
| # --- Run --- | ||||
| 
 | ||||
| for ext in opt.exts: | ||||
|     bot.load_extension(ext_dir + '.' + ext) | ||||
|     bot.load_extension(ext_dir + "." + ext) | ||||
| 
 | ||||
| 
 | ||||
| try: | ||||
|  | ||||
| @ -11,45 +11,45 @@ from collections import OrderedDict | ||||
| 
 | ||||
| 
 | ||||
| us_calls_title = "Valid US Vanity Callsigns" | ||||
| us_calls_desc = ('#x# is the number of letters in the prefix and suffix of a callsign. ' | ||||
|                  'E.g., WY4RC would be a 2x2 callsign, with prefix WY and suffix RC.') | ||||
| us_calls = OrderedDict([('**Group A** (Extra Only)', ('**Any:** K, N, W (1x2)\n' | ||||
|                                                       '    AA-AL, KA-KZ, NA-NZ, WA-WZ (2x1)\n' | ||||
|                                                       '    AA-AL (2x2)\n' | ||||
|                                                       '*Except*\n' | ||||
|                                                       '**Alaska:** AL, KL, NL, WL (2x1)\n' | ||||
|                                                       '**Caribbean:** KP, NP, WP (2x1)\n' | ||||
|                                                       '**Pacific:** AH, KH, NH, WH (2x1)')), | ||||
|                         ('**Group B** (Advanced and Extra Only)', ('**Any:** KA-KZ, NA-NZ, WA-WZ (2x2)\n' | ||||
|                                                                    '*Except*\n' | ||||
|                                                                    '**Alaska:** AL (2x2)\n' | ||||
|                                                                    '**Caribbean:** KP (2x2)\n' | ||||
|                                                                    '**Pacific:** AH (2x2)')), | ||||
|                         ('**Group C** (Technician, General, Advanced, Extra Only)', ('**Any Region:** K, N, W (1x3)\n' | ||||
|                                                                                      '*Except*\n' | ||||
|                                                                                      '**Alaska:** KL, NL, WL (2x2)\n' | ||||
|                                                                                      '**Caribbean:** NP, WP (2x2)\n' | ||||
|                                                                                      '**Pacific:** KH, NH, WH (2x2)')), | ||||
|                         ('**Group D** (Any License Class)', ('**Any Region:** KA-KZ, WA-WZ (2x3)\n' | ||||
|                                                              '*Except*\n' | ||||
|                                                              '**Alaska:** KL, WL (2x3)\n' | ||||
|                                                              '**Caribbean:** KP, WP (2x3)\n' | ||||
|                                                              '**Pacific:** KH, WH (2x3)')), | ||||
|                         ('**Unavailable**', ('- KA2AA-KA9ZZ: US Army in Japan\n' | ||||
|                                              '- KC4AAA-KC4AAF: NSF in Antartica\n' | ||||
|                                              '- KC4USA-KC4USZ: US Navy in Antartica\n' | ||||
|                                              '- KG4AA-KG4ZZ: US Navy in Guantanamo Bay\n' | ||||
|                                              '- KL9KAA-KL9KHZ: US military in Korea\n' | ||||
|                                              '- KC6AA-KC6ZZ: Former US (Eastern and Western Caroline Islands), ' | ||||
|                                              'now Federated States of Micronesia (V6) and Republic of Palau (T8)\n' | ||||
|                                              '- KX6AA-KX6ZZ: Former US (Marshall Islands), ' | ||||
|                                              'now Republic of the Marshall Islands (V73)\n' | ||||
|                                              '- Any suffix SOS or QRA-QUZ\n' | ||||
|                                              '- Any 2x3 with X as the first suffix letter\n' | ||||
|                                              '- Any 2x3 with AF, KF, NF, or WF prefix and suffix EMA: FEMA\n' | ||||
|                                              '- Any 2x3 with AA-AL, NA-NZ, WC, WK, WM, WR, or WT prefix: "Group X"\n' | ||||
|                                              '- Any 2x1, 2x2, or 2x3 with KP, NP, WP prefix and 0, 6, 7, 8, 9 number\n' | ||||
|                                              '- Any 1x1 callsign: Special Event'))]) | ||||
| us_calls_desc = ("#x# is the number of letters in the prefix and suffix of a callsign. " | ||||
|                  "E.g., WY4RC would be a 2x2 callsign, with prefix WY and suffix RC.") | ||||
| us_calls = OrderedDict([("**Group A** (Extra Only)", ("**Any:** K, N, W (1x2)\n" | ||||
|                                                       "    AA-AL, KA-KZ, NA-NZ, WA-WZ (2x1)\n" | ||||
|                                                       "    AA-AL (2x2)\n" | ||||
|                                                       "*Except*\n" | ||||
|                                                       "**Alaska:** AL, KL, NL, WL (2x1)\n" | ||||
|                                                       "**Caribbean:** KP, NP, WP (2x1)\n" | ||||
|                                                       "**Pacific:** AH, KH, NH, WH (2x1)")), | ||||
|                         ("**Group B** (Advanced and Extra Only)", ("**Any:** KA-KZ, NA-NZ, WA-WZ (2x2)\n" | ||||
|                                                                    "*Except*\n" | ||||
|                                                                    "**Alaska:** AL (2x2)\n" | ||||
|                                                                    "**Caribbean:** KP (2x2)\n" | ||||
|                                                                    "**Pacific:** AH (2x2)")), | ||||
|                         ("**Group C** (Technician, General, Advanced, Extra Only)", ("**Any Region:** K, N, W (1x3)\n" | ||||
|                                                                                      "*Except*\n" | ||||
|                                                                                      "**Alaska:** KL, NL, WL (2x2)\n" | ||||
|                                                                                      "**Caribbean:** NP, WP (2x2)\n" | ||||
|                                                                                      "**Pacific:** KH, NH, WH (2x2)")), | ||||
|                         ("**Group D** (Any License Class)", ("**Any Region:** KA-KZ, WA-WZ (2x3)\n" | ||||
|                                                              "*Except*\n" | ||||
|                                                              "**Alaska:** KL, WL (2x3)\n" | ||||
|                                                              "**Caribbean:** KP, WP (2x3)\n" | ||||
|                                                              "**Pacific:** KH, WH (2x3)")), | ||||
|                         ("**Unavailable**", ("- KA2AA-KA9ZZ: US Army in Japan\n" | ||||
|                                              "- KC4AAA-KC4AAF: NSF in Antartica\n" | ||||
|                                              "- KC4USA-KC4USZ: US Navy in Antartica\n" | ||||
|                                              "- KG4AA-KG4ZZ: US Navy in Guantanamo Bay\n" | ||||
|                                              "- KL9KAA-KL9KHZ: US military in Korea\n" | ||||
|                                              "- KC6AA-KC6ZZ: Former US (Eastern and Western Caroline Islands), " | ||||
|                                              "now Federated States of Micronesia (V6) and Republic of Palau (T8)\n" | ||||
|                                              "- KX6AA-KX6ZZ: Former US (Marshall Islands), " | ||||
|                                              "now Republic of the Marshall Islands (V73)\n" | ||||
|                                              "- Any suffix SOS or QRA-QUZ\n" | ||||
|                                              "- Any 2x3 with X as the first suffix letter\n" | ||||
|                                              "- Any 2x3 with AF, KF, NF, or WF prefix and suffix EMA: FEMA\n" | ||||
|                                              "- Any 2x3 with AA-AL, NA-NZ, WC, WK, WM, WR, or WT prefix: \"Group X\"\n" | ||||
|                                              "- Any 2x1, 2x2, or 2x3 with KP, NP, WP prefix and 0, 6, 7, 8, 9 number\n" | ||||
|                                              "- Any 1x1 callsign: Special Event"))]) | ||||
| 
 | ||||
| # format: country: (title, description, text) | ||||
| options = {'us': (us_calls_title, us_calls_desc, us_calls)} | ||||
| options = {"us": (us_calls_title, us_calls_desc, us_calls)} | ||||
|  | ||||
| @ -7,8 +7,8 @@ This file is part of discord-qrmbot and is released under the terms of the GNU | ||||
| General Public License, version 2. | ||||
| """ | ||||
| 
 | ||||
| phonetics = {'a': 'alfa', 'b': 'bravo', 'c': 'charlie', 'd': 'delta', 'e': 'echo', 'f': 'foxtrot', | ||||
|              'g': 'golf', 'h': 'hotel', 'i': 'india', 'j': 'juliett', 'k': 'kilo', 'l': 'lima', | ||||
|              'm': 'mike', 'n': 'november', 'o': 'oscar', 'p': 'papa', 'q': 'quebec', 'r': 'romeo', | ||||
|              's': 'sierra', 't': 'tango', 'u': 'uniform', 'v': 'victor', 'w': 'whiskey', 'x': 'x-ray', | ||||
|              'y': 'yankee', 'z': 'zulu'} | ||||
| phonetics = {"a": "alfa", "b": "bravo", "c": "charlie", "d": "delta", "e": "echo", "f": "foxtrot", | ||||
|              "g": "golf", "h": "hotel", "i": "india", "j": "juliett", "k": "kilo", "l": "lima", | ||||
|              "m": "mike", "n": "november", "o": "oscar", "p": "papa", "q": "quebec", "r": "romeo", | ||||
|              "s": "sierra", "t": "tango", "u": "uniform", "v": "victor", "w": "whiskey", "x": "x-ray", | ||||
|              "y": "yankee", "z": "zulu"} | ||||
|  | ||||
| @ -7,43 +7,43 @@ This file is part of discord-qrmbot and is released under the terms of the GNU | ||||
| General Public License, version 2. | ||||
| """ | ||||
| 
 | ||||
| pool_names = {'us': {'technician': 'E2', | ||||
|                      'tech': 'E2', | ||||
|                      't': 'E2', | ||||
|                      'general': 'E3', | ||||
|                      'gen': 'E3', | ||||
|                      'g': 'E3', | ||||
|                      'extra': 'E4', | ||||
|                      'e': 'E4'}, | ||||
|               'ca': {'basic': 'CA_B', | ||||
|                      'b': 'CA_B', | ||||
|                      'advanced': 'CA_A', | ||||
|                      'adv': 'CA_A', | ||||
|                      'a': 'CA_A', | ||||
|                      'basic_fr': 'CA_FB', | ||||
|                      'b_fr': 'CA_FB', | ||||
|                      'base': 'CA_FB', | ||||
|                      'advanced_fr': 'CA_FS', | ||||
|                      'adv_fr': 'CA_FS', | ||||
|                      'a_fr': 'CA_FS', | ||||
|                      'supérieure': 'CA_FS', | ||||
|                      'superieure': 'CA_FS', | ||||
|                      's': 'CA_FS'}, | ||||
|               'us_c': {'c1': 'C1', | ||||
|                        'comm1': 'C1', | ||||
|                        'c3': 'C3', | ||||
|                        'comm3': 'C3', | ||||
|                        'c6': 'C6', | ||||
|                        'comm6': 'C6', | ||||
|                        'c7': 'C7', | ||||
|                        'comm7': 'C7', | ||||
|                        'c7r': 'C7R', | ||||
|                        'comm7r': 'C7R', | ||||
|                        'c8': 'C8', | ||||
|                        'comm8': 'C8', | ||||
|                        'c9': 'C9', | ||||
|                        'comm9': 'C9'}} | ||||
| pool_names = {"us": {"technician": "E2", | ||||
|                      "tech": "E2", | ||||
|                      "t": "E2", | ||||
|                      "general": "E3", | ||||
|                      "gen": "E3", | ||||
|                      "g": "E3", | ||||
|                      "extra": "E4", | ||||
|                      "e": "E4"}, | ||||
|               "ca": {"basic": "CA_B", | ||||
|                      "b": "CA_B", | ||||
|                      "advanced": "CA_A", | ||||
|                      "adv": "CA_A", | ||||
|                      "a": "CA_A", | ||||
|                      "basic_fr": "CA_FB", | ||||
|                      "b_fr": "CA_FB", | ||||
|                      "base": "CA_FB", | ||||
|                      "advanced_fr": "CA_FS", | ||||
|                      "adv_fr": "CA_FS", | ||||
|                      "a_fr": "CA_FS", | ||||
|                      "supérieure": "CA_FS", | ||||
|                      "superieure": "CA_FS", | ||||
|                      "s": "CA_FS"}, | ||||
|               "us_c": {"c1": "C1", | ||||
|                        "comm1": "C1", | ||||
|                        "c3": "C3", | ||||
|                        "comm3": "C3", | ||||
|                        "c6": "C6", | ||||
|                        "comm6": "C6", | ||||
|                        "c7": "C7", | ||||
|                        "comm7": "C7", | ||||
|                        "c7r": "C7R", | ||||
|                        "comm7r": "C7R", | ||||
|                        "c8": "C8", | ||||
|                        "comm8": "C8", | ||||
|                        "c9": "C9", | ||||
|                        "comm9": "C9"}} | ||||
| 
 | ||||
| pool_emojis = {'us': '🇺🇸', | ||||
|                'ca': '🇨🇦', | ||||
|                'us_c': '🇺🇸 🏢'} | ||||
| pool_emojis = {"us": "🇺🇸", | ||||
|                "ca": "🇨🇦", | ||||
|                "us_c": "🇺🇸 🏢"} | ||||
|  | ||||
| @ -27,7 +27,7 @@ debug = False | ||||
| owners_uids = (200102491231092736,) | ||||
| 
 | ||||
| # The extensions to load when running the bot. | ||||
| exts = ['ae7q', 'base', 'fun', 'grid', 'ham', 'image', 'lookup', 'morse', 'qrz', 'study', 'weather'] | ||||
| exts = ["ae7q", "base", "fun", "grid", "ham", "image", "lookup", "morse", "qrz", "study", "weather"] | ||||
| 
 | ||||
| # Either "time", "random", or "fixed" (first item in statuses) | ||||
| status_mode = "fixed" | ||||
| @ -37,17 +37,17 @@ statuses = ["with lids on the air", "with fire"] | ||||
| 
 | ||||
| # Timezone for the status (string) | ||||
| # See https://pythonhosted.org/pytz/ for more info | ||||
| status_tz = 'US/Eastern' | ||||
| status_tz = "US/Eastern" | ||||
| 
 | ||||
| # The text to put in the "playing" status, with start and stop times | ||||
| time_statuses = [('with lids on 3.840', (00, 00), (6, 00)), | ||||
|                  ('with lids on 7.200', (6, 00), (10, 00)), | ||||
|                  ('with lids on 14.313', (10, 00), (18, 00)), | ||||
|                  ('with lids on 7.200', (18, 00), (20, 00)), | ||||
|                  ('with lids on 3.840', (20, 00), (23, 59))] | ||||
| time_statuses = [("with lids on 3.840", (00, 00), (6, 00)), | ||||
|                  ("with lids on 7.200", (6, 00), (10, 00)), | ||||
|                  ("with lids on 14.313", (10, 00), (18, 00)), | ||||
|                  ("with lids on 7.200", (18, 00), (20, 00)), | ||||
|                  ("with lids on 3.840", (20, 00), (23, 59))] | ||||
| 
 | ||||
| # Emoji IDs and keywords for emoji reactions | ||||
| # Use the format {emoji_id (int): ('tuple', 'of', 'lowercase', 'keywords')} | ||||
| # Use the format {emoji_id (int): ("tuple", "of", "lowercase", "keywords")} | ||||
| msg_reacts = {} | ||||
| 
 | ||||
| # A :pika: emote's ID, None for no emote :c | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user