diff --git a/public_html/dbloader.js b/public_html/dbloader.js
new file mode 100644
index 0000000..e824232
--- /dev/null
+++ b/public_html/dbloader.js
@@ -0,0 +1,118 @@
+// -*- mode: javascript; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+
+// Part of dump1090, a Mode S message decoder for RTLSDR devices.
+//
+// dbloader.js: load aircraft metadata from static json files
+//
+// Copyright (c) 2014,2015 Oliver Jowett
+//
+// This file is free software: you may copy, redistribute and/or modify it
+// under the terms of the GNU General Public License as published by the
+// Free Software Foundation, either version 2 of the License, or (at your
+// option) any later version.
+//
+// This file is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+"use strict";
+
+var _aircraft_cache = {};
+
+function getAircraftData(icao) {
+ var defer;
+
+ icao = icao.toUpperCase();
+
+ if (icao in _aircraft_cache) {
+ defer = _aircraft_cache[icao];
+ } else {
+ // load from blocks:
+ defer = _aircraft_cache[icao] = $.Deferred();
+ request_from_db(icao, 1, defer);
+ }
+
+ return defer;
+}
+
+function request_from_db(icao, level, defer) {
+ var bkey = icao.substring(0, level);
+ var dkey = icao.substring(level);
+ var req = db_ajax(bkey);
+
+ req.done(function(data) {
+ var subkey;
+
+ if ("children" in data) {
+ subkey = bkey + dkey.substring(0,1);
+ if (data.children.indexOf(subkey) == -1) {
+ defer.reject();
+ } else {
+ request_from_db(icao, level+1, defer);
+ }
+ } else {
+ if (dkey in data) {
+ defer.resolve(data[dkey]);
+ } else {
+ defer.reject();
+ }
+ }
+ });
+
+ req.fail(function(jqXHR,textStatus,errorThrown) {
+ defer.reject();
+ });
+}
+
+var _request_count = 0;
+var _request_queue = [];
+var _request_cache = {};
+
+var MAX_REQUESTS = 2;
+
+function db_ajax(bkey) {
+ var defer;
+
+ if (bkey in _request_cache) {
+ return _request_cache[bkey];
+ }
+
+ if (_request_count < MAX_REQUESTS) {
+ // just do ajax directly
+ ++_request_count;
+ defer = _request_cache[bkey] = $.ajax({ url: 'db/' + bkey + '.json',
+ cache: true,
+ timeout: 5000,
+ dataType : 'json' });
+ defer.always(db_ajax_request_complete);
+ } else {
+ // put it in the queue
+ defer = _request_cache[bkey] = $.Deferred();
+ defer.bkey = bkey;
+ _request_queue.push(defer);
+ }
+
+ return defer;
+}
+
+function db_ajax_request_complete() {
+ var req;
+ var ajaxreq;
+
+ if (_request_queue.length == 0) {
+ --_request_count;
+ } else {
+ req = _request_queue.shift();
+ ajaxreq = $.ajax({ url: 'db/' + req.bkey + '.json',
+ cache: true,
+ timeout: 5000,
+ dataType : 'json' });
+ ajaxreq.done(function(data) { req.resolve(data); });
+ ajaxreq.fail(function(jqxhr, status, error) { req.reject(jqxhr, status, error); });
+ ajaxreq.always(db_ajax_request_complete);
+ }
+}
diff --git a/public_html/gmap.html b/public_html/gmap.html
index 0b4bc97..3288fc0 100644
--- a/public_html/gmap.html
+++ b/public_html/gmap.html
@@ -8,6 +8,7 @@
+
@@ -114,6 +115,8 @@
+
+
[FR24]
diff --git a/public_html/planeObject.js b/public_html/planeObject.js
index 187c03f..1a7fd4b 100644
--- a/public_html/planeObject.js
+++ b/public_html/planeObject.js
@@ -36,6 +36,23 @@ function PlaneObject(icao) {
this.marker = null;
this.icon = { type: 'generic',
fillOpacity: 0.9 };
+
+ // request metadata
+ this.registration = null;
+ this.icaotype = null;
+ getAircraftData(this.icao).done(function(data) {
+ if ("r" in data) {
+ this.registration = data.r;
+ }
+
+ if ("t" in data) {
+ this.icaotype = data.t;
+ }
+
+ if (this.selected) {
+ refreshSelected();
+ }
+ }.bind(this));
}
// Appends data to the running track so we can get a visual tail on the plane
diff --git a/public_html/script.js b/public_html/script.js
index aff834e..06d2691 100644
--- a/public_html/script.js
+++ b/public_html/script.js
@@ -554,7 +554,19 @@ function refreshSelected() {
$('#selected_callsign').text('n/a');
$('#selected_links').css('display','none');
}
-
+
+ if (selected.registration !== null) {
+ $('#selected_registration').text(selected.registration);
+ } else {
+ $('#selected_registration').text("");
+ }
+
+ if (selected.icaotype !== null) {
+ $('#selected_icaotype').text(selected.icaotype);
+ } else {
+ $('#selected_icaotype').text("");
+ }
+
var emerg = document.getElementById('selected_emergency');
if (selected.squawk in SpecialSquawks) {
emerg.className = SpecialSquawks[selected.squawk].cssClass;
diff --git a/public_html/style.css b/public_html/style.css
index 7234d12..0f098f2 100644
--- a/public_html/style.css
+++ b/public_html/style.css
@@ -34,6 +34,8 @@ div#loader { z-index: 99; position: absolute; left: 0; top: 0; bottom: 0; right:
.infoblock_body { font-size: small; }
#selected_icao { font-size: x-small; }
+#selected_registration { font-size: x-small; }
+#selected_icaotype { font-size: x-small; }
.dim { opacity: 0.3; filter:alpha(opacity=30); /* For IE8 and earlier */ }
diff --git a/tools/vrs-basicaircraft-to-json.py b/tools/vrs-basicaircraft-to-json.py
new file mode 100755
index 0000000..9db9f8f
--- /dev/null
+++ b/tools/vrs-basicaircraft-to-json.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python2
+
+#
+# Converts a Virtual Radar Server BasicAircraftLookup.sqb database
+# into a bunch of json files suitable for use by the webmap
+#
+
+import sqlite3, json
+from contextlib import closing
+
+def extract(dbfile, todir, blocklimit):
+ ac_count = 0
+ block_count = 0
+
+ blocks = {}
+ for i in xrange(16):
+ blocks['%01X' % i] = {}
+
+ print 'Reading', dbfile
+ with closing(sqlite3.connect(dbfile)) as db:
+ with closing(db.execute('SELECT a.Icao, a.Registration, m.Icao FROM Aircraft a, Model m WHERE a.ModelID = m.ModelID')) as c:
+ for icao24, reg, icaotype in c:
+ bkey = icao24[0:1].upper()
+ dkey = icao24[1:].upper()
+ blocks[bkey][dkey] = {}
+ if reg: blocks[bkey][dkey]['r'] = reg
+ if icaotype: blocks[bkey][dkey]['t'] = icaotype
+ ac_count += 1
+ print 'Read', ac_count, 'aircraft'
+
+ queue = list(blocks.keys())
+ while queue:
+ bkey = queue[0]
+ del queue[0]
+
+ blockdata = blocks[bkey]
+ if len(blockdata) > blocklimit:
+ print 'Splitting block', bkey, 'with', len(blockdata), 'entries..',
+ children = {}
+ for dkey in blockdata.keys():
+ new_bkey = bkey + dkey[0]
+ new_dkey = dkey[1:]
+
+ if new_bkey not in children: blocks[new_bkey] = children[new_bkey] = {}
+ children[new_bkey][new_dkey] = blockdata[dkey]
+
+ print len(children), 'children'
+ queue.extend(children.keys())
+ blockdata = blocks[bkey] = { 'children' : sorted(children.keys()) }
+
+ path = todir + '/' + bkey + '.json'
+ print 'Writing', len(blockdata), 'entries to', path
+ block_count += 1
+ with closing(open(path, 'w')) as f:
+ json.dump(obj=blockdata, fp=f, check_circular=False, separators=(',',':'), sort_keys=True)
+
+ print 'Wrote', block_count, 'blocks'
+
+if __name__ == '__main__':
+ import sys
+ if len(sys.argv) < 3:
+ print 'Syntax: %s ' % sys.argv[0]
+ sys.exit(1)
+ else:
+ extract(sys.argv[1], sys.argv[2], 1000)
+ sys.exit(0)