@@ -5,6 +5,7 @@ const Flight = require("./entities/flight");
55const FlightTrackerConfig = require ( "./flightTrackerConfig" ) ;
66const { AirportNotFoundError, LoginError} = require ( "./errors" ) ;
77const { isNumeric} = require ( "./util" ) ;
8+ const { JSDOM } = require ( "jsdom" ) ;
89
910
1011/**
@@ -22,13 +23,90 @@ class FlightRadar24API {
2223 /**
2324 * Return a list with all airlines.
2425 *
25- * @return {object }
26+ * @return {Array< object> }
2627 */
2728 async getAirlines ( ) {
28- const response = new APIRequest ( Core . airlinesDataUrl , null , Core . jsonHeaders ) ;
29+ const response = new APIRequest ( Core . airlinesDataUrl , null , Core . htmlHeaders ) ;
2930 await response . receive ( ) ;
3031
31- return ( await response . getContent ( ) ) [ "rows" ] ;
32+ const htmlContent = await response . getContent ( ) ;
33+ const airlinesData = [ ] ;
34+
35+ // Parse HTML content.
36+ const dom = new JSDOM ( htmlContent ) ;
37+ const document = dom . window . document ;
38+
39+ const tbody = document . querySelector ( "tbody" ) ;
40+
41+ if ( ! tbody ) {
42+ return [ ] ;
43+ }
44+
45+ // Extract data from HTML content.
46+ const trElements = tbody . querySelectorAll ( "tr" ) ;
47+
48+ for ( const tr of trElements ) {
49+ const tdNotranslate = tr . querySelector ( "td.notranslate" ) ;
50+
51+ if ( tdNotranslate ) {
52+ const aElement = tdNotranslate . querySelector ( "a[href^='/data/airlines']" ) ;
53+
54+ if ( aElement ) {
55+ const tdElements = tr . querySelectorAll ( "td" ) ;
56+
57+ // Extract airline name.
58+ const airlineName = aElement . textContent . trim ( ) ;
59+
60+ if ( airlineName . length < 2 ) {
61+ continue ;
62+ }
63+
64+ // Extract IATA / ICAO codes.
65+ let iata = null ;
66+ let icao = null ;
67+
68+ if ( tdElements . length >= 4 ) {
69+ const codesText = tdElements [ 3 ] . textContent . trim ( ) ;
70+
71+ if ( codesText . includes ( " / " ) ) {
72+ const parts = codesText . split ( " / " ) ;
73+
74+ if ( parts . length === 2 ) {
75+ iata = parts [ 0 ] . trim ( ) ;
76+ icao = parts [ 1 ] . trim ( ) ;
77+ }
78+ } else if ( codesText . length === 2 ) {
79+ iata = codesText ;
80+ } else if ( codesText . length === 3 ) {
81+ icao = codesText ;
82+ }
83+ }
84+
85+ // Extract number of aircrafts.
86+ let nAircrafts = null ;
87+
88+ if ( tdElements . length >= 5 ) {
89+ const aircraftsText = tdElements [ 4 ] . textContent . trim ( ) ;
90+
91+ if ( aircraftsText ) {
92+ nAircrafts = aircraftsText . split ( " " ) [ 0 ] . trim ( ) ;
93+ nAircrafts = parseInt ( nAircrafts ) ;
94+ }
95+ }
96+
97+ const airlineData = {
98+ "Name" : airlineName ,
99+ "ICAO" : icao ,
100+ "IATA" : iata ,
101+ "n_aircrafts" : nAircrafts
102+ } ;
103+
104+ airlinesData . push ( airlineData ) ;
105+ }
106+ }
107+ }
108+
109+ return airlinesData ;
32110 }
33111
34112 /**
@@ -171,21 +249,112 @@ class FlightRadar24API {
171249 }
172250
173251 /**
174- * Return a list with all airports.
252+ * Return a list with all airports for specified countries .
175253 *
254+ * @param {Array<string> } countries - Array of country names from Countries enum
176255 * @return {Array<Airport> }
177256 */
178- async getAirports ( ) {
179- const response = new APIRequest ( Core . airportsDataUrl , null , Core . jsonHeaders ) ;
180- await response . receive ( ) ;
181-
182- const content = await response . getContent ( ) ;
257+ async getAirports ( countries ) {
183258 const airports = [ ] ;
184259
185- for ( const airportData of content [ "rows" ] ) {
186- const airport = new Airport ( airportData ) ;
187- airports . push ( airport ) ;
260+ for ( const countryName of countries ) {
261+ const countryHref = Core . airportsDataUrl + "/" + countryName ;
262+
263+ const response = new APIRequest ( countryHref , null , Core . htmlHeaders ) ;
264+ await response . receive ( ) ;
265+
266+ const htmlContent = await response . getContent ( ) ;
267+
268+ // Parse HTML content.
269+ const dom = new JSDOM ( htmlContent ) ;
270+ const document = dom . window . document ;
271+
272+ const tbody = document . querySelector ( "tbody" ) ;
273+
274+ if ( ! tbody ) {
275+ continue ;
276+ }
277+
278+ // Extract country name from the URL
279+ const countryDisplayName = countryHref . split ( "/" ) . pop ( ) . replace ( / - / g, " " )
280+ . split ( " " ) . map ( word => word . charAt ( 0 ) . toUpperCase ( ) + word . slice ( 1 ) ) . join ( " " ) ;
281+
282+ const trElements = tbody . querySelectorAll ( "tr" ) ;
283+
284+ for ( const tr of trElements ) {
285+ const aElements = tr . querySelectorAll ( "a[data-iata][data-lat][data-lon]" ) ;
286+
287+ if ( aElements . length > 0 ) {
288+ const aElement = aElements [ 0 ] ;
289+
290+ let icao = "" ;
291+ let iata = aElement . getAttribute ( "data-iata" ) || "" ;
292+ const latitude = aElement . getAttribute ( "data-lat" ) || "" ;
293+ const longitude = aElement . getAttribute ( "data-lon" ) || "" ;
294+
295+ const airportText = aElement . textContent . trim ( ) ;
296+ let namePart = airportText ;
297+
298+ // Get IATA / ICAO from airport text.
299+ const smallElement = aElement . querySelector ( "small" ) ;
300+
301+ if ( smallElement ) {
302+ let codesText = smallElement . textContent . trim ( ) ;
303+ codesText = codesText . replace ( / ^ \( / , "" ) . replace ( / \) $ / , "" ) . trim ( ) ;
304+
305+ // Remove IATA / ICAO from name part.
306+ namePart = namePart . replace ( smallElement . textContent , "" ) . replace ( / \( \) / , "" ) . trim ( ) ;
307+
308+ // Parse codes (can be "IATA/ICAO", "IATA", or "ICAO")
309+ if ( codesText . includes ( "/" ) ) {
310+ const codes = codesText . split ( "/" ) ;
311+ const code1 = codes [ 0 ] . trim ( ) ;
312+ const code2 = codes [ 1 ] . trim ( ) ;
313+
314+ // Use length to determine IATA vs ICAO
315+ if ( code1 . length === 3 && code2 . length === 4 ) {
316+ iata = code1 ;
317+ icao = code2 ;
318+ } else if ( code1 . length === 4 && code2 . length === 3 ) {
319+ iata = code2 ;
320+ icao = code1 ;
321+ }
322+ } else if ( codesText . length === 3 ) {
323+ iata = codesText ;
324+ } else if ( codesText . length === 4 ) {
325+ icao = codesText ;
326+ }
327+ }
328+
329+ // Convert latitude and longitude to float
330+ let latFloat = 0.0 ;
331+ let lonFloat = 0.0 ;
332+
333+ try {
334+ latFloat = latitude ? parseFloat ( latitude ) : 0.0 ;
335+ lonFloat = longitude ? parseFloat ( longitude ) : 0.0 ;
336+ } catch ( error ) {
337+ latFloat = 0.0 ;
338+ lonFloat = 0.0 ;
339+ }
340+
341+ // Create Airport instance with basic_info format
342+ const airportData = {
343+ "name" : namePart ,
344+ "icao" : icao ,
345+ "iata" : iata ,
346+ "lat" : latFloat ,
347+ "lon" : lonFloat ,
348+ "alt" : null , // Altitude not available in this format
349+ "country" : countryDisplayName
350+ } ;
351+
352+ const airport = new Airport ( airportData ) ;
353+ airports . push ( airport ) ;
354+ }
355+ }
188356 }
357+
189358 return airports ;
190359 }
191360
0 commit comments