FlightRadarAPI 1.4.2__tar.gz → 1.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. flightradarapi-1.5.0/.gitignore +31 -0
  2. flightradarapi-1.5.0/FlightRadar24/__init__.py +36 -0
  3. flightradarapi-1.5.0/FlightRadar24/api.py +522 -0
  4. {flightradarapi-1.4.2 → flightradarapi-1.5.0}/FlightRadar24/core.py +17 -8
  5. flightradarapi-1.5.0/FlightRadar24/entities/airport.py +193 -0
  6. flightradarapi-1.5.0/FlightRadar24/entities/entity.py +45 -0
  7. flightradarapi-1.5.0/FlightRadar24/entities/flight.py +240 -0
  8. flightradarapi-1.5.0/FlightRadar24/errors.py +20 -0
  9. flightradarapi-1.5.0/FlightRadar24/flight_tracker_config.py +23 -0
  10. flightradarapi-1.5.0/FlightRadar24/parsers.py +143 -0
  11. flightradarapi-1.5.0/FlightRadar24/py.typed +0 -0
  12. flightradarapi-1.5.0/FlightRadar24/request.py +271 -0
  13. {flightradarapi-1.4.2 → flightradarapi-1.5.0}/Makefile +5 -5
  14. {flightradarapi-1.4.2 → flightradarapi-1.5.0}/PKG-INFO +3 -2
  15. {flightradarapi-1.4.2 → flightradarapi-1.5.0}/pyproject.toml +21 -3
  16. flightradarapi-1.4.2/.flake8 +0 -11
  17. flightradarapi-1.4.2/.gitignore +0 -9
  18. flightradarapi-1.4.2/FlightRadar24/__init__.py +0 -18
  19. flightradarapi-1.4.2/FlightRadar24/api.py +0 -639
  20. flightradarapi-1.4.2/FlightRadar24/entities/airport.py +0 -178
  21. flightradarapi-1.4.2/FlightRadar24/entities/entity.py +0 -31
  22. flightradarapi-1.4.2/FlightRadar24/entities/flight.py +0 -208
  23. flightradarapi-1.4.2/FlightRadar24/errors.py +0 -17
  24. flightradarapi-1.4.2/FlightRadar24/request.py +0 -114
  25. flightradarapi-1.4.2/pytest.ini +0 -15
  26. flightradarapi-1.4.2/requirements.txt +0 -4
  27. flightradarapi-1.4.2/tests/conftest.py +0 -5
  28. flightradarapi-1.4.2/tests/package.py +0 -5
  29. flightradarapi-1.4.2/tests/test_api.py +0 -143
  30. flightradarapi-1.4.2/tests/util.py +0 -41
  31. {flightradarapi-1.4.2 → flightradarapi-1.5.0}/.tool-versions +0 -0
  32. {flightradarapi-1.4.2 → flightradarapi-1.5.0}/FlightRadar24/entities/__init__.py +0 -0
  33. {flightradarapi-1.4.2 → flightradarapi-1.5.0}/FlightRadar24/zones.py +0 -0
  34. {flightradarapi-1.4.2 → flightradarapi-1.5.0}/LICENSE +0 -0
  35. {flightradarapi-1.4.2 → flightradarapi-1.5.0}/README.md +0 -0
@@ -0,0 +1,31 @@
1
+ # Python
2
+ __pycache__
3
+ *.pyc
4
+ *.pyo
5
+ *.pyd
6
+ *.so
7
+ dist/
8
+ build/
9
+ *.egg-info/
10
+ .eggs/
11
+ .venv/
12
+ venv/
13
+ .mypy_cache/
14
+ .pytest_cache/
15
+ htmlcov/
16
+ .coverage
17
+ coverage.xml
18
+
19
+ # Node.js
20
+ node_modules/
21
+
22
+ # Editors / OS
23
+ .idea/
24
+ .vscode/
25
+ .DS_Store
26
+ Thumbs.db
27
+
28
+ # Misc
29
+ .env
30
+ .cache
31
+ *.log
@@ -0,0 +1,36 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ Unofficial SDK for FlightRadar24.
5
+
6
+ This SDK provides flight and airport data available to the public
7
+ on the FlightRadar24 website.
8
+
9
+ See more information at:
10
+ https://www.flightradar24.com/premium/
11
+ https://www.flightradar24.com/terms-and-conditions
12
+ """
13
+
14
+ __author__ = "Jean Loui Bernard Silva de Jesus"
15
+ __version__ = "1.5.0"
16
+
17
+ from .api import FlightRadar24API
18
+ from .core import Countries
19
+ from .entities import Airport, Entity, Flight
20
+ from .errors import AirportNotFoundError, CloudflareError, FlightRadarError, LoginError
21
+ from .flight_tracker_config import FlightTrackerConfig
22
+ from .request import RetryPolicy
23
+
24
+ __all__ = [
25
+ "FlightRadar24API",
26
+ "Countries",
27
+ "Airport",
28
+ "Entity",
29
+ "Flight",
30
+ "AirportNotFoundError",
31
+ "CloudflareError",
32
+ "FlightRadarError",
33
+ "LoginError",
34
+ "FlightTrackerConfig",
35
+ "RetryPolicy",
36
+ ]
@@ -0,0 +1,522 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import dataclasses
4
+ import math
5
+ from concurrent.futures import ThreadPoolExecutor, as_completed
6
+ from typing import Any, Dict, List, Optional, Tuple, Union
7
+ from urllib.parse import quote
8
+
9
+ from .core import Core, Countries
10
+ from .entities.airport import Airport
11
+ from .entities.flight import Flight
12
+ from .errors import AirportNotFoundError, LoginError
13
+ from .flight_tracker_config import FlightTrackerConfig
14
+ from .parsers import parse_airlines_html, parse_airports_html
15
+ from .request import APIClient, RetryPolicy
16
+
17
+
18
+ class FlightRadar24API:
19
+ """
20
+ Main class of the FlightRadarAPI
21
+ """
22
+
23
+ def __init__(
24
+ self,
25
+ user: Optional[str] = None,
26
+ password: Optional[str] = None,
27
+ timeout: int = 30,
28
+ max_workers: int = 8,
29
+ impersonate: Optional[str] = None,
30
+ retry: Optional[RetryPolicy] = None,
31
+ ):
32
+ """
33
+ Constructor of the FlightRadar24API class.
34
+
35
+ :param user: Your email
36
+ :param password: Your password
37
+ :param timeout: Request timeout in seconds
38
+ :param max_workers: Maximum threads used when fetching flight details concurrently
39
+ :param impersonate: TLS impersonation profile (curl_cffi). Override when FR24
40
+ updates its Cloudflare bot mitigation faster than this library releases.
41
+ See ``FlightRadar24.request.DEFAULT_IMPERSONATE`` for the current default.
42
+ :param retry: Optional :class:`RetryPolicy` applied to transient failures
43
+ (``CloudflareError`` and curl_cffi network errors). Defaults to no retry.
44
+ """
45
+ self.__flight_tracker_config = FlightTrackerConfig()
46
+ self.__login_data: Optional[Dict] = None
47
+ client_kwargs: Dict[str, Any] = {"retry": retry}
48
+ if impersonate:
49
+ client_kwargs["impersonate"] = impersonate
50
+ self.__client = APIClient(**client_kwargs)
51
+
52
+ self.timeout: int = timeout
53
+ self.max_workers: int = max_workers
54
+
55
+ if user is not None and password is not None:
56
+ self.login(user, password)
57
+
58
+ def get_airlines(self) -> List[Dict]:
59
+ """
60
+ Return a list with all airlines.
61
+ """
62
+ response = self.__client.request(Core.airlines_data_url, headers=Core.html_headers, timeout=self.timeout)
63
+ return parse_airlines_html(response.get_bytes_content())
64
+
65
+ def get_airline_logo(self, iata: str, icao: str) -> Optional[Tuple[bytes, str]]:
66
+ """
67
+ Download the logo of an airline from FlightRadar24 and return it as bytes.
68
+ """
69
+ iata, icao = iata.upper(), icao.upper()
70
+
71
+ first_logo_url = Core.airline_logo_url.format(iata, icao)
72
+
73
+ # Try to get the image by the first URL option.
74
+ response = self.__client.request(
75
+ first_logo_url, headers=Core.image_headers,
76
+ allowed_error_codes=[403, 404], timeout=self.timeout,
77
+ )
78
+ status_code = response.get_status_code()
79
+
80
+ if not (400 <= status_code < 500):
81
+ return response.get_bytes_content(), first_logo_url.split(".")[-1]
82
+
83
+ # Get the image by the second airline logo URL.
84
+ second_logo_url = Core.alternative_airline_logo_url.format(icao)
85
+
86
+ response = self.__client.request(
87
+ second_logo_url, headers=Core.image_headers,
88
+ allowed_error_codes=[403, 404], timeout=self.timeout,
89
+ )
90
+ status_code = response.get_status_code()
91
+
92
+ if not (400 <= status_code < 500):
93
+ return response.get_bytes_content(), second_logo_url.split(".")[-1]
94
+
95
+ return None
96
+
97
+ def get_airport(self, code: str, *, details: bool = False) -> Airport:
98
+ """
99
+ Return basic information about a specific airport.
100
+
101
+ :param code: ICAO or IATA of the airport
102
+ :param details: If True, it returns an Airport instance with detailed information.
103
+ """
104
+ if not (3 <= len(code) <= 4):
105
+ raise ValueError(f"The code '{code}' is invalid. It must be the IATA or ICAO of the airport.")
106
+
107
+ if details:
108
+ airport = Airport()
109
+ airport.set_airport_details(self.get_airport_details(code))
110
+ return airport
111
+
112
+ response = self.__client.request(
113
+ Core.airport_data_url.format(code),
114
+ headers=Core.json_headers, timeout=self.timeout,
115
+ )
116
+ content = response.get_json_content()
117
+
118
+ if not content or not content.get("details"):
119
+ raise AirportNotFoundError(f"Could not find an airport by the code '{code}'.")
120
+
121
+ return Airport(info=content["details"])
122
+
123
+ def get_airport_details(self, code: str, flight_limit: int = 100, page: int = 1) -> Dict:
124
+ """
125
+ Return the airport details from FlightRadar24.
126
+
127
+ :param code: ICAO or IATA of the airport
128
+ :param flight_limit: Limit of flights related to the airport
129
+ :param page: Page of result to display
130
+ """
131
+ if not (3 <= len(code) <= 4):
132
+ raise ValueError(f"The code '{code}' is invalid. It must be the IATA or ICAO of the airport.")
133
+
134
+ request_params: Dict[str, Any] = {"format": "json"}
135
+
136
+ if self.is_logged_in():
137
+ request_params["token"] = self.__client.get_cookie("_frPl")
138
+
139
+ # Insert the method parameters into the dictionary for the request.
140
+ request_params["code"] = code
141
+ request_params["limit"] = flight_limit
142
+ request_params["page"] = page
143
+
144
+ # Request details from the FlightRadar24.
145
+ response = self.__client.request(
146
+ Core.api_airport_data_url,
147
+ params=request_params,
148
+ headers=Core.json_headers,
149
+ allowed_error_codes=[400],
150
+ timeout=self.timeout,
151
+ )
152
+ content = response.get_json_content()
153
+
154
+ if response.get_status_code() == 400 and content.get("errors"):
155
+ errors = content["errors"]["errors"]["parameters"]
156
+
157
+ if errors.get("limit"):
158
+ raise ValueError(errors["limit"]["notBetween"])
159
+
160
+ raise AirportNotFoundError(f"Could not find an airport by the code '{code}'.", errors)
161
+
162
+ result = content["result"]["response"]
163
+
164
+ # Check whether it received data of an airport.
165
+ data = result.get("airport", dict()).get("pluginData", dict())
166
+
167
+ if "details" not in data and len(data.get("runways", [])) == 0 and len(data) <= 3:
168
+ raise AirportNotFoundError(f"Could not find an airport by the code '{code}'.")
169
+
170
+ # Return the airport details.
171
+ return result
172
+
173
+ def get_airport_disruptions(self) -> Dict:
174
+ """
175
+ Return airport disruptions.
176
+ """
177
+ response = self.__client.request(
178
+ Core.airport_disruptions_url,
179
+ headers=Core.json_headers, timeout=self.timeout,
180
+ )
181
+ return response.get_json_content()
182
+
183
+ def get_airports(self, countries: List[Countries]) -> List[Airport]:
184
+ """
185
+ Return a list with all airports for specified countries.
186
+
187
+ :param countries: List of country names from Countries enum.
188
+ """
189
+ def _fetch(country):
190
+ href = Core.airports_data_url + "/" + country.value
191
+ response = self.__client.request_standalone(href, headers=Core.html_headers, timeout=self.timeout)
192
+ return parse_airports_html(response.get_bytes_content(), href)
193
+
194
+ with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
195
+ results = executor.map(_fetch, countries)
196
+
197
+ return [airport for result in results for airport in result]
198
+
199
+ def get_bookmarks(self) -> Dict:
200
+ """
201
+ Get the bookmarks from the FlightRadar24 account.
202
+ """
203
+ if self.__login_data is None:
204
+ raise LoginError("You must log in to your account.")
205
+
206
+ headers = {**Core.json_headers, "accesstoken": self.get_login_data()["accessToken"]}
207
+
208
+ response = self.__client.request(Core.bookmarks_url, headers=headers, timeout=self.timeout)
209
+ return response.get_json_content()
210
+
211
+ def get_bounds(self, zone: Dict[str, float]) -> str:
212
+ """
213
+ Convert coordinate dictionary to a string "y1, y2, x1, x2".
214
+
215
+ :param zone: Dictionary containing the following keys: tl_y, tl_x, br_y, br_x
216
+ """
217
+ return f"{zone['tl_y']},{zone['br_y']},{zone['tl_x']},{zone['br_x']}"
218
+
219
+ def get_bounds_by_point(self, latitude: float, longitude: float, radius: float) -> str:
220
+ """
221
+ Convert a point coordinate and a radius to a string "y1, y2, x1, x2".
222
+
223
+ :param latitude: Latitude of the point
224
+ :param longitude: Longitude of the point
225
+ :param radius: Radius in meters to create area around the point
226
+ """
227
+ half_side_in_km = abs(radius) / 1000
228
+
229
+ lat = math.radians(latitude)
230
+ lon = math.radians(longitude)
231
+
232
+ approx_earth_radius = 6371
233
+ hypotenuse_distance = math.sqrt(2 * (math.pow(half_side_in_km, 2)))
234
+
235
+ lat_min = math.asin(
236
+ math.sin(lat) * math.cos(hypotenuse_distance / approx_earth_radius)
237
+ + math.cos(lat)
238
+ * math.sin(hypotenuse_distance / approx_earth_radius)
239
+ * math.cos(225 * (math.pi / 180)),
240
+ )
241
+ lon_min = lon + math.atan2(
242
+ math.sin(225 * (math.pi / 180))
243
+ * math.sin(hypotenuse_distance / approx_earth_radius)
244
+ * math.cos(lat),
245
+ math.cos(hypotenuse_distance / approx_earth_radius)
246
+ - math.sin(lat) * math.sin(lat_min),
247
+ )
248
+
249
+ lat_max = math.asin(
250
+ math.sin(lat) * math.cos(hypotenuse_distance / approx_earth_radius)
251
+ + math.cos(lat)
252
+ * math.sin(hypotenuse_distance / approx_earth_radius)
253
+ * math.cos(45 * (math.pi / 180)),
254
+ )
255
+ lon_max = lon + math.atan2(
256
+ math.sin(45 * (math.pi / 180))
257
+ * math.sin(hypotenuse_distance / approx_earth_radius)
258
+ * math.cos(lat),
259
+ math.cos(hypotenuse_distance / approx_earth_radius)
260
+ - math.sin(lat) * math.sin(lat_max),
261
+ )
262
+
263
+ rad2deg = math.degrees
264
+
265
+ zone = {
266
+ "tl_y": rad2deg(lat_max),
267
+ "br_y": rad2deg(lat_min),
268
+ "tl_x": rad2deg(lon_min),
269
+ "br_x": rad2deg(lon_max)
270
+ }
271
+ return self.get_bounds(zone)
272
+
273
+ def get_country_flag(self, country: str) -> Optional[Tuple[bytes, str]]:
274
+ """
275
+ Download the flag of a country from FlightRadar24 and return it as bytes.
276
+
277
+ :param country: Country name
278
+ """
279
+ flag_url = Core.country_flag_url.format(country.lower().replace(" ", "-"))
280
+ headers = Core.image_headers.copy()
281
+
282
+ headers.pop("origin", None) # Does not work for this request.
283
+
284
+ response = self.__client.request(
285
+ flag_url, headers=headers,
286
+ allowed_error_codes=[403, 404], timeout=self.timeout,
287
+ )
288
+ status_code = response.get_status_code()
289
+
290
+ if not (400 <= status_code < 500):
291
+ return response.get_bytes_content(), flag_url.split(".")[-1]
292
+
293
+ return None
294
+
295
+ def get_flight_details(self, flight: Flight) -> Dict[Any, Any]:
296
+ """
297
+ Return the flight details from Data Live FlightRadar24.
298
+
299
+ :param flight: A Flight instance
300
+ """
301
+ response = self.__client.request_standalone(
302
+ Core.flight_data_url.format(flight.id), headers=Core.json_headers, timeout=self.timeout,
303
+ )
304
+ return response.get_json_content()
305
+
306
+ def get_flights(
307
+ self,
308
+ airline: Optional[str] = None,
309
+ bounds: Optional[str] = None,
310
+ registration: Optional[str] = None,
311
+ aircraft_type: Optional[str] = None,
312
+ *,
313
+ details: bool = False
314
+ ) -> List[Flight]:
315
+ """
316
+ Return a list of flights. See more options at set_flight_tracker_config() method.
317
+
318
+ :param airline: The airline ICAO. Ex: "DAL"
319
+ :param bounds: Coordinates (y1, y2 ,x1, x2). Ex: "75.78,-75.78,-427.56,427.56"
320
+ :param registration: Aircraft registration
321
+ :param aircraft_type: Aircraft model code. Ex: "B737"
322
+ :param details: If True, it returns flights with detailed information
323
+ """
324
+ request_params = dataclasses.asdict(self.__flight_tracker_config)
325
+
326
+ if self.is_logged_in():
327
+ request_params["enc"] = self.__client.get_cookie("_frPl")
328
+
329
+ # Insert the method parameters into the dictionary for the request.
330
+ if airline is not None: request_params["airline"] = airline
331
+ if bounds is not None: request_params["bounds"] = bounds
332
+ if registration is not None: request_params["reg"] = registration
333
+ if aircraft_type is not None: request_params["type"] = aircraft_type
334
+
335
+ # Get all flights from Data Live FlightRadar24.
336
+ response = self.__client.request(
337
+ Core.real_time_flight_tracker_data_url,
338
+ params=request_params,
339
+ headers=Core.json_headers,
340
+ timeout=self.timeout,
341
+ )
342
+ content = response.get_json_content()
343
+
344
+ flights: List[Flight] = list()
345
+
346
+ for flight_id, flight_info in content.items():
347
+
348
+ # Get flights only.
349
+ if not flight_id[0].isnumeric():
350
+ continue
351
+
352
+ flights.append(Flight(flight_id, flight_info))
353
+
354
+ if details:
355
+ with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
356
+ futures = {executor.submit(self.get_flight_details, f): f for f in flights}
357
+ for future in as_completed(futures):
358
+ futures[future].set_flight_details(future.result())
359
+
360
+ return flights
361
+
362
+ def get_flight_tracker_config(self) -> FlightTrackerConfig:
363
+ """
364
+ Return a copy of the current config of the Real Time Flight Tracker, used by get_flights() method.
365
+ """
366
+ return dataclasses.replace(self.__flight_tracker_config)
367
+
368
+ def get_history_data(self, flight: Flight, file_type: str, timestamp: int) -> str:
369
+ """
370
+ Download historical data of a flight.
371
+
372
+ :param flight: A Flight instance
373
+ :param file_type: Must be "CSV" or "KML"
374
+ :param timestamp: A Unix timestamp
375
+ """
376
+ if self.__login_data is None:
377
+ raise LoginError("You must log in to your account.")
378
+
379
+ file_type = file_type.lower()
380
+
381
+ if file_type not in ["csv", "kml"]:
382
+ raise ValueError(f"File type '{file_type}' is not supported. Only CSV and KML are supported.")
383
+
384
+ headers = {**Core.json_headers, "accesstoken": self.get_login_data()["accessToken"]}
385
+
386
+ response = self.__client.request(
387
+ Core.historical_data_url.format(flight.id, file_type, timestamp),
388
+ headers=headers,
389
+ timeout=self.timeout,
390
+ )
391
+
392
+ return response.get_bytes_content().decode("utf-8")
393
+
394
+ def get_login_data(self) -> Dict[Any, Any]:
395
+ """
396
+ Return the user data.
397
+ """
398
+ if self.__login_data is None:
399
+ raise LoginError("You must log in to your account.")
400
+
401
+ return self.__login_data["userData"].copy()
402
+
403
+ def get_most_tracked(self) -> Dict:
404
+ """
405
+ Return the most tracked data.
406
+ """
407
+ response = self.__client.request(Core.most_tracked_url, headers=Core.json_headers, timeout=self.timeout)
408
+ return response.get_json_content()
409
+
410
+ def get_volcanic_eruptions(self) -> Dict:
411
+ """
412
+ Return boundaries of volcanic eruptions and ash clouds impacting aviation.
413
+ """
414
+ response = self.__client.request(
415
+ Core.volcanic_eruption_data_url,
416
+ headers=Core.json_headers, timeout=self.timeout,
417
+ )
418
+ return response.get_json_content()
419
+
420
+ def get_zones(self) -> Dict[str, Any]:
421
+ """
422
+ Return all major zones on the globe.
423
+ """
424
+ zones = Core.static_zones.copy()
425
+ zones.pop("version", None)
426
+ return zones
427
+
428
+ def search(self, query: str, limit: int = 50) -> Dict:
429
+ """
430
+ Return the search result.
431
+ """
432
+ response = self.__client.request(
433
+ Core.search_data_url.format(quote(query), limit),
434
+ headers=Core.json_headers, timeout=self.timeout,
435
+ )
436
+ content = response.get_json_content()
437
+ results = content.get("results", [])
438
+ stats = content.get("stats", {})
439
+
440
+ i = 0
441
+ data: Dict[str, Any] = {}
442
+ for name, count in stats.get("count", {}).items():
443
+ data[name] = results[i:i + count]
444
+ i += count
445
+ return data
446
+
447
+ def is_logged_in(self) -> bool:
448
+ """
449
+ Check if the user is logged into the FlightRadar24 account.
450
+ """
451
+ return self.__login_data is not None
452
+
453
+ def login(self, user: str, password: str) -> None:
454
+ """
455
+ Log in to a FlightRadar24 account.
456
+
457
+ :param user: Your email.
458
+ :param password: Your password.
459
+ """
460
+ self.__login_data = None
461
+ self.__client.clear_cookies()
462
+
463
+ data = {
464
+ "email": user,
465
+ "password": password,
466
+ "remember": "true",
467
+ "type": "web"
468
+ }
469
+
470
+ response = self.__client.request(
471
+ Core.user_login_url,
472
+ headers=Core.json_headers, data=data, timeout=self.timeout,
473
+ )
474
+ status_code = response.get_status_code()
475
+ content = response.get_json_content()
476
+
477
+ if not (200 <= status_code < 300) or not content.get("success"):
478
+ raise LoginError(content.get("message", "Your email or password is incorrect"))
479
+
480
+ self.__login_data = {
481
+ "userData": content["userData"],
482
+ }
483
+
484
+ def logout(self) -> bool:
485
+ """
486
+ Log out of the FlightRadar24 account.
487
+
488
+ Return a boolean indicating that it successfully logged out of the server.
489
+ """
490
+ if self.__login_data is None:
491
+ return True
492
+
493
+ self.__login_data = None
494
+ try:
495
+ response = self.__client.request(Core.user_logout_url, headers=Core.json_headers, timeout=self.timeout)
496
+ return 200 <= response.get_status_code() < 300
497
+ finally:
498
+ self.__client.clear_cookies()
499
+
500
+ def set_flight_tracker_config(
501
+ self,
502
+ flight_tracker_config: Optional[FlightTrackerConfig] = None,
503
+ **config: Union[int, str]
504
+ ) -> None:
505
+ """
506
+ Set config for the Real Time Flight Tracker, used by get_flights() method.
507
+ """
508
+ if flight_tracker_config is not None:
509
+ self.__flight_tracker_config = flight_tracker_config
510
+
511
+ current_config_dict = dataclasses.asdict(self.__flight_tracker_config)
512
+
513
+ for key, value in config.items():
514
+ value = str(value)
515
+
516
+ if key not in current_config_dict:
517
+ raise KeyError(f"Unknown option: '{key}'")
518
+
519
+ if not value.isdecimal():
520
+ raise TypeError(f"Value must be a number. Got '{value}' for key '{key}'")
521
+
522
+ setattr(self.__flight_tracker_config, key, value)
@@ -1,11 +1,10 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- from abc import ABC
4
3
  from enum import Enum
5
4
  from .zones import static_zones
6
5
 
7
6
 
8
- class Core(ABC):
7
+ class Core:
9
8
 
10
9
  # Base URLs.
11
10
  api_flightradar_base_url = "https://api.flightradar24.com/common/v1"
@@ -62,7 +61,7 @@ class Core(ABC):
62
61
 
63
62
  headers = {
64
63
  "accept-encoding": "gzip, br",
65
- "accept-language": "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7",
64
+ "accept-language": "en-US,en;q=0.9",
66
65
  "cache-control": "max-age=0",
67
66
  "origin": "https://www.flightradar24.com",
68
67
  "referer": "https://www.flightradar24.com/",
@@ -72,7 +71,10 @@ class Core(ABC):
72
71
  "sec-fetch-dest": "empty",
73
72
  "sec-fetch-mode": "cors",
74
73
  "sec-fetch-site": "same-site",
75
- "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36"
74
+ "user-agent": (
75
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
76
+ " (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36"
77
+ ),
76
78
  }
77
79
 
78
80
  json_headers = headers.copy()
@@ -82,9 +84,13 @@ class Core(ABC):
82
84
  image_headers["accept"] = "image/gif, image/jpg, image/jpeg, image/png"
83
85
 
84
86
  html_headers = {
85
- "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
87
+ "accept": (
88
+ "text/html,application/xhtml+xml,application/xml;q=0.9,"
89
+ "image/avif,image/webp,image/apng,*/*;q=0.8,"
90
+ "application/signed-exchange;v=b3;q=0.7"
91
+ ),
86
92
  "accept-encoding": "gzip, deflate, br",
87
- "accept-language": "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7",
93
+ "accept-language": "en-US,en;q=0.9",
88
94
  "cache-control": "max-age=0",
89
95
  "referer": "https://www.flightradar24.com/",
90
96
  "sec-ch-ua": '"Google Chrome";v="136", "Chromium";v="136", "Not-A.Brand";v="24"',
@@ -95,7 +101,10 @@ class Core(ABC):
95
101
  "sec-fetch-site": "same-origin",
96
102
  "sec-fetch-user": "?1",
97
103
  "upgrade-insecure-requests": "1",
98
- "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36"
104
+ "user-agent": (
105
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
106
+ " (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36"
107
+ ),
99
108
  }
100
109
 
101
110
 
@@ -330,4 +339,4 @@ class Countries(Enum):
330
339
  WALLIS_AND_FUTUNA = "wallis-and-futuna"
331
340
  YEMEN = "yemen"
332
341
  ZAMBIA = "zambia"
333
- ZIMBABWE = "zimbabwe"
342
+ ZIMBABWE = "zimbabwe"