mirror of
https://github.com/miaowware/qrm2.git
synced 2024-11-26 01:38:57 -05:00
parent
4139b23fe6
commit
43a24d614b
@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### Added
|
||||||
- MUF and foF2 maps from [prop.kc2g.com](https://prop.kc2g.com/).
|
- MUF and foF2 maps from [prop.kc2g.com](https://prop.kc2g.com/).
|
||||||
|
- Commands to show METAR (`?metar`) and TAF (`?taf`) (aeronautical weather conditions).
|
||||||
### Changed
|
### Changed
|
||||||
- New colour theme for `?greyline`.
|
- New colour theme for `?greyline`.
|
||||||
- Moved great circle distance and bearing calculation from `?ungrid` to `?griddistance`.
|
- Moved great circle distance and bearing calculation from `?ungrid` to `?griddistance`.
|
||||||
|
@ -9,7 +9,11 @@ the GNU General Public License, version 2.
|
|||||||
|
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
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
|
||||||
@ -20,8 +24,10 @@ class WeatherCog(commands.Cog):
|
|||||||
|
|
||||||
def __init__(self, bot: commands.Bot):
|
def __init__(self, bot: commands.Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
self.session = aiohttp.ClientSession(connector=bot.qrm.connector)
|
||||||
|
|
||||||
@commands.command(aliases=["solar", "bandconditions", "cond", "condx", "conditions"], category=cmn.cat.weather)
|
@commands.command(name="solarweather", aliases=["solar", "bandconditions", "cond", "condx", "conditions"],
|
||||||
|
category=cmn.cat.weather)
|
||||||
async def solarweather(self, ctx: commands.Context):
|
async def solarweather(self, ctx: commands.Context):
|
||||||
"""Gets a solar weather report."""
|
"""Gets a solar weather report."""
|
||||||
embed = cmn.embed_factory(ctx)
|
embed = cmn.embed_factory(ctx)
|
||||||
@ -103,6 +109,73 @@ class WeatherCog(commands.Cog):
|
|||||||
embed.set_image(url=f"http://wttr.in/{loc}_0{units}pnFQ.png")
|
embed.set_image(url=f"http://wttr.in/{loc}_0{units}pnFQ.png")
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@commands.command(name="metar", category=cmn.cat.weather)
|
||||||
|
async def metar(self, ctx: commands.Context, airport: str, hours: int = 0):
|
||||||
|
"""Gets current raw METAR (Meteorological Terminal Aviation Routine Weather Report) for an airport. \
|
||||||
|
Optionally, a number of hours can be given to show a number of hours of historical METAR data.
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
@commands.command(name="taf", category=cmn.cat.weather)
|
||||||
|
async def taf(self, ctx: commands.Context, airport: str):
|
||||||
|
"""Gets forecasted raw TAF (Terminal Aerodrome Forecast) data for an airport. Includes the latest METAR data.
|
||||||
|
|
||||||
|
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:
|
||||||
|
embed.title = "Invalid airport given!"
|
||||||
|
embed.colour = cmn.colours.bad
|
||||||
|
return embed
|
||||||
|
|
||||||
|
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")
|
||||||
|
async with self.session.get(url) as r:
|
||||||
|
if r.status != 200:
|
||||||
|
raise cmn.BotHTTPError(r)
|
||||||
|
page = 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))
|
||||||
|
|
||||||
|
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(" ", " ")
|
||||||
|
line = line.strip("\n")
|
||||||
|
parsed.append(line)
|
||||||
|
return parsed
|
||||||
|
|
||||||
|
|
||||||
def setup(bot: commands.Bot):
|
def setup(bot: commands.Bot):
|
||||||
bot.add_cog(WeatherCog(bot))
|
bot.add_cog(WeatherCog(bot))
|
||||||
|
Loading…
Reference in New Issue
Block a user