Files
spothole/providers/spot/wota.py
T
2026-08-17 06:47:20 +01:00

103 lines
3.9 KiB
Python

import logging
import re
from datetime import datetime
from typing import cast
import pytz
from rss_parser import Parser
from rss_parser.models.rss import RSS
from data.sig_ref import SIGRef
from data.spot import Spot
from providers.spot.http_spot_provider import HTTPSpotProvider
logger = logging.getLogger(__name__)
class WOTA(HTTPSpotProvider):
"""Spot provider for Wainwrights on the Air"""
POLL_INTERVAL_SEC = 120
SPOTS_URL = "https://www.wota.org.uk/spots_rss.php"
RSS_DATE_TIME_FORMAT = "%a, %d %b %Y %H:%M:%S %z"
def __init__(self, provider_config):
super().__init__("WOTA", provider_config, self.SPOTS_URL, self.POLL_INTERVAL_SEC)
def _http_response_to_spots(self, http_response):
new_spots = []
rss = cast(RSS, Parser.parse(http_response.content.decode("utf-8-sig")))
# Iterate through source data
for source_spot in rss.channel.items:
try:
# Reject GUID missing or zero
if (
not source_spot.guid
or not source_spot.guid.content
or source_spot.guid.content == "http://www.wota.org.uk/spots/0"
):
continue
# Pick apart the title
dx_call = None
ref = None
ref_name = None
try:
title_split = source_spot.title.split(" on ")
dx_call = title_split[0]
if len(title_split) > 1:
ref_split = title_split[1].split(" - ")
ref = str(ref_split[0])
if len(ref_split) > 1:
ref_name = str(ref_split[1])
except Exception:
logger.warning(f"Could not parse WOTA spot title: {source_spot.title}")
# Pick apart the description
freq_hz = None
mode = None
comment = None
spotter = None
try:
desc_split = source_spot.description.split(". ")
freq_mode = desc_split[0].replace("Frequencies/modes:", "").strip()
freq_mode_split = re.split(r"[\-\s]+", freq_mode)
freq_hz = float(freq_mode_split[0].replace("'", ".")) * 1000000
if len(freq_mode_split) > 1:
mode = freq_mode_split[1].upper()
if len(desc_split) > 1:
comment = desc_split[1].strip()
if len(desc_split) > 2:
spotter = desc_split[2].replace("Spotted by ", "").replace(".", "").upper().strip()
except Exception:
logger.warning(f"Could not parse WOTA spot description: {source_spot.description}")
time = datetime.strptime(source_spot.pub_date.content, self.RSS_DATE_TIME_FORMAT).astimezone(pytz.UTC)
# Convert to our spot format
spot = Spot(
source=self.name,
source_id=source_spot.guid.content,
dx_call=dx_call,
de_call=spotter,
freq=freq_hz,
mode=mode,
comment=comment,
sig="WOTA",
sig_refs=[SIGRef(id=ref, sig="WOTA", name=ref_name)] if ref else [],
time=time.timestamp(),
)
new_spots.append(spot)
except Exception:
logger.exception("Exception parsing WOTA spot")
return new_spots
def can_submit_spot(self, sig):
return sig == "WOTA"
def submit_spot(self, spot, credentials):
# TODO Ask M5TEA if he's happy to share how this is done from his app
raise NotImplementedError("WOTA upstream spot submission is not yet implemented")