mirror of
https://git.ianrenton.com/ian/spothole.git
synced 2025-10-27 16:59:25 +00:00
Allow alerts to have more than one DX callsign, and parse the "as CALL" fields from NG3K. Not yet working #38
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import re
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
@@ -11,6 +12,7 @@ from data.alert import Alert
|
|||||||
class NG3K(HTTPAlertProvider):
|
class NG3K(HTTPAlertProvider):
|
||||||
POLL_INTERVAL_SEC = 3600
|
POLL_INTERVAL_SEC = 3600
|
||||||
ALERTS_URL = "https://www.ng3k.com/adxo.xml"
|
ALERTS_URL = "https://www.ng3k.com/adxo.xml"
|
||||||
|
AS_CALL_PATTERN = re.compile("as ([a-z0-9/]+)", re.IGNORECASE)
|
||||||
|
|
||||||
def __init__(self, provider_config):
|
def __init__(self, provider_config):
|
||||||
super().__init__(provider_config, self.ALERTS_URL, self.POLL_INTERVAL_SEC)
|
super().__init__(provider_config, self.ALERTS_URL, self.POLL_INTERVAL_SEC)
|
||||||
@@ -49,18 +51,26 @@ class NG3K(HTTPAlertProvider):
|
|||||||
end_timestamp = datetime.strptime(end_year + " " + end_mon + " " + end_day + " 23:59", "%Y %b %d %H:%M").replace(
|
end_timestamp = datetime.strptime(end_year + " " + end_mon + " " + end_day + " 23:59", "%Y %b %d %H:%M").replace(
|
||||||
tzinfo=pytz.UTC).timestamp()
|
tzinfo=pytz.UTC).timestamp()
|
||||||
|
|
||||||
dx_country = parts[1]
|
# Sometimes the DX callsign is "real", sometimes you just get a prefix with the real working callsigns being
|
||||||
dx_call = parts[2]
|
# provided in the "by" field. e.g. call="JW", by="By LA7XK as JW7XK, LA6VM as JW6VM, LA9DL as JW9DL". So
|
||||||
qsl_info = parts[3]
|
# if there are "as" callsigns in the "by" field, we extract them and replace the main call with them.
|
||||||
|
# TODO this doesn't work yet, debug
|
||||||
extra_parts = parts[5].split("; ")
|
extra_parts = parts[5].split("; ")
|
||||||
by = extra_parts[0]
|
by = extra_parts[0]
|
||||||
|
dx_calls = [parts[2].upper()]
|
||||||
|
match = self.AS_CALL_PATTERN.match(by)
|
||||||
|
if match:
|
||||||
|
dx_calls = [x.group(1) for x in re.finditer(self.AS_CALL_PATTERN, by)]
|
||||||
|
|
||||||
|
dx_country = parts[1]
|
||||||
|
qsl_info = parts[3]
|
||||||
bands = extra_parts[1]
|
bands = extra_parts[1]
|
||||||
modes = extra_parts[2] if len(extra_parts) > 3 else ""
|
modes = extra_parts[2] if len(extra_parts) > 3 else ""
|
||||||
comment = extra_parts[-1]
|
comment = extra_parts[-1]
|
||||||
|
|
||||||
# Convert to our alert format
|
# Convert to our alert format
|
||||||
alert = Alert(source=self.name,
|
alert = Alert(source=self.name,
|
||||||
dx_call=dx_call.upper(),
|
dx_calls=dx_calls,
|
||||||
dx_country=dx_country,
|
dx_country=dx_country,
|
||||||
freqs_modes=bands + (("; " + modes) if modes != "" else ""),
|
freqs_modes=bands + (("; " + modes) if modes != "" else ""),
|
||||||
comment=by + "; " + comment + "; " + qsl_info,
|
comment=by + "; " + comment + "; " + qsl_info,
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class POTA(HTTPAlertProvider):
|
|||||||
# Convert to our alert format
|
# Convert to our alert format
|
||||||
alert = Alert(source=self.name,
|
alert = Alert(source=self.name,
|
||||||
source_id=source_alert["scheduledActivitiesId"],
|
source_id=source_alert["scheduledActivitiesId"],
|
||||||
dx_call=source_alert["activator"].upper(),
|
dx_calls=[source_alert["activator"].upper()],
|
||||||
freqs_modes=source_alert["frequencies"],
|
freqs_modes=source_alert["frequencies"],
|
||||||
comment=source_alert["comments"],
|
comment=source_alert["comments"],
|
||||||
sig="POTA",
|
sig="POTA",
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class SOTA(HTTPAlertProvider):
|
|||||||
# Convert to our alert format
|
# Convert to our alert format
|
||||||
alert = Alert(source=self.name,
|
alert = Alert(source=self.name,
|
||||||
source_id=source_alert["id"],
|
source_id=source_alert["id"],
|
||||||
dx_call=source_alert["activatingCallsign"].upper(),
|
dx_calls=[source_alert["activatingCallsign"].upper()],
|
||||||
dx_name=source_alert["activatorName"].upper(),
|
dx_name=source_alert["activatorName"].upper(),
|
||||||
freqs_modes=source_alert["frequency"],
|
freqs_modes=source_alert["frequency"],
|
||||||
comment=source_alert["comments"],
|
comment=source_alert["comments"],
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class WWFF(HTTPAlertProvider):
|
|||||||
# Convert to our alert format
|
# Convert to our alert format
|
||||||
alert = Alert(source=self.name,
|
alert = Alert(source=self.name,
|
||||||
source_id=source_alert["id"],
|
source_id=source_alert["id"],
|
||||||
dx_call=source_alert["activator_call"].upper(),
|
dx_calls=[source_alert["activator_call"].upper()],
|
||||||
freqs_modes=source_alert["band"] + " " + source_alert["mode"],
|
freqs_modes=source_alert["band"] + " " + source_alert["mode"],
|
||||||
comment=source_alert["remarks"],
|
comment=source_alert["remarks"],
|
||||||
sig="WWFF",
|
sig="WWFF",
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ from core.utils import infer_continent_from_callsign, \
|
|||||||
class Alert:
|
class Alert:
|
||||||
# Unique identifier for the alert
|
# Unique identifier for the alert
|
||||||
id: str = None
|
id: str = None
|
||||||
# Callsign of the operator that has been alertted
|
# Callsigns of the operators that has been alerted
|
||||||
dx_call: str = None
|
dx_calls: list = None
|
||||||
# Name of the operator that has been alertted
|
# Names of the operators that has been alerted
|
||||||
dx_name: str = None
|
dx_names: list = None
|
||||||
# Country of the DX operator
|
# Country of the DX operator
|
||||||
dx_country: str = None
|
dx_country: str = None
|
||||||
# Country flag of the DX operator
|
# Country flag of the DX operator
|
||||||
@@ -88,24 +88,24 @@ class Alert:
|
|||||||
self.received_time_iso = datetime.fromtimestamp(self.received_time, pytz.UTC).isoformat()
|
self.received_time_iso = datetime.fromtimestamp(self.received_time, pytz.UTC).isoformat()
|
||||||
|
|
||||||
# DX country, continent, zones etc. from callsign
|
# DX country, continent, zones etc. from callsign
|
||||||
if self.dx_call and not self.dx_country:
|
if self.dx_calls and self.dx_calls[0] and not self.dx_country:
|
||||||
self.dx_country = infer_country_from_callsign(self.dx_call)
|
self.dx_country = infer_country_from_callsign(self.dx_calls[0])
|
||||||
if self.dx_call and not self.dx_continent:
|
if self.dx_calls and self.dx_calls[0] and not self.dx_continent:
|
||||||
self.dx_continent = infer_continent_from_callsign(self.dx_call)
|
self.dx_continent = infer_continent_from_callsign(self.dx_calls[0])
|
||||||
if self.dx_call and not self.dx_cq_zone:
|
if self.dx_calls and self.dx_calls[0] and not self.dx_cq_zone:
|
||||||
self.dx_cq_zone = infer_cq_zone_from_callsign(self.dx_call)
|
self.dx_cq_zone = infer_cq_zone_from_callsign(self.dx_calls[0])
|
||||||
if self.dx_call and not self.dx_itu_zone:
|
if self.dx_calls and self.dx_calls[0] and not self.dx_itu_zone:
|
||||||
self.dx_itu_zone = infer_itu_zone_from_callsign(self.dx_call)
|
self.dx_itu_zone = infer_itu_zone_from_callsign(self.dx_calls[0])
|
||||||
if self.dx_call and not self.dx_dxcc_id:
|
if self.dx_calls and self.dx_calls[0] and not self.dx_dxcc_id:
|
||||||
self.dx_dxcc_id = infer_dxcc_id_from_callsign(self.dx_call)
|
self.dx_dxcc_id = infer_dxcc_id_from_callsign(self.dx_calls[0])
|
||||||
if self.dx_dxcc_id and not self.dx_flag:
|
if self.dx_dxcc_id and not self.dx_flag:
|
||||||
self.dx_flag = DXCC_FLAGS[self.dx_dxcc_id]
|
self.dx_flag = DXCC_FLAGS[self.dx_dxcc_id]
|
||||||
|
|
||||||
# DX operator details lookup, using QRZ.com. This should be the last resort compared to taking the data from
|
# DX operator details lookup, using QRZ.com. This should be the last resort compared to taking the data from
|
||||||
# the actual alertting service, e.g. we don't want to accidentally use a user's QRZ.com home lat/lon instead of
|
# the actual alertting service, e.g. we don't want to accidentally use a user's QRZ.com home lat/lon instead of
|
||||||
# the one from the park reference they're at.
|
# the one from the park reference they're at.
|
||||||
if self.dx_call and not self.dx_name:
|
if self.dx_calls and not self.dx_names:
|
||||||
self.dx_name = infer_name_from_callsign(self.dx_call)
|
self.dx_names = list(map(lambda c: infer_name_from_callsign(c), self.dx_calls))
|
||||||
|
|
||||||
# Always create an ID based on a hash of every parameter *except* received_time. This is used as the index
|
# Always create an ID based on a hash of every parameter *except* received_time. This is used as the index
|
||||||
# to a map, which as a byproduct avoids us having multiple duplicate copies of the object that are identical
|
# to a map, which as a byproduct avoids us having multiple duplicate copies of the object that are identical
|
||||||
|
|||||||
@@ -708,17 +708,21 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
description: Unique identifier based on a hash of the alert to distinguish this one from any others.
|
description: Unique identifier based on a hash of the alert to distinguish this one from any others.
|
||||||
example: 442c5d56ac467341f1943e8596685073b38f5a5d4c3802ca1e16ecf98967956c
|
example: 442c5d56ac467341f1943e8596685073b38f5a5d4c3802ca1e16ecf98967956c
|
||||||
dx_call:
|
dx_calls:
|
||||||
type: string
|
type: array
|
||||||
description: Callsign of the operator that is going to be activating
|
description: Callsigns of the operator(s) that are going to be activating
|
||||||
example: M0TRT
|
items:
|
||||||
|
type: string
|
||||||
|
example: M0TRT
|
||||||
dx_name:
|
dx_name:
|
||||||
type: string
|
type: array
|
||||||
description: Name of the operator that is going to be activating
|
description: Names of the operator(s) that are going to be activating
|
||||||
example: Ian
|
items:
|
||||||
|
type: string
|
||||||
|
example: Ian
|
||||||
dx_country:
|
dx_country:
|
||||||
type: string
|
type: string
|
||||||
description: Country of the DX operator
|
description: Country of the DX operator. This, and the subsequent fields, assume that all activators will be in the same country!
|
||||||
example: United Kingdom
|
example: United Kingdom
|
||||||
dx_flag:
|
dx_flag:
|
||||||
type: string
|
type: string
|
||||||
|
|||||||
@@ -171,7 +171,8 @@ function addAlertRowsToTable(tbody, alerts) {
|
|||||||
// Populate the row
|
// Populate the row
|
||||||
$tr.append(`<td class='nowrap'>${start_time_formatted}</td>`);
|
$tr.append(`<td class='nowrap'>${start_time_formatted}</td>`);
|
||||||
$tr.append(`<td class='nowrap'>${end_time_formatted}</td>`);
|
$tr.append(`<td class='nowrap'>${end_time_formatted}</td>`);
|
||||||
$tr.append(`<td class='nowrap'><span class='flag-wrapper hideonmobile' title='${dx_country}'>${dx_flag}</span><a class='dx-link' href='https://qrz.com/db/${a["dx_call"]}' target='_new'>${a["dx_call"]}</a></td>`);
|
// TODO take a["dx_calls"] and add a callsign to the following td for every one in the list.
|
||||||
|
$tr.append(`<td class='nowrap'><span class='flag-wrapper hideonmobile' title='${dx_country}'>${dx_flag}</span><a class='dx-link' href='https://qrz.com/db/${call}' target='_new'>${call}</a></td>`);
|
||||||
$tr.append(`<td class='hideonmobile'>${freqsModesText}</td>`);
|
$tr.append(`<td class='hideonmobile'>${freqsModesText}</td>`);
|
||||||
$tr.append(`<td class='hideonmobile'>${commentText}</td>`);
|
$tr.append(`<td class='hideonmobile'>${commentText}</td>`);
|
||||||
$tr.append(`<td class='nowrap hideonmobile'><span class='icon-wrapper'><i class='fa-solid fa-${a["icon"]}'></i></span> ${sigSourceText}</td>`);
|
$tr.append(`<td class='nowrap hideonmobile'><span class='icon-wrapper'><i class='fa-solid fa-${a["icon"]}'></i></span> ${sigSourceText}</td>`);
|
||||||
|
|||||||
Reference in New Issue
Block a user