mirror of
https://github.com/smittix/intercept.git
synced 2026-04-24 06:40:00 -07:00
feat: Consolidate VDL2 into ADS-B dashboard, fix blue bar, add CSV export
Remove VDL2 as a standalone mode since it's already integrated into the ADS-B dashboard sidebar. Remove the blue border-top on the controls bar. Add CSV export button to VDL2 panel for downloading collected messages. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1128,7 +1128,7 @@ body {
|
||||
gap: 8px;
|
||||
padding: 8px 15px;
|
||||
background: var(--bg-panel);
|
||||
border-top: 1px solid rgba(74, 158, 255, 0.3);
|
||||
border-top: none;
|
||||
font-size: 11px;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
|
||||
@@ -198,6 +198,7 @@
|
||||
<span>VDL2 MESSAGES</span>
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<span id="vdl2Count" style="font-size: 10px; color: var(--accent-cyan);">0</span>
|
||||
<button onclick="exportVdl2Csv()" title="Export VDL2 to CSV" style="background: none; border: 1px solid var(--border-color); color: var(--text-muted); cursor: pointer; font-size: 9px; padding: 2px 6px; border-radius: 3px; font-family: var(--font-mono);">CSV</button>
|
||||
<div class="panel-indicator" id="vdl2PanelIndicator"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -4113,6 +4114,7 @@ sudo make install</code>
|
||||
let vdl2CurrentAgent = null;
|
||||
let vdl2PollTimer = null;
|
||||
let vdl2MessageCount = 0;
|
||||
let vdl2CollectedData = [];
|
||||
let vdl2SidebarCollapsed = localStorage.getItem('vdl2SidebarCollapsed') !== 'false';
|
||||
let vdl2Frequencies = {
|
||||
'na': ['136975000', '136100000', '136650000', '136700000', '136800000'],
|
||||
@@ -4226,6 +4228,7 @@ sudo make install</code>
|
||||
if (vdl2Result.status === 'started' || vdl2Result.status === 'success') {
|
||||
isVdl2Running = true;
|
||||
vdl2MessageCount = 0;
|
||||
vdl2CollectedData = [];
|
||||
document.getElementById('vdl2ToggleBtn').innerHTML = '■ STOP VDL2';
|
||||
document.getElementById('vdl2ToggleBtn').classList.add('active');
|
||||
document.getElementById('vdl2PanelIndicator').classList.add('active');
|
||||
@@ -4550,6 +4553,27 @@ sudo make install</code>
|
||||
const msgText = acars.msg_text || '';
|
||||
const time = new Date().toLocaleTimeString();
|
||||
const freq = inner.freq ? (inner.freq / 1000000).toFixed(3) : '';
|
||||
|
||||
// Store for CSV export
|
||||
vdl2CollectedData.push({
|
||||
timestamp: new Date().toISOString(),
|
||||
frequency: freq ? freq + ' MHz' : '',
|
||||
source: avlc.src?.addr || '',
|
||||
source_type: avlc.src?.type || '',
|
||||
destination: avlc.dst?.addr || '',
|
||||
destination_type: avlc.dst?.type || '',
|
||||
frame_type: avlc.frame_type || '',
|
||||
flight: flight,
|
||||
registration: acars.reg || '',
|
||||
label: acars.label || '',
|
||||
sublabel: acars.sublabel || '',
|
||||
block_id: acars.blk_id || '',
|
||||
msg_number: acars.msg_num || '',
|
||||
message: msgText.replace(/\n/g, ' '),
|
||||
signal_level: inner.sig_level != null ? inner.sig_level.toFixed(1) : '',
|
||||
noise_level: inner.noise_level != null ? inner.noise_level.toFixed(1) : '',
|
||||
agent: data.agent_name || ''
|
||||
});
|
||||
const label = flight || src || (avlc.frame_type || 'VDL2');
|
||||
|
||||
msg.innerHTML = `
|
||||
@@ -4571,6 +4595,28 @@ sudo make install</code>
|
||||
}
|
||||
}
|
||||
|
||||
function exportVdl2Csv() {
|
||||
if (vdl2CollectedData.length === 0) {
|
||||
alert('No VDL2 messages to export.');
|
||||
return;
|
||||
}
|
||||
const headers = Object.keys(vdl2CollectedData[0]);
|
||||
const csvRows = [headers.join(',')];
|
||||
for (const row of vdl2CollectedData) {
|
||||
csvRows.push(headers.map(h => {
|
||||
const val = String(row[h] || '');
|
||||
return '"' + val.replace(/"/g, '""') + '"';
|
||||
}).join(','));
|
||||
}
|
||||
const blob = new Blob([csvRows.join('\n')], { type: 'text/csv' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `vdl2_${new Date().toISOString().slice(0, 19).replace(/[T:]/g, '-')}.csv`;
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
// Populate VDL2 device selector
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
fetch('/devices')
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/global-nav.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/index.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/modes/acars.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/modes/vdl2.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/modes/aprs.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/modes/tscm.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/components/signal-cards.css') }}">
|
||||
@@ -572,7 +571,6 @@
|
||||
|
||||
{% include 'partials/modes/acars.html' %}
|
||||
|
||||
{% include 'partials/modes/vdl2.html' %}
|
||||
|
||||
<button class="preset-btn" onclick="killAll()"
|
||||
style="width: 100%; margin-top: 10px; border-color: #ff3366; color: #ff3366;">
|
||||
@@ -3164,7 +3162,7 @@
|
||||
'pager', 'sensor', 'rtlamr', 'aprs', 'listening',
|
||||
'spystations', 'meshtastic', 'wifi', 'bluetooth', 'bt_locate',
|
||||
'tscm', 'satellite', 'sstv', 'weathersat', 'sstv_general', 'gps', 'websdr', 'subghz',
|
||||
'acars', 'vdl2'
|
||||
'acars'
|
||||
]);
|
||||
|
||||
function getModeFromQuery() {
|
||||
@@ -3623,7 +3621,7 @@
|
||||
'wifi': 'wireless', 'bluetooth': 'wireless', 'bt_locate': 'wireless',
|
||||
'tscm': 'security',
|
||||
'rtlamr': 'sdr', 'ais': 'sdr', 'spystations': 'sdr',
|
||||
'meshtastic': 'sdr', 'acars': 'sdr', 'vdl2': 'sdr',
|
||||
'meshtastic': 'sdr', 'acars': 'sdr',
|
||||
'satellite': 'space', 'sstv': 'space', 'weathersat': 'space', 'sstv_general': 'space', 'gps': 'space',
|
||||
'subghz': 'sdr'
|
||||
};
|
||||
@@ -3701,7 +3699,7 @@
|
||||
'satellite': 'satellite', 'wifi': 'wifi', 'bluetooth': 'bluetooth', 'bt_locate': 'bt locate',
|
||||
'listening': 'listening', 'aprs': 'aprs', 'tscm': 'tscm', 'meshtastic': 'meshtastic',
|
||||
'dmr': 'dmr', 'websdr': 'websdr', 'sstv_general': 'hf sstv',
|
||||
'acars': 'acars', 'vdl2': 'vdl2'
|
||||
'acars': 'acars'
|
||||
};
|
||||
document.querySelectorAll('.mode-nav-btn').forEach(btn => {
|
||||
const label = btn.querySelector('.nav-label');
|
||||
@@ -3730,7 +3728,7 @@
|
||||
document.getElementById('websdrMode')?.classList.toggle('active', mode === 'websdr');
|
||||
document.getElementById('subghzMode')?.classList.toggle('active', mode === 'subghz');
|
||||
document.getElementById('acarsMode')?.classList.toggle('active', mode === 'acars');
|
||||
document.getElementById('vdl2Mode')?.classList.toggle('active', mode === 'vdl2');
|
||||
|
||||
const pagerStats = document.getElementById('pagerStats');
|
||||
const sensorStats = document.getElementById('sensorStats');
|
||||
const satelliteStats = document.getElementById('satelliteStats');
|
||||
@@ -3772,8 +3770,7 @@
|
||||
'dmr': 'DIGITAL VOICE',
|
||||
'websdr': 'WEBSDR',
|
||||
'subghz': 'SUBGHZ',
|
||||
'acars': 'ACARS',
|
||||
'vdl2': 'VDL2'
|
||||
'acars': 'ACARS'
|
||||
};
|
||||
const activeModeIndicator = document.getElementById('activeModeIndicator');
|
||||
if (activeModeIndicator) activeModeIndicator.innerHTML = '<span class="pulse-dot"></span>' + (modeNames[mode] || mode.toUpperCase());
|
||||
@@ -3848,8 +3845,7 @@
|
||||
'dmr': 'Digital Voice Decoder',
|
||||
'websdr': 'HF/Shortwave WebSDR',
|
||||
'subghz': 'SubGHz Transceiver',
|
||||
'acars': 'ACARS Aircraft Messaging',
|
||||
'vdl2': 'VDL2 Aircraft Datalink'
|
||||
'acars': 'ACARS Aircraft Messaging'
|
||||
};
|
||||
const outputTitle = document.getElementById('outputTitle');
|
||||
if (outputTitle) outputTitle.textContent = titles[mode] || 'Signal Monitor';
|
||||
@@ -3867,7 +3863,7 @@
|
||||
const reconBtn = document.getElementById('reconBtn');
|
||||
const intelBtn = document.querySelector('[onclick="exportDeviceDB()"]');
|
||||
const reconPanel = document.getElementById('reconPanel');
|
||||
if (mode === 'satellite' || mode === 'sstv' || mode === 'weathersat' || mode === 'sstv_general' || mode === 'gps' || mode === 'listening' || mode === 'aprs' || mode === 'tscm' || mode === 'spystations' || mode === 'meshtastic' || mode === 'dmr' || mode === 'websdr' || mode === 'subghz' || mode === 'acars' || mode === 'vdl2') {
|
||||
if (mode === 'satellite' || mode === 'sstv' || mode === 'weathersat' || mode === 'sstv_general' || mode === 'gps' || mode === 'listening' || mode === 'aprs' || mode === 'tscm' || mode === 'spystations' || mode === 'meshtastic' || mode === 'dmr' || mode === 'websdr' || mode === 'subghz' || mode === 'acars') {
|
||||
if (reconPanel) reconPanel.style.display = 'none';
|
||||
if (reconBtn) reconBtn.style.display = 'none';
|
||||
if (intelBtn) intelBtn.style.display = 'none';
|
||||
@@ -3882,12 +3878,12 @@
|
||||
|
||||
// Show agent selector for modes that support remote agents
|
||||
const agentSection = document.getElementById('agentSection');
|
||||
const agentModes = ['pager', 'sensor', 'rtlamr', 'listening', 'aprs', 'wifi', 'bluetooth', 'aircraft', 'tscm', 'ais', 'acars', 'vdl2', 'dsc'];
|
||||
const agentModes = ['pager', 'sensor', 'rtlamr', 'listening', 'aprs', 'wifi', 'bluetooth', 'aircraft', 'tscm', 'ais', 'acars', 'dsc'];
|
||||
if (agentSection) agentSection.style.display = agentModes.includes(mode) ? 'block' : 'none';
|
||||
|
||||
// Show RTL-SDR device section for modes that use it
|
||||
const rtlDeviceSection = document.getElementById('rtlDeviceSection');
|
||||
if (rtlDeviceSection) rtlDeviceSection.style.display = (mode === 'pager' || mode === 'sensor' || mode === 'rtlamr' || mode === 'listening' || mode === 'aprs' || mode === 'sstv' || mode === 'weathersat' || mode === 'sstv_general' || mode === 'dmr' || mode === 'acars' || mode === 'vdl2') ? 'block' : 'none';
|
||||
if (rtlDeviceSection) rtlDeviceSection.style.display = (mode === 'pager' || mode === 'sensor' || mode === 'rtlamr' || mode === 'listening' || mode === 'aprs' || mode === 'sstv' || mode === 'weathersat' || mode === 'sstv_general' || mode === 'dmr' || mode === 'acars') ? 'block' : 'none';
|
||||
|
||||
// Show waterfall panel if running in listening mode
|
||||
const waterfallPanel = document.getElementById('waterfallPanel');
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
{{ mode_item('adsb', 'Aircraft', '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16v-2l-8-5V3.5a1.5 1.5 0 0 0-3 0V9l-8 5v2l8-2.5V19l-2 1.5V22l3.5-1 3.5 1v-1.5L13 19v-5.5l8 2.5z"/></svg>', '/adsb/dashboard') }}
|
||||
{{ mode_item('ais', 'Vessels', '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 18l2 2h14l2-2"/><path d="M5 18v-4a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v4"/><path d="M12 12V6"/><path d="M12 6l4 3"/></svg>', '/ais/dashboard') }}
|
||||
{{ mode_item('acars', 'ACARS', '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16v-2l-8-5V3.5a1.5 1.5 0 0 0-3 0V9l-8 5v2l8-2.5V19l-2 1.5V22l3.5-1 3.5 1v-1.5L13 19v-5.5l8 2.5z"/><line x1="4" y1="4" x2="8" y2="8"/><line x1="20" y1="4" x2="16" y2="8"/></svg>') }}
|
||||
{{ mode_item('vdl2', 'VDL2', '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16v-2l-8-5V3.5a1.5 1.5 0 0 0-3 0V9l-8 5v2l8-2.5V19l-2 1.5V22l3.5-1 3.5 1v-1.5L13 19v-5.5l8 2.5z"/><path d="M2 2l4 4M22 2l-4 4M12 12v0"/></svg>') }}
|
||||
|
||||
{{ mode_item('aprs', 'APRS', '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z"/><circle cx="12" cy="10" r="3"/></svg>') }}
|
||||
{{ mode_item('listening', 'Listening Post', '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18"/><path d="M9 21V9"/></svg>') }}
|
||||
{{ mode_item('spystations', 'Spy Stations', '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4.9 19.1C1 15.2 1 8.8 4.9 4.9"/><path d="M7.8 16.2c-2.3-2.3-2.3-6.1 0-8.5"/><circle cx="12" cy="12" r="2"/><path d="M16.2 7.8c2.3 2.3 2.3 6.1 0 8.5"/><path d="M19.1 4.9C23 8.8 23 15.1 19.1 19"/></svg>') }}
|
||||
@@ -181,7 +181,7 @@
|
||||
{{ mobile_item('adsb', 'Aircraft', '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 16v-2l-8-5V3.5a1.5 1.5 0 0 0-3 0V9l-8 5v2l8-2.5V19l-2 1.5V22l3.5-1 3.5 1v-1.5L13 19v-5.5l8 2.5z"/></svg>', '/adsb/dashboard') }}
|
||||
{{ mobile_item('ais', 'Vessels', '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 18l2 2h14l2-2"/><path d="M5 18v-4a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v4"/><path d="M12 12V6"/><path d="M12 6l4 3"/></svg>', '/ais/dashboard') }}
|
||||
{{ mobile_item('acars', 'ACARS', '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 16v-2l-8-5V3.5a1.5 1.5 0 0 0-3 0V9l-8 5v2l8-2.5V19l-2 1.5V22l3.5-1 3.5 1v-1.5L13 19v-5.5l8 2.5z"/></svg>') }}
|
||||
{{ mobile_item('vdl2', 'VDL2', '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 16v-2l-8-5V3.5a1.5 1.5 0 0 0-3 0V9l-8 5v2l8-2.5V19l-2 1.5V22l3.5-1 3.5 1v-1.5L13 19v-5.5l8 2.5z"/></svg>') }}
|
||||
|
||||
{{ mobile_item('aprs', 'APRS', '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z"/><circle cx="12" cy="10" r="3"/></svg>') }}
|
||||
{{ mobile_item('wifi', 'WiFi', '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12.55a11 11 0 0 1 14.08 0"/><path d="M8.53 16.11a6 6 0 0 1 6.95 0"/><circle cx="12" cy="20" r="1" fill="currentColor"/></svg>') }}
|
||||
{{ mobile_item('bluetooth', 'BT', '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6.5 6.5 17.5 17.5 12 22 12 2 17.5 6.5 6.5 17.5"/></svg>') }}
|
||||
|
||||
Reference in New Issue
Block a user