mirror of
https://github.com/smittix/intercept.git
synced 2026-07-20 07:18:11 -07:00
fix: Persist tracked satellites to database (fixes #135)
Satellites added via CelesTrak import or TLE paste are now stored in SQLite and survive page reloads and app restarts. Adds CRUD API endpoints and wires frontend sidebar + dashboard to use them. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+97
-45
@@ -10621,10 +10621,7 @@
|
||||
}
|
||||
|
||||
// Satellite management
|
||||
let trackedSatellites = [
|
||||
{ id: 'ISS', name: 'ISS (ZARYA)', norad: '25544', builtin: true, checked: true },
|
||||
{ id: 'METEOR-M2', name: 'Meteor-M 2', norad: '40069', builtin: true, checked: true }
|
||||
];
|
||||
let trackedSatellites = [];
|
||||
|
||||
function renderSatelliteList() {
|
||||
const list = document.getElementById('satTrackingList');
|
||||
@@ -10643,14 +10640,27 @@
|
||||
}
|
||||
|
||||
function toggleSatellite(idx) {
|
||||
trackedSatellites[idx].checked = !trackedSatellites[idx].checked;
|
||||
const sat = trackedSatellites[idx];
|
||||
sat.checked = !sat.checked;
|
||||
fetch(`/satellite/tracked/${sat.norad}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ enabled: sat.checked })
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
function removeSatellite(idx) {
|
||||
if (!trackedSatellites[idx].builtin) {
|
||||
trackedSatellites.splice(idx, 1);
|
||||
renderSatelliteList();
|
||||
}
|
||||
const sat = trackedSatellites[idx];
|
||||
if (sat.builtin) return;
|
||||
fetch(`/satellite/tracked/${sat.norad}`, { method: 'DELETE' })
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.status === 'success') {
|
||||
trackedSatellites.splice(idx, 1);
|
||||
renderSatelliteList();
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
function getSelectedSatellites() {
|
||||
@@ -10686,7 +10696,7 @@
|
||||
}
|
||||
|
||||
const lines = tleText.split('\\n').map(l => l.trim()).filter(l => l);
|
||||
let added = 0;
|
||||
const toAdd = [];
|
||||
|
||||
for (let i = 0; i < lines.length; i += 3) {
|
||||
if (i + 2 < lines.length) {
|
||||
@@ -10696,32 +10706,33 @@
|
||||
|
||||
if (line1.startsWith('1 ') && line2.startsWith('2 ')) {
|
||||
const norad = line1.substring(2, 7).trim();
|
||||
const id = name.replace(/[^a-zA-Z0-9]/g, '-').toUpperCase();
|
||||
|
||||
// Check if already exists
|
||||
if (!trackedSatellites.find(s => s.norad === norad)) {
|
||||
trackedSatellites.push({
|
||||
id: id,
|
||||
name: name,
|
||||
norad: norad,
|
||||
builtin: false,
|
||||
checked: true,
|
||||
tle: [name, line1, line2]
|
||||
});
|
||||
added++;
|
||||
toAdd.push({ norad_id: norad, name: name, tle1: line1, tle2: line2, enabled: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (added > 0) {
|
||||
renderSatelliteList();
|
||||
document.getElementById('tleInput').value = '';
|
||||
closeSatModal();
|
||||
showInfo(`Added ${added} satellite(s)`);
|
||||
} else {
|
||||
if (toAdd.length === 0) {
|
||||
alert('No valid TLE data found. Format: Name, Line 1, Line 2 (3 lines per satellite)');
|
||||
return;
|
||||
}
|
||||
|
||||
fetch('/satellite/tracked', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(toAdd)
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.status === 'success') {
|
||||
_loadSatellitesFromAPI();
|
||||
document.getElementById('tleInput').value = '';
|
||||
closeSatModal();
|
||||
showInfo(`Added ${data.added} satellite(s)`);
|
||||
}
|
||||
})
|
||||
.catch(() => alert('Failed to save satellites'));
|
||||
}
|
||||
|
||||
function fetchCelestrak() {
|
||||
@@ -10737,35 +10748,76 @@
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.status === 'success' && data.satellites) {
|
||||
let added = 0;
|
||||
data.satellites.forEach(sat => {
|
||||
const noradStr = String(sat.norad);
|
||||
if (!trackedSatellites.find(s => s.norad === noradStr)) {
|
||||
trackedSatellites.push({
|
||||
id: sat.name.replace(/[^a-zA-Z0-9-]/g, '-'),
|
||||
name: sat.name,
|
||||
norad: noradStr,
|
||||
builtin: false,
|
||||
checked: false, // Don't auto-select
|
||||
tle: [sat.name, sat.tle1, sat.tle2]
|
||||
});
|
||||
added++;
|
||||
const toAdd = data.satellites
|
||||
.filter(sat => !trackedSatellites.find(s => s.norad === String(sat.norad)))
|
||||
.map(sat => ({
|
||||
norad_id: String(sat.norad),
|
||||
name: sat.name,
|
||||
tle1: sat.tle1,
|
||||
tle2: sat.tle2,
|
||||
enabled: false
|
||||
}));
|
||||
|
||||
if (toAdd.length === 0) {
|
||||
status.innerHTML = `<span style="color: var(--accent-green);">All ${data.satellites.length} satellites already tracked</span>`;
|
||||
return;
|
||||
}
|
||||
|
||||
fetch('/satellite/tracked', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(toAdd)
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(result => {
|
||||
if (result.status === 'success') {
|
||||
_loadSatellitesFromAPI();
|
||||
status.innerHTML = `<span style="color: var(--accent-green);">Added ${result.added} satellites (${data.satellites.length} total in category)</span>`;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
status.innerHTML = `<span style="color: var(--accent-red);">Failed to save satellites</span>`;
|
||||
});
|
||||
renderSatelliteList();
|
||||
status.innerHTML = `<span style="color: var(--accent-green);">Added ${added} satellites (${data.satellites.length} total in category)</span>`;
|
||||
} else {
|
||||
status.innerHTML = `<span style="color: var(--accent-red);">Error: ${data.message || 'Failed to fetch'}</span>`;
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
.catch(() => {
|
||||
status.innerHTML = `<span style="color: var(--accent-red);">Network error</span>`;
|
||||
});
|
||||
}
|
||||
|
||||
function _loadSatellitesFromAPI() {
|
||||
fetch('/satellite/tracked')
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.status === 'success' && data.satellites) {
|
||||
trackedSatellites = data.satellites.map(sat => ({
|
||||
id: sat.name.replace(/[^a-zA-Z0-9]/g, '-').toUpperCase(),
|
||||
name: sat.name,
|
||||
norad: sat.norad_id,
|
||||
builtin: sat.builtin,
|
||||
checked: sat.enabled,
|
||||
tle: sat.tle_line1 ? [sat.name, sat.tle_line1, sat.tle_line2] : null
|
||||
}));
|
||||
renderSatelliteList();
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// Fallback to hardcoded defaults if API fails
|
||||
if (trackedSatellites.length === 0) {
|
||||
trackedSatellites = [
|
||||
{ id: 'ISS', name: 'ISS (ZARYA)', norad: '25544', builtin: true, checked: true },
|
||||
{ id: 'METEOR-M2', name: 'Meteor-M 2', norad: '40069', builtin: true, checked: true }
|
||||
];
|
||||
renderSatelliteList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize satellite list when satellite mode is loaded
|
||||
function initSatelliteList() {
|
||||
renderSatelliteList();
|
||||
_loadSatellitesFromAPI();
|
||||
}
|
||||
|
||||
// Utility function
|
||||
|
||||
@@ -269,12 +269,42 @@
|
||||
let currentLocationSource = 'local';
|
||||
let agents = [];
|
||||
|
||||
const satellites = {
|
||||
let satellites = {
|
||||
25544: { name: 'ISS (ZARYA)', color: '#00ffff' },
|
||||
40069: { name: 'METEOR-M2', color: '#9370DB' },
|
||||
57166: { name: 'METEOR-M2-3', color: '#ff00ff' }
|
||||
};
|
||||
|
||||
const satColors = ['#00ffff', '#9370DB', '#ff00ff', '#00ff00', '#ff6600', '#ffff00', '#ff69b4', '#7b68ee'];
|
||||
|
||||
function loadDashboardSatellites() {
|
||||
fetch('/satellite/tracked?enabled=true')
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.status === 'success' && data.satellites && data.satellites.length > 0) {
|
||||
const newSats = {};
|
||||
const select = document.getElementById('satSelect');
|
||||
select.innerHTML = '';
|
||||
data.satellites.forEach((sat, i) => {
|
||||
const norad = parseInt(sat.norad_id);
|
||||
newSats[norad] = {
|
||||
name: sat.name,
|
||||
color: satellites[norad]?.color || satColors[i % satColors.length]
|
||||
};
|
||||
const opt = document.createElement('option');
|
||||
opt.value = norad;
|
||||
opt.textContent = sat.name;
|
||||
select.appendChild(opt);
|
||||
});
|
||||
satellites = newSats;
|
||||
// Default to ISS if available
|
||||
if (newSats[25544]) select.value = '25544';
|
||||
selectedSatellite = parseInt(select.value);
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
function onSatelliteChange() {
|
||||
const select = document.getElementById('satSelect');
|
||||
selectedSatellite = parseInt(select.value);
|
||||
@@ -331,6 +361,7 @@
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
loadDashboardSatellites();
|
||||
setupEmbeddedMode();
|
||||
const usedShared = applySharedObserverLocation();
|
||||
initGroundMap();
|
||||
|
||||
Reference in New Issue
Block a user