33 Commits

Author SHA1 Message Date
classabbyamp 1160c73a56 release 2.10.0 2026-02-10 01:16:42 -05:00
Posimagi bff289d168 render morse conversion output in fixed width, and escape bullets at the start of morse deconversion
Linting / flake8 (push) Has been cancelled
Fixes: #484
2026-02-10 01:13:26 -05:00
Jason Schollenberger 6b4f985f07 Remove deprecated ae7q extension from options.py template 2026-02-10 01:08:22 -05:00
classabbyamp 312da11631 add deprecation notice 2026-02-10 01:03:33 -05:00
classabbyamp 3527df7cd9 fix indentation in some text responses 2026-02-10 01:03:33 -05:00
classabbyamp c8f42cb6b1 use discord application emojis 2026-02-10 01:03:33 -05:00
classabbyamp 926489ae3a run.sh: respect VIRTUAL_ENV 2026-02-10 01:03:33 -05:00
classabbyamp 8e4f8b3fe0 update pycord to 2.7.1, lint/fix issues, support python 3.14 2026-02-10 01:03:33 -05:00
classabbyamp 4b55ab49b7 .github/workflows/docker.yml: fix labels, again
Docker Build and Deploy / Build and push docker images (push) Failing after 1m51s
Linting / flake8 (push) Successful in 1m6s
2023-12-15 14:47:33 -05:00
classabbyamp cf378a2ef4 CHANGELOG.md: relbump 2023-12-15 14:30:59 -05:00
classabbyamp 13a8a63300 info.py: use pomelo usernames, relbump 2023-12-15 14:30:59 -05:00
classabbyamp 23619949d7 .github/workflows/docker.yml: fix tagging latest
turns out, most of this is handled automatically.
see https://github.com/docker/metadata-action#latest-tag
2023-12-15 14:20:05 -05:00
classabbyamp 444687bd12 .github/workflows/docker.yml: use metadata action, run on PRs
Docker Build and Deploy / Build and push docker images (push) Has been cancelled
Linting / flake8 (push) Has been cancelled
2023-12-11 08:21:33 -05:00
classabbyamp 86da8d135a Dockerfile: use new void container, python3.11 2023-12-11 08:21:33 -05:00
classabbyamp 67add85a7a run.sh: shellcheck 2023-12-11 08:21:33 -05:00
0x5c abdc5ebacb Merge pull request #476 from miaowware/fix/metar
Docker Build and Deploy / Build and push docker images (push) Waiting to run
Linting / flake8 (push) Waiting to run
Fix metar + version bumps
2023-12-10 14:17:35 -05:00
0x5c a5cbb5a09a exts/land_weather: switch to the new aviationweather.gov API
Fixes #475
2023-12-10 07:47:59 -05:00
0x5c ce99cc194e bump pydantic to version 2 2023-12-10 07:19:45 -05:00
0x5c f8d7316071 bump pycord to pre-release v5 2023-12-10 07:16:41 -05:00
0x5c 9feeb01e42 Merge pull request #474 from cschmittiey/hamqsl-https
hamqsl.com has moved to https
2023-04-22 02:55:08 -04:00
Caleb Smith fcb682ec4a hamqsl.com has moved to https 2023-04-22 00:53:03 -06:00
Judd West c8a1128927 Add NOAA D-RAP map to propagation plugin 2023-01-30 05:25:01 -05:00
classabbyamp df08cefe25 exts/callsign: fix mail qsl display 2023-01-29 15:40:43 -05:00
0x5c cf93773a3c Merge pull request #471 from miaowware/rel-2.9.1
rel 2.9.1
2023-01-29 00:52:48 -05:00
classabbyamp 642b49041a bump version 2.9.1 2023-01-29 00:44:29 -05:00
classabbyamp e95f991300 bump copyright 2023-01-29 00:43:56 -05:00
0x5c 56ae14a5c3 Merge pull request #469 from miaowware/new-clt
exts/callsign: unworkaround some things solved in CLT 1.1.0
2023-01-29 00:34:04 -05:00
classabbyamp 30c6e96883 exts/callsign: unworkaround some things solved in CLT 1.1.0
fixes #466
2023-01-29 00:23:20 -05:00
0x5c 44a6905f7b Merge pull request #468 from miaowware/embed-avatar
Embed factory/pycord fixes
2023-01-28 23:41:01 -05:00
classabbyamp d7de78e582 common.py: use tz-aware datetime for proper timestamp display
https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.timestamp
2023-01-28 20:11:23 -05:00
classabbyamp b000c9173e common.py: don't error when creating embeds for users without avatars
behaviour changed in pycord 2.0:
https://docs.pycord.dev/en/stable/api/models.html#discord.User.display_avatar

fixes #467
2023-01-28 20:11:00 -05:00
0x5c 5460dd811b Merge pull request #465 from miaowware/fix-rel-workflow
.github/workflows/release.yml: move to ncipollo/create-release action
2023-01-13 18:57:54 -05:00
classabbyamp a00d613430 .github/workflows/release.yml: move to ncipollo/create-release action
fixes #464
2023-01-13 12:42:26 -05:00
36 changed files with 236 additions and 190 deletions
+35 -49
View File
@@ -3,6 +3,10 @@
name: Docker Build and Deploy
on:
workflow_dispatch:
pull_request:
branches:
- master
push:
# Publish `master` as Docker `dev` image.
branches:
@@ -11,29 +15,42 @@ on:
tags:
- v*
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
docker:
name: Build and push docker images
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- name: Checkout
uses: actions/checkout@v2
with:
ref: ${{ github.ref }}
uses: classabbyamp/treeless-checkout-action@v1
- name: Write ref to file
if: ${{ github.event_name != 'pull_request' }}
run: git rev-list -n 1 $GITHUB_REF > ./git_commit
- name: Build image
id: build_image
run: |
IMAGE_ID=${GITHUB_REPOSITORY,,}
IMAGE_NAME=${IMAGE_ID#*/}
echo "image_id=$IMAGE_ID" >> $GITHUB_ENV
echo "image_name=$IMAGE_NAME" >> $GITHUB_ENV
docker build . --file Dockerfile -t $IMAGE_NAME
- name: Docker metadata
id: meta
uses: docker/metadata-action@v4
with:
images: |
ghcr.io/${{ github.repository }}
tags: |
type=sha,prefix=
type=raw,value=dev,enable={{is_default_branch}}
type=match,pattern=v(.*),group=1
labels: |
org.opencontainers.image.authors=classabbyamp and 0x5c
org.opencontainers.image.url=https://github.com/miaowware/qrm2
org.opencontainers.image.source=https://github.com/${{ github.repository }}
org.opencontainers.image.vendor=miaowware
org.opencontainers.image.title=qrm2
org.opencontainers.image.description=Discord bot with ham radio functions
org.opencontainers.image.licenses=LiLiQ-Rplus-1.1
- name: Login to Github Container Registry
uses: docker/login-action@v1
@@ -42,41 +59,10 @@ jobs:
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Tag image
id: tag_image
run: |
IMAGE_NAME=${{ env.image_name }}
IMAGE_ID=ghcr.io/${{ env.image_id }}
echo IMAGE_ID=$IMAGE_ID
echo "image_id=$IMAGE_ID" >> $GITHUB_ENV
# 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//')
# if version is master, set version to dev
[[ "$VERSION" == "master" ]] && VERSION=dev
echo VERSION=$VERSION
echo "version=$VERSION" >> $GITHUB_ENV
# tag dev or x.x.x
docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
# tag latest if not a dev release
[[ "$VERSION" != "dev" ]] && docker tag $IMAGE_NAME $IMAGE_ID:latest || true
- name: Push images to registry
run: |
VERSION=${{ env.version }}
IMAGE_ID=${{ env.image_id }}
[[ "$VERSION" != "dev" ]] && docker push $IMAGE_ID:latest || true
docker push $IMAGE_ID:$VERSION
- name: Deploy official images
id: deploy_images
uses: satak/webrequest-action@v1
- name: Build and push
uses: docker/build-push-action@v5
with:
url: ${{ secrets.DEPLOY_URL }}
method: POST
headers: '{"Authentication": "Token ${{ secrets.DEPLOY_TOKEN }}"}'
payload: '{"version": "${{ env.version }}"}'
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
+5 -5
View File
@@ -12,6 +12,8 @@ jobs:
release:
name: Create Release
runs-on: ubuntu-20.04
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v2
@@ -46,12 +48,10 @@ jobs:
- name: Publish Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
uses: ncipollo/release-action@v1
with:
tag_name: ${{ env.tag_version }}
release_name: ${{ env.tag_subject }}
tag: ${{ env.tag_version }}
name: ${{ env.tag_subject }}
body: |
${{ env.tag_body }}
+35 -1
View File
@@ -7,6 +7,37 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]
## [2.10.0] - 2026-02-10
### Added
- Support for Python 3.14.
- Bot deprecation notice in all embeds.
### Changed
- Updated Pycord to 2.7.1.
- `run.sh` to respect the `VIRTUAL_ENV` environment variable.
- Use Discord application emojis.
- Fix indentation in some text responses.
### Removed
- Deprecated `ae7q` extension from the default configuration (#486).
### Fixed
- Issue where ?morse/?demorse outputs beginning with `-` rendered as a bulleted list (#484).
## [2.9.2] - 2023-12-15
### Added
- `?drapmap` command to display NOAA D Region Absorption Predictions map.
- Support for the new username format.
### Fixed
- Issue where `?solarweather` would not show a picture (#474).
- Issue where `?metar` and `?taf` failed to fetch data (#475).
## [2.9.1] - 2023-01-29
### Fixed
- Issue where embeds would not work for users without avatars (#467).
- Issue where embeds would show the wrong timezone.
- Several issues with `?call` caused by issues in a library (#466).
## [2.9.0] - 2023-01-13
### Changed
- Migrated to Pycord.
@@ -239,7 +270,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## 1.0.0 - 2019-07-31 [YANKED]
[Unreleased]: https://github.com/miaowware/qrm2/compare/v2.9.0...HEAD
[Unreleased]: https://github.com/miaowware/qrm2/compare/v2.10.0...HEAD
[2.10.0]: https://github.com/miaowware/qrm2/releases/tag/v2.10.0
[2.9.2]: https://github.com/miaowware/qrm2/releases/tag/v2.9.2
[2.9.1]: https://github.com/miaowware/qrm2/releases/tag/v2.9.1
[2.9.0]: https://github.com/miaowware/qrm2/releases/tag/v2.9.0
[2.8.0]: https://github.com/miaowware/qrm2/releases/tag/v2.8.0
[2.7.6]: https://github.com/miaowware/qrm2/releases/tag/v2.7.6
+9 -10
View File
@@ -1,11 +1,10 @@
FROM ghcr.io/void-linux/void-linux:latest-full-x86_64-musl
LABEL org.opencontainers.image.source https://github.com/miaowware/qrm2
FROM ghcr.io/void-linux/void-glibc-full
COPY . /app
WORKDIR /app
ARG REPOSITORY=https://repo-us.voidlinux.org/current
ARG PKGS="cairo libjpeg-turbo"
ARG REPOSITORY=https://repo-fastly.voidlinux.org/current
ARG PKGS="cairo libjpeg-turbo libgcc"
ARG UID 1000
ARG GID 1000
@@ -14,19 +13,19 @@ RUN \
xbps-install -Suy xbps -R ${REPOSITORY} && \
xbps-install -uy -R ${REPOSITORY} && \
echo "**** install system packages ****" && \
xbps-install -y -R ${REPOSITORY} ${PKGS} python3 python3-pip && \
xbps-install -y -R ${REPOSITORY} ${PKGS} python3 && \
echo "**** install pip packages ****" && \
pip3 install -U pip setuptools wheel && \
pip3 install -r requirements.txt && \
python3 -m venv botenv && \
botenv/bin/pip install -U pip setuptools wheel && \
botenv/bin/pip install --ignore-requires-python -r requirements.txt && \
echo "**** clean up ****" && \
rm -rf \
/root/.cache \
/tmp/* \
/var/cache/xbps/*
ENV PYTHON_BIN python3
ENV PYTHONUNBUFFERED 1
ENV PYTHONUNBUFFERED=1
USER $UID:$GID
CMD ["/bin/sh", "run.sh", "--pass-errors", "--no-botenv"]
CMD ["/bin/sh", "run.sh", "--pass-errors"]
+1 -1
View File
@@ -38,7 +38,7 @@ All issues and requests related to resources (including maps, band charts, data)
## Copyright
Copyright (C) 2019-2021 classabbyamp, 0x5c
Copyright (C) 2019-2023 classabbyamp, 0x5c
This program is released under the terms of the *Québec Free and Open-Source Licence Strong Reciprocity (LiLiQ-R+)*, version 1.1.
See [`LICENCE`](LICENCE) for full license text (Français / English).
+11 -5
View File
@@ -1,18 +1,18 @@
"""
Common tools for the bot.
---
Copyright (C) 2019-2021 classabbyamp, 0x5c
Copyright (C) 2019-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
import collections
import collections.abc
import enum
import json
import re
import traceback
from datetime import datetime
from datetime import datetime, timezone
from pathlib import Path
from types import SimpleNamespace
from typing import Union
@@ -165,9 +165,15 @@ class GlobalChannelConverter(commands.IDConverter):
def embed_factory(ctx: commands.Context) -> discord.Embed:
"""Creates an embed with neutral colour and standard footer."""
embed = discord.Embed(timestamp=datetime.utcnow(), colour=colours.neutral)
embed = discord.Embed(timestamp=datetime.now(timezone.utc), colour=colours.neutral)
if opt.deprecation_mode:
embed.add_field(name="⚠️ Warning ⚠️",
value=("QRM development has ended. "
"This bot may go offline at some point in the future. "
"For more information, visit [here](https://miaow.io/goodbye-discord)."),
inline=False)
if ctx.author:
embed.set_footer(text=str(ctx.author), icon_url=str(ctx.author.avatar.url))
embed.set_footer(text=str(ctx.author), icon_url=str(ctx.author.avatar))
return embed
+1 -1
View File
@@ -1,7 +1,7 @@
"""
ae7q extension for qrm
---
Copyright (C) 2019-2021 classabbyamp, 0x5c
Copyright (C) 2019-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
+5 -8
View File
@@ -1,12 +1,13 @@
"""
Base extension for qrm
---
Copyright (C) 2019-2021 classabbyamp, 0x5c
Copyright (C) 2019-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
import inspect
import random
import re
from typing import Union, Iterable
@@ -187,11 +188,11 @@ class BaseCog(commands.Cog):
"""Shows info about qrm."""
embed = cmn.embed_factory(ctx)
embed.title = "About qrm"
embed.description = info.description
embed.description = inspect.cleandoc(info.description)
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} {'(`' + self.commit + '`)' if self.commit else ''}")
embed.add_field(name="Contributing", value=info.contributing, inline=False)
embed.add_field(name="Contributing", value=inspect.cleandoc(info.contributing), inline=False)
embed.add_field(name="Official Server", value=info.bot_server, inline=False)
embed.add_field(name="Donate", value="\n".join(f"{k}: {v}" for k, v in self.donation_links.items()),
inline=False)
@@ -255,11 +256,7 @@ class BaseCog(commands.Cog):
"""Shows how to create a bug report or feature request about the bot."""
embed = cmn.embed_factory(ctx)
embed.title = "Found a bug? Have a feature request?"
embed.description = """Submit an issue on the [issue tracker](https://github.com/miaowware/qrm2/issues)!
All issues and requests related to resources (including maps, band charts, data) \
should be added in \
[miaowware/qrm-resources](https://github.com/miaowware/qrm-resources/issues)."""
embed.description = inspect.cleandoc(info.issue_tracker)
await ctx.send(embed=embed)
@commands.command(name="donate", aliases=["tip"], category=cmn.BoltCats.INFO)
+6 -7
View File
@@ -2,7 +2,7 @@
Callsign Lookup extension for qrm
---
Copyright (C) 2019-2020 classabbyamp, 0x5c (as qrz.py)
Copyright (C) 2021 classabbyamp, 0x5c
Copyright (C) 2021-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
@@ -12,7 +12,6 @@ from typing import Dict
import aiohttp
from callsignlookuptools import QrzAsyncClient, CallsignLookupError, CallsignData
from callsignlookuptools.common.dataclasses import Trustee
from discord.ext import commands
@@ -74,7 +73,7 @@ class QRZCog(commands.Cog):
embed.title = f"QRZ Data for {data.callsign}"
embed.colour = cmn.colours.good
embed.url = data.url
if data.image is not None and data.image.url is not None:
if data.image is not None:
embed.set_thumbnail(url=data.image.url)
for title, val in qrz_process_info(data).items():
@@ -101,9 +100,9 @@ def qrz_process_info(data: CallsignData) -> Dict:
qsl = dict()
if data.qsl is not None:
qsl = {
"eQSL?": data.qsl.eqsl.name.title(),
"Paper QSL?": data.qsl.mail.name.title(),
"LotW?": data.qsl.lotw.name.title(),
"eQSL?": data.qsl.eqsl,
"Paper QSL?": data.qsl.mail,
"LotW?": data.qsl.lotw,
"QSL Info": data.qsl.info,
}
@@ -120,7 +119,7 @@ def qrz_process_info(data: CallsignData) -> Dict:
"Aliases": ", ".join(data.aliases) if data.aliases else None,
"Previous Callsign": data.prev_call,
"License Class": data.lic_class,
"Trustee": data.trustee if data.trustee is not None and data.trustee != Trustee(None, None) else None,
"Trustee": data.trustee,
"Born": data.born,
} | qsl
+1 -1
View File
@@ -2,7 +2,7 @@
Codes extension for qrm
---
Copyright (C) 2019-2021 classabbyamp, 0x5c (as ham.py)
Copyright (C) 2021 classabbyamp, 0x5c
Copyright (C) 2021-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
+1 -1
View File
@@ -1,7 +1,7 @@
"""
Contest Calendar extension for qrm
---
Copyright (C) 2021 classabbyamp, 0x5c
Copyright (C) 2021-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
+1 -1
View File
@@ -1,7 +1,7 @@
"""
Conversion extension for qrm
---
Copyright (C) 2020-2021 classabbyamp, 0x5c
Copyright (C) 2020-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
+1 -1
View File
@@ -2,7 +2,7 @@
DXCC Prefix Lookup extension for qrm
---
Copyright (C) 2019-2020 classabbyamp, 0x5c (as lookup.py)
Copyright (C) 2021 classabbyamp, 0x5c
Copyright (C) 2021-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
+1 -1
View File
@@ -1,7 +1,7 @@
"""
Fun extension for qrm
---
Copyright (C) 2019-2021 classabbyamp, 0x5c
Copyright (C) 2019-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
+1 -1
View File
@@ -1,7 +1,7 @@
"""
Grid extension for qrm
---
Copyright (C) 2019-2021 classabbyamp, 0x5c
Copyright (C) 2019-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
+1 -1
View File
@@ -1,7 +1,7 @@
"""
Image extension for qrm
---
Copyright (C) 2019-2021 classabbyamp, 0x5c
Copyright (C) 2019-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
+37 -43
View File
@@ -2,18 +2,16 @@
Land Weather extension for qrm
---
Copyright (C) 2019-2020 classabbyamp, 0x5c (as weather.py)
Copyright (C) 2021 classabbyamp, 0x5c
Copyright (C) 2021-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
import re
from typing import List
import aiohttp
from discord import Embed
import discord.ext.commands as commands
import common as cmn
@@ -102,7 +100,32 @@ class WeatherCog(commands.Cog):
Airports should be given as an \
[ICAO code](https://en.wikipedia.org/wiki/List_of_airports_by_IATA_and_ICAO_code)."""
await ctx.send(embed=await self.gen_metar_taf_embed(ctx, airport, hours, False))
embed = cmn.embed_factory(ctx)
airport = airport.upper()
if not re.fullmatch(r"\w(\w|\d){2,3}", airport):
embed.title = "Invalid airport given!"
embed.colour = cmn.colours.bad
await ctx.send(embed=embed)
return
url = f"https://aviationweather.gov/api/data/metar?ids={airport}&format=raw&taf=false&hours={hours}"
async with self.session.get(url) as r:
if r.status != 200:
raise cmn.BotHTTPError(r)
metar = await r.text()
if hours > 0:
embed.title = f"METAR for {airport} for the last {hours} hour{'s' if hours > 1 else ''}"
else:
embed.title = f"Current METAR for {airport}"
embed.description = "Data from [aviationweather.gov](https://www.aviationweather.gov/)."
embed.colour = cmn.colours.good
embed.description += f"\n\n```\n{metar}\n```"
await ctx.send(embed=embed)
@commands.command(name="taf", category=cmn.Cats.WEATHER)
async def taf(self, ctx: commands.Context, airport: str):
@@ -110,57 +133,28 @@ class WeatherCog(commands.Cog):
Airports should be given as an \
[ICAO code](https://en.wikipedia.org/wiki/List_of_airports_by_IATA_and_ICAO_code)."""
await ctx.send(embed=await self.gen_metar_taf_embed(ctx, airport, 0, True))
async def gen_metar_taf_embed(self, ctx: commands.Context, airport: str, hours: int, taf: bool) -> Embed:
embed = cmn.embed_factory(ctx)
airport = airport.upper()
if re.fullmatch(r"\w(\w|\d){2,3}", airport):
metar = await self.get_metar_taf_data(airport, hours, taf)
if taf:
embed.title = f"Current TAF for {airport}"
elif hours > 0:
embed.title = f"METAR for {airport} for the last {hours} hour{'s' if hours > 1 else ''}"
else:
embed.title = f"Current METAR for {airport}"
embed.description = "Data from [aviationweather.gov](https://www.aviationweather.gov/metar/data)."
embed.colour = cmn.colours.good
data = "\n".join(metar)
embed.description += f"\n\n```\n{data}\n```"
else:
if not re.fullmatch(r"\w(\w|\d){2,3}", airport):
embed.title = "Invalid airport given!"
embed.colour = cmn.colours.bad
return embed
await ctx.send(embed=embed)
return
async def get_metar_taf_data(self, airport: str, hours: int, taf: bool) -> List[str]:
url = (f"https://www.aviationweather.gov/metar/data?ids={airport}&format=raw&hours={hours}"
f"&taf={'on' if taf else 'off'}&layout=off")
url = f"https://aviationweather.gov/api/data/taf?ids={airport}&format=raw&metar=true"
async with self.session.get(url) as r:
if r.status != 200:
raise cmn.BotHTTPError(r)
page = await r.text()
taf = await r.text()
# pare down to just the data
page = page.split("<!-- Data starts here -->")[1].split("<!-- Data ends here -->")[0].strip()
# split at <hr>s
data = re.split(r"<hr.*>", page, maxsplit=len(airport))
embed.title = f"Current TAF for {airport}"
embed.description = "Data from [aviationweather.gov](https://www.aviationweather.gov/)."
embed.colour = cmn.colours.good
embed.description += f"\n\n```\n{taf}\n```"
parsed = []
for sec in data:
if sec.strip():
for line in sec.split("\n"):
line = line.strip()
# remove HTML stuff
line = line.replace("<code>", "").replace("</code>", "")
line = line.replace("<strong>", "").replace("</strong>", "")
line = line.replace("<br/>", "\n").replace("&nbsp;", " ")
line = line.strip("\n")
parsed.append(line)
return parsed
await ctx.send(embed=embed)
def setup(bot: commands.Bot):
+3 -3
View File
@@ -1,7 +1,7 @@
"""
Morse Code extension for qrm
---
Copyright (C) 2019-2021 classabbyamp, 0x5c
Copyright (C) 2019-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
@@ -34,7 +34,7 @@ class MorseCog(commands.Cog):
result += " "
embed = cmn.embed_factory(ctx)
embed.title = f"Morse Code for {msg}"
embed.description = "**" + result + "**"
embed.description = "**`" + result + "`**"
embed.colour = cmn.colours.good
await ctx.send(embed=embed)
@@ -54,7 +54,7 @@ class MorseCog(commands.Cog):
result += " "
embed = cmn.embed_factory(ctx)
embed.title = f"ASCII for {msg0}"
embed.description = result
embed.description = "`" + result + "`"
embed.colour = cmn.colours.good
await ctx.send(embed=embed)
+1 -1
View File
@@ -1,7 +1,7 @@
"""
Prefixes Lookup extension for qrm
---
Copyright (C) 2021 classabbyamp, 0x5c
Copyright (C) 2021-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
+14 -2
View File
@@ -1,7 +1,7 @@
"""
Propagation extension for qrm
---
Copyright (C) 2019-2021 classabbyamp, 0x5c
Copyright (C) 2019-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
@@ -23,7 +23,8 @@ class PropagationCog(commands.Cog):
muf_url = "https://prop.kc2g.com/renders/current/mufd-normal-now.svg"
fof2_url = "https://prop.kc2g.com/renders/current/fof2-normal-now.svg"
gl_baseurl = "https://www.fourmilab.ch/cgi-bin/uncgi/Earth?img=ETOPO1_day-m.evif&dynimg=y&opt=-p"
n0nbh_sun_url = "http://www.hamqsl.com/solarsun.php"
n0nbh_sun_url = "https://www.hamqsl.com/solarsun.php"
noaa_drap_url = "https://services.swpc.noaa.gov/images/animations/d-rap/global/d-rap/latest.png"
def __init__(self, bot):
self.bot = bot
@@ -86,6 +87,17 @@ class PropagationCog(commands.Cog):
embed.set_image(url="attachment://solarweather.png")
await ctx.send(file=file, embed=embed)
@commands.command(name="drapmap", aliases=["drap"], category=cmn.Cats.WEATHER)
async def drapmap(self, ctx: commands.Context):
"""Gets the current D-RAP map for radio blackouts"""
embed = cmn.embed_factory(ctx)
embed.title = "D Region Absorption Predictions (D-RAP) Map"
embed.colour = cmn.colours.good
embed.description = \
"Image from [swpc.noaa.gov](https://www.swpc.noaa.gov/products/d-region-absorption-predictions-d-rap)"
embed.set_image(url=self.noaa_drap_url)
await ctx.send(embed=embed)
def setup(bot: commands.Bot):
bot.add_cog(PropagationCog(bot))
+1 -1
View File
@@ -1,7 +1,7 @@
"""
Study extension for qrm
---
Copyright (C) 2019-2021 classabbyamp, 0x5c
Copyright (C) 2019-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
+1 -1
View File
@@ -1,7 +1,7 @@
"""
TeX extension for qrm
---
Copyright (C) 2021 classabbyamp, 0x5c
Copyright (C) 2021-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
+2 -2
View File
@@ -1,7 +1,7 @@
"""
Time extension for qrm
---
Copyright (C) 2021 classabbyamp, 0x5c
Copyright (C) 2021-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
@@ -65,7 +65,7 @@ class TimeCog(commands.Cog):
embed.title = f"{cmn.emojis.clock} Military Time Zones Now"
embed.colour = cmn.colours.good
embed.description = "```"
embed.description += "\n".join([f"{x}: {time + z :%Y-%m-%d %H:%M} {y}" for x, y, z in self.offsets])
embed.description += "\n".join([f"{x}: {time + z:%Y-%m-%d %H:%M} {y}" for x, y, z in self.offsets])
embed.description += "```"
embed.add_field(name="Notes", value=(
"**J** is not present in the table, and is used for local time.\n"
+19 -8
View File
@@ -1,18 +1,29 @@
# flake8: noqa
"""
Static info about the bot.
---
Copyright (C) 2019-2021 classabbyamp, 0x5c
Copyright (C) 2019-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
authors = ("@ClassAbbyAmplifier#2229", "@0x5c#0639")
description = """A bot with various useful ham radio-related functions, written in Python."""
license = "Québec Free and Open-Source Licence Strong Reciprocity (LiLiQ-R+), version 1.1"
contributing = """Check out the [source on GitHub](https://github.com/miaowware/qrm2). Contributions are welcome!
authors = ("@classabbyamp", "@0x5c.io")
description = """
A bot with various useful ham radio-related functions, written in Python.
All issues and requests related to resources (including maps, band charts, data) should be added \
in [miaowware/qrm-resources](https://github.com/miaowware/qrm-resources)."""
release = "2.9.0"
qrm is a <:miaowware_irl:678275824436379678> MiaowWare project.
"""
license = "Québec Free and Open-Source Licence Strong Reciprocity (LiLiQ-R+), version 1.1"
contributing = """
Check out the [source on GitHub](https://github.com/miaowware/qrm2). Contributions are welcome!
All issues and requests related to resources (including maps, band charts, data) should be added in [miaowware/qrm-resources](https://github.com/miaowware/qrm-resources).
"""
issue_tracker = """
Submit an issue on the [issue tracker](https://github.com/miaowware/qrm2/issues)!
All issues and requests related to resources (including maps, band charts, data) should be added in [miaowware/qrm-resources](https://github.com/miaowware/qrm-resources/issues).
"""
release = "2.10.0"
bot_server = "https://discord.gg/Ntbg3J4"
+7 -2
View File
@@ -2,7 +2,7 @@
"""
qrm, a bot for Discord
---
Copyright (C) 2019-2021 classabbyamp, 0x5c
Copyright (C) 2019-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
@@ -44,7 +44,12 @@ debug_mode = opt.debug # Separate assignement in-case we define an override (te
# --- Bot setup ---
# Loop/aiohttp stuff
loop = asyncio.get_event_loop()
try:
loop = asyncio.get_event_loop()
except RuntimeError:
# restore <=3.13 get_event_loop() behaviour
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
connector = loop.run_until_complete(conn.new_connector())
# Defining the intents
+3 -4
View File
@@ -1,10 +1,9 @@
py-cord~=2.3.2
aiohttp[speedups]
py-cord[speed]==2.7.1
ctyparser~=2.0
gridtools~=1.0
callsignlookuptools[async]~=1.0
callsignlookuptools[async]~=1.1
beautifulsoup4
pytz
cairosvg
httpx
pydantic
pydantic~=2.5
+3 -2
View File
@@ -1,17 +1,18 @@
"""
Resource schemas generator for qrm2.
---
Copyright (C) 2021 classabbyamp, 0x5c
Copyright (C) 2021-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
import json
import utils.resources_models as models
print("Generating schema for index.json")
with open("./dev-notes/rs_index_schema.json", "w") as file:
file.write(models.Index.schema_json(indent=4))
json.dump(models.Index.model_json_schema(), file)
print("Done!")
+1 -1
View File
@@ -1,7 +1,7 @@
"""
Information about callsigns for the prefixes command in hamcog.
---
Copyright (C) 2019-2021 classabbyamp, 0x5c
Copyright (C) 2019-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
+1 -1
View File
@@ -1,7 +1,7 @@
"""
Information about callsigns for the CA prefixes command in hamcog.
---
Copyright (C) 2019-2021 classabbyamp, 0x5c
Copyright (C) 2019-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
+1 -1
View File
@@ -1,7 +1,7 @@
"""
Information about callsigns for the US prefixes command in hamcog.
---
Copyright (C) 2019-2021 classabbyamp, 0x5c
Copyright (C) 2019-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
+1 -1
View File
@@ -1,7 +1,7 @@
"""
A listing of hamstudy command resources
---
Copyright (C) 2019-2021 classabbyamp, 0x5c
Copyright (C) 2019-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
+11 -9
View File
@@ -8,16 +8,18 @@
# https://github.com/0x5c/quick-bot-no-pain
# If $BOTENV is not defined, default to 'botenv'
if [ -z "$BOTENV" ]; then
BOTENV='botenv'
if [ -n "$VIRTUAL_ENV" ]; then
BOTENV="$VIRTUAL_ENV"
fi
if [ -z "$BOTENV" ]; then
BOTENV='./botenv'
fi
# Argument handling
_PASS_ERRORS=0
_NO_BOTENV=0
while [ ! -z "$1" ]; do
while [ -n "$1" ]; do
case $1 in
--pass-errors)
_PASS_ERRORS=1
@@ -34,9 +36,9 @@ while [ ! -z "$1" ]; do
done
# If $PYTHON_BIN is not defined, default to 'python3.11'
if [ $_NO_BOTENV -eq 1 -a -z "$PYTHON_BIN" ]; then
PYTHON_BIN='python3.11'
# If $PYTHON_BIN is not defined, default to 'python3'
if [ $_NO_BOTENV -eq 1 ] && [ -z "$PYTHON_BIN" ]; then
PYTHON_BIN='python3'
fi
@@ -69,9 +71,9 @@ echo "$0: Starting bot..."
# The loop
while true; do
if [ $_NO_BOTENV -eq 1 ]; then
"$PYTHON_BIN" main.py $@
"$PYTHON_BIN" main.py "$@"
else
./$BOTENV/bin/python3 main.py $@
"$BOTENV/bin/python3" main.py "$@"
fi
err=$?
_message="$0: The bot exited with [$err]"
+4 -2
View File
@@ -24,6 +24,9 @@ display_prefix = "?"
# or be nice and only print small messages: `False` (the default).
debug = False
# Whether the bot should print a deprecation notice in all embeds
deprecation_mode = True
# A tuple of user IDs that should be considered "bot owners".
# * Those users will have full control over the bot.
# ! This MUST be a tuple of integers. Single element tuple: `(123,)`
@@ -32,7 +35,6 @@ owners_uids = (200102491231092736, 564766093051166729)
# The extensions to load when running the bot.
exts = [
"base",
"ae7q",
"callsign",
"codes",
"contests",
@@ -89,7 +91,7 @@ show_help = False
msg_reacts = {}
# A :pika: emote's ID, None for no emote :c
pika = 658733876176355338
pika = 1271888780340756651
# Base URL to a deployment of rTeX, which performs LaTeX rendering.
rtex_instance = "https://rtex.probablyaweb.site/"
+1 -1
View File
@@ -1,7 +1,7 @@
"""
Wrapper to handle aiohttp connector creation.
---
Copyright (C) 2020-2021 classabbyamp, 0x5c
Copyright (C) 2020-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
+2 -2
View File
@@ -1,7 +1,7 @@
"""
Resources manager for qrm2.
---
Copyright (C) 2021 classabbyamp, 0x5c
Copyright (C) 2021-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
@@ -23,7 +23,7 @@ class ResourcesManager:
def parse_index(self, index: str):
"""Parses the index."""
return Index.parse_raw(index)
return Index.model_validate_json(index)
def sync_fetch(self, filepath: str):
"""Fetches files in sync mode."""
+8 -9
View File
@@ -1,7 +1,7 @@
"""
Resource index models for qrm2.
---
Copyright (C) 2021 classabbyamp, 0x5c
Copyright (C) 2021-2023 classabbyamp, 0x5c
SPDX-License-Identifier: LiLiQ-Rplus-1.1
"""
@@ -10,7 +10,7 @@ SPDX-License-Identifier: LiLiQ-Rplus-1.1
from collections.abc import Mapping
from datetime import datetime
from pydantic import BaseModel
from pydantic import BaseModel, RootModel
class File(BaseModel):
@@ -22,18 +22,17 @@ class File(BaseModel):
return repr(self)
class Resource(BaseModel, Mapping):
# 'A Beautiful Hack' https://github.com/samuelcolvin/pydantic/issues/1802
__root__: dict[str, list[File]]
class Resource(RootModel, Mapping):
root: dict[str, list[File]]
def __getitem__(self, key: str) -> list[File]:
return self.__root__[key]
return self.root[key]
def __iter__(self):
return iter(self.__root__)
return iter(self.root)
def __len__(self) -> int:
return len(self.__root__)
return len(self.root)
# For some reason those were not the same???
def __str__(self) -> str:
@@ -41,7 +40,7 @@ class Resource(BaseModel, Mapping):
# Make the repr more logical (despite the technical inaccuracy)
def __repr_args__(self):
return self.__root__.items()
return self.root.items()
class Index(BaseModel, Mapping):