This commit is contained in:
Ian Renton
2025-10-02 12:17:42 +01:00
parent 99d60cced0
commit 09082b5d62
16 changed files with 39 additions and 7 deletions

View File

@@ -31,3 +31,11 @@ If you're extending the `HTTPProvider` class, you will need to provide a URI to
When constructing spots, use the comments in the Spot class and the existing implementations as an example. All parameters are optional, but you will at least want to provide a `time` (which must be timezone-aware) and a `dx_call`.
Finally, simply add the appropriate config to the `providers` section of `config.yml`, and your provider should be instantiated on startup.
### Third Party Libraries
The project contains a self-hosted copy of Font Awesome's free library, in the `/fa/` directory. This is subject to Font Awesome's licence and is not covered by the overall licence declared in the `LICENSE` file. This approach was taken in preference to using their hosted kits due to the popularity of this project exceeding the page view limit for their free hosted offering.
TODO JS & Python libs...
This project would not have been possible without these libraries, so many thanks to their developers.

View File

@@ -73,6 +73,8 @@ class Spot:
sig_refs_names: list = None
# Activation score. SOTA only
activation_score: int = None
# Icon, from the Font Awesome set. This is fairly opinionated but is here to help the Spothole web UI and Field Spotter. Does not include the "fa-" prefix.
icon: str = "question"
# Maidenhead grid locator for the spot. This could be from a geographical reference e.g. POTA, or just from the country
grid: str = None
# Latitude & longitude, in degrees. This could be from a geographical reference e.g. POTA, or from a QRZ lookup

View File

@@ -47,6 +47,7 @@ class APRSIS(Provider):
comment=data["comment"] if "comment" in data else None,
latitude=data["latitude"] if "latitude" in data else None,
longitude=data["longitude"] if "longitude" in data else None,
icon="tower-cell",
time=datetime.now(pytz.UTC)) # APRS-IS spots are live so we can assume spot time is "now"
# Add to our list

View File

@@ -69,6 +69,7 @@ class DXCluster(Provider):
de_call=match.group(1),
freq=float(match.group(2)),
comment=match.group(4).strip(),
icon="desktop",
time=spot_datetime)
# Add to our list

View File

@@ -32,6 +32,7 @@ class GMA(HTTPProvider):
comment=source_spot["TEXT"],
sig_refs=[source_spot["REF"]],
sig_refs_names=[source_spot["NAME"]],
icon="person-hiking",
time=datetime.strptime(source_spot["DATE"] + source_spot["TIME"], "%Y%m%d%H%M").replace(tzinfo=pytz.UTC),
latitude=float(source_spot["LAT"]) if (source_spot["LAT"] != "") else None, # Seen GMA spots with no lat/lon
longitude=float(source_spot["LON"]) if (source_spot["LON"] != "") else None)

View File

@@ -54,6 +54,7 @@ class HEMA(HTTPProvider):
sig="HEMA",
sig_refs=[spot_items[3].upper()],
sig_refs_names=[spot_items[4]],
icon="person-hiking",
time=datetime.strptime(spot_items[0], "%d/%m/%Y %H:%M").replace(tzinfo=pytz.UTC),
latitude=float(spot_items[7]),
longitude=float(spot_items[8]))

View File

@@ -29,6 +29,7 @@ class ParksNPeaks(HTTPProvider):
comment=source_spot["actComments"],
sig=source_spot["actClass"],
sig_refs=[source_spot["actSiteID"]],
icon="question", # todo determine from actClass
time=datetime.strptime(source_spot["actTime"], "%Y-%m-%d %H:%M:%S").replace(tzinfo=pytz.UTC))
# If this is POTA, SOTA or WWFF data we already have it through other means, so ignore.

View File

@@ -29,6 +29,7 @@ class POTA(HTTPProvider):
sig="POTA",
sig_refs=[source_spot["reference"]],
sig_refs_names=[source_spot["name"]],
icon="tree",
time=datetime.strptime(source_spot["spotTime"], "%Y-%m-%dT%H:%M:%S").replace(tzinfo=pytz.UTC),
grid=source_spot["grid6"],
latitude=source_spot["latitude"],

View File

@@ -70,6 +70,7 @@ class RBN(Provider):
de_call=match.group(1),
freq=float(match.group(2)),
comment=match.group(4).strip(),
icon="tower-cell",
time=spot_datetime)
# Add to our list

View File

@@ -48,6 +48,7 @@ class SOTA(HTTPProvider):
sig="SOTA",
sig_refs=[source_spot["summitCode"]],
sig_refs_names=[source_spot["summitName"]],
icon="mountain-sun",
time=datetime.fromisoformat(source_spot["timeStamp"]),
activation_score=source_spot["points"])

View File

@@ -32,6 +32,7 @@ class WWBOTA(HTTPProvider):
sig="WWBOTA",
sig_refs=refs,
sig_refs_names=ref_names,
icon="radiation",
time=datetime.fromisoformat(source_spot["time"]),
# WWBOTA spots can contain multiple references for bunkers being activated simultaneously. For
# now, we will just pick the first one to use as our grid, latitude and longitude.

View File

@@ -29,6 +29,7 @@ class WWFF(HTTPProvider):
sig="WWFF",
sig_refs=[source_spot["reference"]],
sig_refs_names=[source_spot["reference_name"]],
icon="seedling",
time=datetime.fromtimestamp(source_spot["spot_time"]).replace(tzinfo=pytz.UTC),
latitude=source_spot["latitude"],
longitude=source_spot["longitude"])

View File

@@ -6,15 +6,17 @@
<title>(S)pothole</title>
<link rel="stylesheet" href="css/style.css" type="text/css">
<link rel="stylesheet" href="/css/style.css" type="text/css">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
<link href="/fa/css/fontawesome.min.css" rel="stylesheet" />
<link href="/fa/css/solid.min.css" rel="stylesheet" />
<link rel="icon" type="image/png" href="img/icon-512.png">
<link rel="alternate icon" type="image/png" href="img/icon-192.png">
<link rel="alternate icon" type="image/png" href="img/icon-32.png">
<link rel="alternate icon" type="image/png" href="img/icon-16.png">
<link rel="alternate icon" type="image/x-icon" href="img/favicon.ico">
<link rel="icon" type="image/png" href="/img/icon-512.png">
<link rel="alternate icon" type="image/png" href="/img/icon-192.png">
<link rel="alternate icon" type="image/png" href="/img/icon-32.png">
<link rel="alternate icon" type="image/png" href="/img/icon-16.png">
<link rel="alternate icon" type="image/x-icon" href="/img/favicon.ico">
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/moment@2.29.4/moment.min.js"></script>

View File

@@ -493,6 +493,10 @@ components:
type: integer
description: Activation score. SOTA only
example: 0
icon:
type: string
descripton: Icon, from the Font Awesome set. This is fairly opinionated but is here to help the Spothole web UI and Field Spotter. Does not include the "fa-" prefix.
example: tree
grid:
type: string
description: Maidenhead grid locator for the spot. This could be from a geographical reference e.g. POTA, or just from the country

View File

@@ -8,3 +8,9 @@
margin: 0 auto;
}
}
span.icon-wrapper {
display: inline-block;
width: 1.5em;
text-align: center;
}

View File

@@ -36,7 +36,7 @@ function loadSpots() {
$tr.append(`<td>${row["freq"]}</td>`);
$tr.append(`<td>${row["mode"]}</td>`);
$tr.append('<td>' + escapeHtml(`${row["comment"]}`) + '</td>');
$tr.append(`<td>${row["source"]}</td>`);
$tr.append(`<td><span class='icon-wrapper'><i class='fa-solid fa-${row["icon"]}'></i></span> ${row["source"]}</td>`);
$tr.append(`<td>${row["de_flag"]}&nbsp;${row["de_call"]}</td>`);
table.find('tbody').append($tr);
});