Support PGA. Closes #135

This commit is contained in:
Ian Renton
2026-08-31 21:54:13 +01:00
parent b0caf697ae
commit 1b62d4742b
15 changed files with 94 additions and 19 deletions
+3
View File
@@ -261,6 +261,9 @@ sig_ref_data_providers:
- class: "COTA" - class: "COTA"
enabled: true enabled: true
- class: "PGA"
enabled: true
- class: "Toilets" - class: "Toilets"
enabled: true enabled: true
+9
View File
@@ -242,6 +242,15 @@ SIGS = [
region_flag="🇩🇪", region_flag="🇩🇪",
refs_globally_unique=False refs_globally_unique=False
), ),
SIG(
name="PGA",
comment_names=["PGA"],
description="Polish Gmina Award",
ref_regex=r"[A-Z]{2}[0-9]{2}",
icon="fa-g",
region_flag="🇵🇱",
refs_globally_unique=False
),
SIG( SIG(
name="Toilets", name="Toilets",
comment_names=[], comment_names=[],
+2 -2
View File
@@ -31,10 +31,10 @@ def infer_mode_from_comment(comment):
"""Infer a mode from the comment""" """Infer a mode from the comment"""
for mode in ALL_MODES: for mode in ALL_MODES:
if re.match(r"(^|\W)" + mode + r"($|\W)", comment, re.IGNORECASE): if re.search(r"(^|\W)" + mode + r"($|\W)", comment, re.IGNORECASE):
return mode return mode
for mode in MODE_ALIASES: for mode in MODE_ALIASES:
if re.match(r"(^|\W)" + mode + r"($|\W)", comment, re.IGNORECASE): if re.search(r"(^|\W)" + mode + r"($|\W)", comment, re.IGNORECASE):
return MODE_ALIASES[mode] return MODE_ALIASES[mode]
return None return None
+57
View File
@@ -0,0 +1,57 @@
from time import sleep
from bs4 import BeautifulSoup
from data.sig_ref import SIGRef
from providers.sigrefdata.file_download_sig_ref_data_provider import FileDownloadSIGRefDataProvider
class PGA(FileDownloadSIGRefDataProvider):
"""SIG ref data provider for Polish Gmina Award"""
POLL_INTERVAL_DAYS = 30
SIG = "PGA"
DATA_URL = "http://www.spga.pl/lista_pga2.php"
def __init__(self, provider_config):
super().__init__(self.SIG, provider_config, self.DATA_URL, self.POLL_INTERVAL_DAYS)
def _http_response_to_data(self, http_response):
new_data = []
soup = BeautifulSoup(http_response.text, "html.parser")
# Iterate through tables in the page
for table in soup.find_all("table"):
header_cells = table.find_all(["th", "td"], limit=10)
header_texts = [c.get_text(strip=True) for c in header_cells]
# If it has "PGA" and "Nazwa" in the header, it's the main data table
if any("PGA" in t for t in header_texts) and any("Nazwa" in t for t in header_texts):
# Iterate through all rows except the first
rows = table.find_all("tr")
for row in rows[1:]:
cells = row.find_all("td")
ref_id = cells[0].get_text(strip=True)
name = cells[1].get_text(strip=True)
if not ref_id:
continue
new_data.append(
SIGRef(
sig=self.SIG,
id=ref_id,
name=name,
ref_type="Region",
)
)
# Bail out if a stop has been requested, i.e. the program is shutting down - no need to parse the rest
# of the data in this case
if self._stop_event.is_set():
break
# Very short pause. This will extend the time to handle sig refs by a few seconds but will ensure some time
# is available for other threads e.g. the web server.
sleep(0.001)
return new_data
+4
View File
@@ -10,6 +10,7 @@ from core.constants import SOFTWARE_VERSION
from core.data_providers import DATA_PROVIDERS from core.data_providers import DATA_PROVIDERS
from core.data_store import DATA_STORE from core.data_store import DATA_STORE
from core.status_reporter import StatusReporter from core.status_reporter import StatusReporter
from core.utils import infer_mode_from_comment
from server.webserver import WEB_SERVER from server.webserver import WEB_SERVER
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -28,6 +29,9 @@ def shutdown(_signum=None, _frame=None):
# Main function # Main function
if __name__ == "__main__": if __name__ == "__main__":
result = infer_mode_from_comment("Test FT8")
print(result)
# Set up logging # Set up logging
root = logging.getLogger() root = logging.getLogger()
root.setLevel(LOG_LEVEL) root.setLevel(LOG_LEVEL)
+3 -1
View File
@@ -17,7 +17,7 @@ info:
### 2.1 ### 2.1
* Added DTMBA, FEA and BIWOTA SIGs * Added DTMBA, FEA, BIWOTA, COTA & PGA SIGs
* Removed the distinction between LSB & USB (both will now show as SSB) and between the various digital voice modes, which will now show as DV. * Removed the distinction between LSB & USB (both will now show as SSB) and between the various digital voice modes, which will now show as DV.
* Added `icon`, `region_flag` and `refs_globally_unique` to SIG information * Added `icon`, `region_flag` and `refs_globally_unique` to SIG information
@@ -861,6 +861,8 @@ components:
- FEA - FEA
- DTMBA - DTMBA
- BIWOTA - BIWOTA
- COTA
- PGA
- Toilets - Toilets
example: POTA example: POTA
+1 -1
View File
@@ -104,7 +104,7 @@
Air (WOTA), Beaches on the Air (BOTA), Lagos y Lagunas On the Air (LLOTA), Towers on the Air, Tiles on Air (WOTA), Beaches on the Air (BOTA), Lagos y Lagunas On the Air (LLOTA), Towers on the Air, Tiles on
the Air, Worked All Britain (WAB), Worked All Ireland (WAI), el Diploma Municipios de España (DME), el Diploma the Air, Worked All Britain (WAB), Worked All Ireland (WAI), el Diploma Municipios de España (DME), el Diploma
Faros de España (FEA), il Diploma Teatri Musei e Belle Arti (DTMBA), British Inland Waterways on the Air Faros de España (FEA), il Diploma Teatri Musei e Belle Arti (DTMBA), British Inland Waterways on the Air
(BIWOTA) and Toilets on the Air.</p> (BIWOTA), Castles on the Air (COTA), Polish Gmina Award (PGA), and Toilets on the Air.</p>
<p>As of the time of writing in August 2026, I think Spothole captures most outdoor radio programmes that have a <p>As of the time of writing in August 2026, I think Spothole captures most outdoor radio programmes that have a
defined, downloadable reference list, and almost certainly those that have a spotting/alerting API. If you know defined, downloadable reference list, and almost certainly those that have a spotting/alerting API. If you know
of one I've missed, please let me know!</p> of one I've missed, please let me know!</p>
+1 -1
View File
@@ -76,7 +76,7 @@
</div> </div>
<script src="/static/js/add-spot.js?v=1788207475"></script> <script src="/static/js/add-spot.js?v=1788209654"></script>
<script>$(document).ready(function () { <script>$(document).ready(function () {
$("#nav-link-add-spot").addClass("active"); $("#nav-link-add-spot").addClass("active");
}); <!-- highlight active page in nav --></script> }); <!-- highlight active page in nav --></script>
+1 -1
View File
@@ -84,7 +84,7 @@
</div> </div>
<script src="/static/js/alerts.js?v=1788207475"></script> <script src="/static/js/alerts.js?v=1788209654"></script>
<script>$(document).ready(function () { <script>$(document).ready(function () {
$("#nav-link-alerts").addClass("active"); $("#nav-link-alerts").addClass("active");
}); <!-- highlight active page in nav --></script> }); <!-- highlight active page in nav --></script>
+2 -2
View File
@@ -76,8 +76,8 @@
</div> </div>
<script src="/static/js/spotsbandsandmap.js?v=1788207475"></script> <script src="/static/js/spotsbandsandmap.js?v=1788209654"></script>
<script src="/static/js/bands.js?v=1788207475"></script> <script src="/static/js/bands.js?v=1788209654"></script>
<script>$(document).ready(function () { <script>$(document).ready(function () {
$("#nav-link-bands").addClass("active"); $("#nav-link-bands").addClass("active");
}); <!-- highlight active page in nav --></script> }); <!-- highlight active page in nav --></script>
+5 -5
View File
@@ -1,6 +1,6 @@
{% extends "skeleton.html" %} {% extends "skeleton.html" %}
{% block head_extra %} {% block head_extra %}
<link rel="stylesheet" href="/static/css/style.css?v=1788207475" type="text/css"> <link rel="stylesheet" href="/static/css/style.css?v=1788209654" type="text/css">
<link href="/static/vendor/css/bootstrap-5.3.8.min.css" rel="stylesheet"> <link href="/static/vendor/css/bootstrap-5.3.8.min.css" rel="stylesheet">
<link href="/static/vendor/css/fontawesome-6.7.2.min.css" rel="stylesheet"> <link href="/static/vendor/css/fontawesome-6.7.2.min.css" rel="stylesheet">
<link href="/static/vendor/css/solid-6.7.2.min.css" rel="stylesheet"> <link href="/static/vendor/css/solid-6.7.2.min.css" rel="stylesheet">
@@ -15,10 +15,10 @@
window.fetchEventSource = fetchEventSource; window.fetchEventSource = fetchEventSource;
</script> </script>
<script src="/static/js/utils.js?v=1788207475"></script> <script src="/static/js/utils.js?v=1788209654"></script>
<script src="/static/js/ui-ham.js?v=1788207475"></script> <script src="/static/js/ui-ham.js?v=1788209654"></script>
<script src="/static/js/geo.js?v=1788207475"></script> <script src="/static/js/geo.js?v=1788209654"></script>
<script src="/static/js/common.js?v=1788207475"></script> <script src="/static/js/common.js?v=1788209654"></script>
{% end %} {% end %}
{% block body %} {% block body %}
<div class="container"> <div class="container">
+1 -1
View File
@@ -284,7 +284,7 @@
</div> </div>
<script src="/static/vendor/js/chart-4.4.9.umd.min.js"></script> <script src="/static/vendor/js/chart-4.4.9.umd.min.js"></script>
<script src="/static/js/conditions.js?v=1788207475"></script> <script src="/static/js/conditions.js?v=1788209654"></script>
<script>$(document).ready(function () { <script>$(document).ready(function () {
$("#nav-link-conditions").addClass("active"); $("#nav-link-conditions").addClass("active");
}); <!-- highlight active page in nav --></script> }); <!-- highlight active page in nav --></script>
+2 -2
View File
@@ -113,8 +113,8 @@
const CARTODB_API_KEY = "{{ web_ui_options.get('cartodb_api_key', '') }}"; const CARTODB_API_KEY = "{{ web_ui_options.get('cartodb_api_key', '') }}";
</script> </script>
<script src="/static/js/spotsbandsandmap.js?v=1788207475"></script> <script src="/static/js/spotsbandsandmap.js?v=1788209653"></script>
<script src="/static/js/map.js?v=1788207475"></script> <script src="/static/js/map.js?v=1788209653"></script>
<script>$(document).ready(function () { <script>$(document).ready(function () {
$("#nav-link-map").addClass("active"); $("#nav-link-map").addClass("active");
}); <!-- highlight active page in nav --></script> }); <!-- highlight active page in nav --></script>
+2 -2
View File
@@ -113,8 +113,8 @@
</div> </div>
<script src="/static/js/spotsbandsandmap.js?v=1788207475"></script> <script src="/static/js/spotsbandsandmap.js?v=1788209653"></script>
<script src="/static/js/spots.js?v=1788207475"></script> <script src="/static/js/spots.js?v=1788209653"></script>
<script>$(document).ready(function () { <script>$(document).ready(function () {
$("#nav-link-spots").addClass("active"); $("#nav-link-spots").addClass("active");
}); <!-- highlight active page in nav --></script> }); <!-- highlight active page in nav --></script>
+1 -1
View File
@@ -86,7 +86,7 @@
</div> </div>
</div> </div>
<script src="/static/js/status.js?v=1788207475"></script> <script src="/static/js/status.js?v=1788209654"></script>
<script> <script>
$(document).ready(function () { $(document).ready(function () {
$("#nav-link-status").addClass("active"); $("#nav-link-status").addClass("active");