mirror of
https://github.com/miaowware/qrm2.git
synced 2026-06-02 22:14:53 -04:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f4ed93dc76 | |||
| 2cb4b03532 | |||
| bc93462c29 | |||
| 6867c45c8c | |||
| dcbb7acab8 | |||
| 3803ce6045 | |||
| 8ca4911072 | |||
| 6e2468f04f | |||
| b17a8a1749 | |||
| 8dfa7001ef | |||
| f6ed8430b9 | |||
| d650cbd6c1 | |||
| 4d9f9d1b19 | |||
| 1c649aacc2 | |||
| 2049ca9fca |
@@ -0,0 +1,58 @@
|
|||||||
|
name: Docker Build and Push
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
# Publish `master` as Docker `dev` image.
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
# Publish `v*` tags as releases and as `latest`.
|
||||||
|
tags:
|
||||||
|
- v*
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE_NAME: qrm2
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-push:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Build image
|
||||||
|
run: |
|
||||||
|
echo ${{ github.sha }} > git_commit
|
||||||
|
docker build . --file Dockerfile -t $IMAGE_NAME
|
||||||
|
|
||||||
|
- name: Log into Github Package Registry
|
||||||
|
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login docker.pkg.github.com -u ${{ github.actor }} --password-stdin
|
||||||
|
|
||||||
|
- name: Log into Docker Hub
|
||||||
|
run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
|
||||||
|
|
||||||
|
- name: Push image to registries
|
||||||
|
run: |
|
||||||
|
GITHUB_IMAGE_ID=docker.pkg.github.com/${{ github.repository }}/$IMAGE_NAME
|
||||||
|
DOCKER_IMAGE_ID=${{ secrets.DOCKER_USERNAME }}/$IMAGE_NAME
|
||||||
|
|
||||||
|
# Strip git ref prefix from version
|
||||||
|
VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
|
||||||
|
|
||||||
|
# Strip "v" prefix from tag name
|
||||||
|
[[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
|
||||||
|
|
||||||
|
[[ "$VERSION" == "master" ]] && VERSION=dev
|
||||||
|
|
||||||
|
echo GITHUB_IMAGE_ID=$GITHUB_IMAGE_ID
|
||||||
|
echo DOCKER_IMAGE_ID=$DOCKER_IMAGE_ID
|
||||||
|
echo VERSION=$VERSION
|
||||||
|
|
||||||
|
# tag for Github Registry
|
||||||
|
docker tag $IMAGE_NAME $GITHUB_IMAGE_ID:$VERSION
|
||||||
|
[[ "$VERSION" != "dev" ]] && docker tag $IMAGE_NAME $GITHUB_IMAGE_ID:latest
|
||||||
|
docker push $GITHUB_IMAGE_ID
|
||||||
|
|
||||||
|
# tag for Docker Hub
|
||||||
|
docker tag $IMAGE_NAME $DOCKER_IMAGE_ID:$VERSION
|
||||||
|
[[ "$VERSION" != "dev" ]] && docker tag $IMAGE_NAME $DOCKER_IMAGE_ID:latest
|
||||||
|
docker push $DOCKER_IMAGE_ID
|
||||||
+23
-1
@@ -7,6 +7,25 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
|
||||||
|
## [2.3.0] - 2020-03-30
|
||||||
|
### Added
|
||||||
|
- `?phoneticweight` command, which calculates a message's length in syllables.
|
||||||
|
- `?standards` command to display [xkcd 927](https://xkcd.com/927/).
|
||||||
|
### Changed
|
||||||
|
- Python>=3.7 now required.
|
||||||
|
|
||||||
|
|
||||||
|
## [2.2.3] - 2020-03-29
|
||||||
|
### Fixed
|
||||||
|
- Commands are no longer case-sensitive.
|
||||||
|
|
||||||
|
|
||||||
|
## [2.2.2] - 2020-02-25
|
||||||
|
### Fixed
|
||||||
|
- Fixed issue where HamStudy questions with images would cause an error.
|
||||||
|
- Added/fixed/removed typing indicators in numerous commands.
|
||||||
|
|
||||||
|
|
||||||
## [2.2.1] - 2020-02-20
|
## [2.2.1] - 2020-02-20
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fixed issue where some HamStudy pools will become unselectable.
|
- Fixed issue where some HamStudy pools will become unselectable.
|
||||||
@@ -81,7 +100,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
## 1.0.0 - 2019-07-31 [YANKED]
|
## 1.0.0 - 2019-07-31 [YANKED]
|
||||||
|
|
||||||
|
|
||||||
[Unreleased]: https://github.com/miaowware/qrm2/compare/v2.2.0...HEAD
|
[Unreleased]: https://github.com/miaowware/qrm2/compare/v2.2.3...HEAD
|
||||||
|
[2.2.3]: https://github.com/miaowware/qrm2/releases/tag/v2.2.3
|
||||||
|
[2.2.2]: https://github.com/miaowware/qrm2/releases/tag/v2.2.2
|
||||||
|
[2.2.1]: https://github.com/miaowware/qrm2/releases/tag/v2.2.1
|
||||||
[2.2.0]: https://github.com/miaowware/qrm2/releases/tag/v2.2.0
|
[2.2.0]: https://github.com/miaowware/qrm2/releases/tag/v2.2.0
|
||||||
[2.1.0]: https://github.com/miaowware/qrm2/releases/tag/v2.1.0
|
[2.1.0]: https://github.com/miaowware/qrm2/releases/tag/v2.1.0
|
||||||
[2.0.0]: https://github.com/miaowware/qrm2/releases/tag/v2.0.0
|
[2.0.0]: https://github.com/miaowware/qrm2/releases/tag/v2.0.0
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ See [README-DOCKER.md](./README-DOCKER.md)
|
|||||||
|
|
||||||
### Without Docker
|
### Without Docker
|
||||||
|
|
||||||
|
Requires Python 3.7 or newer.
|
||||||
|
|
||||||
Prep the environment. For more information on extra options, see the [quick-bot-no-pain Makefile documentation](https://github.com/0x5c/quick-bot-no-pain/blob/master/docs/makefile.md).
|
Prep the environment. For more information on extra options, see the [quick-bot-no-pain Makefile documentation](https://github.com/0x5c/quick-bot-no-pain/blob/master/docs/makefile.md).
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"_id": "56956f51f65e5c590272e372",
|
||||||
|
"appears": "2016-04-01T06:00:00.000Z",
|
||||||
|
"class": "Amateur Extra",
|
||||||
|
"subtext": "Expires Jul 1, 2020",
|
||||||
|
"valid_from": "2016-07-01T06:00:00.000Z",
|
||||||
|
"expires": "2020-07-01T06:00:00.000Z",
|
||||||
|
"official_name": "Element 4",
|
||||||
|
"id": "E4_2016",
|
||||||
|
"slug": "extra2016",
|
||||||
|
"passing": 37,
|
||||||
|
"year": 2016,
|
||||||
|
"pool": [{
|
||||||
|
"_id": "5cd63f15910d9b003d545bd7",
|
||||||
|
"qcount": 4,
|
||||||
|
"id": "E5",
|
||||||
|
"name": "ELECTRICAL PRINCIPLES",
|
||||||
|
"sections": [{
|
||||||
|
"_id": "5cd63f15910d9b003d545beb",
|
||||||
|
"id": "E5C",
|
||||||
|
"questions": [{
|
||||||
|
"_id": "5cd63f15910d9b003d545bef",
|
||||||
|
"keywords": ["4"],
|
||||||
|
"answer": "B",
|
||||||
|
"answers": {
|
||||||
|
"A": "Point 2",
|
||||||
|
"B": "Point 4",
|
||||||
|
"C": "Point 5",
|
||||||
|
"D": "Point 6"
|
||||||
|
},
|
||||||
|
"fccpart": "",
|
||||||
|
"id": "E5C14",
|
||||||
|
"image": "E5-2.png",
|
||||||
|
"text": "Which point on Figure E5-2 best represents the impedance of a series circuit consisting of a 400 ohm resistor and a 38 picofarad capacitor at 14 MHz?"
|
||||||
|
}],
|
||||||
|
"summary": "Coordinate systems and phasors in electronics: Rectangular Coordinates; Polar Coordinates; Phasors"
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"updated": "2019-05-11T03:18:46.121Z",
|
||||||
|
"category": "default",
|
||||||
|
"testIdEnd": 19999,
|
||||||
|
"testIdStart": 10000,
|
||||||
|
"__v": 12,
|
||||||
|
"mat_icon": "flash_on",
|
||||||
|
"tagline": "Serious General operators only! This is the most advanced US license class!",
|
||||||
|
"keywords": ["ham radio extra test prep", "amateur extra class radio study", "amateur extra class ham exam", "ham radio amateur extra test 2016", "2016 amateur extra class", "ham radio license exam", "extra class flash card"],
|
||||||
|
"replaces": "E4_2012"
|
||||||
|
}
|
||||||
+1
-1
@@ -29,7 +29,7 @@ class AE7QCog(commands.Cog):
|
|||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.session = aiohttp.ClientSession(connector=bot.qrm.connector)
|
self.session = aiohttp.ClientSession(connector=bot.qrm.connector)
|
||||||
|
|
||||||
@commands.group(name="ae7q", aliases=["ae"], category=cmn.cat.lookup)
|
@commands.group(name="ae7q", aliases=["ae"], case_insensitive=True, category=cmn.cat.lookup)
|
||||||
async def _ae7q_lookup(self, ctx: commands.Context):
|
async def _ae7q_lookup(self, ctx: commands.Context):
|
||||||
"""Looks up a callsign, FRN, or Licensee ID on [ae7q.com](http://ae7q.com/)."""
|
"""Looks up a callsign, FRN, or Licensee ID on [ae7q.com](http://ae7q.com/)."""
|
||||||
if ctx.invoked_subcommand is None:
|
if ctx.invoked_subcommand is None:
|
||||||
|
|||||||
+1
-2
@@ -10,7 +10,6 @@ the GNU General Public License, version 2.
|
|||||||
|
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
from collections import OrderedDict
|
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
@@ -189,7 +188,7 @@ class BaseCog(commands.Cog):
|
|||||||
|
|
||||||
|
|
||||||
def parse_changelog():
|
def parse_changelog():
|
||||||
changelog = OrderedDict()
|
changelog = {}
|
||||||
ver = ""
|
ver = ""
|
||||||
heading = ""
|
heading = ""
|
||||||
|
|
||||||
|
|||||||
+16
-12
@@ -31,6 +31,11 @@ class FunCog(commands.Cog):
|
|||||||
"""Returns xkcd: tar."""
|
"""Returns xkcd: tar."""
|
||||||
await ctx.send("http://xkcd.com/1168")
|
await ctx.send("http://xkcd.com/1168")
|
||||||
|
|
||||||
|
@commands.command(name="standards", category=cmn.cat.fun)
|
||||||
|
async def _standards(self, ctx: commands.Context):
|
||||||
|
"""Returns xkcd: Standards."""
|
||||||
|
await ctx.send("http://xkcd.com/927")
|
||||||
|
|
||||||
@commands.command(name="xd", hidden=True, category=cmn.cat.fun)
|
@commands.command(name="xd", hidden=True, category=cmn.cat.fun)
|
||||||
async def _xd(self, ctx: commands.Context):
|
async def _xd(self, ctx: commands.Context):
|
||||||
"""ecks dee"""
|
"""ecks dee"""
|
||||||
@@ -39,18 +44,17 @@ class FunCog(commands.Cog):
|
|||||||
@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):
|
async def _funetics_lookup(self, ctx: commands.Context, *, msg: str):
|
||||||
"""Generates fun/wacky phonetics for a word or phrase."""
|
"""Generates fun/wacky phonetics for a word or phrase."""
|
||||||
with ctx.typing():
|
result = ""
|
||||||
result = ""
|
for char in msg.lower():
|
||||||
for char in msg.lower():
|
if char.isalpha():
|
||||||
if char.isalpha():
|
result += random.choice([word for word in self.words if word[0] == char])
|
||||||
result += random.choice([word for word in self.words if word[0] == char])
|
else:
|
||||||
else:
|
result += char
|
||||||
result += char
|
result += " "
|
||||||
result += " "
|
embed = cmn.embed_factory(ctx)
|
||||||
embed = cmn.embed_factory(ctx)
|
embed.title = f"Funetics for {msg}"
|
||||||
embed.title = f"Funetics for {msg}"
|
embed.description = result.title()
|
||||||
embed.description = result.title()
|
embed.colour = cmn.colours.good
|
||||||
embed.colour = cmn.colours.good
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+75
-77
@@ -23,93 +23,91 @@ class GridCog(commands.Cog):
|
|||||||
async def _grid_sq_lookup(self, ctx: commands.Context, lat: str, lon: str):
|
async def _grid_sq_lookup(self, ctx: commands.Context, lat: str, lon: str):
|
||||||
("""Calculates the grid square for latitude and longitude coordinates, """
|
("""Calculates the grid square for latitude and longitude coordinates, """
|
||||||
"""with negative being latitude South and longitude West.""")
|
"""with negative being latitude South and longitude West.""")
|
||||||
with ctx.typing():
|
grid = "**"
|
||||||
grid = "**"
|
latf = float(lat) + 90
|
||||||
latf = float(lat) + 90
|
lonf = float(lon) + 180
|
||||||
lonf = float(lon) + 180
|
if 0 <= latf <= 180 and 0 <= lonf <= 360:
|
||||||
if 0 <= latf <= 180 and 0 <= lonf <= 360:
|
grid += chr(ord("A") + int(lonf / 20))
|
||||||
grid += chr(ord("A") + int(lonf / 20))
|
grid += chr(ord("A") + int(latf / 10))
|
||||||
grid += chr(ord("A") + int(latf / 10))
|
grid += chr(ord("0") + int((lonf % 20)/2))
|
||||||
grid += chr(ord("0") + int((lonf % 20)/2))
|
grid += chr(ord("0") + int((latf % 10)/1))
|
||||||
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((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((latf - (int(latf/1)*1)) / (2.5/60)))
|
grid += "**"
|
||||||
grid += "**"
|
embed = cmn.embed_factory(ctx)
|
||||||
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.description = grid
|
embed.colour = cmn.colours.good
|
||||||
embed.colour = cmn.colours.good
|
else:
|
||||||
else:
|
embed = cmn.embed_factory(ctx)
|
||||||
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.
|
||||||
embed.description = """Coordinates out of range.
|
The valid ranges are:
|
||||||
The valid ranges are:
|
- Latitude: `-90` to `+90`
|
||||||
- Latitude: `-90` to `+90`
|
- Longitude: `-180` to `+180`"""
|
||||||
- Longitude: `-180` to `+180`"""
|
embed.colour = cmn.colours.bad
|
||||||
embed.colour = cmn.colours.bad
|
|
||||||
await ctx.send(embed=embed)
|
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):
|
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.
|
"""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."""
|
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:
|
||||||
try:
|
grid = grid.upper()
|
||||||
grid = grid.upper()
|
loc = get_coords(grid)
|
||||||
loc = get_coords(grid)
|
|
||||||
|
|
||||||
embed = cmn.embed_factory(ctx)
|
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
|
embed.colour = cmn.colours.good
|
||||||
|
|
||||||
if len(grid) >= 6:
|
if len(grid) >= 6:
|
||||||
embed.description = f"**{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}"
|
embed.url = f"https://www.openstreetmap.org/#map=13/{loc[0]:.5f}/{loc[1]:.5f}"
|
||||||
else:
|
else:
|
||||||
embed.description = f"**{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}"
|
embed.url = f"https://www.openstreetmap.org/#map=10/{loc[0]:.1f}/{loc[1]:.1f}"
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
embed = cmn.embed_factory(ctx)
|
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.description = str(e)
|
||||||
embed.colour = cmn.colours.bad
|
embed.colour = cmn.colours.bad
|
||||||
else:
|
else:
|
||||||
radius = 6371
|
radius = 6371
|
||||||
try:
|
try:
|
||||||
grid = grid.upper()
|
grid = grid.upper()
|
||||||
grid2 = grid2.upper()
|
grid2 = grid2.upper()
|
||||||
loc = get_coords(grid)
|
loc = get_coords(grid)
|
||||||
loc2 = get_coords(grid2)
|
loc2 = get_coords(grid2)
|
||||||
# Haversine formula
|
# Haversine formula
|
||||||
d_lat = math.radians(loc2[0] - loc[0])
|
d_lat = math.radians(loc2[0] - loc[0])
|
||||||
d_lon = math.radians(loc2[1] - loc[1])
|
d_lon = math.radians(loc2[1] - loc[1])
|
||||||
a = (math.sin(d_lat/2) ** 2
|
a = (math.sin(d_lat/2) ** 2
|
||||||
+ math.cos(math.radians(loc[0]))
|
+ math.cos(math.radians(loc[0]))
|
||||||
* math.cos(math.radians(loc2[0]))
|
* math.cos(math.radians(loc2[0]))
|
||||||
* math.sin(d_lon/2) ** 2)
|
* math.sin(d_lon/2) ** 2)
|
||||||
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
|
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
|
||||||
d = radius * c
|
d = radius * c
|
||||||
d_mi = 0.6213712 * d
|
d_mi = 0.6213712 * d
|
||||||
|
|
||||||
# Bearing
|
# Bearing
|
||||||
y_dist = math.sin(math.radians(loc2[1]-loc[1])) * math.cos(math.radians(loc2[0]))
|
y_dist = math.sin(math.radians(loc2[1]-loc[1])) * math.cos(math.radians(loc2[0]))
|
||||||
x_dist = (math.cos(math.radians(loc[0]))
|
x_dist = (math.cos(math.radians(loc[0]))
|
||||||
* math.sin(math.radians(loc2[0]))
|
* math.sin(math.radians(loc2[0]))
|
||||||
- math.sin(math.radians(loc[0]))
|
- math.sin(math.radians(loc[0]))
|
||||||
* math.cos(math.radians(loc2[0]))
|
* math.cos(math.radians(loc2[0]))
|
||||||
* math.cos(math.radians(loc2[1] - loc[1])))
|
* math.cos(math.radians(loc2[1] - loc[1])))
|
||||||
bearing = (math.degrees(math.atan2(y_dist, x_dist)) + 360) % 360
|
bearing = (math.degrees(math.atan2(y_dist, x_dist)) + 360) % 360
|
||||||
|
|
||||||
embed = cmn.embed_factory(ctx)
|
embed = cmn.embed_factory(ctx)
|
||||||
embed.title = f"Great Circle Distance and Bearing from {grid} to {grid2}"
|
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.description = f"**Distance:** {d:.1f} km ({d_mi:.1f} mi)\n**Bearing:** {bearing:.1f}°"
|
||||||
embed.colour = cmn.colours.good
|
embed.colour = cmn.colours.good
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
embed = cmn.embed_factory(ctx)
|
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.description = str(e)
|
||||||
embed.colour = cmn.colours.bad
|
embed.colour = cmn.colours.bad
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+46
-29
@@ -25,45 +25,42 @@ class HamCog(commands.Cog):
|
|||||||
@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):
|
async def _qcode_lookup(self, ctx: commands.Context, qcode: str):
|
||||||
"""Looks up the meaning of a Q Code."""
|
"""Looks up the meaning of a Q Code."""
|
||||||
with ctx.typing():
|
qcode = qcode.upper()
|
||||||
qcode = qcode.upper()
|
embed = cmn.embed_factory(ctx)
|
||||||
embed = cmn.embed_factory(ctx)
|
if qcode in qcodes.qcodes:
|
||||||
if qcode in qcodes.qcodes:
|
embed.title = qcode
|
||||||
embed.title = qcode
|
embed.description = qcodes.qcodes[qcode]
|
||||||
embed.description = qcodes.qcodes[qcode]
|
embed.colour = cmn.colours.good
|
||||||
embed.colour = cmn.colours.good
|
else:
|
||||||
else:
|
embed.title = f"Q Code {qcode} not found"
|
||||||
embed.title = f"Q Code {qcode} not found"
|
embed.colour = cmn.colours.bad
|
||||||
embed.colour = cmn.colours.bad
|
|
||||||
await ctx.send(embed=embed)
|
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):
|
async def _phonetics_lookup(self, ctx: commands.Context, *, msg: str):
|
||||||
"""Returns NATO phonetics for a word or phrase."""
|
"""Returns NATO phonetics for a word or phrase."""
|
||||||
with ctx.typing():
|
result = ""
|
||||||
result = ""
|
for char in msg.lower():
|
||||||
for char in msg.lower():
|
if char.isalpha():
|
||||||
if char.isalpha():
|
result += phonetics.phonetics[char]
|
||||||
result += phonetics.phonetics[char]
|
else:
|
||||||
else:
|
result += char
|
||||||
result += char
|
result += " "
|
||||||
result += " "
|
embed = cmn.embed_factory(ctx)
|
||||||
embed = cmn.embed_factory(ctx)
|
embed.title = f"Phonetics for {msg}"
|
||||||
embed.title = f"Phonetics for {msg}"
|
embed.description = result.title()
|
||||||
embed.description = result.title()
|
embed.colour = cmn.colours.good
|
||||||
embed.colour = cmn.colours.good
|
|
||||||
await ctx.send(embed=embed)
|
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):
|
async def _utc_lookup(self, ctx: commands.Context):
|
||||||
"""Returns the current time in UTC."""
|
"""Returns the current time in UTC."""
|
||||||
with ctx.typing():
|
now = datetime.utcnow()
|
||||||
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 = cmn.embed_factory(ctx)
|
embed.title = "The current time is:"
|
||||||
embed.title = "The current time is:"
|
embed.description = result
|
||||||
embed.description = result
|
embed.colour = cmn.colours.good
|
||||||
embed.colour = cmn.colours.good
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
@commands.command(name="prefixes", aliases=["vanity", "pfx", "vanities", "prefix"], category=cmn.cat.ref)
|
@commands.command(name="prefixes", aliases=["vanity", "pfx", "vanities", "prefix"], category=cmn.cat.ref)
|
||||||
@@ -95,6 +92,26 @@ class HamCog(commands.Cog):
|
|||||||
embed.colour = cmn.colours.good
|
embed.colour = cmn.colours.good
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@commands.command(name="phoneticweight", aliases=["pw"], category=cmn.cat.ref)
|
||||||
|
async def _weight(self, ctx: commands.Context, *, msg: str):
|
||||||
|
"""Calculates the phonetic weight of a callsign or message."""
|
||||||
|
embed = cmn.embed_factory(ctx)
|
||||||
|
msg = msg.upper()
|
||||||
|
weight = 0
|
||||||
|
for char in msg:
|
||||||
|
try:
|
||||||
|
weight += phonetics.pweights[char]
|
||||||
|
except KeyError:
|
||||||
|
embed.title = "Error in calculation of phonetic weight"
|
||||||
|
embed.description = f"Unknown character `{char}` in message"
|
||||||
|
embed.colour = cmn.colours.bad
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
return
|
||||||
|
embed.title = f"Phonetic Weight of {msg}"
|
||||||
|
embed.description = f"The phonetic weight is **{weight}**"
|
||||||
|
embed.colour = cmn.colours.good
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
|
||||||
def setup(bot: commands.Bot):
|
def setup(bot: commands.Bot):
|
||||||
bot.add_cog(HamCog(bot))
|
bot.add_cog(HamCog(bot))
|
||||||
|
|||||||
+22
-23
@@ -40,30 +40,29 @@ class LookupCog(commands.Cog):
|
|||||||
@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):
|
async def _dxcc_lookup(self, ctx: commands.Context, query: str):
|
||||||
"""Gets DXCC info about a callsign prefix."""
|
"""Gets DXCC info about a callsign prefix."""
|
||||||
with ctx.typing():
|
query = query.upper()
|
||||||
query = query.upper()
|
full_query = query
|
||||||
full_query = query
|
embed = cmn.embed_factory(ctx)
|
||||||
embed = cmn.embed_factory(ctx)
|
embed.title = "DXCC Info for "
|
||||||
embed.title = "DXCC Info for "
|
embed.description = f"*Last Updated: {self.cty.formatted_version}*"
|
||||||
embed.description = f"*Last Updated: {self.cty.formatted_version}*"
|
embed.colour = cmn.colours.bad
|
||||||
embed.colour = cmn.colours.bad
|
while query:
|
||||||
while query:
|
if query in self.cty.keys():
|
||||||
if query in self.cty.keys():
|
data = self.cty[query]
|
||||||
data = self.cty[query]
|
embed.add_field(name="Entity", value=data["entity"])
|
||||||
embed.add_field(name="Entity", value=data["entity"])
|
embed.add_field(name="CQ Zone", value=data["cq"])
|
||||||
embed.add_field(name="CQ Zone", value=data["cq"])
|
embed.add_field(name="ITU Zone", value=data["itu"])
|
||||||
embed.add_field(name="ITU Zone", value=data["itu"])
|
embed.add_field(name="Continent", value=data["continent"])
|
||||||
embed.add_field(name="Continent", value=data["continent"])
|
embed.add_field(name="Time Zone",
|
||||||
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.title += query
|
embed.colour = cmn.colours.good
|
||||||
embed.colour = cmn.colours.good
|
break
|
||||||
break
|
|
||||||
else:
|
|
||||||
query = query[:-1]
|
|
||||||
else:
|
else:
|
||||||
embed.title += full_query + " not found"
|
query = query[:-1]
|
||||||
embed.colour = cmn.colours.bad
|
else:
|
||||||
|
embed.title += full_query + " not found"
|
||||||
|
embed.colour = cmn.colours.bad
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
@tasks.loop(hours=24)
|
@tasks.loop(hours=24)
|
||||||
|
|||||||
+41
-44
@@ -21,61 +21,58 @@ class MorseCog(commands.Cog):
|
|||||||
@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):
|
async def _morse(self, ctx: commands.Context, *, msg: str):
|
||||||
"""Converts ASCII to international morse code."""
|
"""Converts ASCII to international morse code."""
|
||||||
with ctx.typing():
|
result = ""
|
||||||
result = ""
|
for char in msg.upper():
|
||||||
for char in msg.upper():
|
try:
|
||||||
try:
|
result += morse.morse[char]
|
||||||
result += morse.morse[char]
|
except KeyError:
|
||||||
except KeyError:
|
result += "<?>"
|
||||||
result += "<?>"
|
result += " "
|
||||||
result += " "
|
embed = cmn.embed_factory(ctx)
|
||||||
embed = cmn.embed_factory(ctx)
|
embed.title = f"Morse Code for {msg}"
|
||||||
embed.title = f"Morse Code for {msg}"
|
embed.description = "**" + result + "**"
|
||||||
embed.description = "**" + result + "**"
|
embed.colour = cmn.colours.good
|
||||||
embed.colour = cmn.colours.good
|
|
||||||
await ctx.send(embed=embed)
|
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):
|
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
|
||||||
msg0 = msg
|
msg = msg.split("/")
|
||||||
msg = msg.split("/")
|
msg = [m.split() for m in msg]
|
||||||
msg = [m.split() for m in msg]
|
for word in msg:
|
||||||
for word in msg:
|
for char in word:
|
||||||
for char in word:
|
try:
|
||||||
try:
|
result += morse.ascii[char]
|
||||||
result += morse.ascii[char]
|
except KeyError:
|
||||||
except KeyError:
|
result += "<?>"
|
||||||
result += "<?>"
|
result += " "
|
||||||
result += " "
|
embed = cmn.embed_factory(ctx)
|
||||||
embed = cmn.embed_factory(ctx)
|
embed.title = f"ASCII for {msg0}"
|
||||||
embed.title = f"ASCII for {msg0}"
|
embed.description = result
|
||||||
embed.description = result
|
embed.colour = cmn.colours.good
|
||||||
embed.colour = cmn.colours.good
|
|
||||||
await ctx.send(embed=embed)
|
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):
|
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)
|
embed = cmn.embed_factory(ctx)
|
||||||
with ctx.typing():
|
msg = msg.upper()
|
||||||
msg = msg.upper()
|
weight = 0
|
||||||
weight = 0
|
for char in msg:
|
||||||
for char in msg:
|
try:
|
||||||
try:
|
cw_char = morse.morse[char].replace("-", "==")
|
||||||
cw_char = morse.morse[char].replace("-", "==")
|
weight += len(cw_char) * 2 + 2
|
||||||
weight += len(cw_char) * 2 + 2
|
except KeyError:
|
||||||
except KeyError:
|
embed.title = "Error in calculation of CW weight"
|
||||||
embed.title = "Error in calculation of CW weight"
|
embed.description = f"Unknown character `{char}` in message"
|
||||||
embed.description = f"Unknown character `{char}` in message"
|
embed.colour = cmn.colours.bad
|
||||||
embed.colour = cmn.colours.bad
|
await ctx.send(embed=embed)
|
||||||
await ctx.send(embed=embed)
|
return
|
||||||
return
|
embed.title = f"CW Weight of {msg}"
|
||||||
embed.title = f"CW Weight of {msg}"
|
embed.description = f"The CW weight is **{weight}**"
|
||||||
embed.description = f"The CW weight is **{weight}**"
|
embed.colour = cmn.colours.good
|
||||||
embed.colour = cmn.colours.good
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+58
-61
@@ -8,7 +8,6 @@ the GNU General Public License, version 2.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
from collections import OrderedDict
|
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
@@ -36,50 +35,51 @@ class QRZCog(commands.Cog):
|
|||||||
await ctx.send(f"http://qrz.com/db/{callsign}")
|
await ctx.send(f"http://qrz.com/db/{callsign}")
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
async with ctx.typing():
|
||||||
await qrz_test_session(self.key, self.session)
|
try:
|
||||||
except ConnectionError:
|
await qrz_test_session(self.key, self.session)
|
||||||
await self.get_session()
|
except ConnectionError:
|
||||||
|
|
||||||
url = f"http://xmldata.qrz.com/xml/current/?s={self.key};callsign={callsign}"
|
|
||||||
async with self.session.get(url) as resp:
|
|
||||||
if resp.status != 200:
|
|
||||||
raise ConnectionError(f"Unable to connect to QRZ (HTTP Error {resp.status})")
|
|
||||||
with BytesIO(await resp.read()) as resp_file:
|
|
||||||
resp_xml = etree.parse(resp_file).getroot()
|
|
||||||
|
|
||||||
resp_xml_session = resp_xml.xpath("/x:QRZDatabase/x:Session", namespaces={"x": "http://xmldata.qrz.com"})
|
|
||||||
resp_session = {el.tag.split("}")[1]: el.text for el in resp_xml_session[0].getiterator()}
|
|
||||||
if "Error" in resp_session:
|
|
||||||
if "Session Timeout" in resp_session["Error"]:
|
|
||||||
await self.get_session()
|
await self.get_session()
|
||||||
await self._qrz_lookup(ctx, callsign)
|
|
||||||
return
|
|
||||||
if "Not found" in resp_session["Error"]:
|
|
||||||
embed = cmn.embed_factory(ctx)
|
|
||||||
embed.title = f"QRZ Data for {callsign.upper()}"
|
|
||||||
embed.colour = cmn.colours.bad
|
|
||||||
embed.description = "No data found!"
|
|
||||||
await ctx.send(embed=embed)
|
|
||||||
return
|
|
||||||
raise ValueError(resp_session["Error"])
|
|
||||||
|
|
||||||
resp_xml_data = resp_xml.xpath("/x:QRZDatabase/x:Callsign", namespaces={"x": "http://xmldata.qrz.com"})
|
url = f"http://xmldata.qrz.com/xml/current/?s={self.key};callsign={callsign}"
|
||||||
resp_data = {el.tag.split("}")[1]: el.text for el in resp_xml_data[0].getiterator()}
|
async with self.session.get(url) as resp:
|
||||||
|
if resp.status != 200:
|
||||||
|
raise ConnectionError(f"Unable to connect to QRZ (HTTP Error {resp.status})")
|
||||||
|
with BytesIO(await resp.read()) as resp_file:
|
||||||
|
resp_xml = etree.parse(resp_file).getroot()
|
||||||
|
|
||||||
embed = cmn.embed_factory(ctx)
|
resp_xml_session = resp_xml.xpath("/x:QRZDatabase/x:Session", namespaces={"x": "http://xmldata.qrz.com"})
|
||||||
embed.title = f"QRZ Data for {resp_data['call']}"
|
resp_session = {el.tag.split("}")[1]: el.text for el in resp_xml_session[0].getiterator()}
|
||||||
embed.colour = cmn.colours.good
|
if "Error" in resp_session:
|
||||||
embed.url = f"http://www.qrz.com/db/{resp_data['call']}"
|
if "Session Timeout" in resp_session["Error"]:
|
||||||
if "image" in resp_data:
|
await self.get_session()
|
||||||
embed.set_thumbnail(url=resp_data["image"])
|
await self._qrz_lookup(ctx, callsign)
|
||||||
|
return
|
||||||
|
if "Not found" in resp_session["Error"]:
|
||||||
|
embed = cmn.embed_factory(ctx)
|
||||||
|
embed.title = f"QRZ Data for {callsign.upper()}"
|
||||||
|
embed.colour = cmn.colours.bad
|
||||||
|
embed.description = "No data found!"
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
return
|
||||||
|
raise ValueError(resp_session["Error"])
|
||||||
|
|
||||||
data = qrz_process_info(resp_data)
|
resp_xml_data = resp_xml.xpath("/x:QRZDatabase/x:Callsign", namespaces={"x": "http://xmldata.qrz.com"})
|
||||||
|
resp_data = {el.tag.split("}")[1]: el.text for el in resp_xml_data[0].getiterator()}
|
||||||
|
|
||||||
for title, val in data.items():
|
embed = cmn.embed_factory(ctx)
|
||||||
if val is not None:
|
embed.title = f"QRZ Data for {resp_data['call']}"
|
||||||
embed.add_field(name=title, value=val, inline=True)
|
embed.colour = cmn.colours.good
|
||||||
await ctx.send(embed=embed)
|
embed.url = f"http://www.qrz.com/db/{resp_data['call']}"
|
||||||
|
if "image" in resp_data:
|
||||||
|
embed.set_thumbnail(url=resp_data["image"])
|
||||||
|
|
||||||
|
data = qrz_process_info(resp_data)
|
||||||
|
|
||||||
|
for title, val in data.items():
|
||||||
|
if val is not None:
|
||||||
|
embed.add_field(name=title, value=val, inline=True)
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
async def get_session(self):
|
async def get_session(self):
|
||||||
"""Session creation and caching."""
|
"""Session creation and caching."""
|
||||||
@@ -158,27 +158,24 @@ def qrz_process_info(data: dict):
|
|||||||
else:
|
else:
|
||||||
lotw = "Unknown"
|
lotw = "Unknown"
|
||||||
|
|
||||||
return OrderedDict([("Name", name),
|
return {"Name": name,
|
||||||
("Country", data.get("country", None)),
|
"Country": data.get("country", None),
|
||||||
("Address", address),
|
"Address": address,
|
||||||
("Grid Square", data.get("grid", None)),
|
"Grid Square": data.get("grid", None),
|
||||||
("County", data.get("county", None)),
|
"County": data.get("county", None),
|
||||||
("CQ Zone", data.get("cqzone", None)),
|
"CQ Zone": data.get("cqzone", None),
|
||||||
("ITU Zone", data.get("ituzone", None)),
|
"ITU Zone": data.get("ituzone", None),
|
||||||
("IOTA Designator", data.get("iota", None)),
|
"IOTA Designator": data.get("iota", None),
|
||||||
("Expires", data.get("expdate", None)),
|
"Expires": data.get("expdate", None),
|
||||||
("Aliases", data.get("aliases", None)),
|
"Aliases": data.get("aliases", None),
|
||||||
("Previous Callsign", data.get("p_call", None)),
|
"Previous Callsign": data.get("p_call", None),
|
||||||
("License Class", data.get("class", None)),
|
"License Class": data.get("class", None),
|
||||||
("Trustee", data.get("trustee", None)),
|
"Trustee": data.get("trustee", None),
|
||||||
("eQSL?", eqsl),
|
"eQSL?": eqsl,
|
||||||
("Paper QSL?", mqsl),
|
"Paper QSL?": mqsl,
|
||||||
("LotW?", lotw),
|
"LotW?": lotw,
|
||||||
("QSL Info", data.get("qslmgr", None)),
|
"QSL Info": data.get("qslmgr", None),
|
||||||
("CQ Zone", data.get("cqzone", None)),
|
"Born": data.get("born", None)}
|
||||||
("ITU Zone", data.get("ituzone", None)),
|
|
||||||
("IOTA Designator", data.get("iota", None)),
|
|
||||||
("Born", data.get("born", None))])
|
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot):
|
||||||
|
|||||||
+1
-2
@@ -14,7 +14,6 @@ from datetime import datetime
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import pytz
|
|
||||||
|
|
||||||
import discord.ext.commands as commands
|
import discord.ext.commands as commands
|
||||||
|
|
||||||
@@ -134,7 +133,7 @@ class StudyCog(commands.Cog):
|
|||||||
" the answer will be revealed."),
|
" the answer will be revealed."),
|
||||||
inline=False)
|
inline=False)
|
||||||
if "image" in question:
|
if "image" in question:
|
||||||
image_url = f"https://hamstudy.org/_1330011/images/{pool.split('_',1)[1]}/{question['image']}"
|
image_url = f"https://hamstudy.org/images/{pool_meta['year']}/{question['image']}"
|
||||||
embed.set_image(url=image_url)
|
embed.set_image(url=image_url)
|
||||||
|
|
||||||
q_msg = await ctx.send(embed=embed)
|
q_msg = await ctx.send(embed=embed)
|
||||||
|
|||||||
+1
-1
@@ -40,7 +40,7 @@ class WeatherCog(commands.Cog):
|
|||||||
embed.set_image(url="attachment://condx.png")
|
embed.set_image(url="attachment://condx.png")
|
||||||
await ctx.send(embed=embed, file=discord.File(data, "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"], case_insensitive=True, category=cmn.cat.weather)
|
||||||
async def _weather_conditions(self, ctx: commands.Context):
|
async def _weather_conditions(self, ctx: commands.Context):
|
||||||
"""Gets local weather conditions from [wttr.in](http://wttr.in/).
|
"""Gets local weather conditions from [wttr.in](http://wttr.in/).
|
||||||
|
|
||||||
|
|||||||
@@ -12,5 +12,5 @@ authors = ("@ClassAbbyAmplifier#2229", "@0x5c#0639")
|
|||||||
description = """A bot with various useful ham radio-related functions, written in Python."""
|
description = """A bot with various useful ham radio-related functions, written in Python."""
|
||||||
license = "Released under the GNU General Public License v2"
|
license = "Released under the GNU General Public License v2"
|
||||||
contributing = "Check out the source on GitHub, contributions welcome: https://github.com/miaowware/qrm2"
|
contributing = "Check out the source on GitHub, contributions welcome: https://github.com/miaowware/qrm2"
|
||||||
release = "2.2.1"
|
release = "2.3.0"
|
||||||
bot_server = "https://discord.gg/Ntbg3J4"
|
bot_server = "https://discord.gg/Ntbg3J4"
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ loop = asyncio.get_event_loop()
|
|||||||
connector = loop.run_until_complete(conn.new_connector())
|
connector = loop.run_until_complete(conn.new_connector())
|
||||||
|
|
||||||
bot = commands.Bot(command_prefix=opt.prefix,
|
bot = commands.Bot(command_prefix=opt.prefix,
|
||||||
description=info.description,
|
case_insensitive=True,
|
||||||
help_command=commands.MinimalHelpCommand(),
|
description=info.description, help_command=commands.MinimalHelpCommand(),
|
||||||
loop=loop,
|
loop=loop,
|
||||||
connector=connector)
|
connector=connector)
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ async def _shutdown_bot(ctx: commands.Context):
|
|||||||
await bot.logout()
|
await bot.logout()
|
||||||
|
|
||||||
|
|
||||||
@bot.group(name="extctl", aliases=["ex"], category=cmn.cat.admin)
|
@bot.group(name="extctl", aliases=["ex"], case_insensitive=True, category=cmn.cat.admin)
|
||||||
@commands.check(cmn.check_if_owner)
|
@commands.check(cmn.check_if_owner)
|
||||||
async def _extctl(ctx: commands.Context):
|
async def _extctl(ctx: commands.Context):
|
||||||
"""Extension control commands.
|
"""Extension control commands.
|
||||||
|
|||||||
+39
-40
@@ -8,49 +8,48 @@ the GNU General Public License, version 2.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
from collections import OrderedDict
|
|
||||||
|
|
||||||
|
|
||||||
us_calls_title = "Valid US Vanity Callsigns"
|
us_calls_title = "Valid US Vanity Callsigns"
|
||||||
us_calls_desc = ("#x# is the number of letters in the prefix and suffix of a callsign. "
|
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.")
|
"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"
|
us_calls = {
|
||||||
" AA-AL, KA-KZ, NA-NZ, WA-WZ (2x1)\n"
|
"**Group A** (Extra Only)": ("**Any:** K, N, W (1x2)\n"
|
||||||
" AA-AL (2x2)\n"
|
" AA-AL, KA-KZ, NA-NZ, WA-WZ (2x1)\n"
|
||||||
"*Except*\n"
|
" AA-AL (2x2)\n"
|
||||||
"**Alaska:** AL, KL, NL, WL (2x1)\n"
|
"*Except*\n"
|
||||||
"**Caribbean:** KP, NP, WP (2x1)\n"
|
"**Alaska:** AL, KL, NL, WL (2x1)\n"
|
||||||
"**Pacific:** AH, KH, NH, WH (2x1)")),
|
"**Caribbean:** KP, NP, WP (2x1)\n"
|
||||||
("**Group B** (Advanced and Extra Only)", ("**Any:** KA-KZ, NA-NZ, WA-WZ (2x2)\n"
|
"**Pacific:** AH, KH, NH, WH (2x1)"),
|
||||||
"*Except*\n"
|
"**Group B** (Advanced and Extra Only)": ("**Any:** KA-KZ, NA-NZ, WA-WZ (2x2)\n"
|
||||||
"**Alaska:** AL (2x2)\n"
|
"*Except*\n"
|
||||||
"**Caribbean:** KP (2x2)\n"
|
"**Alaska:** AL (2x2)\n"
|
||||||
"**Pacific:** AH (2x2)")),
|
"**Caribbean:** KP (2x2)\n"
|
||||||
("**Group C** (Technician, General, Advanced, Extra Only)", ("**Any Region:** K, N, W (1x3)\n"
|
"**Pacific:** AH (2x2)"),
|
||||||
"*Except*\n"
|
"**Group C** (Technician, General, Advanced, Extra Only)": ("**Any Region:** K, N, W (1x3)\n"
|
||||||
"**Alaska:** KL, NL, WL (2x2)\n"
|
"*Except*\n"
|
||||||
"**Caribbean:** NP, WP (2x2)\n"
|
"**Alaska:** KL, NL, WL (2x2)\n"
|
||||||
"**Pacific:** KH, NH, WH (2x2)")),
|
"**Caribbean:** NP, WP (2x2)\n"
|
||||||
("**Group D** (Any License Class)", ("**Any Region:** KA-KZ, WA-WZ (2x3)\n"
|
"**Pacific:** KH, NH, WH (2x2)"),
|
||||||
"*Except*\n"
|
"**Group D** (Any License Class)": ("**Any Region:** KA-KZ, WA-WZ (2x3)\n"
|
||||||
"**Alaska:** KL, WL (2x3)\n"
|
"*Except*\n"
|
||||||
"**Caribbean:** KP, WP (2x3)\n"
|
"**Alaska:** KL, WL (2x3)\n"
|
||||||
"**Pacific:** KH, WH (2x3)")),
|
"**Caribbean:** KP, WP (2x3)\n"
|
||||||
("**Unavailable**", ("- KA2AA-KA9ZZ: US Army in Japan\n"
|
"**Pacific:** KH, WH (2x3)"),
|
||||||
"- KC4AAA-KC4AAF: NSF in Antartica\n"
|
"**Unavailable**": ("- KA2AA-KA9ZZ: US Army in Japan\n"
|
||||||
"- KC4USA-KC4USZ: US Navy in Antartica\n"
|
"- KC4AAA-KC4AAF: NSF in Antartica\n"
|
||||||
"- KG4AA-KG4ZZ: US Navy in Guantanamo Bay\n"
|
"- KC4USA-KC4USZ: US Navy in Antartica\n"
|
||||||
"- KL9KAA-KL9KHZ: US military in Korea\n"
|
"- KG4AA-KG4ZZ: US Navy in Guantanamo Bay\n"
|
||||||
"- KC6AA-KC6ZZ: Former US (Eastern and Western Caroline Islands), "
|
"- KL9KAA-KL9KHZ: US military in Korea\n"
|
||||||
"now Federated States of Micronesia (V6) and Republic of Palau (T8)\n"
|
"- KC6AA-KC6ZZ: Former US (Eastern and Western Caroline Islands), "
|
||||||
"- KX6AA-KX6ZZ: Former US (Marshall Islands), "
|
"now Federated States of Micronesia (V6) and Republic of Palau (T8)\n"
|
||||||
"now Republic of the Marshall Islands (V73)\n"
|
"- KX6AA-KX6ZZ: Former US (Marshall Islands), "
|
||||||
"- Any suffix SOS or QRA-QUZ\n"
|
"now Republic of the Marshall Islands (V73)\n"
|
||||||
"- Any 2x3 with X as the first suffix letter\n"
|
"- Any suffix SOS or QRA-QUZ\n"
|
||||||
"- Any 2x3 with AF, KF, NF, or WF prefix and suffix EMA: FEMA\n"
|
"- Any 2x3 with X as the first suffix letter\n"
|
||||||
"- Any 2x3 with AA-AL, NA-NZ, WC, WK, WM, WR, or WT prefix: \"Group X\"\n"
|
"- Any 2x3 with AF, KF, NF, or WF prefix and suffix EMA: FEMA\n"
|
||||||
"- Any 2x1, 2x2, or 2x3 with KP, NP, WP prefix and 0, 6, 7, 8, 9 number\n"
|
"- Any 2x3 with AA-AL, NA-NZ, WC, WK, WM, WR, or WT prefix: \"Group X\"\n"
|
||||||
"- Any 1x1 callsign: Special Event"))])
|
"- 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)
|
# 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)}
|
||||||
|
|||||||
@@ -36,3 +36,43 @@ phonetics = {
|
|||||||
"y": "yankee",
|
"y": "yankee",
|
||||||
"z": "zulu"
|
"z": "zulu"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pweights = {
|
||||||
|
"A": 2,
|
||||||
|
"B": 2,
|
||||||
|
"C": 2,
|
||||||
|
"D": 2,
|
||||||
|
"E": 2,
|
||||||
|
"F": 2,
|
||||||
|
"G": 1,
|
||||||
|
"H": 2,
|
||||||
|
"I": 3,
|
||||||
|
"J": 3,
|
||||||
|
"K": 2,
|
||||||
|
"L": 2,
|
||||||
|
"M": 1,
|
||||||
|
"N": 3,
|
||||||
|
"O": 2,
|
||||||
|
"P": 2,
|
||||||
|
"Q": 2,
|
||||||
|
"R": 3,
|
||||||
|
"S": 3,
|
||||||
|
"T": 2,
|
||||||
|
"U": 3,
|
||||||
|
"V": 2,
|
||||||
|
"W": 2,
|
||||||
|
"X": 2,
|
||||||
|
"Y": 2,
|
||||||
|
"Z": 2,
|
||||||
|
"0": 2,
|
||||||
|
"1": 1,
|
||||||
|
"2": 1,
|
||||||
|
"3": 1,
|
||||||
|
"4": 1,
|
||||||
|
"5": 1,
|
||||||
|
"6": 1,
|
||||||
|
"7": 2,
|
||||||
|
"8": 1,
|
||||||
|
"9": 2,
|
||||||
|
"/": 1,
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user