auto-sync: 2026-04-21 01:30:01
This commit is contained in:
@@ -14,6 +14,57 @@ import psycopg2
|
||||
import psycopg2.extras
|
||||
from flask import Flask, jsonify, request, send_from_directory, Response
|
||||
|
||||
# ── IATA → город маппинг ──────────────────────────────────────────────────────
|
||||
IATA_CITY = {
|
||||
"AAQ": "Анапа", "ABA": "Абакан", "ADB": "Измир", "ADD": "Аддис-Абеба",
|
||||
"AER": "Сочи", "AKX": "Актобе", "ALA": "Алматы", "AMM": "Амман",
|
||||
"AMS": "Амстердам", "ARH": "Архангельск", "ARN": "Стокгольм", "ASB": "Ашхабад",
|
||||
"ASF": "Астрахань", "ATH": "Афины", "AUH": "Абу-Даби", "AYT": "Анталья",
|
||||
"AZN": "Андижан", "BAX": "Барнаул", "BCN": "Барселона", "BEG": "Белград",
|
||||
"BER": "Берлин", "BEY": "Бейрут", "BJV": "Бодрум", "BKK": "Бангкок",
|
||||
"BNE": "Брисбен", "BOG": "Богота", "BOM": "Мумбаи", "BQS": "Благовещенск",
|
||||
"BRU": "Брюссель", "BTK": "Братск", "BUS": "Батуми", "BXK": "Бухара",
|
||||
"BZK": "Брянск", "CAI": "Каир", "CCJ": "Кожикоде", "CEK": "Челябинск",
|
||||
"CGK": "Джакарта", "CGN": "Кёльн", "CMN": "Касабланка", "CMB": "Коломбо",
|
||||
"CSY": "Чебоксары", "CXI": "Кашгар", "CZM": "Косумель", "DEL": "Дели",
|
||||
"DME": "Домодедово", "DMJ": "Домодедово", "DOH": "Доха", "DSS": "Дакар",
|
||||
"DXB": "Дубай", "EGO": "Белгород", "EKB": "Екатеринбург", "EVN": "Ереван",
|
||||
"FRA": "Франкфурт", "FRU": "Бишкек", "GDZ": "Геленджик", "GDX": "Магадан",
|
||||
"GIF": "Гифу", "GOI": "Гоа", "GOJ": "Нижний Новгород", "GRV": "Грозный",
|
||||
"GRZ": "Грац", "GYD": "Баку", "HAD": "Ханчжоу", "HAM": "Гамбург",
|
||||
"HEL": "Хельсинки", "HMA": "Ханты-Мансийск", "HRB": "Харбин",
|
||||
"HRG": "Хургада", "HKT": "Пхукет", "HYD": "Хайдарабад", "IKT": "Иркутск",
|
||||
"IKA": "Тегеран", "IST": "Стамбул", "IXC": "Чандигарх", "JED": "Джидда",
|
||||
"JFK": "Нью-Йорк", "KGD": "Калининград", "KGV": "Когалым",
|
||||
"KHV": "Хабаровск", "KJA": "Красноярск", "KLO": "Калининград",
|
||||
"KRR": "Краснодар", "KUF": "Самара", "KUL": "Куала-Лумпур",
|
||||
"KZN": "Казань", "LAX": "Лос-Анджелес", "LED": "Санкт-Петербург",
|
||||
"LHR": "Лондон", "LPK": "Липецк", "MIA": "Майами", "MLE": "Мале",
|
||||
"MMK": "Мурманск", "MRV": "Минеральные Воды", "MSQ": "Минск",
|
||||
"MUC": "Мюнхен", "NBO": "Найроби", "NJC": "Нижневартовск",
|
||||
"NNM": "Нарьян-Мар", "NQZ": "Астана", "NSK": "Норильск", "NVR": "Набережные Челны",
|
||||
"NVT": "Новороссийск", "OVB": "Новосибирск", "OMS": "Омск",
|
||||
"OSL": "Осло", "OSS": "Ош", "OZH": "Ургенч", "PEE": "Пермь",
|
||||
"PEK": "Пекин", "PKC": "Петропавловск-Камчатский", "PRG": "Прага",
|
||||
"PSA": "Пиза", "PUY": "Пула", "PUS": "Пусан", "REN": "Оренбург",
|
||||
"RGK": "Горно-Алтайск", "RIX": "Рига", "ROV": "Ростов-на-Дону",
|
||||
"RTW": "Саратов", "SAW": "Стамбул (Сабиха)", "SGB": "Балаково",
|
||||
"SGC": "Сургут", "SIP": "Симферополь", "SKG": "Салоники", "SLY": "Салехард",
|
||||
"SIN": "Сингапур", "SJJ": "Сараево", "SKZ": "Сыктывкар",
|
||||
"SVO": "Шереметьево", "SVX": "Екатеринбург", "SWT": "Стрежевой",
|
||||
"SYD": "Сидней", "TAS": "Ташкент", "TBS": "Тбилиси", "TJM": "Тюмень",
|
||||
"TKM": "Туркменбаши", "TLL": "Таллин", "TLS": "Тулуза", "TSE": "Астана",
|
||||
"TSQ": "Тамбов", "TXL": "Берлин", "ULV": "Ульяновск", "UFA": "Уфа",
|
||||
"UJD": "Усть-Каменогорск", "VOG": "Волгоград", "VOZ": "Воронеж",
|
||||
"VNO": "Вильнюс", "VVO": "Владивосток", "VKO": "Внуково", "WAW": "Варшава",
|
||||
"WLG": "Веллингтон", "XRY": "Херес", "YKS": "Якутск", "YYZ": "Торонто",
|
||||
"ZIA": "Жуковский", "ZRH": "Цюрих", "ZYR": "Зырянка",
|
||||
}
|
||||
|
||||
def _city(iata: str) -> str:
|
||||
"""IATA code → human-readable city name."""
|
||||
return IATA_CITY.get(iata.strip() if iata else "", iata or "")
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(asctime)s [api] %(levelname)s %(message)s",
|
||||
@@ -439,8 +490,10 @@ def schedule_data():
|
||||
"airline": r["airline_name"],
|
||||
"airport": r["airport_iata"],
|
||||
"direction": r["direction"],
|
||||
"origin": r["origin_iata"],
|
||||
"destination": r["destination_iata"],
|
||||
"origin": _city(r["origin_iata"]) or r["origin_iata"] or "",
|
||||
"destination": _city(r["destination_iata"]) or r["destination_iata"] or "",
|
||||
"origin_iata": r["origin_iata"] or "",
|
||||
"destination_iata": r["destination_iata"] or "",
|
||||
"scheduled_at": sched.isoformat() if sched else None,
|
||||
"actual_at": actual.isoformat() if actual else None,
|
||||
"delay_min": delay_min,
|
||||
@@ -494,8 +547,8 @@ def schedule_export():
|
||||
r["airline_name"] or "",
|
||||
r["airport_iata"],
|
||||
r["direction"],
|
||||
r["origin_iata"] or "",
|
||||
r["destination_iata"] or "",
|
||||
_city(r["origin_iata"]) or r["origin_iata"] or "",
|
||||
_city(r["destination_iata"]) or r["destination_iata"] or "",
|
||||
sched.isoformat() if sched else "",
|
||||
actual.isoformat() if actual else "",
|
||||
delay,
|
||||
|
||||
@@ -184,10 +184,20 @@ function exportCsv() {
|
||||
function routeStr(f) {
|
||||
const o = f.origin || "";
|
||||
const d = f.destination || "";
|
||||
if (!o && !d) return "—";
|
||||
if (!o) return `→ ${d}`;
|
||||
if (!d) return `${o} →`;
|
||||
return `${o} → ${d}`;
|
||||
const oi = f.origin_iata || "";
|
||||
const di = f.destination_iata || "";
|
||||
function fmt(city, iata) {
|
||||
if (!city && !iata) return "";
|
||||
if (!city) return iata;
|
||||
if (city === iata) return city;
|
||||
return city;
|
||||
}
|
||||
const from = fmt(o, oi);
|
||||
const to = fmt(d, di);
|
||||
if (!from && !to) return "—";
|
||||
if (!from) return `→ ${to}`;
|
||||
if (!to) return `${from} →`;
|
||||
return `${from} → ${to}`;
|
||||
}
|
||||
|
||||
function statusBadge(status) {
|
||||
|
||||
Reference in New Issue
Block a user