mirror of
https://github.com/miaowware/qrm2.git
synced 2024-11-21 15:41:51 -05:00
Merge pull request #476 from miaowware/fix/metar
Fix metar + version bumps
This commit is contained in:
commit
abdc5ebacb
@ -7,8 +7,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### Added
|
||||||
- `?drapmap` command to display NOAA D Region Absorption Predictions map.
|
- `?drapmap` command to display NOAA D Region Absorption Predictions map.
|
||||||
|
- Support for the new username format.
|
||||||
### Fixed
|
### Fixed
|
||||||
- Issue where `?solarweather` would not show a picture (#474).
|
- 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
|
## [2.9.1] - 2023-01-29
|
||||||
|
@ -9,11 +9,9 @@ SPDX-License-Identifier: LiLiQ-Rplus-1.1
|
|||||||
|
|
||||||
|
|
||||||
import re
|
import re
|
||||||
from typing import List
|
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
|
||||||
from discord import Embed
|
|
||||||
import discord.ext.commands as commands
|
import discord.ext.commands as commands
|
||||||
|
|
||||||
import common as cmn
|
import common as cmn
|
||||||
@ -102,7 +100,32 @@ class WeatherCog(commands.Cog):
|
|||||||
|
|
||||||
Airports should be given as an \
|
Airports should be given as an \
|
||||||
[ICAO code](https://en.wikipedia.org/wiki/List_of_airports_by_IATA_and_ICAO_code)."""
|
[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)
|
@commands.command(name="taf", category=cmn.Cats.WEATHER)
|
||||||
async def taf(self, ctx: commands.Context, airport: str):
|
async def taf(self, ctx: commands.Context, airport: str):
|
||||||
@ -110,57 +133,28 @@ class WeatherCog(commands.Cog):
|
|||||||
|
|
||||||
Airports should be given as an \
|
Airports should be given as an \
|
||||||
[ICAO code](https://en.wikipedia.org/wiki/List_of_airports_by_IATA_and_ICAO_code)."""
|
[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)
|
embed = cmn.embed_factory(ctx)
|
||||||
airport = airport.upper()
|
airport = airport.upper()
|
||||||
|
|
||||||
if re.fullmatch(r"\w(\w|\d){2,3}", airport):
|
if not 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:
|
|
||||||
embed.title = "Invalid airport given!"
|
embed.title = "Invalid airport given!"
|
||||||
embed.colour = cmn.colours.bad
|
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://aviationweather.gov/api/data/taf?ids={airport}&format=raw&metar=true"
|
||||||
url = (f"https://www.aviationweather.gov/metar/data?ids={airport}&format=raw&hours={hours}"
|
|
||||||
f"&taf={'on' if taf else 'off'}&layout=off")
|
|
||||||
async with self.session.get(url) as r:
|
async with self.session.get(url) as r:
|
||||||
if r.status != 200:
|
if r.status != 200:
|
||||||
raise cmn.BotHTTPError(r)
|
raise cmn.BotHTTPError(r)
|
||||||
page = await r.text()
|
taf = await r.text()
|
||||||
|
|
||||||
# pare down to just the data
|
embed.title = f"Current TAF for {airport}"
|
||||||
page = page.split("<!-- Data starts here -->")[1].split("<!-- Data ends here -->")[0].strip()
|
embed.description = "Data from [aviationweather.gov](https://www.aviationweather.gov/)."
|
||||||
# split at <hr>s
|
embed.colour = cmn.colours.good
|
||||||
data = re.split(r"<hr.*>", page, maxsplit=len(airport))
|
embed.description += f"\n\n```\n{taf}\n```"
|
||||||
|
|
||||||
parsed = []
|
await ctx.send(embed=embed)
|
||||||
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(" ", " ")
|
|
||||||
line = line.strip("\n")
|
|
||||||
parsed.append(line)
|
|
||||||
return parsed
|
|
||||||
|
|
||||||
|
|
||||||
def setup(bot: commands.Bot):
|
def setup(bot: commands.Bot):
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
py-cord~=2.3.2
|
py-cord-dev[speed]==2.5.0rc5
|
||||||
aiohttp[speedups]
|
|
||||||
ctyparser~=2.0
|
ctyparser~=2.0
|
||||||
gridtools~=1.0
|
gridtools~=1.0
|
||||||
callsignlookuptools[async]~=1.1
|
callsignlookuptools[async]~=1.1
|
||||||
@ -7,4 +6,4 @@ beautifulsoup4
|
|||||||
pytz
|
pytz
|
||||||
cairosvg
|
cairosvg
|
||||||
httpx
|
httpx
|
||||||
pydantic
|
pydantic~=2.5
|
||||||
|
@ -23,7 +23,7 @@ class ResourcesManager:
|
|||||||
|
|
||||||
def parse_index(self, index: str):
|
def parse_index(self, index: str):
|
||||||
"""Parses the index."""
|
"""Parses the index."""
|
||||||
return Index.parse_raw(index)
|
return Index.model_validate_json(index)
|
||||||
|
|
||||||
def sync_fetch(self, filepath: str):
|
def sync_fetch(self, filepath: str):
|
||||||
"""Fetches files in sync mode."""
|
"""Fetches files in sync mode."""
|
||||||
|
@ -10,7 +10,7 @@ SPDX-License-Identifier: LiLiQ-Rplus-1.1
|
|||||||
from collections.abc import Mapping
|
from collections.abc import Mapping
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel, RootModel
|
||||||
|
|
||||||
|
|
||||||
class File(BaseModel):
|
class File(BaseModel):
|
||||||
@ -22,18 +22,17 @@ class File(BaseModel):
|
|||||||
return repr(self)
|
return repr(self)
|
||||||
|
|
||||||
|
|
||||||
class Resource(BaseModel, Mapping):
|
class Resource(RootModel, Mapping):
|
||||||
# 'A Beautiful Hack' https://github.com/samuelcolvin/pydantic/issues/1802
|
root: dict[str, list[File]]
|
||||||
__root__: dict[str, list[File]]
|
|
||||||
|
|
||||||
def __getitem__(self, key: str) -> list[File]:
|
def __getitem__(self, key: str) -> list[File]:
|
||||||
return self.__root__[key]
|
return self.root[key]
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return iter(self.__root__)
|
return iter(self.root)
|
||||||
|
|
||||||
def __len__(self) -> int:
|
def __len__(self) -> int:
|
||||||
return len(self.__root__)
|
return len(self.root)
|
||||||
|
|
||||||
# For some reason those were not the same???
|
# For some reason those were not the same???
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
@ -41,7 +40,7 @@ class Resource(BaseModel, Mapping):
|
|||||||
|
|
||||||
# Make the repr more logical (despite the technical inaccuracy)
|
# Make the repr more logical (despite the technical inaccuracy)
|
||||||
def __repr_args__(self):
|
def __repr_args__(self):
|
||||||
return self.__root__.items()
|
return self.root.items()
|
||||||
|
|
||||||
|
|
||||||
class Index(BaseModel, Mapping):
|
class Index(BaseModel, Mapping):
|
||||||
|
Loading…
Reference in New Issue
Block a user