diff --git a/htdocs/map.js b/htdocs/map.js
index 0ed1ad37..c81d57e4 100644
--- a/htdocs/map.js
+++ b/htdocs/map.js
@@ -214,6 +214,7 @@ $(function(){
marker.altitude = update.location.altitude;
marker.device = update.location.device;
marker.antenna = update.location.antenna;
+ marker.schedule = update.location.schedule;
if (expectedCallsign && expectedCallsign == update.callsign) {
map.panTo(pos);
@@ -457,7 +458,7 @@ $(function(){
return '' + callsign + '';
- };
+ }
var distanceKm = function(p1, p2) {
// Earth radius in km
@@ -521,7 +522,8 @@ $(function(){
var makeListItem = function(name, value) {
return '
'
- + '' + name + ''
+ + '' + name.replace(/[ \r\n]+/gm, ' ')
+ + ' '
+ '' + value + ''
+ '
';
}
@@ -664,6 +666,7 @@ $(function(){
var marker = markers[name];
var commentString = "";
var detailsString = "";
+ var scheduleString = "";
var nameString = "";
var distance = "";
@@ -692,17 +695,32 @@ $(function(){
detailsString += makeListItem('Antenna', truncate(marker.antenna, 24));
}
+ if (marker.schedule) {
+ for (var j=0 ; j'
+ + Math.round(marker.schedule[j].freq/1000) + 'kHz';
+ scheduleString += makeListItem(marker.schedule[j].name, freq);
+ }
+ }
+
if (detailsString.length > 0) {
detailsString = '' + makeListTitle('Details') + detailsString + '
';
}
+ if (scheduleString.length > 0) {
+ scheduleString = '' + makeListTitle('Schedule') + scheduleString + '
';
+ }
+
if (receiverMarker) {
distance = " at " + distanceKm(receiverMarker.position, marker.position) + " km";
}
infowindow.setContent(
'' + nameString + distance + '
' +
- commentString + detailsString
+ commentString + detailsString + scheduleString
);
infowindow.open(map, marker);
diff --git a/owrx/eibi.py b/owrx/eibi.py
index 475cae63..15a6094a 100644
--- a/owrx/eibi.py
+++ b/owrx/eibi.py
@@ -46,6 +46,7 @@ class EIBI(object):
def __init__(self):
self.refreshPeriod = 60*60*24*30
self.event = threading.Event()
+ self.lock = threading.Lock()
self.schedule = []
self.thread = None
@@ -74,11 +75,11 @@ class EIBI(object):
ts = os.path.getmtime(file) if os.path.isfile(file) else 0
# Try loading cached schedule from file first, unless stale
- if time.time() - ts < self.refreshPeriod:
- logger.debug("Loading cached schedule from '{0}'...".format(file))
- self.schedule = self.loadSchedule(file)
- else:
- self.schedule = self.updateSchedule()
+ with self.lock:
+ if time.time() - ts < self.refreshPeriod:
+ self.schedule = self.loadSchedule(file)
+ else:
+ self.schedule = self.updateSchedule()
while not self.event.is_set():
# Sleep until it is time to update schedule
@@ -87,22 +88,25 @@ class EIBI(object):
if not self.event.is_set():
# Update schedule
logger.debug("Refreshing schedule...")
- self.schedule = self.updateSchedule()
+ with self.lock:
+ self.schedule = self.updateSchedule()
# Done
logger.debug("Stopped EIBI main thread.")
self.thread = None
# Load schedule from a given JSON file
- def loadSchedule(self, fileName: str):
+ def loadSchedule(self, file: str):
+ logger.debug("Loading schedule from '{0}'...".format(file))
try:
- with open(fileName, "r") as f:
+ with open(file, "r") as f:
result = json.load(f)
f.close()
except Exception as e:
logger.debug("loadSchedule() exception: {0}".format(e))
result = []
# Done
+ logger.debug("Loaded {0} entries from '{1}'...".format(len(result), file))
return result
# Update schedule
@@ -122,33 +126,66 @@ class EIBI(object):
# Done
return schedule
+ # Find all current broadcasts for a given source
def findBySource(self, src: str):
# Get entries active at the current time
now = datetime.utcnow()
now = now.hour * 100 + now.minute
result = []
# Search for entries originating from given source at current time
- for entry in self.schedule:
- if entry["time1"] <= now and entry["time2"] > now:
- if entry["itu"] + entry["src"] == src:
- result.append(entry)
+ with self.lock:
+ for entry in self.schedule:
+ if entry["time1"] <= now and entry["time2"] > now:
+ if entry["itu"] + entry["src"] == src:
+ result.append(entry)
# Done
return result
+ # Find all current broadcasts for a given frequency range
def findCurrent(self, freq1: int, freq2: int):
# Get entries active at the current time
now = datetime.utcnow()
now = now.hour * 100 + now.minute
return self.find(freq1, freq2, now, now)
+ # Find all broadcasts for given frequency and time ranges
def find(self, freq1: int, freq2: int, time1: int, time2: int):
result = []
# Search for entries within given frequency and time ranges
- for entry in self.schedule:
- f = entry["freq"]
- if f >= freq1 and f <= freq2:
- if entry["time1"] <= time2 and entry["time2"] > time1:
- result.append(entry)
+ with self.lock:
+ for entry in self.schedule:
+ f = entry["freq"]
+ if f >= freq1 and f <= freq2:
+ if entry["time1"] <= time2 and entry["time2"] > time1:
+ result.append(entry)
+ # Done
+ return result
+
+ # Create list of currently broadcasting locations
+ def currentTransmitters(self):
+ # Get entries active at the current time
+ now = datetime.utcnow()
+ day = str(now.weekday() + 1)
+ now = now.hour * 100 + now.minute
+ result = {}
+ # Search for current entries
+ with self.lock:
+ for entry in self.schedule:
+ # For every current schedule entry...
+ if entry["time1"] <= now and entry["time2"] > now and day in entry["days"]:
+ src = entry["itu"] + entry["src"]
+ # Find all matching transmitter locations
+ for loc in EIBI_Locations:
+ if loc["code"] == src:
+ # Add location to the result
+ name = loc["name"]
+ logger.debug("Found {0} .. {1} .. {2} from {3} ({4})".format(
+ entry["time1"], now, entry["time2"], name, src))
+ if name not in result:
+ result[name] = loc.copy()
+ result[name]["schedule"] = []
+ # Add schedule entry to the location
+ result[name]["schedule"].append(entry)
# Done
return result
@@ -197,8 +234,25 @@ class EIBI(object):
# When we encounter a location...
m = pattern.match(line)
if m is not None:
+ # Guess modulation by language and name fields
+ name = m.group(6).lower()
+ lang = m.group(7)
+ mode = (
+ "hfdl" if lang == "-HF" else
+ "rtty450" if lang == "-TY" else
+ "cw" if lang == "-CW" else
+ "fax" if " fax" in name else
+ "usb" if "volmet" in name else
+ "usb" if "ldoc" in name else
+ "usb" if "car-" in name else
+ "usb" if "nat-" in name else
+ "usb" if " usb" in name else
+ "usb" if "fsk" in name else
+ "am")
+ # Append a new entry to the result
result.append({
"freq" : int(float(m.group(1)) * 1000),
+ "mode" : mode,
"time1" : int(m.group(2)),
"time2" : int(m.group(3)),
"days" : self.convertDays(m.group(4)),
diff --git a/owrx/markers.py b/owrx/markers.py
index 0b48ab10..71ae0cf4 100644
--- a/owrx/markers.py
+++ b/owrx/markers.py
@@ -2,7 +2,7 @@ from owrx.config.core import CoreConfig
from owrx.map import Map, Location
from owrx.aprs import getSymbolData
from json import JSONEncoder
-from owrx.eibi import EIBI_Locations
+from owrx.eibi import EIBI_Locations, EIBI
import urllib
import threading
@@ -107,25 +107,23 @@ class Markers(object):
# Load markers from local files
for file in self.fileList:
if os.path.isfile(file):
- logger.debug("Loading markers from '{0}'...".format(file))
self.markers.update(self.loadMarkers(file))
- # Load markers from the EIBI database
- #logger.debug("Loading EIBI transmitter locations...")
- #self.markers.update(self.loadEIBI())
-
# This file contains cached database
file = self._getCachedMarkersFile()
ts = os.path.getmtime(file) if os.path.isfile(file) else 0
# Try loading cached database from file first, unless stale
if time.time() - ts < self.refreshPeriod:
- logger.debug("Loading cached markers from '{0}'...".format(file))
self.markers.update(self.loadMarkers(file))
else:
# Add scraped data to the database
self.markers.update(self.updateCache())
+ # Load markers from the EIBI database
+ time.sleep(30)
+ self.markers.update(self.loadEIBI())
+
while not self.event.is_set():
# Update map with markers
logger.debug("Updating map...")
@@ -143,10 +141,11 @@ class Markers(object):
self.thread = None
# Load markers from a given file
- def loadMarkers(self, fileName: str):
+ def loadMarkers(self, file: str):
+ logger.debug("Loading markers from '{0}'...".format(file))
# Load markers list from JSON file
try:
- with open(fileName, "r") as f:
+ with open(file, "r") as f:
db = json.load(f)
f.close()
except Exception as e:
@@ -160,6 +159,7 @@ class Markers(object):
result[key] = MarkerLocation(attrs)
# Done
+ logger.debug("Loaded {0} markers from '{1}'.".format(len(result), file))
return result
# Update markers on the map
@@ -194,11 +194,12 @@ class Markers(object):
#
def loadEIBI(self):
+ logger.debug("Loading EIBI transmitter locations...")
#url = "https://www.short-wave.info/index.php?txsite="
url = "https://www.google.com/search?q="
result = {}
# Load transmitter sites from EIBI database
- for entry in EIBI_Locations:
+ for entry in EIBI.getSharedInstance().currentTransmitters().values():
rl = MarkerLocation({
"type" : "feature",
"mode" : "Stations",
@@ -206,10 +207,12 @@ class Markers(object):
"id" : entry["name"],
"lat" : entry["lat"],
"lon" : entry["lon"],
- "url" : url + urllib.parse.quote_plus(entry["name"])
+ "url" : url + urllib.parse.quote_plus(entry["name"]),
+ "schedule": entry["schedule"]
})
result[rl.getId()] = rl
# Done
+ logger.debug("Loaded {0} EIBI transmitter locations.".format(len(result)))
return result
def scrapeOWRX(self, url: str = "https://www.receiverbook.de/map"):