mirror of
https://github.com/smittix/intercept.git
synced 2026-04-24 06:40:00 -07:00
feat(adsb): add IATA↔ICAO airline code translation for ACARS cross-linking
ACARS messages use IATA codes (e.g. UA2412) while ADS-B uses ICAO callsigns (e.g. UAL2412). Add a translation layer so the two can match, enabling click-to-highlight and datalink message correlation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
161
utils/airline_codes.py
Normal file
161
utils/airline_codes.py
Normal file
@@ -0,0 +1,161 @@
|
||||
"""IATA ↔ ICAO airline code mapping for flight number translation."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
# IATA (2-letter) → ICAO (3-letter) mapping for common airlines
|
||||
IATA_TO_ICAO: dict[str, str] = {
|
||||
# North America — Major
|
||||
"AA": "AAL", # American Airlines
|
||||
"DL": "DAL", # Delta Air Lines
|
||||
"UA": "UAL", # United Airlines
|
||||
"WN": "SWA", # Southwest Airlines
|
||||
"B6": "JBU", # JetBlue Airways
|
||||
"AS": "ASA", # Alaska Airlines
|
||||
"NK": "NKS", # Spirit Airlines
|
||||
"F9": "FFT", # Frontier Airlines
|
||||
"G4": "AAY", # Allegiant Air
|
||||
"HA": "HAL", # Hawaiian Airlines
|
||||
"SY": "SCX", # Sun Country Airlines
|
||||
"WS": "WJA", # WestJet
|
||||
"AC": "ACA", # Air Canada
|
||||
"WG": "WGN", # Sunwing Airlines
|
||||
"TS": "TSC", # Air Transat
|
||||
"PD": "POE", # Porter Airlines
|
||||
"MX": "MXA", # Breeze Airways
|
||||
"QX": "QXE", # Horizon Air
|
||||
"OH": "COM", # PSA Airlines (Compass)
|
||||
"OO": "SKW", # SkyWest Airlines
|
||||
"YX": "RPA", # Republic Airways
|
||||
"9E": "FLG", # Endeavor Air (Pinnacle)
|
||||
"CP": "CPZ", # Compass Airlines
|
||||
"PT": "SWQ", # Piedmont Airlines
|
||||
"MQ": "ENY", # Envoy Air
|
||||
"YV": "ASH", # Mesa Airlines
|
||||
"AX": "LOF", # Trans States / GoJet
|
||||
"ZW": "AWI", # Air Wisconsin
|
||||
"G7": "GJS", # GoJet Airlines
|
||||
"EV": "ASQ", # ExpressJet / Atlantic Southeast
|
||||
"AM": "AMX", # Aeromexico
|
||||
"VB": "VIV", # VivaAerobus
|
||||
"4O": "AIJ", # Interjet
|
||||
"Y4": "VOI", # Volaris
|
||||
# North America — Cargo
|
||||
"5X": "UPS", # UPS Airlines
|
||||
"FX": "FDX", # FedEx Express
|
||||
# Europe — Major
|
||||
"BA": "BAW", # British Airways
|
||||
"LH": "DLH", # Lufthansa
|
||||
"AF": "AFR", # Air France
|
||||
"KL": "KLM", # KLM Royal Dutch
|
||||
"IB": "IBE", # Iberia
|
||||
"AZ": "ITY", # ITA Airways
|
||||
"SK": "SAS", # SAS Scandinavian
|
||||
"AY": "FIN", # Finnair
|
||||
"OS": "AUA", # Austrian Airlines
|
||||
"LX": "SWR", # Swiss International
|
||||
"SN": "BEL", # Brussels Airlines
|
||||
"TP": "TAP", # TAP Air Portugal
|
||||
"EI": "EIN", # Aer Lingus
|
||||
"U2": "EZY", # easyJet
|
||||
"FR": "RYR", # Ryanair
|
||||
"W6": "WZZ", # Wizz Air
|
||||
"VY": "VLG", # Vueling
|
||||
"PC": "PGT", # Pegasus Airlines
|
||||
"TK": "THY", # Turkish Airlines
|
||||
"LO": "LOT", # LOT Polish
|
||||
"BT": "BTI", # airBaltic
|
||||
"DY": "NAX", # Norwegian Air Shuttle
|
||||
"VS": "VIR", # Virgin Atlantic
|
||||
"EW": "EWG", # Eurowings
|
||||
# Asia-Pacific — Major
|
||||
"SQ": "SIA", # Singapore Airlines
|
||||
"CX": "CPA", # Cathay Pacific
|
||||
"QF": "QFA", # Qantas
|
||||
"JL": "JAL", # Japan Airlines
|
||||
"NH": "ANA", # All Nippon Airways
|
||||
"KE": "KAL", # Korean Air
|
||||
"OZ": "AAR", # Asiana Airlines
|
||||
"CI": "CAL", # China Airlines
|
||||
"BR": "EVA", # EVA Air
|
||||
"CZ": "CSN", # China Southern
|
||||
"MU": "CES", # China Eastern
|
||||
"CA": "CCA", # Air China
|
||||
"AI": "AIC", # Air India
|
||||
"GA": "GIA", # Garuda Indonesia
|
||||
"TG": "THA", # Thai Airways
|
||||
"MH": "MAS", # Malaysia Airlines
|
||||
"PR": "PAL", # Philippine Airlines
|
||||
"VN": "HVN", # Vietnam Airlines
|
||||
"NZ": "ANZ", # Air New Zealand
|
||||
"3K": "JSA", # Jetstar Asia
|
||||
"JQ": "JST", # Jetstar Airways
|
||||
"AK": "AXM", # AirAsia
|
||||
"TR": "TGW", # Scoot
|
||||
"5J": "CEB", # Cebu Pacific
|
||||
# Middle East / Africa
|
||||
"EK": "UAE", # Emirates
|
||||
"QR": "QTR", # Qatar Airways
|
||||
"EY": "ETD", # Etihad Airways
|
||||
"GF": "GFA", # Gulf Air
|
||||
"SV": "SVA", # Saudia
|
||||
"ET": "ETH", # Ethiopian Airlines
|
||||
"MS": "MSR", # EgyptAir
|
||||
"SA": "SAA", # South African Airways
|
||||
"RJ": "RJA", # Royal Jordanian
|
||||
"WY": "OMA", # Oman Air
|
||||
# South America
|
||||
"LA": "LAN", # LATAM Airlines
|
||||
"G3": "GLO", # Gol Transportes Aéreos
|
||||
"AD": "AZU", # Azul Brazilian Airlines
|
||||
"AV": "AVA", # Avianca
|
||||
"CM": "CMP", # Copa Airlines
|
||||
"AR": "ARG", # Aerolíneas Argentinas
|
||||
# ACARS-specific addressing codes
|
||||
"MC": "MCO", # Possible: some ACARS systems use MC
|
||||
}
|
||||
|
||||
# Build reverse mapping (ICAO → IATA)
|
||||
ICAO_TO_IATA: dict[str, str] = {v: k for k, v in IATA_TO_ICAO.items()}
|
||||
|
||||
# Regex to split flight number into airline prefix and numeric part
|
||||
_FLIGHT_RE = re.compile(r'^([A-Z]{2,3})(\d+[A-Z]?)$')
|
||||
|
||||
|
||||
def translate_flight(flight: str) -> list[str]:
|
||||
"""Translate a flight number to all possible equivalent forms.
|
||||
|
||||
Given "UA2412" (IATA), returns ["UAL2412"] (ICAO).
|
||||
Given "UAL2412" (ICAO), returns ["UA2412"] (IATA).
|
||||
Returns empty list if no translation found.
|
||||
"""
|
||||
if not flight:
|
||||
return []
|
||||
|
||||
upper = flight.strip().upper()
|
||||
m = _FLIGHT_RE.match(upper)
|
||||
if not m:
|
||||
return []
|
||||
|
||||
prefix, number = m.group(1), m.group(2)
|
||||
results = []
|
||||
|
||||
# Try IATA → ICAO
|
||||
if prefix in IATA_TO_ICAO:
|
||||
results.append(IATA_TO_ICAO[prefix] + number)
|
||||
|
||||
# Try ICAO → IATA
|
||||
if prefix in ICAO_TO_IATA:
|
||||
results.append(ICAO_TO_IATA[prefix] + number)
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def expand_search_terms(terms: set[str]) -> set[str]:
|
||||
"""Expand a set of callsign/flight search terms with translated variants."""
|
||||
expanded = set(terms)
|
||||
for term in list(terms):
|
||||
for translated in translate_flight(term):
|
||||
expanded.add(translated)
|
||||
return expanded
|
||||
Reference in New Issue
Block a user