mirror of
https://github.com/smittix/intercept.git
synced 2026-04-24 06:40:00 -07:00
Add ADS-B voice alerts for military and emergency detections
This commit is contained in:
@@ -1281,6 +1281,7 @@ function loadVoiceAlertConfig() {
|
|||||||
const pager = document.getElementById('voiceCfgPager');
|
const pager = document.getElementById('voiceCfgPager');
|
||||||
const tscm = document.getElementById('voiceCfgTscm');
|
const tscm = document.getElementById('voiceCfgTscm');
|
||||||
const tracker = document.getElementById('voiceCfgTracker');
|
const tracker = document.getElementById('voiceCfgTracker');
|
||||||
|
const military = document.getElementById('voiceCfgAdsbMilitary');
|
||||||
const squawk = document.getElementById('voiceCfgSquawk');
|
const squawk = document.getElementById('voiceCfgSquawk');
|
||||||
const rate = document.getElementById('voiceCfgRate');
|
const rate = document.getElementById('voiceCfgRate');
|
||||||
const pitch = document.getElementById('voiceCfgPitch');
|
const pitch = document.getElementById('voiceCfgPitch');
|
||||||
@@ -1290,6 +1291,7 @@ function loadVoiceAlertConfig() {
|
|||||||
if (pager) pager.checked = cfg.streams.pager !== false;
|
if (pager) pager.checked = cfg.streams.pager !== false;
|
||||||
if (tscm) tscm.checked = cfg.streams.tscm !== false;
|
if (tscm) tscm.checked = cfg.streams.tscm !== false;
|
||||||
if (tracker) tracker.checked = cfg.streams.bluetooth !== false;
|
if (tracker) tracker.checked = cfg.streams.bluetooth !== false;
|
||||||
|
if (military) military.checked = cfg.streams.adsb_military !== false;
|
||||||
if (squawk) squawk.checked = cfg.streams.squawks !== false;
|
if (squawk) squawk.checked = cfg.streams.squawks !== false;
|
||||||
if (rate) rate.value = cfg.rate;
|
if (rate) rate.value = cfg.rate;
|
||||||
if (pitch) pitch.value = cfg.pitch;
|
if (pitch) pitch.value = cfg.pitch;
|
||||||
@@ -1314,10 +1316,11 @@ function saveVoiceAlertConfig() {
|
|||||||
pitch: parseFloat(document.getElementById('voiceCfgPitch')?.value) || 0.9,
|
pitch: parseFloat(document.getElementById('voiceCfgPitch')?.value) || 0.9,
|
||||||
voiceName: document.getElementById('voiceCfgVoice')?.value || '',
|
voiceName: document.getElementById('voiceCfgVoice')?.value || '',
|
||||||
streams: {
|
streams: {
|
||||||
pager: !!document.getElementById('voiceCfgPager')?.checked,
|
pager: !!document.getElementById('voiceCfgPager')?.checked,
|
||||||
tscm: !!document.getElementById('voiceCfgTscm')?.checked,
|
tscm: !!document.getElementById('voiceCfgTscm')?.checked,
|
||||||
bluetooth: !!document.getElementById('voiceCfgTracker')?.checked,
|
bluetooth: !!document.getElementById('voiceCfgTracker')?.checked,
|
||||||
squawks: !!document.getElementById('voiceCfgSquawk')?.checked,
|
adsb_military: !!document.getElementById('voiceCfgAdsbMilitary')?.checked,
|
||||||
|
squawks: !!document.getElementById('voiceCfgSquawk')?.checked,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,13 @@ const VoiceAlerts = (function () {
|
|||||||
rate: 1.1,
|
rate: 1.1,
|
||||||
pitch: 0.9,
|
pitch: 0.9,
|
||||||
voiceName: '',
|
voiceName: '',
|
||||||
streams: { pager: true, tscm: true, bluetooth: true },
|
streams: {
|
||||||
|
pager: true,
|
||||||
|
tscm: true,
|
||||||
|
bluetooth: true,
|
||||||
|
adsb_military: true,
|
||||||
|
squawks: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function _toNumberInRange(value, fallback, min, max) {
|
function _toNumberInRange(value, fallback, min, max) {
|
||||||
|
|||||||
@@ -419,6 +419,7 @@
|
|||||||
let agentPollTimer = null; // Polling fallback for agent mode
|
let agentPollTimer = null; // Polling fallback for agent mode
|
||||||
let isTracking = false;
|
let isTracking = false;
|
||||||
let currentFilter = 'all';
|
let currentFilter = 'all';
|
||||||
|
// ICAO -> { emergency: bool, watchlist: bool, military: bool }
|
||||||
let alertedAircraft = {};
|
let alertedAircraft = {};
|
||||||
let alertsEnabled = true;
|
let alertsEnabled = true;
|
||||||
let detectionSoundEnabled = localStorage.getItem('adsb_detectionSound') !== 'false'; // Default on
|
let detectionSoundEnabled = localStorage.getItem('adsb_detectionSound') !== 'false'; // Default on
|
||||||
@@ -668,24 +669,64 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function speakAircraftAlert(kind, icao, ac, detail) {
|
||||||
|
if (typeof VoiceAlerts === 'undefined' || typeof VoiceAlerts.speak !== 'function') return;
|
||||||
|
|
||||||
|
const cfg = (typeof VoiceAlerts.getConfig === 'function')
|
||||||
|
? VoiceAlerts.getConfig()
|
||||||
|
: { streams: {} };
|
||||||
|
const streams = cfg && cfg.streams ? cfg.streams : {};
|
||||||
|
const callsign = (ac && ac.callsign ? String(ac.callsign).trim() : '') || icao;
|
||||||
|
|
||||||
|
if (kind === 'emergency') {
|
||||||
|
if (streams.squawks === false) return;
|
||||||
|
const squawk = detail && detail.squawk ? ` squawk ${detail.squawk}.` : '.';
|
||||||
|
const meaning = detail && detail.name ? ` ${detail.name}.` : '';
|
||||||
|
VoiceAlerts.speak(`Aircraft emergency: ${callsign}.${squawk}${meaning}`, VoiceAlerts.PRIORITY.HIGH);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kind === 'military') {
|
||||||
|
if (streams.adsb_military === false) return;
|
||||||
|
const country = detail && detail.country ? ` ${detail.country}.` : '';
|
||||||
|
VoiceAlerts.speak(`Military aircraft detected: ${callsign}.${country}`, VoiceAlerts.PRIORITY.HIGH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function checkAndAlertAircraft(icao, ac) {
|
function checkAndAlertAircraft(icao, ac) {
|
||||||
if (alertedAircraft[icao]) return;
|
if (!alertedAircraft[icao]) {
|
||||||
|
alertedAircraft[icao] = { emergency: false, watchlist: false, military: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
const alertState = alertedAircraft[icao];
|
||||||
const militaryInfo = isMilitaryAircraft(icao, ac.callsign);
|
const militaryInfo = isMilitaryAircraft(icao, ac.callsign);
|
||||||
const squawkInfo = checkSquawkCode(ac);
|
const squawkInfo = checkSquawkCode(ac);
|
||||||
const onWatchlist = isOnWatchlist(ac);
|
const onWatchlist = isOnWatchlist(ac);
|
||||||
|
|
||||||
if (squawkInfo && squawkInfo.type === 'emergency') {
|
if (squawkInfo && squawkInfo.type === 'emergency') {
|
||||||
alertedAircraft[icao] = 'emergency';
|
if (!alertState.emergency) {
|
||||||
playAlertSound('emergency');
|
alertState.emergency = true;
|
||||||
showAlertBanner(`EMERGENCY: ${squawkInfo.name} - ${ac.callsign || icao}`, '#ff0000');
|
playAlertSound('emergency');
|
||||||
} else if (onWatchlist) {
|
showAlertBanner(`EMERGENCY: ${squawkInfo.name} - ${ac.callsign || icao}`, '#ff0000');
|
||||||
alertedAircraft[icao] = 'watchlist';
|
speakAircraftAlert('emergency', icao, ac, {
|
||||||
|
squawk: ac.squawk,
|
||||||
|
name: squawkInfo.name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onWatchlist && !alertState.watchlist) {
|
||||||
|
alertState.watchlist = true;
|
||||||
playAlertSound('military'); // Use military sound for watchlist
|
playAlertSound('military'); // Use military sound for watchlist
|
||||||
showAlertBanner(`WATCHLIST: ${ac.callsign || ac.registration || icao} detected!`, '#00d4ff');
|
showAlertBanner(`WATCHLIST: ${ac.callsign || ac.registration || icao} detected!`, '#00d4ff');
|
||||||
} else if (militaryInfo.military) {
|
} else if (militaryInfo.military && !alertState.military) {
|
||||||
alertedAircraft[icao] = 'military';
|
alertState.military = true;
|
||||||
playAlertSound('military');
|
playAlertSound('military');
|
||||||
showAlertBanner(`MILITARY: ${ac.callsign || icao}${militaryInfo.country ? ' (' + militaryInfo.country + ')' : ''}`, '#556b2f');
|
showAlertBanner(`MILITARY: ${ac.callsign || icao}${militaryInfo.country ? ' (' + militaryInfo.country + ')' : ''}`, '#556b2f');
|
||||||
|
speakAircraftAlert('military', icao, ac, {
|
||||||
|
country: militaryInfo.country || null,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5037,7 +5078,13 @@ sudo make install</code>
|
|||||||
<!-- Help Modal -->
|
<!-- Help Modal -->
|
||||||
{% include 'partials/help-modal.html' %}
|
{% include 'partials/help-modal.html' %}
|
||||||
|
|
||||||
|
<script src="{{ url_for('static', filename='js/core/voice-alerts.js') }}?v={{ version }}&r=adsbvoice1"></script>
|
||||||
<script src="{{ url_for('static', filename='js/core/settings-manager.js') }}?v={{ version }}&r=maptheme17"></script>
|
<script src="{{ url_for('static', filename='js/core/settings-manager.js') }}?v={{ version }}&r=maptheme17"></script>
|
||||||
|
<script>
|
||||||
|
window.addEventListener('DOMContentLoaded', () => {
|
||||||
|
if (typeof VoiceAlerts !== 'undefined') VoiceAlerts.init();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
<!-- Agent Manager -->
|
<!-- Agent Manager -->
|
||||||
<script src="{{ url_for('static', filename='js/core/agents.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/core/agents.js') }}"></script>
|
||||||
|
|||||||
@@ -323,6 +323,17 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-row">
|
||||||
|
<div class="settings-label">
|
||||||
|
<span class="settings-label-text">Military Aircraft</span>
|
||||||
|
<span class="settings-label-desc">Speak when military aircraft are detected</span>
|
||||||
|
</div>
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input type="checkbox" id="voiceCfgAdsbMilitary" checked onchange="saveVoiceAlertConfig()">
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="settings-row">
|
<div class="settings-row">
|
||||||
<div class="settings-label">
|
<div class="settings-label">
|
||||||
<span class="settings-label-text">Emergency Squawks</span>
|
<span class="settings-label-text">Emergency Squawks</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user