diff --git a/alertproviders/sota.py b/alertproviders/sota.py new file mode 100644 index 0000000..ced3579 --- /dev/null +++ b/alertproviders/sota.py @@ -0,0 +1,37 @@ +from datetime import datetime + +import pytz + +from alertproviders.http_alert_provider import HTTPAlertProvider +from data.alert import Alert + + +# Alert provider for Summits on the Air +class SOTA(HTTPAlertProvider): + POLL_INTERVAL_SEC = 3600 + ALERTS_URL = "https://api-db2.sota.org.uk/api/alerts/365/all/all" + + def __init__(self, provider_config): + super().__init__(provider_config, self.ALERTS_URL, self.POLL_INTERVAL_SEC) + + def http_response_to_alerts(self, http_response): + new_alerts = [] + # Iterate through source data + for source_alert in http_response.json(): + # Convert to our alert format + alert = Alert(source=self.name, + source_id=source_alert["id"], + dx_call=source_alert["activatingCallsign"].upper(), + dx_name=source_alert["activatorName"].upper(), + freqs_modes=source_alert["frequency"], + comment=source_alert["comments"], + sig="SOTA", + sig_refs=[source_alert["associationCode"] + "/" + source_alert["summitCode"]], + sig_refs_names=[source_alert["summitDetails"]], + icon="mountain-sun", + start_time=datetime.strptime(source_alert["dateActivated"], + "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=pytz.UTC).timestamp()) + + # Add to our list + new_alerts.append(alert) + return new_alerts diff --git a/alertproviders/wwff.py b/alertproviders/wwff.py new file mode 100644 index 0000000..98cc34c --- /dev/null +++ b/alertproviders/wwff.py @@ -0,0 +1,37 @@ +from datetime import datetime + +import pytz + +from alertproviders.http_alert_provider import HTTPAlertProvider +from data.alert import Alert + + +# Alert provider for Worldwide Flora and Fauna +class WWFF(HTTPAlertProvider): + POLL_INTERVAL_SEC = 3600 + ALERTS_URL = "https://spots.wwff.co/static/agendas.json" + + def __init__(self, provider_config): + super().__init__(provider_config, self.ALERTS_URL, self.POLL_INTERVAL_SEC) + + def http_response_to_alerts(self, http_response): + new_alerts = [] + # Iterate through source data + for source_alert in http_response.json(): + # Convert to our alert format + alert = Alert(source=self.name, + source_id=source_alert["id"], + dx_call=source_alert["activator_call"].upper(), + freqs_modes=source_alert["band"] + " " + source_alert["mode"], + comment=source_alert["remarks"], + sig="WWFF", + sig_refs=[source_alert["reference"]], + icon="seedling", + start_time=datetime.strptime(source_alert["utc_start"], + "%Y-%m-%d %H:%M:%S").replace(tzinfo=pytz.UTC).timestamp(), + end_time=datetime.strptime(source_alert["utc_end"], + "%Y-%m-%d %H:%M:%S").replace(tzinfo=pytz.UTC).timestamp()) + + # Add to our list + new_alerts.append(alert) + return new_alerts diff --git a/config-example.yml b/config-example.yml index 180d3d2..448394e 100644 --- a/config-example.yml +++ b/config-example.yml @@ -68,6 +68,14 @@ alert-providers: class: "POTA" name: "POTA" enabled: true + - + class: "SOTA" + name: "SOTA" + enabled: true + - + class: "WWFF" + name: "WWFF" + enabled: true # Port to open the local web server on web-server-port: 8080 diff --git a/webassets/css/style.css b/webassets/css/style.css index 7060cd1..26504d7 100644 --- a/webassets/css/style.css +++ b/webassets/css/style.css @@ -63,7 +63,7 @@ appears on mobile */ --bs-table-bg-type: var(--bs-table-striped-bg); } -td.nowrap { +td.nowrap, span.nowrap { text-wrap: nowrap; } diff --git a/webassets/js/alerts.js b/webassets/js/alerts.js index e09fb7a..1d8b13e 100644 --- a/webassets/js/alerts.js +++ b/webassets/js/alerts.js @@ -85,8 +85,15 @@ function addAlertRowsToTable(tbody, alerts) { // Format UTC times for display var start_time = moment.unix(a["start_time"]).utc(); var start_time_formatted = start_time.format("YYYY-MM-DD HH:mm"); - var end_time = moment.unix(a["end_time"]).utc(); - var end_time_formatted = (end_time != null) ? end_time.format("YYYY-MM-DD HH:mm") : "Not specified"; + var end_time_unix = moment.unix(a["end_time"]); + var end_time = end_time_unix.utc(); + var end_time_formatted = (end_time_unix != null && end_time_unix > 0 && end_time != null) ? end_time.format("YYYY-MM-DD HH:mm") : "---"; + + // Format DX flag + var dx_flag = ""; + if (a["dx_flag"] && a["dx_flag"] != null && a["dx_flag"] != "") { + dx_flag = a["dx_flag"]; + } // Format dx country var dx_country = a["dx_country"] @@ -115,13 +122,13 @@ function addAlertRowsToTable(tbody, alerts) { // Format sig_refs var sig_refs = "" if (a["sig_refs"]) { - sig_refs = a["sig_refs"].join(", ") + sig_refs = a["sig_refs"].map(a => `${a}`).join(", "); } // Populate the row $tr.append(`${start_time_formatted}`); $tr.append(`${end_time_formatted}`); - $tr.append(`${a["dx_flag"]}${a["dx_call"]}`); + $tr.append(`${dx_flag}${a["dx_call"]}`); $tr.append(`${freqsModesText}`); $tr.append(`${commentText}`); $tr.append(` ${sigSourceText}`); diff --git a/webassets/js/spots.js b/webassets/js/spots.js index 6200206..8dff7e4 100644 --- a/webassets/js/spots.js +++ b/webassets/js/spots.js @@ -59,6 +59,12 @@ function updateTable() { var time = moment.unix(s["time"]).utc(); var time_formatted = time.format("HH:mm"); + // Format DX flag + var dx_flag = ""; + if (s["dx_flag"] && s["dx_flag"] != null && s["dx_flag"] != "") { + dx_flag = s["dx_flag"]; + } + // Format dx country var dx_country = s["dx_country"]; if (dx_country == null) { @@ -96,12 +102,12 @@ function updateTable() { // Format sig_refs var sig_refs = ""; if (s["sig_refs"]) { - sig_refs = s["sig_refs"].join(", "); + sig_refs = a["sig_refs"].map(a => `${a}`).join(", "); } // Format DE flag var de_flag = ""; - if (s["de_flag"] && s["de_flag"] != "") { + if (s["de_flag"] && s["de_flag"] != null && s["de_flag"] != "") { de_flag = s["de_flag"]; } @@ -118,7 +124,7 @@ function updateTable() { // Populate the row $tr.append(`${time_formatted}`); - $tr.append(`${s["dx_flag"]}${s["dx_call"]}`); + $tr.append(`${dx_flag}${s["dx_call"]}`); $tr.append(`${freq_string}`); $tr.append(`${mode_string}`); $tr.append(`${commentText}`);