auto-sync: 2026-04-19 20:30:01

This commit is contained in:
Stream
2026-04-19 20:30:02 +03:00
parent 6b195a493d
commit cb6a779be7
2 changed files with 43 additions and 6 deletions

View File

@@ -81,6 +81,7 @@ services:
environment:
<<: *common-env
SERVICE_ROLE: preprocess
BATCH_SIZE: "500"
volumes:
- ../logs/preprocess:/var/log/fr24
- ../backup:/backup

View File

@@ -76,7 +76,8 @@ function planeIcon(heading) {
});
}
const markers = {}; // icao24 -> L.marker
const markers = {}; // icao24 -> L.marker
let trackLayers = []; // active track polylines
function fmt(v, unit, decimals=0) {
if (v == null) return '—';
@@ -86,8 +87,12 @@ function fmt(v, unit, decimals=0) {
function showPopup(props) {
document.getElementById('pop-callsign').textContent = props.callsign || props.icao24;
document.getElementById('pop-icao').textContent = props.icao24;
document.getElementById('pop-alt').textContent = fmt(props.altitude_m, 'm');
document.getElementById('pop-spd').textContent = fmt(props.ground_speed_kt, 'kt');
// altitude: m → ft
const altFt = props.altitude_m != null ? Math.round(props.altitude_m * 3.281) : null;
document.getElementById('pop-alt').textContent = altFt != null ? altFt + ' ft' : '—';
// speed: kt → km/h
const spdKmh = props.ground_speed_kt != null ? Math.round(props.ground_speed_kt * 1.852) : null;
document.getElementById('pop-spd').textContent = spdKmh != null ? spdKmh + ' km/h' : '—';
document.getElementById('pop-hdg').textContent = fmt(props.heading_deg, '°');
document.getElementById('pop-vr').textContent = fmt(props.vertical_rate_fpm, 'fpm');
document.getElementById('pop-ts').textContent = props.observed_at
@@ -99,11 +104,42 @@ function closePopup() {
document.getElementById('popup-box').style.display = 'none';
}
async function refreshTracks() {
try {
const res = await fetch('/api/tracks?minutes=180');
if (!res.ok) return;
const geojson = await res.json();
let features = geojson.features || [];
// cap at 200 tracks — keep the most recent (already ordered by last_point_at DESC)
if (features.length > 200) features = features.slice(0, 200);
// remove old track layers
for (const layer of trackLayers) map.removeLayer(layer);
trackLayers = [];
for (const f of features) {
const coords = f.geometry.coordinates.map(([lon, lat]) => [lat, lon]);
const callsign = f.properties.callsign || f.properties.icao24;
const line = L.polyline(coords, {
color: '#58a6ff',
weight: 1.5,
opacity: 0.4,
}).addTo(map);
line.bindPopup(callsign);
trackLayers.push(line);
}
} catch (_) { /* silent — tracks are non-critical */ }
}
async function refresh() {
try {
const res = await fetch('/api/aircraft/live?minutes=60');
if (!res.ok) throw new Error('HTTP ' + res.status);
const geojson = await res.json();
const [acRes] = await Promise.all([
fetch('/api/aircraft/live?minutes=180'),
refreshTracks(),
]);
if (!acRes.ok) throw new Error('HTTP ' + acRes.status);
const geojson = await acRes.json();
const features = geojson.features || [];
const seen = new Set();