Various UI things #7

This commit is contained in:
Ian Renton
2025-10-02 18:13:48 +01:00
parent 6a3f1d2e10
commit 9f3fc8146b
7 changed files with 82 additions and 658441 deletions

24
.idea/runConfigurations/Run.xml generated Normal file
View File

@@ -0,0 +1,24 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Run" type="PythonConfigurationType" factoryName="Python">
<module name="metaspot" />
<option name="ENV_FILES" value="" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/main.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
</component>

View File

@@ -16,10 +16,12 @@ Supported data sources include DX Clusters, the Reverse Beacon Network (RBN), th
TODO TODO
### Installing your own copy ### Running your own copy
TODO TODO
The software can take a few seconds to start up, mostly because it is downloading an updated file to match callsigns to countries. This is normal, don't panic!
### Writing your own Providers ### Writing your own Providers
(S)pothole is designed to be easily extensible. If you want to write your own provider, simply add a module to the `providers` package containing your class. (Currently, in order to be loaded correctly, the module (file) name should be the same as the class name, but lower case.) (S)pothole is designed to be easily extensible. If you want to write your own provider, simply add a module to the `providers` package containing your class. (Currently, in order to be loaded correctly, the module (file) name should be the same as the class name, but lower case.)

View File

@@ -48,7 +48,7 @@ DXCC_FLAGS = {
3: "\U0001F1E6\U0001F1EB", # AFGHANISTAN 3: "\U0001F1E6\U0001F1EB", # AFGHANISTAN
4: "", # AGALEGA & ST BRANDON ISLANDS 4: "", # AGALEGA & ST BRANDON ISLANDS
5: "\U0001F1E6\U0001F1FD", # ALAND ISLANDS 5: "\U0001F1E6\U0001F1FD", # ALAND ISLANDS
6: "", # ALASKA 6: "\U0001F1FA\U0001F1F8", # ALASKA
7: "\U0001F1E6\U0001F1F1", # ALBANIA 7: "\U0001F1E6\U0001F1F1", # ALBANIA
8: "", # ALDABRA 8: "", # ALDABRA
9: "\U0001F1E6\U0001F1F8", # AMERICAN SAMOA 9: "\U0001F1E6\U0001F1F8", # AMERICAN SAMOA
@@ -63,7 +63,7 @@ DXCC_FLAGS = {
18: "\U0001F1E6\U0001F1FF", # AZERBAIJAN 18: "\U0001F1E6\U0001F1FF", # AZERBAIJAN
19: "", # BAJO NUEVO 19: "", # BAJO NUEVO
20: "", # BAKER HOWLAND ISLANDS 20: "", # BAKER HOWLAND ISLANDS
21: "", # BALEARIC ISLANDS 21: "\U0001F1EA\U0001F1F8", # BALEARIC ISLANDS
22: "\U0001F1F5\U0001F1FC", # PALAU 22: "\U0001F1F5\U0001F1FC", # PALAU
23: "", # BLENHEIM REEF 23: "", # BLENHEIM REEF
24: "\U0001F1E7\U0001F1FB", # BOUVET ISLAND 24: "\U0001F1E7\U0001F1FB", # BOUVET ISLAND
@@ -71,10 +71,10 @@ DXCC_FLAGS = {
26: "", # BRITISH SOMALILAND 26: "", # BRITISH SOMALILAND
27: "\U0001F1E7\U0001F1FE", # BELARUS 27: "\U0001F1E7\U0001F1FE", # BELARUS
28: "\U0001F1E8\U0001F1FB", # CANAL ZONE 28: "\U0001F1E8\U0001F1FB", # CANAL ZONE
29: "", # CANARY ISLANDS 29: "\U0001F1EA\U0001F1F8", # CANARY ISLANDS
30: "", # CELEBE & MOLUCCA ISLANDS 30: "", # CELEBE & MOLUCCA ISLANDS
31: "\U0001F1F0\U0001F1EE", # CENTRAL KIRIBATI 31: "\U0001F1F0\U0001F1EE", # CENTRAL KIRIBATI
32: "", # CEUTA & MELILLA 32: "\U0001F1EA\U0001F1F8", # CEUTA & MELILLA
33: "", # CHAGOS ISLANDS 33: "", # CHAGOS ISLANDS
34: "", # CHATHAM ISLAND 34: "", # CHATHAM ISLAND
35: "\U0001F1E8\U0001F1FD", # CHRISTMAS ISLAND 35: "\U0001F1E8\U0001F1FD", # CHRISTMAS ISLAND

View File

@@ -10,7 +10,7 @@ from core.config import config
from core.constants import BANDS, UNKNOWN_BAND, CW_MODES, PHONE_MODES, DATA_MODES, ALL_MODES from core.constants import BANDS, UNKNOWN_BAND, CW_MODES, PHONE_MODES, DATA_MODES, ALL_MODES
# Lookup helpers from pyhamtools # Lookup helpers from pyhamtools
LOOKUP_LIB_BASIC = LookupLib(lookuptype="countryfile", filename="cty.plist") LOOKUP_LIB_BASIC = LookupLib(lookuptype="countryfile")
CALL_INFO_BASIC = Callinfo(LOOKUP_LIB_BASIC) CALL_INFO_BASIC = Callinfo(LOOKUP_LIB_BASIC)
QRZ_AVAILABLE = config["qrz-password"] != "" QRZ_AVAILABLE = config["qrz-password"] != ""
if QRZ_AVAILABLE: if QRZ_AVAILABLE:

658427
cty.plist

File diff suppressed because it is too large Load Diff

View File

@@ -12,17 +12,20 @@
span.flag-wrapper { span.flag-wrapper {
display: inline-block; display: inline-block;
width: 1.7em; width: 1.7em;
text-align: center;
cursor: default;
} }
span.icon-wrapper { span.icon-wrapper {
display: inline-block; display: inline-block;
width: 1.5em; width: 1.5em;
text-align: center; text-align: center;
cursor: default;
} }
span.freq-mhz { span.freq-mhz {
display: inline-block; display: inline-block;
width: 2em; min-width: 1.5em;
text-align: right; text-align: right;
font-weight: bold; font-weight: bold;
} }
@@ -35,7 +38,13 @@ span.freq-hz {
font-size: 0.8em; font-size: 0.8em;
} }
span.mode-q {
padding-left: 0.5em;
font-size: 0.7em;
color: lightgray;
}
tr.table-faded td { tr.table-faded td {
color: gray; color: lightgray;
text-decoration: line-through !important; text-decoration: line-through !important;
} }

View File

@@ -7,6 +7,8 @@ var spots = []
var options = {}; var options = {};
// Last time we updated the spots list on display. // Last time we updated the spots list on display.
var lastUpdateTime; var lastUpdateTime;
// Options-based lookups for band colours
band_colors = {}
// Load spots and populate the table. // Load spots and populate the table.
function loadSpots() { function loadSpots() {
@@ -41,6 +43,12 @@ function updateTable() {
var time = moment.utc(s["time"], moment.ISO_8601); var time = moment.utc(s["time"], moment.ISO_8601);
var time_formatted = time.format("HH:mm") var time_formatted = time.format("HH:mm")
// Format dx country
var dx_country = s["dx_country"]
if (dx_country == null) {
dx_country = "Unknown or not a country"
}
// Format the frequency // Format the frequency
var mhz = Math.floor(s["freq"] / 1000.0); var mhz = Math.floor(s["freq"] / 1000.0);
var khz = Math.floor(s["freq"] - (mhz * 1000.0)); var khz = Math.floor(s["freq"] - (mhz * 1000.0));
@@ -48,6 +56,18 @@ function updateTable() {
var hz_string = (hz > 0) ? hz.toFixed(0) : ""; var hz_string = (hz > 0) ? hz.toFixed(0) : "";
var freq_string = `<span class='freq-mhz'>${mhz.toFixed(0)}</span><span class='freq-khz'>${khz.toFixed(0).padStart(3, '0')}</span><span class='freq-hz'>${hz_string}</span>` var freq_string = `<span class='freq-mhz'>${mhz.toFixed(0)}</span><span class='freq-khz'>${khz.toFixed(0).padStart(3, '0')}</span><span class='freq-hz'>${hz_string}</span>`
// Format the mode
mode_string = s["mode"];
if (s["mode_source"] == "BANDPLAN") {
mode_string = mode_string + "<span class='mode-q'><i class='fa-solid fa-circle-question' title='The mode was not reported via the spotting service. This is a guess based on the frequency.'></i></span>"
}
// Band-based colour
var band_dot_style = ""
if (band_colors[s["band"]]) {
band_dot_style = `color: ${band_colors[s["band"]]}; `
}
// Format sig_refs // Format sig_refs
var sig_refs = "" var sig_refs = ""
if (s["sig_refs"]) { if (s["sig_refs"]) {
@@ -55,20 +75,26 @@ function updateTable() {
} }
// Format DE flag // Format DE flag
var de_flag = "<i class='fa-solid fa-question'></i>"; var de_flag = "<i class='fa-solid fa-circle-question'></i>";
if (s["de_flag"] && s["de_flag"] != "") { if (s["de_flag"] && s["de_flag"] != "") {
de_flag = s["de_flag"]; de_flag = s["de_flag"];
} }
// Format de country
var de_country = s["de_country"]
if (de_country == null) {
de_country = "Unknown or not a country"
}
// Populate the row // Populate the row
$tr.append(`<td>${time_formatted}</td>`); $tr.append(`<td>${time_formatted}</td>`);
$tr.append(`<td><span class='flag-wrapper'>${s["dx_flag"]}</span>${s["dx_call"]}</td>`); $tr.append(`<td><span class='flag-wrapper' title='${dx_country}'>${s["dx_flag"]}</span>${s["dx_call"]}</td>`);
$tr.append(`<td>${freq_string}</td>`); $tr.append(`<td><span class='band-dot' style='${band_dot_style}'>&#9632;</span>${freq_string}</td>`);
$tr.append(`<td>${s["mode"]}</td>`); $tr.append(`<td>${mode_string}</td>`);
$tr.append('<td>' + escapeHtml(`${s["comment"]}`) + '</td>'); $tr.append('<td>' + escapeHtml(`${s["comment"]}`) + '</td>');
$tr.append(`<td><span class='icon-wrapper'><i class='fa-solid fa-${s["icon"]}'></i></span> ${s["source"]}</td>`); $tr.append(`<td><span class='icon-wrapper'><i class='fa-solid fa-${s["icon"]}'></i></span> ${s["source"]}</td>`);
$tr.append(`<td>${sig_refs}</td>`); $tr.append(`<td>${sig_refs}</td>`);
$tr.append(`<td><span class='flag-wrapper'>${s["de_flag"]}</span>${s["de_call"]}</td>`); $tr.append(`<td><span class='flag-wrapper' title='${de_country}'>${de_flag}</span>${s["de_call"]}</td>`);
table.find('tbody').append($tr); table.find('tbody').append($tr);
}); });
@@ -87,8 +113,15 @@ function loadStatus() {
// spots repeatedly. // spots repeatedly.
function loadOptions() { function loadOptions() {
$.getJSON('/api/options', function(jsonData) { $.getJSON('/api/options', function(jsonData) {
// Store options
options = jsonData; options = jsonData;
console.log(options); //todo remove
// Separately store colour lookups for bands
options["bands"].forEach(m => {
band_colors[m["name"]] = m["color"]
});
// Load spots and set up the timer
loadSpots(); loadSpots();
setInterval(loadSpots, REFRESH_INTERVAL_SEC * 1000) setInterval(loadSpots, REFRESH_INTERVAL_SEC * 1000)
}); });