Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions .github/workflows/node-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,16 @@ jobs:
run: npm run lint
- name: Type check
run: npm run test:types
- name: Test package
- name: Offline tests (PR gate)
run: npm run test:offline
- name: Integration tests (live FR24)
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || github.event_name == 'push'
uses: nick-fields/retry@v3
with:
timeout_minutes: 10
max_attempts: 3
command: cd nodejs && npm test
command: cd nodejs && npm run test:integration
continue-on-error: ${{ github.event_name == 'push' }}
- name: Dependency audit
if: matrix.node-version == '22.x'
run: cd nodejs && npm audit --omit=dev --audit-level=high || true
Comment thread
JeanExtreme002 marked this conversation as resolved.
Outdated
13 changes: 10 additions & 3 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,24 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install -e "./python[tests]"
pip install flake8 mypy build
pip install flake8 mypy build pytest-cov pip-audit
- name: Lint
run: cd python && python -m flake8 FlightRadar24 tests
- name: Type check
run: cd python && python -m mypy FlightRadar24 --ignore-missing-imports
- name: Test with pytest
- name: Offline tests (PR gate)
run: cd python && pytest -m "not integration" --cov=FlightRadar24 --cov-report=term --cov-report=xml -v
- name: Integration tests (live FR24)
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || github.event_name == 'push'
uses: nick-fields/retry@v3
with:
timeout_minutes: 10
max_attempts: 3
command: cd python && pytest tests -vv -s
command: cd python && pytest -m integration -vv -s
continue-on-error: ${{ github.event_name == 'push' }}
- name: Dependency audit
if: matrix.python-version == '3.13'
run: pip-audit --strict --skip-editable -r <(pip freeze | grep -v "^FlightRadarAPI") || true
Comment thread
JeanExtreme002 marked this conversation as resolved.
Outdated
- name: Build and verify install
run: |
python -m build ./python
Expand Down
7 changes: 5 additions & 2 deletions nodejs/FlightRadar24/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,14 @@ class FlightRadar24API {
* @param {object} [options={}]
* @param {number} [options.timeout=30000] - Request timeout in milliseconds
* @param {number} [options.maxWorkers=8] - Maximum concurrent requests when fetching flight details
* @param {object} [options.impersonate] - TLS impersonation profile override
* (`{ciphers, sigalgs, ecdhCurve}`). Use when FR24 updates its Cloudflare
* bot mitigation faster than this library releases.
*/
constructor({ timeout = 30000, maxWorkers = 8 } = {}) {
constructor({ timeout = 30000, maxWorkers = 8, impersonate = null, retry = null } = {}) {
this.__flightTrackerConfig = new FlightTrackerConfig();
this.__loginData = null;
this.__client = new APIClient();
this.__client = new APIClient({ impersonate, retry });
this.timeout = timeout;
this.maxWorkers = maxWorkers;
}
Expand Down
4 changes: 2 additions & 2 deletions nodejs/FlightRadar24/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const DATA_CLOUD_BASE = "https://data-cloud.flightradar24.com";

const baseHeaders = {
"accept-encoding": "gzip, br",
"accept-language": "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7",
"accept-language": "en-US,en;q=0.9",
"cache-control": "max-age=0",
"origin": FR24_BASE,
"referer": `${FR24_BASE}/`,
Expand Down Expand Up @@ -73,7 +73,7 @@ const Core = {
htmlHeaders: {
"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",
"accept-encoding": "gzip, deflate, br",
"accept-language": "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7",
"accept-language": "en-US,en;q=0.9",
"cache-control": "max-age=0",
"referer": `${FR24_BASE}/`,
// eslint-disable-next-line quotes
Expand Down
32 changes: 32 additions & 0 deletions nodejs/FlightRadar24/entities/airport.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,38 @@ class Airport extends Entity {
}
}

/**
* Build an Airport from the listing payload (lat/lon/name/iata/icao/country).
*
* @param {object} basicInfo
* @return {Airport}
*/
static fromBasicInfo(basicInfo) {
return new Airport(basicInfo);
}

/**
* Build an Airport from the airport.json `details` block.
*
* @param {object} info
* @return {Airport}
*/
static fromInfo(info) {
return new Airport({}, info);
}

/**
* Build an Airport from a full `getAirportDetails` response.
*
* @param {object} airportDetails
* @return {Airport}
*/
static fromDetails(airportDetails) {
const airport = new Airport();
airport.setAirportDetails(airportDetails);
return airport;
}

/**
* Initialize instance with basic information about the airport.
*
Expand Down
6 changes: 5 additions & 1 deletion nodejs/FlightRadar24/entities/entity.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const { radians } = require("../util");

const DEFAULT_TEXT = "N/A";
const EARTH_RADIUS_KM = 6371;

/**
* Representation of a real entity, at some location.
Expand Down Expand Up @@ -52,8 +53,11 @@ class Entity {
const lat2 = radians(entity.latitude);
const lon2 = radians(entity.longitude);

return Math.acos(Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1)) * 6371;
const angle = Math.acos(Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1));
return angle * EARTH_RADIUS_KM;
}
}

module.exports = Entity;
module.exports.DEFAULT_TEXT = DEFAULT_TEXT;
module.exports.EARTH_RADIUS_KM = EARTH_RADIUS_KM;
6 changes: 6 additions & 0 deletions nodejs/FlightRadar24/entities/flight.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const Entity = require("./entity");
const { DEFAULT_TEXT } = require("./entity");

// Positional field mapping for the raw array returned by the FlightRadar24 feed.
// If the upstream API adds or shifts a field, update only this map.
Expand Down Expand Up @@ -105,6 +106,7 @@ class Flight extends Entity {
* @return {string}
*/
getAltitude() {
if (typeof this.altitude !== "number") return DEFAULT_TEXT;
return this.altitude.toString() + " ft";
}

Expand All @@ -114,6 +116,7 @@ class Flight extends Entity {
* @return {string}
*/
getFlightLevel() {
if (typeof this.altitude !== "number") return DEFAULT_TEXT;
if (this.altitude >= 10000) {
return this.altitude.toString().slice(0, 3) + " FL";
}
Expand All @@ -126,6 +129,7 @@ class Flight extends Entity {
* @return {string}
*/
getGroundSpeed() {
if (typeof this.groundSpeed !== "number") return DEFAULT_TEXT;
const suffix = this.groundSpeed > 1 ? "s" : "";
return this.groundSpeed.toString() + " kt" + suffix;
}
Expand All @@ -136,6 +140,7 @@ class Flight extends Entity {
* @return {string}
*/
getHeading() {
if (typeof this.heading !== "number") return DEFAULT_TEXT;
return this.heading.toString() + "°";
}

Expand All @@ -145,6 +150,7 @@ class Flight extends Entity {
* @return {string}
*/
getVerticalSpeed() {
if (typeof this.verticalSpeed !== "number") return DEFAULT_TEXT;
return this.verticalSpeed.toString() + " fpm";
}

Expand Down
62 changes: 57 additions & 5 deletions nodejs/FlightRadar24/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,59 @@ export interface Zone {
br_x: number;
}

/**
* Options for TLS impersonation. Currently maps Chrome major versions to
* the ciphers/sigalgs/curves the runtime should use.
*/
export interface ImpersonateOptions {
/** Chrome major version label, e.g. "chrome136". Defaults to the latest supported. */
profile?: string;
}

/**
* Central HTTP client. Internal class exposed for advanced use cases (custom retries,
* cookie inspection). Most users should rely on FlightRadar24API directly.
*/
export class APIClient {
constructor(options?: { impersonate?: ImpersonateOptions; retry?: RetryPolicy });
request(url: string, options?: object): Promise<{content: any; statusCode: number; cookies: Record<string, string>}>;
getCookie(name: string): string | undefined;
clearCookies(): void;
}

/**
* Retry policy for transient errors (CloudflareError + AbortError / network errors).
*/
export class RetryPolicy {
maxAttempts: number;
baseDelayMs: number;
maxDelayMs: number;
jitterMs: number;
constructor(options?: {
maxAttempts?: number;
baseDelayMs?: number;
maxDelayMs?: number;
jitterMs?: number;
});
sleepFor(attemptIndex: number): number;
}

/**
* Main class of the FlightRadarAPI
*/
export class FlightRadar24API {
private __flightTrackerConfig: FlightTrackerConfig;
private __loginData: {userData: any; cookies: any;} | null;

constructor(options?: {timeout?: number; maxWorkers?: number});
private __loginData: {userData: any} | null;
private __client: APIClient;
timeout: number;
maxWorkers: number;

constructor(options?: {
timeout?: number;
maxWorkers?: number;
impersonate?: ImpersonateOptions;
retry?: RetryPolicy;
});

/**
* Return a list with all airlines.
Expand Down Expand Up @@ -196,7 +241,7 @@ export class FlightRadar24API {
*/
setFlightTrackerConfig(
flightTrackerConfig: FlightTrackerConfig | null,
config?: object,
config?: Partial<Record<keyof FlightTrackerConfig, string | number>>,
): void;
}

Expand Down Expand Up @@ -300,7 +345,14 @@ export class Airport extends Entity {
* @param {object} [info] - Dictionary with more information about the airport received from FlightRadar24
*/
constructor(basicInfo?: object, info?: object);


/** Build an Airport from the listing payload. */
static fromBasicInfo(basicInfo: object): Airport;
/** Build an Airport from the airport.json `details` block. */
static fromInfo(info: object): Airport;
/** Build an Airport from a full `getAirportDetails` response. */
static fromDetails(airportDetails: object): Airport;

/**
* Initialize instance with basic information about the airport.
*
Expand Down
2 changes: 2 additions & 0 deletions nodejs/FlightRadar24/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const Airport = require("./entities/airport");
const Entity = require("./entities/entity");
const Flight = require("./entities/flight");
const { Countries } = require("./core");
const { RetryPolicy, APIClient } = require("./request");

const { version, author } = require("../package.json");

Expand All @@ -25,5 +26,6 @@ module.exports = {
Countries,
Airport, Entity, Flight,
FlightRadarError, AirportNotFoundError, CloudflareError, LoginError,
RetryPolicy, APIClient,
author, version,
};
Loading
Loading