diff --git a/client/src/components/Aircraft.vue b/client/src/components/Aircraft.vue index ee148c6..de7c161 100644 --- a/client/src/components/Aircraft.vue +++ b/client/src/components/Aircraft.vue @@ -46,7 +46,7 @@ const speedVal = computed(() => speed.value.convert(props.plane.speed || prop const altVal = computed(() => props.plane.landed ? 'LANDED' : altitude.value.convert(altitudeVal.value)) const altUnit = computed(() => props.plane.landed ? '' : altitude.value.label) const climbVal = computed(() => { const v = vertical.value.convert(props.plane.climb || props.plane.baro_rate || 0); return v >= 0 ? `+${v}` : String(v) }) -const description = computed(() => props.plane.desc || [props.plane.manufacturer, props.plane.model].filter(Boolean).join(' ') || '') +const description = computed(() => props.plane.desc || [props.plane.manufacturer, props.plane.model].filter(Boolean).join(' ') || props.plane.aircraft || '') const operator = computed(() => props.plane.operator || props.plane.owner || '') const altitudeHistory = computed(() => (props.history || []) diff --git a/server/src/adsb.mjs b/server/src/adsb.mjs index c184666..2cbcb50 100644 --- a/server/src/adsb.mjs +++ b/server/src/adsb.mjs @@ -13,7 +13,7 @@ const DATA = resolve(DIR, '../data'); const IMAGES_DIR = resolve(DATA, 'aircraft'); const DB_PATH = resolve(DATA, 'aircraft.db'); const CSV_CACHE = resolve(DATA, 'aircraft_db.csv'); -const AIRLINES_CACHE = resolve(DATA, 'airlines.dat'); +const AIRLINES_CACHE = resolve(DATA, 'airlines.csv'); const MAX_HISTORY = 500; const HISTORY_TTL = 1000 * 60 * 60; // 1 hour @@ -178,38 +178,36 @@ export async function initAircraftDb() { }))); fs.unlinkSync(CSV_CACHE); - console.log(`✈️ Aircraft imported: ${csv.length}`); + console.log(`✈️ Registrations imported: ${csv.length}`); } else { const count = db.prepare('SELECT COUNT(*) as c FROM aircraft').get(); - console.log(`✈️ Aircraft loaded: ${count.c}`); + console.log(`✈️ Registrations loaded: ${count.c}`); } } +function isMilitaryIcao(icao) { + if (!icao) return false; + const hex = icao.toUpperCase(); + return milRanges.some(([s, e]) => hex >= s && hex <= e); +} + async function syncAirlines() { try { if (!fs.existsSync(AIRLINES_CACHE)) { console.log('✈️ Downloading airline database'); const res = await fetchWithTimeout(AIRLINES_URL, 10000); - if (!res.ok) throw new Error(`HTTP ${res.status}`); + if(!res.ok) throw new Error(`HTTP ${res.status}`); fs.writeFileSync(AIRLINES_CACHE, await res.text()); } const text = fs.readFileSync(AIRLINES_CACHE, 'utf8'); - const airlines = fromCsv(text, true); - const names = new Set(); - for (const row of airlines) { - if (row.active !== 'Y') continue; - for (const value of [row.name, row.alias, row.callsign]) { - const normalized = normalizeName(value); - if (normalized.length >= 3) names.add(normalized); - } - } - for (const value of PASSENGER_OPERATORS) names.add(normalizeName(value)); - passengerOperators = [...names].sort((a, b) => b.length - a.length); - console.log(`✈️ Airline operators loaded: ${passengerOperators.length}`); + const airlines = text.split('\n').slice(1).map(row => + row.split(',')[1]?.slice(1, -1).toLowerCase()).filter(Boolean).flat(); + console.log(airlines); + passengerOperators = airlines.sort((a, b) => b.length - a.length); + console.log(`✈️ Airlines loaded: ${airlines.length}`); } catch (e) { console.warn(`⚠️ Could not load airline database: ${e.message}`); - passengerOperators = PASSENGER_OPERATORS.map(normalizeName); } } @@ -236,12 +234,6 @@ async function syncMilitaryIcao() { } } -function isMilitaryIcao(icao) { - if (!icao) return false; - const hex = icao.toUpperCase(); - return milRanges.some(([s, e]) => hex >= s && hex <= e); -} - export function classifyAircraft(row) { if (!row) return 'unknown'; @@ -250,16 +242,13 @@ export function classifyAircraft(row) { return value && list.some(k => value.includes(normalizeName(k))); }); - const allFields = [row.operator, row.operatorCallsign, row.owner, row.categoryDescription]; if (isMilitaryIcao(row.icao) || MILITARY_CLASSES.includes(row.class)) { return 'military'; } - if (row.categoryDescription?.toLowerCase().includes('cargo') || matchesAny(allFields, CARGO_OPERATORS)) { - return 'cargo'; - } - - if (matchesAny(allFields, passengerOperators)) return 'passenger'; + const operators = [row.operator, row.operatorCallsign]; + if (row.categoryDescription?.toLowerCase().includes('cargo') || matchesAny(operators, CARGO_OPERATORS)) return 'cargo'; + if (matchesAny(operators, passengerOperators)) return 'passenger'; if (row.owner && !row.operator) return 'private'; return 'unknown'; }