fr24 web · hujjat xarita API test jurnal

fr24 web — tizim hujjati

Jonli reyslar xaritasi + JSON API. Bitta Python servisi (webapp.py), faqat fr24 paketi va bir nechta yordamchi kutubxonaga bog‘liq. Barchasi bitta portда (8070): xarita, API, bu hujjat, /api-docs/, /test/.

0. Ishga tushirish

Lokal (Python 3.12+)

cd standalone
python -m venv .venv
./.venv/Scripts/python.exe -m pip install -r requirements.txt

$env:FR24_WEB_PORT = "8070"
# ixtiyoriy — boshqa vektor karta uslubi (default: OpenFreeMap Positron, kalitsiz):
# $env:FR24_BASEMAP_STYLE = "https://tiles.openfreemap.org/styles/liberty"
# ixtiyoriy — PostgreSQL (reyslar jurnali + playback + baza bo‘yicha ko‘rish):
# $env:FR24_DATABASE_URL = "postgresql://user:pass@host:5432/db"
./.venv/Scripts/python.exe webapp.py

Linux / macOS: python3 -m venv .venv && . .venv/bin/activate && pip install -r requirements.txt && FR24_WEB_PORT=8070 python webapp.py. Ishga tushganда joriy katalog standalone/ bo‘lsin (./fr24/, ./flags/, airports.json shu yerдан o‘qilади).

Docker

docker build -t fr24-web .
docker run --rm -p 8070:8070 fr24-web

# web + PostgreSQL birga:
cp .env.example .env          # va tahrirlang
docker compose up -d --build

Tekshirish

curl http://localhost:8070/healthz            # {"status":"ok"}
curl http://localhost:8070/api/selftest       # 20 ichki tekshiruv (FR24’siz)
curl "http://localhost:8070/api/flights?bbox=41,43,68,71"

Poller birinchi to‘liq dunyo aylanишини ~30–50 s dа tugатади; shundан so‘ng /api/selftest 200 qaytаради. Xizmatни to‘xtатиш: Ctrl‑C yoki SIGTERM.

1. Umumiy

Fon jarayoni (poller) butun dunyoni doimiy yig‘ib turadi va xotirada bitta “surat” saqlaydi. Brauzer so‘rovlari (/api/flights) faqat shu suratdan o‘qiydi — hech qachon Flightradar24’ga tegmaydi.

Yo‘lVazifasi
/Jonli xarita (HTML)
/api/flights?bbox=&limit=Hudud ichidagi reyslar
/api/airports?bbox=Hudud ichidagi aeroportlar
/api/search?q=&class=&field=Reys qidiruvi + tur bo‘yicha sanoq (7-bo‘lim)
/api/metaPoller holati + tur bo‘yicha sanoq
/api/selftestAvtotest natijasi
/flags/<cc>.svgDavlat bayrog‘i (lokal, ~260 ta)
/aircraft_photos/<tip>Samolyot tipi surati (lokal, Wikimedia)
/log/Reyslar jurnali jadvali (PostgreSQL, 8-bo‘lim)
/api/log?q=&class=&field=Jurnal qatorlarini o‘qish (JSON)
/api/track?id=|reg=Bitta reys legi / bort raqamining 24 soatlik trayektoriyasi (13-bo‘lim)
/api/fleet/classes, /api/fleet/aircraft?class=Bazadagi klasslar → o‘sha klassdagi bortlar (13-bo‘lim)
/api-docs/, /openapi.jsonInteraktiv Swagger UI + OpenAPI 3.1 spetsifikatsiyasi
/aircraft_types.jsonICAO tип belgisi → nom / harbiy?
/aircraft_photos.jsonTip → surat muallifi / litsenziyasi
/countries.jsonISO kod → davlat nomi
/borders.geojsonDavlat chegaralari (Natural Earth)
/healthzSog‘lomlik (FR24’ga so‘rovsiz)

2. Arxitektura (poller)

ishga tushganda:
  poller thread  --  o‘z asyncio loop’i, bitta doimiy HTTP/2 ulanish (FR24)
     |  har 18 s:
     |    dunyoni vertikal kesimlarga bo‘ladi (fr24 LNGS_WORLD_PER_HALF_HR,
     |    yarim soatda o‘zgaradi) × 3 ta kenglik zonasi
     |    = ~36 ta ketma-ket so‘rov, interval bo‘ylab tarqatilgan
     |    har javob xotiradagi { flightid: reys } lug‘atiga birlashtiriladi
     |    75 s ko‘rinmagan reys o‘chiriladi
     v  2° to‘rli indeks bilan “surat” atomik almashtiriladi

brauzer:
  GET /api/flights?bbox  --  suratdan to‘rli indeks orqali filtrlaydi (~1 ms)
     v
  interpolyatsiya (track + tezlik) bilan silliq harakat + qisqa izlar

3. Yuk va bloklanish

FR24’ga boradigan so‘rovlar soni foydalanuvchilar soniga bog‘liq emas — faqat poller so‘raydi: sikl uchun ~36 ta so‘rov, 18 soniyaga tarqatilgan (≈ 2.0 so‘rov/soniya), bitta ulanish, jitter bilan. 1 kishi ham, 10 000 kishi ham — bir xil.

4. Sozlamalar (env)

O‘zgaruvchiDefaultMa’no
FR24_WEB_HOST127.0.0.1Bog‘lanish manzili
FR24_WEB_PORT8070Port
FR24_BASEMAP_STYLEOpenFreeMap PositronMapLibre GL uslub URL yoki lokal /static/…/style.json (oflayn .pmtiles uchun)
FR24_BASEMAP_CSPO‘z tayl serveringiz uchun CSP’ga qo‘shimcha host
FR24_POLL_INTERVAL18Bir to‘liq dunyo siklи, soniya
FR24_POLL_MAXAGE7200FR24 “maxage” — eski reyslar chiqmaydi
FR24_FLIGHT_TTL75Ko‘rinmagan reysni o‘chirish, soniya
FR24_LAT_BANDS-85,20,48,85Kenglik zonasi chegaralari
FR24_MAX_FLIGHTS2000Bitta API javobidagi maks. reys
FR24_RATE_LIMIT240/api/* so‘rov/daqiqa (IP)
FR24_SLICESdynamicdynamic (yarim soatlik) yoki static
FR24_SHOW_GROUND_VEHICLES0Yer transporti (tortuvchi, «follow-me», muzdan tozalagich — GRND) reys sifatida sanalsinmi. Default: yo‘q
FR24_SATELLITE_URLEsri World ImagerySun’iy yo‘ldosh rejimi uchun {z}/{y}/{x} raster manba; hosti CSP’ga avtomatik qo‘shiladi
FR24_SATELLITE_ATTR© Esri, Maxar…Tasvir atributsiyasi (xarita burchagida)
FR24_SATELLITE_MAXZOOM19Tasvir manbasining maksimal zoomi

5. GET /api/flights

curl "http://localhost:8070/api/flights?bbox=42,52,-8,10&limit=2000"

{
  "flights": [ { "id": 981234567, "latitude": 46.6, "longitude": 6.5,
    "track": 169, "altitude": 35000, "ground_speed": 459, "on_ground": false,
    "callsign": "BEL4KE", "registration": "OO-SFF", "typecode": "A333",
    "origin": "BRU", "destination": "KGL", "cat": "widebody",
    "cls": "passenger", "op": "Brussels Airlines", "tn": "A-330-300",
    "vertical_speed": 0, "squawk": 0, "source": 0, "ts": 1756351234.1 } ],
  "shown": 812, "matched": 812, "world_total": 16044,
  "counts": { "military": 118, "government": 25, "passenger": 15100,
              "cargo": 340, "helicopter": 210, "other": 250 },
  "snapshot_age": 4.3
}

bbox = south,north,west,east (gradus). west > east — antimeridian kesib o‘tish, qo‘llab-quvvatlanadi. limit — ixtiyoriy, default 2000. Ko‘p bo‘lsa javob fazoviy tekis siyraklashtiriladi (shakli saqlanadi). class — ixtiyoriy: military|government|passenger|cargo| helicopter|other — faqat shu turdagi reyslar. ids — ixtiyoriy, vergul bilan (maks 20): shu reys id’lari limit/bboxdan qat’i nazar javobga kiritiladi (front-end tanlangan reysни shu bilan “mahkamlaydi”).

cls — reys turi (tasnif), op — operator / aviakompaniya, tn — samolyot modeli nomi (7-bo‘lim).

6. GET /api/airports

{ "airports": [ [41.2579, 69.2812, "TAS",
   "Tashkent International Airport", 1, "uz"] ] }

Element: [lat, lon, IATA, nom, size, cc]size 1=yirik 0=o‘rta, cc=ISO davlat kodi (kичik harf, /flags/<cc>.svg ga mos). Yiriklari oldinda, 900 ta bilan cheklangan.

Har bir reys server tomonida tasniflanadi (cls): harbiy, hukumat, yo‘lovchi, yuk, vertolyot yoki boshqa. Belgilar:

  1. Bort raqamiplane-alert-db (sdr-enthusiasts, ~12 000 harbiy/hukumat/politsiya bort raqami) bo‘yicha aniq moslik.
  2. Chaqiruv prefiksi — curated harbiy/hukumat prefikslari (RCH, RRR, GAF, CTM, IAM…).
  3. Samolyot tipi — 224 ta shubhasiz harbiy ICAO tип belgisi (F16, C130, E3TF, AH64…) va vertolyot tiplari.
  4. Aviakompaniya — OpenFlights ICAO kodi bo‘yicha yo‘lovchi/yuk.

Operator nomi va airline_overrides.json

airlines.json manbasi — OpenFlights, u taxminan 2014-yildan beri yangilanmagan. Buning uchta oqibati bor: yopilgan aviakompaniyalar hali ro‘yxatda; 2015-yildan keyin tashkil etilganlari umuman yo‘q; va ba’zi ICAO kodlari boshqa tashkilotga qayta berilgan — bu eng yomoni, chunki jonli reysga ishonch bilan noto‘g‘ri operator yoziladi.

Haqiqiy misol: USA kodi endi Silk Avia (O‘zbekiston, ATR-72-600) niki, lekin OpenFlights uni hali US Airways deb biladi — natijada Toshkent–Buxoro reysi amerika aviakompaniyasi sifatida ko‘rinardi.

airline_overrides.json shu xatolarni airlines.json ga tegmasdan tuzatadi (u fayl scripts/make_aircraftdb.py tomonidan qayta generatsiya qilinishi mumkin):

{
  "add":     { "USA": ["Silk Avia", "Uzbekistan", 0] },
  "retired": ["AWE", "COA", "NWA", "TWA", "BER", "AZA", "..."]
}
KalitMa’no
addICAO kodi → [nom, davlat, yuk_tashuvchimi]. Mavjud qatorni almashtiradi yoki yangisini qo‘shadi.
retiredIshlatilmaydigan kodlar butunlay olib tashlanadi — noto‘g‘ri nom ko‘rsatgandan ko‘ra hech nima ko‘rsatmagan afzal.

Fayl tahrirlangandan keyin webapp.py ni qayta ishga tushiring.

curl "http://localhost:8070/api/search?q=RCH&class=military&field=callsign"

{
  "results": [ { ...flight..., "cls": "military", "op": "US Air Mobility Command",
                 "tn": "C-17 Globemaster III" } ],
  "shown": 12,
  "counts": { "military": 118, "government": 25, "passenger": 15100, ... },
  "world_total": 16044, "snapshot_age": 3.1
}
ParametrMa’no
qQidiruv matni (bo‘sh bo‘lса — faqat filtr)
classTur bo‘yicha filtr (yuqoridagi 6 tadan biri)
fieldany (default) · callsign · reg · type · operator · route
bboxBerilса — faqat shu to‘rtburchak ichida qidiradi
limit1–400, default 120

Xaritadagi qidiruv paneli (HUD’dagi tugma): 6 ta tur yorlig‘i (jonli sanoq bilan), maydon tanlagichi va matn qatori. Bir turni tanlash xaritani ham o‘sha turga filtrlaydi. “harbiy samolyotlar bazasi” — barcha 224 ta harbiy tип nomi katalogи (/aircraft_types.jsonдан).

8. PostgreSQL — reyslar jurnali

Ixtiyoriy. FR24_DATABASE_URL berilса, poller har siklda uchayotgan / harakatlanayotgan (on_ground=false yoki tezlik ≥ FR24_DB_MIN_SPEED) har bir reysни flight_log jadvaliga upsert qiladi (har FR24 reys legи — bitta qator, yangilanib boradi). Berilмаса — servis o‘zgarishsiz ishlaydi.

Yozuv alohida oqimда (thread) navbat orqali amalga oshadi — DB kechiksa poller hech qачон kutmaydi; navbat to‘lса bir sikl tashlanadi. Yozuvchi oqim orqада qolса eski (navbatдаги) suratlar tashlanиб, faqat eng yangиси yozилади. Sxема ishга tushганда avtomatik yaratiladi (scripts/schema.sql).

Jadval cheksiz o‘smаsлиги uchun yozuvchi oqim soatda bir marta last_seen FR24_DB_RETENTION_DAYS kundan eski qatorларни o‘chиради (0 = cheksiz saqlash). /log/ va boshqa o‘qиш yo‘llаri FR24_DB_POOL ta qайта ishlатилаdиган ulanишни bo‘lишади — har so‘rovда yangi ulanиш ochилmaydi.

flight_log jadvali

UstunMa’no
idTartib raqam (BIGSERIAL)
flight_codeReys kodi (callsign)
aircraft_typeSamolyot turi — ICAO belgisi (masalan A333)
aircraft_modelTo‘liq nomi (Airbus A330-300)
registrationRegistr raqami (bort raqami)
origin_code / origin_nameQayerdan — IATA / to‘liq (Brussels Airport, Belgium)
destination_code / destination_nameQayerga — IATA / to‘liq
routeBrussels Airport, Belgium → Kigali International Airport, Rwanda
flight_class, operatorTur (7-bo‘lim) va operator
first_seen, last_seen, observationsKuzatuv oynasi
last_latitudelast_trackOxirgi pozitsiya / tezlik / kurs
# docker-compose bilan (db servisi ichida):
FR24_DATABASE_URL=postgresql://fr24:fr24@db:5432/fr24

# lokal test:
docker run -d --name pg -e POSTGRES_PASSWORD=fr24 -e POSTGRES_DB=fr24 \
  -p 5432:5432 postgres:16-alpine
export FR24_DATABASE_URL=postgresql://postgres:fr24@localhost:5432/fr24
python webapp.py
# ko‘rish:  http://localhost:8070/log/
EnvDefaultMa’no
FR24_DATABASE_URLPostgreSQL DSN. Berilса jurnal yoqiladi
FR24_DB_MIN_SPEED5Yerда shundan sekin reys yozilmaydi (kt)
FR24_DB_QUEUE4Navbat shundan uzunlashса sikl tashlanadi
FR24_DB_RETENTION_DAYS30Shundan eski (ko‘rinmagan) qatorlar o‘chiriladi; 0 = cheksiz
FR24_DB_POOL4O‘qish yo‘llari uchun qayta ishlatiladigan PG ulanishlari

9. Boshqa marshrutlar

/api/meta{poller, world_flights, counts, db, tracking, snapshot_age, ...}
/api/selftest20 ta tekshiruv; hammasi o‘tса 200, aks holda 503. FR24’ga so‘rov yubormaydi.
/healthz{"status":"ok"}
/flags/<cc>.svgLokal SVG bayroq (flag-icons, MIT), Cache-Control: 30 kun
/aircraft_types.jsonICAO tип belgisi → {nom, ishlab chiqaruvchi, sinf, harbiy?}

10. Xarita: ikonka, iz, bayroq

Ikki asos rejimi

HUD’dagi segment tugmasi asos xaritani almashtiradi; tanlov localStorage da saqlanadi va /?basemap=satellite bilan ulashiladi.

RejimNimaManba
xaritaflightradar24.com uslubidagi vektor MapLibre GL + OpenFreeMap Positron (kalitsiz)
sun’iy yo‘ldoshorbitadan olingan tasvir Esri World Imagery (kalitsiz) — FR24_SATELLITE_URL

Raster qatlam birinchi symbol qatlamining ostiga qo‘yiladi (map.addLayer(…, firstSymbolId)), shuning uchun tasvir butun vektor fonini yopadi, lekin joy nomlari, chegaralar va reyslar ustida qoladi. Almashish — bu visibility o‘zgarishi: style qayta yuklanmaydi, keshdagi tayllar qayta so‘ralmaydi. Tasvir ustida yorliqlar oq rangga va qalin qora halo’ga o‘tadi — cho‘lda ham, o‘rmonda ham o‘qiladigan yagona kombinatsiya.

Chizish: bitta <canvas> (GPU)

Barcha reyslar, izlar va aeroportlar bitta <canvas> elementига chizилади (Path2D siluetlari, GPU-kompozitsiya). Ilgари har reys alohida DOM element (marker) edi va har yangilanishda o‘chirilib qayta yaratilardi — shu “qotib qolish” ga sabab bo‘lardi. Endi DOM umuman o‘zgarmaydi; har kadrda faqat canvas qayta chiziladi (~1–2 ming siluet, <5 ms).

Canvas doim (0,0)’da turadi va har kadr MapLibre’ning map.project()’i orqali qayta proyeksiyalanadi. MapLibre o‘z transformini har render kadrida yangilab turadi, shuning uchun surish, zoom va inertsiya paytida reyslar plitka bilan 1:1 siljiydi — qotish yoki sakrash yo‘q (flightradar24.com bilan bir xil yondashuv). Leaflet tarmog‘ida esa canvas xarita pane’i ichida.

Ikonka — rusumga qarab

Siluet ICAO tип belgisiga qarab tanlanади: keng fyuzelyaj (A380/747), oddiy layner, regional, biznes-jet, turboprop, yengil, harbiy jet (delta), harbiy transport, vertolyot, planer, dron. Rang — balandlik bo‘yicha (legenda). Kursorni ustiga olib borsangiz siluet oqaради va yonида chaqiruv/model/balandlik yorlig‘i chiqади.

Marshrut chizig‘i

Reysни tanlaganда, agar uchgan va boradiган aeroporti ma’lum bo‘lса, katta doira yoyи bilan avtomatik marshrut chizилади: o‘tilган qism xira, qolgani yorqin uzuq chiziq; ikki uchида aeroport kodi (FRA, LHR).

Silliq harakat

Server har 18 s yangilanадi, lekin brauzer reysни track va ground_speed bo‘yicha har kadrда (60 fps) hisoblab siljitади — FR24’dagi kabi uzluksiz. Yangi surat kelganда pozitsiya yumshoq tuzatилади (lerp). Zoom paytида canvas 250 ms yashirилиб, keyin qайта tekislанади.

Izlar

Har reys uchun oxirgi ~40 nuqta brauzerда saqlanadi. HUD’dagi izlar tugmasi hammasини ko‘rsatadi; aks holда faqat tanlangan (ustiga bosilgan) reysning izi chiziladi. Rang — balandlik bo‘yicha.

Aeroport + bayroq

Aeroport — tomchi-pin + boshqaruv minorasi belgisi (oq disk, yumshoq soya); uchi aynan aeroport ustida. Rang/o‘lcham: oltin — yirik xalqaro, moviy — o‘rta, kulrang — kichik (jadvalli). z≥7 dan hamma aeroport ko‘rinadi (~6145 ta: yirik + o‘rta + jadvalli kichik); undan uzoqroqda faqat yirik/o‘rtalari. IATA kod yorlig‘i darajama-daraja ochiladi (yirik z≥7, o‘rta z≥8, hammasi z≥10) yoki kursor ostida. Ustiga bosилганда kartoчka: davlat bayrog‘i, nomi, IATA / ICAO (MAD / LEMD), davlat, turi, koordinata, Google Maps. airports.jsonни python scripts/make_airports.py yangилайди; ICAO qo‘shиш uchun scripts/add_airport_icao.py.

Samolyot surati — uch bosqichli

Popup eng aniq mos suratni tanlaydi. Faqat tur bo‘yicha bitta rasm ko‘rsatish “Aeroflot A330” ni umumiy A330 sifatida ko‘rsatardi; endi operator va davlat variantlari ham bor:

KalitQayerdan olinadiMa’noMisol
<TIP>__<OPERATOR>chaqiruvning 1–3-harfi o‘sha aviakompaniya bo‘yog‘idaB738__RYR
<TIP>__<DAVLAT>registratsiya prefiksi o‘sha davlat belgilaridaC30J__US
<TIP>ICAO tip belgisi umumiy tur suratiA333

Hammasi lokal (/aircraft_photos/<kalit>), bayroqlar kabi bundlangan. Faqat erkin litsenziya (Public Domain, CC0, CC BY, CC BY-SA), har biri ≤ 440 px; muallif + litsenziya popup’da ko‘rsatiladi (/aircraft_photos.json). Mos surat topilmasa popup o‘zgarishsiz.

python scripts/make_aircraft_photos.py                        # tur suratlari
python scripts/make_aircraft_photos.py --variants --from-db   # jurnaldagi eng ko‘p juftliklar
python scripts/make_aircraft_photos.py --variants --from-api --top 150

Variantlar Wikipedia maqolasining bosh rasmidan emas, Wikimedia Commons fayl qidiruvidan olinadi (“Aeroflot Airbus A330-300” uchun maqola yo‘q, lekin fotosuratlar bor). Nomzodlar baholanadi: kabina, salon, dvigatel, dum yaqin planlari rad etiladi; in flight / takeoff / landing kadrlari ustun turadi.

Bort davlati va bayroq

Registratsiya prefiksi ISO davlat kodiga aylantiriladi (registration_prefixes.json) va popup’da bayroq bo‘lib chiqadi: UK-72601 → uz. Har reys /api/flights javobida cc maydonini oladi.

Eng uzun moslik ustun: VP-B… (Bermuda — u yerda ko‘p rus operatorlarining samolyotlari ro‘yxatga olingan) VP dan oldin tekshiriladi, C-F/C-G (Kanada) C dan oldin. Bir harfli belgilar (F, N, D, G…) juda ochko‘z, shuning uchun ular faqat qolgan qism o‘sha davlatning shakliga mos kelganda ishlaydi — F-GKXL → Fransiya, lekin FAB2019 (Braziliya harbiy seriyasi) → aniqlanmadi. Noto‘g‘ri bayroq ko‘rsatgandan ko‘ra hech nima ko‘rsatmagan afzal.

Balandlik → rang

Ranglar ichki hisobda futda: hue = 20 + 320 × (ft / 40000) — 0 to‘q sariq → 3k m yashil → 6k m moviy → 9k m ko‘k → 12k+ m pushti.

O‘lchov birliklari — to‘liq metrik

FR24 feed’i aviatsiya birliklarida keladi (fut, tugun, fut/daqiqa). Ekranda hammasi metrik ko‘rsatiladi:

NimaFeedEkrandaFormula
BalandlikfutmetraltM(ft) = ft × 0.3048
Tezliktugun (kt)km/hspdKmh(kt) = kt × 1.852
Vertikal tezlikfut/daqm/svsMs(fpm) = fpm × 0.00508

Ichki qiymatlar o‘zgarmaydi — API javobi, PostgreSQL ustunlari, rang formulasi va brauzerdagi dead-reckoning hisobi asl birliklarda qoladi. Faqat ekranga chiqadigan matn konvertatsiya qilinadi, shuning uchun API iste’molchilari uchun hech narsa buzilmaydi.

11. Cheklovlar

12. Nima o‘zgardi (v3) — qadamma-qadam

Quyidagilar oxirgi ish bosqichida qo‘shildi / tuzatildi.

  1. PostgreSQL drayveri birlashtirildi. tracking/ quyi tizimi psycopg2 dan webapp.py bilan bir xil psycopg 3 ga ko‘chirildi — bitta drayver, bitta ulanish pooli uslubi.
  2. Chuqur tarix webapp ичига ulandi. FR24_TRACKING=1 + DSN berilса, poller o‘z process’ида har sweepdan keyin tracking/ sxемасига yozadi (alohida thread + navbat — poller kutmaydi) va har FR24_TRACKING_ROLLUP_INTERVAL s da kunlik / haftalik / oylik yig‘malарни hisoblaydi. Ikkinchi FR24 poller ishga tushмайди.
  3. Trayektoriya saqlashда klass filtri. flight_position_log (24 soatlik playback jadvali) endi faqat harbiy, hukumat, yuk, vertolyot klasslаrини saqlaydi. Yo‘lovchi (feed’ning ~90% i) va boshqa (evristik) yozилмайди — bu bazani keskin kичрайтиради. Sozlash: FR24_TRACK_CLASSES (all = hammаси, yoki vergul bilan ro‘yxat). flight_log (reyslar jurnali) baribir har klassни yozади.
  4. “Baza bo‘yicha ko‘rish” (3 bosqich). Qidiruv panelидаги baza bo‘yicha ko‘rish → havolаси: klasslar ro‘yxати → klassni tanlash → o‘sha klassдаги bortlar (rusumi, nuqtalar soni) → bortni tanlash yangi oynада jonli xaritани ochади va o‘sha samolyotning 24 soatlik harakати playback rejimида chizилади.
  5. /api/track?reg= qo‘shилди — bitta bort raqамининг barcha reys leglаrини bitta 24 soatlik izга birlashtiради (ilgари faqat ?id= — bitta leg edi). Javobга flight meta-bloki (callsign, model, klass, operator) qo‘shildi, shuning uchun deep-link jonli reyssiz ham ishlaydi.
  6. Interaktiv API sahifasi. /api-docs/ — bundlланган Swagger UI (CDN’siz) + qo‘lда yozilган /openapi.json (OpenAPI 3.1). Har endpointни “Try it out” bilan sinаб ko‘rish mumkin.
  7. Self-test endi 19 ta tekshiruv — tracking holати va openapi + swagger ui qo‘shildi. /api/meta javobiга tracking bloki kirди.

v3.1 — xarita va ikonkalar

  1. Ikonka rusumga qarab — ~12 siluet (keng fyuzelyaj, layner, regional, biznes-jet, turboprop, yengil, harbiy jet, harbiy transport, vertolyot, planer, dron). Server ICAO tип belgisini tanlаб beради (cat maydoni).
  2. Hover — kursor ustида: siluet oqаради + chaqiruv / model / balandlik yorlig‘i.
  3. Avtomatik marshrut — reys tanlanганда origin↔destination katta doira yoyи (o‘tilган qism xira, qolgani yorqin, uch kodlаri bilan). Yangi endpoint: /api/airports?codes=TAS,IST.
  4. Aeroport markerlari — tomchi-pin + minora belgisi, uchи aynан aeroport ustида; kartochkада IATA / ICAO. airports.json qайта generatsiya qilинди (6145 aeroport, 3 daraja, 5788 tasida ICAO). scripts/add_airport_icao.py qo‘shildi.
  5. “Baza bo‘yicha ko‘rish” endi playback’ни shu oynada ochади (yangi tab emas).
  6. Xarita adapteri — surish/zoom paytida samolyotlar “qotib qolib keyin sakraydigan” xatosi tuzatildi: canvas doim (0,0)’da, har kadr xarita markazidan qayta proyeksiyalanadi.

v3.2 — marshrut chizig‘i, HUD, hujjat

  1. Marshrut chizig‘i endi samolyot ustidan o‘tади (FR24 uslуби): katta doira origin → hozirgi joy → destination orqали qайта quriladi (har kadr, jonli pozitsiyaдан). Uchgan qism to‘liq, qolgani punktir; ikki uchида aeroport kodi. Faqat bosilganда chiqади — hover holати o‘zgармайди.
  2. HUD qайта dizayn — soddaроq, aniqроq bloklar. izlar, API, hujjat tugмалаri olib tashlанди. API va hujjat endi faqat /api-docs/ va /docs/ manzilидан (bu sahifa /hujjat bilan ham ochилади).
  3. 0-bo‘lim “Ishga tushirish” — lokal / Docker / tekshiruv ko‘rsатмалаri shu sahifada.

v3.3 — yagona MapLibre xarita (FR24 ko‘rinishi)

  1. Google va Yandex adapterlari olib tashlandi. Endi bitta xarita: MapLibre GL + flightradar24.com’ga o‘xshash vektor uslub (kalitsiz OpenFreeMap Positron; suv/quruqlik palitrasi FR24 ostiga moslandi).
  2. Surganda samolyotlar qotmaydi. MapLibre o‘z transformini har render kadrida yangilaydi — reyslar map.project() orqali har kadr proyeksiyalanib, plitka bilan 1:1 siljiydi (surish, zoom, inertsiya). Bu FR24’ning o‘z yondashuvi.
  3. Reys kartochkasi samolyot ustida emas — o‘ng pastki burchakka biriktirildi (docked); samolyotni to‘smaydi, ichi uzun bo‘lsa skroll bo‘ladi.
  4. Oflayn yo‘li: FR24_BASEMAP_STYLE ni lokal style.json ga qaratib, .pmtiles faylini bundlaganda xarita internetsiz ishlaydi (Docker .tar uchun).

v3.4 — balandlik metrda, aeroportlar, marshrut nomlari

  1. Balandlik hamma joyda metrda (FR24 metrik uslubi): altM(ft)=ft×0.3048. Ichki qiymatlar (API, DB, rang formulasi) futda qoladi. Legenda: Balandlik (m).
  2. Aeroportlar qayta chizildi — yangi pin (oq disk + minora + soya), IATA kodi pill’da. Yiriklar endi z≥5 dan ko‘rinadi (ilgari z7), o‘rta z≥7, kichik z≥9.
  3. Marshrut nomlari — reysga bosilганда popup’da kod bilan birga aeroport nomi ham chiqadi (TAS Toshkent → IST Istanbul), agar /api/airports?codes= dan topilса.
  4. “Baza bo‘yicha ko‘rish” da filtr — bort raqami / rusum / klass bo‘yicha ro‘yxatni tez suzgich.

v3.5 — FR24 palitra, lotin yozuvi, marshrut zoomda qoladi

  1. Xarita rangi flightradar24.com uslubidafr24Palette() Positron uslubini qayta bo‘yaydi: tiniq ko‘k suv (#a3ccec), oq-issiq quruqlik, jimgina yo‘llar, kulrang chegaralar.
  2. Joy nomlari lotin yozuvida — har bir yorliq coalesce(name:uz, name:latin, name): O‘zbekiston ichida o‘zbekcha, tashqarida lotin transliteratsiya (kirill / arab / ieroglif emas). Eslatma: bepul OpenMapTiles ma’lumotida name:uz maydoni yo‘q — to‘liq o‘zbekcha (chet el shaharlari) uchun alohida lug‘at yoki pullik multitil plitka kerak.
  3. Tanlangan reys va marshrut zoomda yo‘qolmaydi/api/flights?ids= tanlangan reysни reys-cheklovi/bbox’dan qat’i nazar javobga qo‘shadi; marshrut here bo‘lmasa ham origin→dest to‘liq katta doira sifatida chiziladi.

13. Baza bo‘yicha ko‘rish + API test

3 bosqich

1) /api/fleet/classes      → klass · samolyot soni · nuqta soni  (oxirgi 24 soat)
2) /api/fleet/aircraft?class=military
                           → bort · rusum · nuqta soni · leg soni  (≥ 2 nuqta)
3) /?track=reg:<REG>        → jonli xarita: faqat o‘sha samolyot, DB
                             koordinatalari bo‘yicha yo‘nalish; pastdagi
                             shkala bilan vaqtni orqaga surasiz (teskari iz)

Xaritada Qidiruv → baza bo‘yicha ko‘rish → shu oqimни UI orqали beради. Bortni tanlaganда /?track=reg:<REG> yangi tabда ochилади: barcha jonli reyslar yashirилади, faqat tanlangan bort qolади, uning bazага yozилган nuqталаri chizилади. Shkалани surсангиз — o‘sha vaqтга qайтади va iz teskari qisqаради; strelkалаr haqiqiy uchish tarafини ko‘rsатади. “Jonli xaritaga qaytish” tugмаси playback’ни yopади.

/api/track parametrlari

ParamMa’no
idBitta FR24 reys legi id’si (/api/flights dan)
regBort raqami — 24 soатдаги barcha leglar bitta izга

Ikkalasi ham FR24_DATABASE_URL ni talab qiladi; aks holда 503. Faqat FR24_TRACK_CLASSES ga kirган klasslar uchun ma’lumot bo‘lади.

API test sahifasi

/api-docs/ — barcha /api/* endpointлаri Swagger UI’да. Har birини brauzerдан to‘g‘ridan-to‘g‘ri chaqirib, javоbни ko‘rish mumkin (“Try it out”). Spetsifikatsiya: /openapi.json.

14. Testlash tartibi

To‘liq to‘plamni ishga tushirish

pip install -r requirements-dev.txt
pytest                      # hammasi
pytest -q -k gzip           # bitta mavzu
pytest --collect-only -q    # nima qamralganini ko‘rish

Testlar tarmoqqa chiqmaydi va pollerni ishga tushirmaydi: STATE soxta surat bilan almashtiriladi, HTTP server esa tasodifiy portda ko‘tariladi. Shuning uchun ular FR24 holatiga bog‘liq emas.

Baza kerak bo‘lgan testlar

Bir nechta test PostgreSQL talab qiladi va usiz skip bo‘ladi — yiqilmaydi. Yoqish uchun bir martalik bazani ko‘rsating:

docker run -d --name pg -e POSTGRES_PASSWORD=fr24   -e POSTGRES_DB=fr24 -p 5432:5432 postgres:16-alpine

FR24_TEST_DATABASE_URL=postgresql://postgres:fr24@localhost:5432/fr24 TRACKING_TEST_DATABASE_URL=postgresql://postgres:fr24@localhost:5432/fr24 pytest

Diqqat: bu bazaga sxema qo‘llanadi va jadvallar TRUNCATE qilinadi — faqat bir martalik bazani bering.

Qism-tizimlarni qo‘lda tekshirish

NimaQandayKutilgan natija
Poller tirikmicurl -s localhost:8070/api/meta snapshot_age kichik, sweeps o‘smoqda
20 ta ichki tekshiruvcurl -s localhost:8070/api/selftest 200 va ok:true; aks holda 503
Metrikalarcurl -s localhost:8070/metrics Prometheus matni; bazaga so‘rov yubormaydi
Siqishcurl -sH "Accept-Encoding: gzip" -o /dev/null -w "%{size_download}" localhost:8070/api/flights siqilmaganidan ~6–7× kichik
Keshcurl -sI localhost:8070/ dagi ETag bilan If-None-Match ikkinchi so‘rovda 304
Rate limitketma-ket 240 dan ortiq /api/meta chegaradan keyin 429
Xavfsizlik sarlavhalaricurl -sI localhost:8070/ Server: fr24web, CSP, COOP/CORP, Permissions-Policy
Yo‘l bo‘ylab chiqishcurl -s localhost:8070/static/../webapp.py 404 — statik fayllar xotiradagi lug‘atdan beriladi
Replika feed’icurl -si localhost:8070/api/snapshot token yo‘q — 404; noto‘g‘ri token — 401

Yetakchi + replikani sinash

# 1-terminal — yetakchi
FR24_REPLICA_TOKEN=$(python -c "import secrets;print(secrets.token_hex(32))") python webapp.py

# 2-terminal — replika (FR24 ga tegmaydi)
FR24_POLLER=0 FR24_UPSTREAM=http://127.0.0.1:8070 FR24_REPLICA_TOKEN=<o‘sha token> FR24_WEB_PORT=8071 python webapp.py

Ikkalasi bir xil world_flights berishi, replikada esa sweeps 0 bo‘lib qolishi kerak — u FR24 ga umuman bormaydi.

Linter va CI

ruff check webapp.py scripts tests tracking

.github/workflows/ci.yml har push’da: ruff, pytest (PostgreSQL servisi bilan), tracking uchun uchdan-uchgacha CLI sinovi, so‘ng Docker образни qurib konteynerni ko‘taradi va /api/selftest ni talab qiladi.

15. Xavfsizlik (OWASP Top 10 — 2021)

Har bir band tests/ dagi test_a0* nomli test bilan mustahkamlangan.

OWASPNima qilingan
A01 Kirish nazorati/api/snapshot — butun ma’lumot to‘plami — token sozlanmagan bo‘lsa 404, ya’ni mavjudligini ham bildirmaydi. Statik fayllar xotiradagi lug‘atdan beriladi, ya’ni yo‘l bo‘ylab chiqish imkonsiz.
A02 KriptografiyaToken hmac.compare_digest bilan doimiy vaqtda solishtiriladi. DSN loglarda niqoblanadi (://***@); token hech qachon loglanmaydi.
A03 InyeksiyaButun SQL parametrlangan; identifikatorlar psycopg.sql.Identifier orqali. Brauzerda barcha maydonlar htmlesc dan o‘tadi. Mijoz satri logga yozilishdan oldin _log_safe bilan tozalanadi — aks holda so‘rov qatoridagi boshqaruv baytlari soxta log qatori yasashi yoki terminal escape yuborishi mumkin edi.
A04 Xavfsiz bo‘lmagan dizaynIP bo‘yicha token-bucket, bir vaqtdagi so‘rovlar chegarasi va undan oshsa yukni tashlash, javob hajmi chegarasi.
A05 Noto‘g‘ri sozlashServer sarlavhasi Python versiyasini oshkor qilmaydi. CSP, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy, Cross-Origin-Opener-Policy, Cross-Origin-Resource-Policy. HSTS — FR24_HSTS_MAX_AGE bilan ixtiyoriy.
A06 Eskirgan komponentlarBog‘liqliklar beshta; fr24/ vendorlangan (yangilash: fr24/UPDATING.md). Ochiq kamchilik: vendorlangan nusxa uchun avtomatik CVE kuzatuvi yo‘q.
A07 AutentifikatsiyaYagona sir — replika tokeni; 24 belgidan qisqa bo‘lsa process ishga tushmaydi. Qolgan hamma narsa ataylab ochiq (bu ommaviy xarita).
A08 Ta’minot zanjiriUchinchi tomon skripti/uslubi umuman yuklanmaydi: MapLibre, Leaflet, Swagger UI — hammasi static/ da. Ilgari ikkala xarita ham topilmasa unpkg.com dan SRI’siz skript yuklanardi; endi bu holda servis aniq xato bilan to‘xtaydi.
A09 Jurnal va monitoring/metrics — poller, HTTP, DB va tracking sanoqlari. Rad etilgan replika urinishi WARNING bilan yoziladi va sanaladi. Poller xato darajasi oynali hisoblanadi, umr bo‘yi emas.
A10 SSRFYagona chiquvchi manzil — FR24_UPSTREAM (operator sozlamasi). Sxema http(s) ekani tekshiriladi, qayta yo‘naltirish rad etiladi — aks holda buzilgan yetakchi tokenni ichki manzilga yo‘naltirishi mumkin — va javob hajmi cheklangan.

Eslatma: servis TLS’ni o‘zi tugatmaydi. Ochiq internetda oldiga reverse-proxy qo‘ying va FR24_TRUSTED_PROXY=1 bering, aks holda rate limiter hamma foydalanuvchini bitta IP deb sanaydi.

16. Funksiyalar ma’lumotnomasi

Jami 188 ta funksiya/klass; 0 tasining nomi tests/ da uchraydi (0%). Bu jadval kodning o‘zidan (ast bilan) har ishga tushganda qayta quriladi — qo‘lda yozilgan ro‘yxat ertasiga eskirardi.

webapp.py · 111 ta

Butun servis: poller, surat, API, HTTP qatlami

qatornomitestvazifasi
87_env_float·
94_env_int·
101_env_bool·
108_env_str·Read a string setting; an empty / whitespace value means "unset".
311_load_json·
333airport_full·'BRU' -> 'Brussels Airport, Belgium' ('???' -> '???').
411_bucket_cls·Fold a flight's stored class into one of the six CLASS_LABELS buckets.
420_class_set·Parse a `FR24_*_CLASSES` value ("all" | "*" | comma list) into a set.
434_track_class_ok·True if this flight's class is one we keep a position history for.
439_tracking_class_ok·True if this flight belongs in the deep-history store.
444_norm_reg·
467reg_country·'UK72601' -> 'uz'. Empty string when the mark is unknown.
486_prefix_lookup·Longest-prefix match of a callsign against a {prefix: label} table.
500classify·-> (class, operator, type_name). class in CLASS_LABELS.
543_airline_name·
625airports_in·Airports inside the viewport, large ones first, capped.
714shape_category·Map an ICAO type designator (+ FR24 icon + class) to a silhouette bucket.
827Snapshot·
862_current_slices·
869_slice_plan·
878_ingest·
919_publish_flights·Index a flight list and publish it as the snapshot readers see.
935_publish·
944_fetch_box·
963_poller_main·
1004_start_poller·
1029_NoRedirect·Refuse redirects when following the leader.
1038_NoRedirect.redirect_request·
1046_fetch_upstream_snapshot·Pull the leader's whole world. Returns the flight list.
1065_replica_once·One pull from the leader, published locally. Raises if the pull fails.
1078_replica_main·
1096_start_replica·
1167_PgPool·Tiny thread-safe connection pool for the read paths (/log/, /api/meta).
1181_PgPool._connect·
1186_PgPool.connection·
1220_PgPool.close·
1234_pool·
1294_flight_row·
1322_position_row·One timestamped observation for the 24-hour playback timeline.
1337_DbBatch·One sweep, fully materialised by the poller thread before it is queued.
1344_moving·Skip parked aircraft: on the ground and not taxiing is not an observation.
1349_db_enqueue·Build a sweep's rows *in the poller thread* and hand them to the writer.
1374_position_retention_hours·Hours of `flight_position_log` to keep. 0 = keep forever.
1381_db_prune·Drop rows past their retention window; runs at most hourly.
1419_db_writer·
1484_start_db·
1496db_query_log·Read recent rows from flight_log (returns [] if DB unavailable).
1545_db_totals·`flight_log` aggregates, memoised — they are full sequential scans.
1577_set_db_totals·
1582db_summary·Writer counters (always live) plus the cached table aggregates.
1600_track_rows·
1606db_flight_track·Timestamped observations for one FR24 flight leg, latest 24 hours.
1625db_track_by_reg·Every logged position for one airframe (all its legs), latest 24 hours.
1645db_flight_meta·Identity fields for a leg (by id) or an airframe (by registration).
1675db_fleet_classes·Per-class rollup over the airframes that have a logged position history.
1703db_fleet_aircraft·Airframes in one class that have >= 2 logged positions in the last 24 h.
1765_tracking_enqueue·Queue one sweep for the deep-history writer (poller thread only).
1779_tracking_writer·
1853_start_tracking·
1865tracking_summary·In-memory status of the deep-history writer (no DB round trip).
1881_lon_ranges·
1887_subsample·Even-ish spatial thinning so a wide view keeps its shape.
1896query_flights·Return (flights, matched_total, world_total). Optional class filter.
1949search_flights·Free-text search over the world snapshot.
1999rate_ok·Token bucket, one bucket per client address.
3537_build_hud·
4238_render·Single-pass %TOKEN% substitution.
4254_js_literal·Make already-serialised JSON safe to paste inside an inline <script>.
4264_js·`value` as a JS literal for an inline <script>.
4269build_index·
4336_check·
4346run_selftest·
4621_collect_functions·(line, qualified name, first docstring line) for one module.
4648_tested_names·Every bare identifier that appears anywhere under tests/.
4662_favicon_credit_html·Attribution for the site icon.
4688_build_reference·Render the whole-project function reference as HTML.
5638_build_openapi·
5969_count·
5979_etag·Strong ETag for a body that never changes while the process lives.
6003_gzippable·
6010_log_safe·Make a client-supplied string safe to write into the log.
6020_gz·
6056_metric·One metric in the Prometheus text exposition format.
6063render_metrics·Prometheus scrape of the counters this process already keeps.
6179Handler·
6189Handler.version_string·
6196Handler.log_message·
6203Handler._client_ip·The address the rate limiter buckets on.
6235Handler._accepts_gzip·Whether the client asked for gzip, honouring an explicit `q=0` veto.
6254Handler._send·Write one response.
6317Handler._json·
6321Handler.do_HEAD·
6324Handler.do_GET·
6339Handler._route·
6463Handler._serve_static·
6479Handler._serve_flag·
6492Handler._serve_photo·
6504Handler._meta·
6530Handler._api_log·
6549Handler._api_search·
6576Handler._api_track·24-hour coordinate history: ?id=<fr24 leg id> or ?reg=<registration>.
6607Handler._api_fleet_classes·Class rollup for airframes with a logged 24-hour position history.
6616Handler._api_fleet_aircraft·Airframes in one class that have >= 2 logged positions (last 24 h).
6636Handler._api_airports·
6659Handler._api_snapshot·The entire world, uncapped — what a replica follows.
6687Handler._api_flights·
6725parse_bbox·
6741Server·
6746Server.handle_error·A client dropping a connection is not a server error.
6763drain_writers·Give the DB and tracking writers a moment to flush before we exit.
6783main·

tracking/config.py · 3 ta

Chuqur tarix: sozlama

qatornomitestvazifasi
9_env_int·
17TrackingConfig·Everything the tracking package needs to talk to PostgreSQL.
44TrackingConfig.from_env·Build a config from ``TRACKING_*`` env vars.

tracking/db.py · 20 ta

Chuqur tarix: ulanish hovuzi va so'rov yordamchilari

qatornomitestvazifasi
39_Pool·Tiny thread-safe LIFO connection pool.
55_Pool._connect·
62_Pool.lease·
101_Pool.closeall·
111_batched·
117_split_values_query·Split a ``... VALUES %s ...`` template around its single placeholder.
125_values_clause·
130Database·Connection pool + query helpers for the tracking store.
144Database.close·Close every pooled connection.
149Database.connection·Lease a connection; commit on success, roll back on error.
161Database.autocommit·Yield a connection in autocommit mode (VACUUM, CREATE DATABASE …).
171Database._retry·Run ``fn`` with exponential-backoff retries on transient failures.
188Database.execute·Run a statement; return the affected row count.
197Database.query·Run a SELECT (or ``SELECT some_function(...)``); return rows as dicts.
212Database.query_one·Run a SELECT; return the first row as a dict, or ``None``.
219Database.scalar·Run a SELECT (or function call); return column one of row one.
235Database.insert_returning·Batched ``INSERT ... VALUES %s ... RETURNING`` in pages.
261Database.copy_values·Batched ``INSERT ... VALUES %s ...`` (no RETURNING). Returns rows written.
286Database.execute_batch·Batched write via ``cursor.executemany`` (no RETURNING).
307Database.run_script·Execute a whole ``.sql`` file in one transaction.

tracking/models.py · 10 ta

Chuqur tarix: yozuv tiplari va validatsiya

qatornomitestvazifasi
25derive_aircraft_type·Fold the webapp class + type code into the schema's aircraft_type enum.
45_clean·
49_int_or_none·
59AircraftRecord·One airframe. Identified by registration when present, else icao_hex.
73AircraftRecord.natural_key·('reg', 'UK12345') or ('hex', '424242') — the ON CONFLICT arbiter.
82FlightRecord·One FlightRadar24 flight leg.
102PositionRecord·One trajectory sample.
117ValidationError·A snapshot row that cannot be turned into records.
121_valid_latlon·
133parse_snapshot_flight·Turn one webapp flight dict into (aircraft, flight, position) records.

tracking/ingest.py · 10 ta

Chuqur tarix: suratni bazaga yozish

qatornomitestvazifasi
36IngestStats·What :func:`ingest_snapshot` did.
47IngestStats.as_dict·
132_seen_at·
140ensure_partitions_for·Create the monthly ``flight_positions`` partitions covering ``moments``.
153ingest_snapshot·Persist one FR24 world snapshot. Returns an :class:`IngestStats`.
193_upsert_aircraft·
214_upsert_flights·
242_position_rows·
258_insert_positions·
276_enqueue_summaries·

tracking/aggregate.py · 8 ta

Chuqur tarix: kunlik/haftalik/oylik yig'malar

qatornomitestvazifasi
21_ids_param·
25refresh_daily·Recompute ``daily_flight_summary`` for ``day``. Returns rows written.
32refresh_weekly·Recompute ``weekly_flight_summary`` for the week containing ``week_start``.
39refresh_monthly·Recompute ``monthly_flight_summary`` for ``year_month`` ('YYYY-MM').
46process_summary_queue·Drain the dirty queue written by the ``flight_positions`` trigger.
58run_rollups·Full rollup pass — safe to run hourly or nightly from cron.
89daily_summary_frame·Return ``daily_flight_summary`` rows in ``[start, end]`` as a DataFrame.
106fleet_activity_frame·One row per airframe active on ``day`` — handy for notebooks/plots.

tracking/maintenance.py · 7 ta

Chuqur tarix: partisiya, arxiv, VACUUM

qatornomitestvazifasi
29_month_floor·
33_add_months·
38ensure_partitions·Create every monthly ``flight_positions`` partition in the working window.
58archive_old·Detach position partitions (and copy flight legs) older than the window.
74drop_archived_before·Permanently drop archived partitions whose range ends before ``cutoff``.
94vacuum_analyze·``VACUUM (ANALYZE)`` the core tables plus every live position partition.
115full_maintenance·Everything a nightly cron should do: partitions, archive, queue, vacuum.

tracking/queries.py · 6 ta

Chuqur tarix: tayyor tahliliy so'rovlar

qatornomitestvazifasi
17resolve_aircraft_id·Look up an aircraft_id from an id, a registration, or an icao_hex.
34aircraft_track_last_24h·Every trajectory point for one airframe in the last 24 hours, oldest first.
55aircraft_stats_last_7d·Rolled-up 7-day activity for one airframe (from ``daily_flight_summary``).
82aircraft_stats_last_30d·Rolled-up 30-day activity for one airframe.
109military_activity_today·Every military airframe with a flight leg today, busiest first.
134top_busiest_aircraft·Top N airframes by flight count over the last ``days`` days.

tracking/reference.py · 1 ta

Chuqur tarix: aeroport ma'lumotnomasi

qatornomitestvazifasi
32load_airports·Load / refresh ``airports_ref``. Returns the number of rows upserted.

tracking/cli.py · 12 ta

Chuqur tarix: buyruq qatori

qatornomitestvazifasi
35_json_default·
41_print·
47cmd_init·
55cmd_load_airports·
63cmd_ingest·
111cmd_rollup·
116cmd_partitions·
122cmd_archive·
127cmd_maintain·
132cmd_query·
162build_parser·
210main·

17. Belgi va manbalar

Sayt belgisi — Airbus A330 suratining qirqimi (A333 turi). Muallif: 4300streetcar, litsenziya: CC BY 4.0.

To‘liq ro‘yxat: README.md §14, har fayl bo‘yicha aircraft_photos/credits.json, litsenziyalar aircraft_photos/LICENSE va flags/LICENSE da.