auto-sync: 2026-04-21 19:00:01
This commit is contained in:
@@ -527,6 +527,58 @@ def schedule_data():
|
||||
return err(str(e))
|
||||
|
||||
|
||||
# ── actual flight data API ──────────────────────────────────────────────────
|
||||
|
||||
@app.get("/api/flight-actual")
|
||||
def flight_actual():
|
||||
"""Query fr24_ext.flight_actual table directly."""
|
||||
try:
|
||||
limit = min(int(request.args.get("limit", 200)), 2000)
|
||||
offset = max(int(request.args.get("offset", 0)), 0)
|
||||
date_from = request.args.get("date_from")
|
||||
date_to = request.args.get("date_to")
|
||||
category = request.args.get("category")
|
||||
airport = request.args.get("airport") # ICAO filter
|
||||
|
||||
clauses = []
|
||||
params = []
|
||||
if date_from:
|
||||
clauses.append("flight_date >= %s"); params.append(date_from)
|
||||
if date_to:
|
||||
clauses.append("flight_date <= %s"); params.append(date_to)
|
||||
if category:
|
||||
clauses.append("category = %s"); params.append(category)
|
||||
if airport:
|
||||
clauses.append("(origin_icao = %s OR dest_icao = %s)"); params.extend([airport, airport])
|
||||
|
||||
where = " AND ".join(clauses) if clauses else "1=1"
|
||||
|
||||
rows = query(
|
||||
f"""
|
||||
SELECT fr24_id, flight, callsign, operated_as,
|
||||
origin_icao, dest_icao,
|
||||
datetime_takeoff, datetime_landed, flight_time,
|
||||
runway_takeoff, runway_landed, actual_distance,
|
||||
category, flight_ended, first_seen, last_seen, flight_date
|
||||
FROM fr24_ext.flight_actual
|
||||
WHERE {where}
|
||||
ORDER BY flight_date DESC, datetime_takeoff DESC NULLS LAST
|
||||
LIMIT %s OFFSET %s
|
||||
""",
|
||||
params + [limit, offset],
|
||||
)
|
||||
|
||||
total_row = query_one(
|
||||
f"SELECT COUNT(*) AS cnt FROM fr24_ext.flight_actual WHERE {where}",
|
||||
params,
|
||||
)
|
||||
|
||||
return ok({"total": total_row["cnt"] if total_row else 0, "flights": rows})
|
||||
except Exception as e:
|
||||
log.exception("flight_actual error")
|
||||
return err(str(e))
|
||||
|
||||
|
||||
@app.get("/api/schedule/export")
|
||||
def schedule_export():
|
||||
try:
|
||||
|
||||
@@ -244,8 +244,9 @@ def enrich_schedule(conn, target_date: date) -> int:
|
||||
"""
|
||||
with conn.cursor() as cur:
|
||||
# Match by normalized flight number + flight_date
|
||||
# For departures: match on origin_icao → airport is origin
|
||||
# For arrivals: match on dest_icao → airport is destination
|
||||
# IATA → ICAO mapping for Moscow airports
|
||||
# For departures: schedule airport is origin → fa.origin_icao must be Moscow ICAO
|
||||
# For arrivals: schedule airport is destination → fa.dest_icao must be Moscow ICAO
|
||||
cur.execute(
|
||||
"""
|
||||
WITH matches AS (
|
||||
@@ -256,12 +257,16 @@ def enrich_schedule(conn, target_date: date) -> int:
|
||||
fa.datetime_landed AS actual_landed,
|
||||
fa.category AS flight_category,
|
||||
CASE
|
||||
WHEN fa.datetime_takeoff IS NOT NULL AND s.scheduled_at IS NOT NULL
|
||||
WHEN s.direction = 'departure' AND fa.datetime_takeoff IS NOT NULL
|
||||
THEN EXTRACT(EPOCH FROM (fa.datetime_takeoff - s.scheduled_at))::int / 60
|
||||
WHEN s.direction = 'arrival' AND fa.datetime_landed IS NOT NULL
|
||||
THEN EXTRACT(EPOCH FROM (fa.datetime_landed - s.scheduled_at))::int / 60
|
||||
END AS delay_takeoff_min,
|
||||
CASE
|
||||
WHEN fa.datetime_landed IS NOT NULL AND s.scheduled_at IS NOT NULL
|
||||
WHEN s.direction = 'arrival' AND fa.datetime_landed IS NOT NULL AND s.scheduled_at IS NOT NULL
|
||||
THEN EXTRACT(EPOCH FROM (fa.datetime_landed - s.scheduled_at))::int / 60
|
||||
WHEN s.direction = 'departure' AND fa.datetime_takeoff IS NOT NULL AND s.scheduled_at IS NOT NULL
|
||||
THEN EXTRACT(EPOCH FROM (fa.datetime_takeoff - s.scheduled_at))::int / 60
|
||||
END AS delay_landed_min
|
||||
FROM fr24_ext.schedule s
|
||||
JOIN fr24_ext.flight_actual fa
|
||||
|
||||
@@ -25,7 +25,7 @@ log = logging.getLogger("tracks_fr24")
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
_last_run: dict = {"at": None, "status": "never", "stats": {}}
|
||||
_last_run: dict = {"at": None, "status": "never", "stats": {}, "fetch_tracks": config.FETCH_TRACKS}
|
||||
_conn = None
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user