From 90834704828ec6ae4ac02211b9f678df62e2ad5b Mon Sep 17 00:00:00 2001
From: Ian Renton
Date: Mon, 31 Aug 2026 08:59:49 +0100
Subject: [PATCH] Add support for DTMBA
---
config-example.yml | 3 +++
core/constants.py | 8 ++++++-
core/sig_lookup_helper.py | 5 +++++
providers/sigrefdata/dtmba.py | 41 +++++++++++++++++++++++++++++++++++
providers/spot/parksnpeaks.py | 1 -
pyproject.toml | 2 +-
static/apidocs/openapi.yml | 1 +
static/js/ui-ham.js | 2 ++
templates/about.html | 6 ++---
templates/add_spot.html | 2 +-
templates/alerts.html | 2 +-
templates/bands.html | 4 ++--
templates/base.html | 10 ++++-----
templates/conditions.html | 2 +-
templates/map.html | 4 ++--
templates/spots.html | 4 ++--
templates/status.html | 2 +-
17 files changed, 78 insertions(+), 21 deletions(-)
create mode 100644 providers/sigrefdata/dtmba.py
diff --git a/config-example.yml b/config-example.yml
index b355182..151bdf4 100644
--- a/config-example.yml
+++ b/config-example.yml
@@ -252,6 +252,9 @@ sig_ref_data_providers:
- class: "SANPCPA"
enabled: true
+ - class: "DTMBA"
+ enabled: true
+
- class: "Toilets"
enabled: true
diff --git a/core/constants.py b/core/constants.py
index 442a961..f767e8f 100644
--- a/core/constants.py
+++ b/core/constants.py
@@ -3,7 +3,7 @@ from data.band import Band
from data.sig import SIG
# General software
-SOFTWARE_VERSION = "2.0.5"
+SOFTWARE_VERSION = "2.1-pre"
# HTTP headers used for spot providers that use HTTP
HTTP_HEADERS = {"User-Agent": f"Spothole v{SOFTWARE_VERSION} (operated by {SERVER_OWNER_CALLSIGN})"}
@@ -150,6 +150,12 @@ SIGS = [
description="Diplomas de Municipios Españoles",
ref_regex=r"\d{4,5}",
),
+ SIG(
+ name="DTMBA",
+ comment_names=["DTMBA"],
+ description="Diploma Teatri Musei e Belle Arti",
+ ref_regex=r"I-?[0-9]{3,4}\s?[A-Z]{2}",
+ ),
SIG(
name="Toilets",
comment_names=[],
diff --git a/core/sig_lookup_helper.py b/core/sig_lookup_helper.py
index 32a4b0e..032ce5c 100644
--- a/core/sig_lookup_helper.py
+++ b/core/sig_lookup_helper.py
@@ -29,6 +29,11 @@ def get_sig_ref_info(sig, ref_id):
if sig.upper() == "DME":
ref_id = ref_id.zfill(5)
+ # DTMBA spotters sometimes include spaces and dashes, our regex allows them but they must be removed here so we
+ # can look up against the official list which doesn't have them
+ if sig.upper() == "DTMBA":
+ ref_id = ref_id.replace("-", "").replace(" ", "")
+
# If the SIG is HEMA, we have no current lookup for this so just skip the lookup here.
if sig.upper() == "HEMA":
sig_ref.ref_type = "Summit"
diff --git a/providers/sigrefdata/dtmba.py b/providers/sigrefdata/dtmba.py
new file mode 100644
index 0000000..801ebb4
--- /dev/null
+++ b/providers/sigrefdata/dtmba.py
@@ -0,0 +1,41 @@
+from time import sleep
+
+from data.sig_ref import SIGRef
+from providers.sigrefdata.file_download_sig_ref_data_provider import FileDownloadSIGRefDataProvider
+
+
+class DTMBA(FileDownloadSIGRefDataProvider):
+ """SIG ref data provider for Diploma Teatri Musei Belle Arti"""
+
+ POLL_INTERVAL_DAYS = 30
+ SIG = "DTMBA"
+ DATA_URL = "https://www.iu1fig.com/share/iz0eik/dtmba/export.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 = []
+ for row in http_response.content.decode("utf-8-sig").splitlines():
+ split = row.split(";")
+ ref_id = split[0]
+ ref_name = split[1]
+ new_data.append(
+ SIGRef(
+ sig=self.SIG,
+ id=ref_id,
+ name=ref_name,
+ ref_type="Building"
+ )
+ )
+
+ # 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
diff --git a/providers/spot/parksnpeaks.py b/providers/spot/parksnpeaks.py
index 9ae4f7c..559700a 100644
--- a/providers/spot/parksnpeaks.py
+++ b/providers/spot/parksnpeaks.py
@@ -19,7 +19,6 @@ class ParksNPeaks(HTTPSpotProvider):
POLL_INTERVAL_SEC = 120
SPOTS_URL = "https://www.parksnpeaks.org/api/ALL"
SUBMIT_URL = "https://www.parksnpeaks.org/api/SPOT/"
- SIOTA_LIST_URL = "https://www.silosontheair.com/data/silos.csv"
SUBMITTABLE_SIGS = [
"POTA",
"SOTA",
diff --git a/pyproject.toml b/pyproject.toml
index 795370e..cf6c309 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "spothole"
-version = "2.0.5"
+version = "2.1-pre"
authors = [
{ name = "Ian Renton", email = "ian@ianrenton.com" },
]
diff --git a/static/apidocs/openapi.yml b/static/apidocs/openapi.yml
index cbcc3cc..e2d495a 100644
--- a/static/apidocs/openapi.yml
+++ b/static/apidocs/openapi.yml
@@ -852,6 +852,7 @@ components:
- WAB
- WAI
- DME
+ - DTMBA
- Toilets
example: POTA
diff --git a/static/js/ui-ham.js b/static/js/ui-ham.js
index fc29a90..cee6cf5 100644
--- a/static/js/ui-ham.js
+++ b/static/js/ui-ham.js
@@ -365,6 +365,7 @@ const SIG_ICONS = {
"WAI": "fa-table-cells-large",
"DME": "fa-building",
"Tiles": "fa-square",
+ "DTMBA": "fa-masks-theater",
"Toilets": "fa-toilet"
}
@@ -392,6 +393,7 @@ const SIG_NAMES = {
"WAB": "Worked All Britain",
"WAI": "Worked All Ireland",
"Tiles": "Tiles on the Air",
+ "DTMBA": "Diploma Teatri Musei e Belle Arti",
"TOTA": "Toilets on the Air"
}
diff --git a/templates/about.html b/templates/about.html
index e853d41..767ec08 100644
--- a/templates/about.html
+++ b/templates/about.html
@@ -101,9 +101,9 @@
(MOTA), the Amateur Radio Lighthouse Society (ARLHS), International Lighthouse Lightship Weekend (ILLW), Silos
on the Air (SIOTA), World Castles Award (WCA), New Zealand on the Air (ZLOTA), Keith Roget Memorial National
Parks Award (KRMNPA), South Australia National Parks and Conservation Parks Award (SANPCPA), Wainwrights on the
- Air (WOTA), Beaches on the Air (BOTA), Lagos y Lagunas On the Air (LLOTA), Towers on the Air (WWTOTA), Tiles on
- the Air, Worked All Britain (WAB), Worked All Ireland (WAI), el Diploma Municipios de España (DME) and Toilets
- on the Air (TOTA).
+ 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), Diploma
+ Teatri Musei e Belle Arti (DTMBA) and Toilets on the Air.
As of the time of writing in June 2026, I think Spothole captures essentially all outdoor radio programmes
that have a defined reference list, and almost certainly those that have a spotting/alerting API. If you know of
one I've missed, please let me know!