4 Commits

13 changed files with 51 additions and 42 deletions

View File

@@ -254,10 +254,11 @@ server {
} }
location / { location / {
add_header Access-Control-Allow-Origin $xssorigin;
proxy_http_version 1.1; proxy_http_version 1.1;
proxy_set_header Connection ""; proxy_set_header Connection "";
proxy_pass http://127.0.0.1:8080; proxy_pass http://127.0.0.1:8080;
proxy_hide_header Access-Control-Allow-Origin;
add_header Access-Control-Allow-Origin $xssorigin;
} }
} }
``` ```
@@ -266,9 +267,9 @@ One further change you might want to make to the file above is the `add_header A
my own Spothole server to make sure that other third-party web-based software can get the data from my instance, and applies to any endpoint underneath `/api`. If you want my own Spothole server to make sure that other third-party web-based software can get the data from my instance, and applies to any endpoint underneath `/api`. If you want
*your* Spothole instance to be set up the same way, so that others can write software in JavaScript that can access it, *your* Spothole instance to be set up the same way, so that others can write software in JavaScript that can access it,
leave this intact. But if you want your Spothole instance to only be usable by scripts running on the web server you write, leave this intact. But if you want your Spothole instance to only be usable by scripts running on the web server you write,
you can remove this block. (Note that this doesn't stop other people writing *non-web-based* software that accesses your you can remove this line. (Note that this doesn't stop other people writing *non-web-based* software that accesses your
Spothole API—the enforcement of cross-origin headers only happens within the user's browser. If you need to lock your Spothole API—the enforcement of cross-origin headers only happens within the user's browser. If you need to lock your
instance down so that no-one else can access it with *any* software, that's an aspect of nginx config that you will need instance down so that no-one else can access it with *any* software, that's an aspect of nginx or firewall config that you will need
to find help with elsewhere.) to find help with elsewhere.)
Now, make a symbolic link to enable the site: Now, make a symbolic link to enable the site:

View File

@@ -6,6 +6,9 @@
# this as "N0CALL" and it shouldn't do any harm, as we're not sending anything to the various networks, only receiving. # this as "N0CALL" and it shouldn't do any harm, as we're not sending anything to the various networks, only receiving.
server-owner-callsign: "N0CALL" server-owner-callsign: "N0CALL"
# The base URL at which the software runs.
base-url: "http://localhost:8080"
# Spot providers to use. This is an example set, tailor it to your liking by commenting and uncommenting. # Spot providers to use. This is an example set, tailor it to your liking by commenting and uncommenting.
# RBN and APRS-IS are supported but have such a high data rate, you probably don't want them enabled. # RBN and APRS-IS are supported but have such a high data rate, you probably don't want them enabled.
# Each provider needs a class, a name, and an enabled/disabled state. Some require more config such as hostnames/IP # Each provider needs a class, a name, and an enabled/disabled state. Some require more config such as hostnames/IP

View File

@@ -14,6 +14,7 @@ with open("config.yml") as f:
config = yaml.safe_load(f) config = yaml.safe_load(f)
logging.info("Loaded config.") logging.info("Loaded config.")
BASE_URL = config["base-url"]
MAX_SPOT_AGE = config["max-spot-age-sec"] MAX_SPOT_AGE = config["max-spot-age-sec"]
MAX_ALERT_AGE = config["max-alert-age-sec"] MAX_ALERT_AGE = config["max-alert-age-sec"]
SERVER_OWNER_CALLSIGN = config["server-owner-callsign"] SERVER_OWNER_CALLSIGN = config["server-owner-callsign"]

View File

@@ -3,7 +3,7 @@ from datetime import datetime
import pytz import pytz
import tornado import tornado
from core.config import ALLOW_SPOTTING, WEB_UI_OPTIONS from core.config import ALLOW_SPOTTING, WEB_UI_OPTIONS, BASE_URL
from core.constants import SOFTWARE_VERSION from core.constants import SOFTWARE_VERSION
from core.prometheus_metrics_handler import page_requests_counter from core.prometheus_metrics_handler import page_requests_counter
@@ -24,4 +24,4 @@ class PageTemplateHandler(tornado.web.RequestHandler):
# Load named template, and provide variables used in templates # Load named template, and provide variables used in templates
self.render(self._template_name + ".html", software_version=SOFTWARE_VERSION, allow_spotting=ALLOW_SPOTTING, self.render(self._template_name + ".html", software_version=SOFTWARE_VERSION, allow_spotting=ALLOW_SPOTTING,
web_ui_options=WEB_UI_OPTIONS) web_ui_options=WEB_UI_OPTIONS, baseurl = BASE_URL, current_path=self.request.path)

View File

@@ -34,26 +34,30 @@ class ParksNPeaks(HTTPSpotProvider):
# Seen PNP spots with empty frequency, and with comma-separated thousands digits # Seen PNP spots with empty frequency, and with comma-separated thousands digits
mode=source_spot["actMode"].upper(), mode=source_spot["actMode"].upper(),
comment=source_spot["actComments"], comment=source_spot["actComments"],
sig=source_spot["actClass"].upper(),
sig_refs=[SIGRef(id=source_spot["actSiteID"], sig=source_spot["actClass"].upper())],
time=datetime.strptime(source_spot["actTime"], "%Y-%m-%d %H:%M:%S").replace( time=datetime.strptime(source_spot["actTime"], "%Y-%m-%d %H:%M:%S").replace(
tzinfo=pytz.UTC).timestamp()) tzinfo=pytz.UTC).timestamp())
# Free text location is not present in all spots, so only add it if it's set
if "actLocation" in source_spot and source_spot["actLocation"] != "":
spot.sig_refs[0].name = source_spot["actLocation"]
# Extract a de_call if it's in the comment but not in the "actSpoter" field # Extract a de_call if it's in the comment but not in the "actSpoter" field
m = re.search(r"\(de ([A-Za-z0-9]*)\)", spot.comment) m = re.search(r"\(de ([A-Za-z0-9]*)\)", spot.comment)
if not spot.de_call and m: if not spot.de_call and m:
spot.de_call = m.group(1) spot.de_call = m.group(1)
# Log a warning for the developer if PnP gives us an unknown programme we've never seen before # Record SIG information. Sometimes we get a "SIG" of "QRP", which we ignore as it's not a programme with a
if spot.sig_refs[0].sig not in ["POTA", "SOTA", "WWFF", "SIOTA", "ZLOTA", "KRMNPA"]: # defined set of references
logging.warning("PNP spot found with sig " + spot.sig + ", developer needs to add support for this!") sig = source_spot["actClass"].upper()
sig_ref = source_spot["actSiteID"]
if sig and sig != "" and sig != "QRP" and sig_ref and sig_ref != "":
spot.sig = sig
spot.sig_refs = [SIGRef(id=source_spot["actSiteID"], sig=source_spot["actClass"].upper())]
# If this is POTA, SOTA, WWFF or ZLOTA data we already have it through other means, so ignore. Otherwise, # Free text location is not present in all spots, so only add it if it's set
# add to the spot list. if "actLocation" in source_spot and source_spot["actLocation"] != "":
if spot.sig_refs[0].sig not in ["POTA", "SOTA", "WWFF", "ZLOTA"]: spot.sig_refs[0].name = source_spot["actLocation"]
new_spots.append(spot)
# Log a warning for the developer if PnP gives us an unknown programme we've never seen before
if sig not in ["POTA", "SOTA", "WWFF", "SIOTA", "ZLOTA", "KRMNPA"]:
logging.warning("PNP spot found with sig " + sig + ", developer needs to add support for this!")
# Add new spot to the list
new_spots.append(spot)
return new_spots return new_spots

View File

@@ -66,7 +66,7 @@
<p>This software is dedicated to the memory of Tom G1PJB, SK, a friend and colleague who sadly passed away around the time I started writing it in Autumn 2025. I was looking forward to showing it to you when it was done.</p> <p>This software is dedicated to the memory of Tom G1PJB, SK, a friend and colleague who sadly passed away around the time I started writing it in Autumn 2025. I was looking forward to showing it to you when it was done.</p>
</div> </div>
<script src="/js/common.js?v=1772224426"></script> <script src="/js/common.js?v=1773090023"></script>
<script>$(document).ready(function() { $("#nav-link-about").addClass("active"); }); <!-- highlight active page in nav --></script> <script>$(document).ready(function() { $("#nav-link-about").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %} {% end %}

View File

@@ -69,8 +69,8 @@
</div> </div>
<script src="/js/common.js?v=1772224426"></script> <script src="/js/common.js?v=1773090023"></script>
<script src="/js/add-spot.js?v=1772224426"></script> <script src="/js/add-spot.js?v=1773090023"></script>
<script>$(document).ready(function() { $("#nav-link-add-spot").addClass("active"); }); <!-- highlight active page in nav --></script> <script>$(document).ready(function() { $("#nav-link-add-spot").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %} {% end %}

View File

@@ -56,8 +56,8 @@
</div> </div>
<script src="/js/common.js?v=1772224426"></script> <script src="/js/common.js?v=1773090023"></script>
<script src="/js/alerts.js?v=1772224426"></script> <script src="/js/alerts.js?v=1773090023"></script>
<script>$(document).ready(function() { $("#nav-link-alerts").addClass("active"); }); <!-- highlight active page in nav --></script> <script>$(document).ready(function() { $("#nav-link-alerts").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %} {% end %}

View File

@@ -62,9 +62,9 @@
<script> <script>
let spotProvidersEnabledByDefault = {% raw json_encode(web_ui_options["spot-providers-enabled-by-default"]) %}; let spotProvidersEnabledByDefault = {% raw json_encode(web_ui_options["spot-providers-enabled-by-default"]) %};
</script> </script>
<script src="/js/common.js?v=1772224426"></script> <script src="/js/common.js?v=1773090023"></script>
<script src="/js/spotsbandsandmap.js?v=1772224426"></script> <script src="/js/spotsbandsandmap.js?v=1773090023"></script>
<script src="/js/bands.js?v=1772224426"></script> <script src="/js/bands.js?v=1773090023"></script>
<script>$(document).ready(function() { $("#nav-link-bands").addClass("active"); }); <!-- highlight active page in nav --></script> <script>$(document).ready(function() { $("#nav-link-bands").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %} {% end %}

View File

@@ -13,10 +13,10 @@
<meta property="twitter:title" content="Spothole"/> <meta property="twitter:title" content="Spothole"/>
<meta name="description" content="An Amateur Radio spotting tool bringing together DX clusters and outdoor programmes, providing a universal JSON API and web interface."/> <meta name="description" content="An Amateur Radio spotting tool bringing together DX clusters and outdoor programmes, providing a universal JSON API and web interface."/>
<meta property="og:description" content="An Amateur Radio spotting tool bringing together DX clusters and outdoor programmes, providing a universal JSON API and web interface."/> <meta property="og:description" content="An Amateur Radio spotting tool bringing together DX clusters and outdoor programmes, providing a universal JSON API and web interface."/>
<link rel="canonical" href="https://spothole.app/"/> <link rel="canonical" href="{{ baseurl }}{{ current_path }}"/>
<meta property="og:url" content="https://spothole.app/"/> <meta property="og:url" content="{{ baseurl }}{{ current_path }}"/>
<meta property="og:image" content="https://spothole.app/img/banner.png"/> <meta property="og:image" content="{{ baseurl }}/img/banner.png"/>
<meta property="twitter:image" content="https://spothole.app/img/banner.png"/> <meta property="twitter:image" content="{{ baseurl }}/img/banner.png"/>
<meta name="twitter:card" content="summary_large_image"/> <meta name="twitter:card" content="summary_large_image"/>
<meta name="author" content="Ian Renton"/> <meta name="author" content="Ian Renton"/>
<meta property="og:locale" content="en_GB"/> <meta property="og:locale" content="en_GB"/>
@@ -46,10 +46,10 @@
crossorigin="anonymous"></script> crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/tinycolor2@1.6.0/cjs/tinycolor.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/tinycolor2@1.6.0/cjs/tinycolor.min.js"></script>
<script src="https://misc.ianrenton.com/jsutils/utils.js?v=1772224426"></script> <script src="https://misc.ianrenton.com/jsutils/utils.js?v=1773090023"></script>
<script src="https://misc.ianrenton.com/jsutils/storage.js?v=1772224426"></script> <script src="https://misc.ianrenton.com/jsutils/storage.js?v=1773090023"></script>
<script src="https://misc.ianrenton.com/jsutils/ui-ham.js?v=1772224426"></script> <script src="https://misc.ianrenton.com/jsutils/ui-ham.js?v=1773090023"></script>
<script src="https://misc.ianrenton.com/jsutils/geo.js?v=1772224426"></script> <script src="https://misc.ianrenton.com/jsutils/geo.js?v=1773090023"></script>
</head> </head>
<body> <body>

View File

@@ -70,9 +70,9 @@
<script> <script>
let spotProvidersEnabledByDefault = {% raw json_encode(web_ui_options["spot-providers-enabled-by-default"]) %}; let spotProvidersEnabledByDefault = {% raw json_encode(web_ui_options["spot-providers-enabled-by-default"]) %};
</script> </script>
<script src="/js/common.js?v=1772224426"></script> <script src="/js/common.js?v=1773090023"></script>
<script src="/js/spotsbandsandmap.js?v=1772224426"></script> <script src="/js/spotsbandsandmap.js?v=1773090023"></script>
<script src="/js/map.js?v=1772224426"></script> <script src="/js/map.js?v=1773090023"></script>
<script>$(document).ready(function() { $("#nav-link-map").addClass("active"); }); <!-- highlight active page in nav --></script> <script>$(document).ready(function() { $("#nav-link-map").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %} {% end %}

View File

@@ -87,9 +87,9 @@
<script> <script>
let spotProvidersEnabledByDefault = {% raw json_encode(web_ui_options["spot-providers-enabled-by-default"]) %}; let spotProvidersEnabledByDefault = {% raw json_encode(web_ui_options["spot-providers-enabled-by-default"]) %};
</script> </script>
<script src="/js/common.js?v=1772224426"></script> <script src="/js/common.js?v=1773090023"></script>
<script src="/js/spotsbandsandmap.js?v=1772224426"></script> <script src="/js/spotsbandsandmap.js?v=1773090023"></script>
<script src="/js/spots.js?v=1772224426"></script> <script src="/js/spots.js?v=1773090023"></script>
<script>$(document).ready(function() { $("#nav-link-spots").addClass("active"); }); <!-- highlight active page in nav --></script> <script>$(document).ready(function() { $("#nav-link-spots").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %} {% end %}

View File

@@ -3,8 +3,8 @@
<div id="status-container" class="row row-cols-1 row-cols-md-4 g-4 mt-4"></div> <div id="status-container" class="row row-cols-1 row-cols-md-4 g-4 mt-4"></div>
<script src="/js/common.js?v=1772224426"></script> <script src="/js/common.js?v=1773090023"></script>
<script src="/js/status.js?v=1772224426"></script> <script src="/js/status.js?v=1773090023"></script>
<script>$(document).ready(function() { $("#nav-link-status").addClass("active"); }); <!-- highlight active page in nav --></script> <script>$(document).ready(function() { $("#nav-link-status").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %} {% end %}