iobroker.jetframe 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +357 -0
- package/admin/SF-Pro.ttf +0 -0
- package/admin/admin.d.ts +65 -0
- package/admin/frame.html +982 -0
- package/admin/frame.html.bak-aircraft-card-real-row-20260518-1608 +1236 -0
- package/admin/frame.html.bak-aircraft-card-structure-20260518-1517 +1236 -0
- package/admin/frame.html.bak-aircraft-logo-id-fix-20260518-1639 +1239 -0
- package/admin/frame.html.bak-shortcut-test +1236 -0
- package/admin/frame.html.bak-tablet-class-20260518-1729 +1239 -0
- package/admin/heatmap.html +216 -0
- package/admin/index.html +268 -0
- package/admin/index_m.html +1749 -0
- package/admin/jetframe.css +1260 -0
- package/admin/jetframe.css.bak-airbus-landscape-fix +4630 -0
- package/admin/jetframe.css.bak-aircraft-card-clean-equal-20260518-1438 +4899 -0
- package/admin/jetframe.css.bak-aircraft-card-real-row-20260518-1608 +4814 -0
- package/admin/jetframe.css.bak-aircraft-card-row-left-20260518-1525 +4604 -0
- package/admin/jetframe.css.bak-aircraft-card-slim-equal-20260518-1446 +4647 -0
- package/admin/jetframe.css.bak-aircraft-card-structure-20260518-1517 +4646 -0
- package/admin/jetframe.css.bak-aircraft-inline-final-20260518-1527 +4654 -0
- package/admin/jetframe.css.bak-aircraft-row-compact-fix-20260518-1639 +4763 -0
- package/admin/jetframe.css.bak-before-aircrafttype-purge +4818 -0
- package/admin/jetframe.css.bak-before-cleanup +4670 -0
- package/admin/jetframe.css.bak-before-remove-tablet-only-20260518-1711 +4896 -0
- package/admin/jetframe.css.bak-before-tablet-layout-rework-20260518-1650 +4914 -0
- package/admin/jetframe.css.bak-clean-duplicate-fonts-20260518-1340 +4975 -0
- package/admin/jetframe.css.bak-clean-old-index-fix-20260518-1937 +5167 -0
- package/admin/jetframe.css.bak-hardleft-airbus +4751 -0
- package/admin/jetframe.css.bak-index-iphone-landscape-20260518-1931 +5030 -0
- package/admin/jetframe.css.bak-index-landscape-final-20260518-1941 +5167 -0
- package/admin/jetframe.css.bak-index-landscape-real-20260518-1936 +5186 -0
- package/admin/jetframe.css.bak-landscape-compact-jumbo-bold-20260518-1343 +4802 -0
- package/admin/jetframe.css.bak-logo-align-final +4551 -0
- package/admin/jetframe.css.bak-logo-final2 +4551 -0
- package/admin/jetframe.css.bak-narrowbody-font-fix +4992 -0
- package/admin/jetframe.css.bak-nuke-airbus-align +4790 -0
- package/admin/jetframe.css.bak-pill-balance-20260518-1603 +4773 -0
- package/admin/jetframe.css.bak-pill-balance-fix +4910 -0
- package/admin/jetframe.css.bak-radar-fix-fonts +4710 -0
- package/admin/jetframe.css.bak-shortcut-test +4899 -0
- package/admin/jetframe.css.bak-smaller-aircraft-card-fonts-20260518-1345 +4897 -0
- package/admin/jetframe.css.bak-tablet-fix-real-20260518-1748 +4945 -0
- package/admin/jetframe.css.bak-tablet-fullscreen-fix-20260518-1804 +4972 -0
- package/admin/jetframe.css.bak-tablet-landscape-layout-20260518-1645 +4802 -0
- package/admin/jetframe.css.bak-tablet-layout-final-20260518-1839 +4802 -0
- package/admin/jetframe.css.bak-tablet-layout-v3-20260518-1729 +4802 -0
- package/admin/jetframe.css.bak-tablet-layout-v4-20260518-1801 +4957 -0
- package/admin/jetframe.css.bak-tablet-layout-v5-20260518-1843 +4970 -0
- package/admin/jetframe.css.bak-tablet-layout-v6-20260518-1848 +4958 -0
- package/admin/jetframe.css.bak-tablet-layout-v7-20260518-1909 +4985 -0
- package/admin/jetframe.css.bak-tablet-only-landscape-v2-20260518-1707 +4802 -0
- package/admin/jetframe.css.bak-tablet-pages-final-20260519-1857 +5188 -0
- package/admin/jetframe.css.bak-tablet-pages-final-20260519-1859 +5347 -0
- package/admin/jetframe.css.bak-tablet-pages-v2-20260519-190807 +5349 -0
- package/admin/jetframe.css.bak-typography-align-final +4818 -0
- package/admin/jetframe.png +0 -0
- package/admin/manifest.webmanifest +15 -0
- package/admin/src/app.tsx +58 -0
- package/admin/src/components/settings.tsx +97 -0
- package/admin/src/i18n/de.json +11 -0
- package/admin/src/i18n/en.json +11 -0
- package/admin/src/i18n/es.json +11 -0
- package/admin/src/i18n/fr.json +11 -0
- package/admin/src/i18n/i18n.d.ts +28 -0
- package/admin/src/i18n/it.json +11 -0
- package/admin/src/i18n/nl.json +11 -0
- package/admin/src/i18n/pl.json +11 -0
- package/admin/src/i18n/pt.json +11 -0
- package/admin/src/i18n/ru.json +11 -0
- package/admin/src/i18n/uk.json +11 -0
- package/admin/src/i18n/zh-cn.json +11 -0
- package/admin/src/index.tsx +25 -0
- package/admin/stats.html +228 -0
- package/admin/style.css +32 -0
- package/admin/tsconfig.json +11 -0
- package/admin/words.js +46 -0
- package/build/lib/adsb.js +218 -0
- package/build/lib/adsb.js.map +7 -0
- package/build/lib/airportNamesDe.js +131 -0
- package/build/lib/airportNamesDe.js.map +7 -0
- package/build/lib/airports.js +281 -0
- package/build/lib/airports.js.map +7 -0
- package/build/lib/classify.js +339 -0
- package/build/lib/classify.js.map +7 -0
- package/build/lib/config.js +103 -0
- package/build/lib/config.js.map +7 -0
- package/build/lib/flightInfo.js +1409 -0
- package/build/lib/flightInfo.js.map +7 -0
- package/build/lib/geo.js +84 -0
- package/build/lib/geo.js.map +7 -0
- package/build/lib/images.js +422 -0
- package/build/lib/images.js.map +7 -0
- package/build/lib/specialLiveries.js +342 -0
- package/build/lib/specialLiveries.js.map +7 -0
- package/build/lib/states.js +971 -0
- package/build/lib/states.js.map +7 -0
- package/build/lib/staticFiles.js +73 -0
- package/build/lib/staticFiles.js.map +7 -0
- package/build/lib/types.js +17 -0
- package/build/lib/types.js.map +7 -0
- package/build/lib/visConfig.js +52 -0
- package/build/lib/visConfig.js.map +7 -0
- package/build/main.js +1454 -0
- package/build/main.js.map +7 -0
- package/io-package.json +169 -0
- package/package.json +82 -0
package/admin/words.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/* eslint no-unused-vars: off */
|
|
2
|
+
/* eslint no-global-assign: off */
|
|
3
|
+
/* global systemDictionary */
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
systemDictionary = {
|
|
7
|
+
'jetframe adapter settings': {
|
|
8
|
+
en: 'Adapter settings for jetframe',
|
|
9
|
+
de: 'Adaptereinstellungen für jetframe',
|
|
10
|
+
ru: 'Настройки адаптера для jetframe',
|
|
11
|
+
pt: 'Configurações do adaptador para jetframe',
|
|
12
|
+
nl: 'Adapterinstellingen voor jetframe',
|
|
13
|
+
fr: "Paramètres d'adaptateur pour jetframe",
|
|
14
|
+
it: "Impostazioni dell'adattatore per jetframe",
|
|
15
|
+
es: 'Ajustes del adaptador para jetframe',
|
|
16
|
+
pl: 'Ustawienia adaptera dla jetframe',
|
|
17
|
+
uk: 'Налаштування адаптера для jetframe',
|
|
18
|
+
'zh-cn': 'jetframe的适配器设置',
|
|
19
|
+
},
|
|
20
|
+
option1: {
|
|
21
|
+
en: 'option1',
|
|
22
|
+
de: 'Option1',
|
|
23
|
+
ru: 'вариант 1',
|
|
24
|
+
pt: 'opção1',
|
|
25
|
+
nl: 'optie1',
|
|
26
|
+
fr: 'option1',
|
|
27
|
+
it: 'opzione1',
|
|
28
|
+
es: 'opción1',
|
|
29
|
+
pl: 'opcja 1',
|
|
30
|
+
uk: 'варіант1',
|
|
31
|
+
'zh-cn': '选项1',
|
|
32
|
+
},
|
|
33
|
+
option2: {
|
|
34
|
+
en: 'option2',
|
|
35
|
+
de: 'Option2',
|
|
36
|
+
ru: 'вариант 2',
|
|
37
|
+
pt: 'opção2',
|
|
38
|
+
nl: 'optie2',
|
|
39
|
+
fr: 'option2',
|
|
40
|
+
it: 'opzione2',
|
|
41
|
+
es: 'opción2',
|
|
42
|
+
pl: 'opcja 2',
|
|
43
|
+
uk: 'варіант2',
|
|
44
|
+
'zh-cn': '选项2',
|
|
45
|
+
},
|
|
46
|
+
};
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var adsb_exports = {};
|
|
20
|
+
__export(adsb_exports, {
|
|
21
|
+
fetchAdsb: () => fetchAdsb,
|
|
22
|
+
parseAircraft: () => parseAircraft
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(adsb_exports);
|
|
25
|
+
const ADSB_ERROR_STATE = {};
|
|
26
|
+
const ADSB_503_STATE = {};
|
|
27
|
+
function clean(v) {
|
|
28
|
+
return String(v || "").trim();
|
|
29
|
+
}
|
|
30
|
+
function toNumber(v) {
|
|
31
|
+
if (v === null || v === void 0 || v === "") {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
const n = Number(v);
|
|
35
|
+
return Number.isFinite(n) ? n : null;
|
|
36
|
+
}
|
|
37
|
+
function parseAltitude(v) {
|
|
38
|
+
if (v === null || v === void 0) {
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
41
|
+
if (typeof v === "string") {
|
|
42
|
+
if (v.toLowerCase() === "ground") {
|
|
43
|
+
return 0;
|
|
44
|
+
}
|
|
45
|
+
const n2 = Number(v);
|
|
46
|
+
return Number.isFinite(n2) ? n2 : 0;
|
|
47
|
+
}
|
|
48
|
+
const n = Number(v);
|
|
49
|
+
return Number.isFinite(n) ? n : 0;
|
|
50
|
+
}
|
|
51
|
+
async function fetchAdsb(config, httpJsonRaw, logWarn, logDebug) {
|
|
52
|
+
const urls = buildAdsbUrls(config);
|
|
53
|
+
const aircraftByKey = {};
|
|
54
|
+
for (const primaryUrl of urls) {
|
|
55
|
+
const sources = [{ name: "adsb.lol", url: primaryUrl }];
|
|
56
|
+
const fallbackUrl = buildAdsbFiFallbackUrl(primaryUrl);
|
|
57
|
+
if (fallbackUrl) {
|
|
58
|
+
sources.push({ name: "adsb.fi", url: fallbackUrl });
|
|
59
|
+
}
|
|
60
|
+
let body = null;
|
|
61
|
+
let usedSource = "";
|
|
62
|
+
for (const source of sources) {
|
|
63
|
+
const maxAttempts = source.name === "adsb.lol" ? 1 : 2;
|
|
64
|
+
if (source.name !== "adsb.lol") {
|
|
65
|
+
logDebug == null ? void 0 : logDebug(`ADSB adsb.lol fehlgeschlagen \u2013 versuche ${source.name} Fallback`);
|
|
66
|
+
}
|
|
67
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
68
|
+
try {
|
|
69
|
+
body = await httpJsonRaw(source.url);
|
|
70
|
+
usedSource = source.name;
|
|
71
|
+
if (source.name !== "adsb.lol") {
|
|
72
|
+
logDebug == null ? void 0 : logDebug(`ADSB Fallback aktiv: ${source.name}`);
|
|
73
|
+
}
|
|
74
|
+
logDebug == null ? void 0 : logDebug(`ADSB Quelle: ${source.name}`);
|
|
75
|
+
break;
|
|
76
|
+
} catch (e) {
|
|
77
|
+
const errText = errorText(e);
|
|
78
|
+
const isSoftAdsbError = errText.includes("HTTP 502") || errText.includes("HTTP 503") || errText.toLowerCase().includes("timeout") || errText.includes("HTML statt JSON");
|
|
79
|
+
const key = `${source.name}:${source.url}`;
|
|
80
|
+
const now = Date.now();
|
|
81
|
+
const st = ADSB_ERROR_STATE[key] || { count: 0, lastWarn: 0 };
|
|
82
|
+
st.count++;
|
|
83
|
+
if (!isSoftAdsbError || now - st.lastWarn > 3e5) {
|
|
84
|
+
if (isSoftAdsbError) {
|
|
85
|
+
logDebug == null ? void 0 : logDebug(`ADSB ${source.name} tempor\xE4r nicht erreichbar (${errText})`);
|
|
86
|
+
} else {
|
|
87
|
+
logDebug == null ? void 0 : logDebug(`ADSB ${source.name} Fehler Versuch ${attempt}: ${errText}`);
|
|
88
|
+
}
|
|
89
|
+
st.lastWarn = now;
|
|
90
|
+
}
|
|
91
|
+
ADSB_ERROR_STATE[key] = st;
|
|
92
|
+
if (attempt < maxAttempts) {
|
|
93
|
+
await sleep(1500);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (body) {
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (!body) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (usedSource) {
|
|
105
|
+
logDebug == null ? void 0 : logDebug(`ADSB Daten empfangen \xFCber ${usedSource}`);
|
|
106
|
+
}
|
|
107
|
+
const arr = Array.isArray(body == null ? void 0 : body.aircraft) ? body.aircraft : Array.isArray(body == null ? void 0 : body.ac) ? body.ac : [];
|
|
108
|
+
for (const item of arr) {
|
|
109
|
+
const key = clean(
|
|
110
|
+
item.hex || item.icao || item.flight || item.call || item.callsign || `${item.lat}_${item.lon}_${item.alt_baro || item.alt_geom || ""}`
|
|
111
|
+
).toLowerCase();
|
|
112
|
+
if (!key) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
aircraftByKey[key] = item;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
aircraft: Object.values(aircraftByKey)
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function buildAdsbUrls(config) {
|
|
123
|
+
var _a, _b, _c, _d, _e, _f;
|
|
124
|
+
const anyConfig = config;
|
|
125
|
+
const customUrl = clean(anyConfig.adsbCustomUrl || anyConfig.customAdsbUrl || "");
|
|
126
|
+
if (customUrl) {
|
|
127
|
+
return [replaceAdsbUrlTokens(customUrl, config)];
|
|
128
|
+
}
|
|
129
|
+
const airportLat = Number((_c = (_b = (_a = anyConfig.airport) == null ? void 0 : _a.lat) != null ? _b : anyConfig.airportLat) != null ? _c : config.homeLat);
|
|
130
|
+
const airportLon = Number((_f = (_e = (_d = anyConfig.airport) == null ? void 0 : _d.lon) != null ? _e : anyConfig.airportLon) != null ? _f : config.homeLon);
|
|
131
|
+
const airportRadiusNm = Math.max(Number(anyConfig.radiusNm || 0), 1);
|
|
132
|
+
const urls = [`https://api.adsb.lol/v2/lat/${airportLat}/lon/${airportLon}/dist/${airportRadiusNm}`];
|
|
133
|
+
if (anyConfig.overflightEnabled || anyConfig.overflightOnly) {
|
|
134
|
+
const homeRadiusNm = Math.max(Number(anyConfig.overflightMaxDistanceNm || 0), 1);
|
|
135
|
+
const homeUrl = `https://api.adsb.lol/v2/lat/${config.homeLat}/lon/${config.homeLon}/dist/${homeRadiusNm}`;
|
|
136
|
+
if (!urls.includes(homeUrl)) {
|
|
137
|
+
urls.push(homeUrl);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return urls;
|
|
141
|
+
}
|
|
142
|
+
function buildAdsbFiFallbackUrl(url) {
|
|
143
|
+
const m = String(url || "").match(/\/lat\/([^/]+)\/lon\/([^/]+)\/dist\/([^/?#]+)/);
|
|
144
|
+
if (!m) {
|
|
145
|
+
return "";
|
|
146
|
+
}
|
|
147
|
+
const lat = m[1];
|
|
148
|
+
const lon = m[2];
|
|
149
|
+
const dist = m[3];
|
|
150
|
+
if (!lat || !lon || !dist) {
|
|
151
|
+
return "";
|
|
152
|
+
}
|
|
153
|
+
return `https://opendata.adsb.fi/api/v3/lat/${lat}/lon/${lon}/dist/${dist}`;
|
|
154
|
+
}
|
|
155
|
+
function replaceAdsbUrlTokens(url, config) {
|
|
156
|
+
var _a, _b, _c, _d, _e, _f;
|
|
157
|
+
const anyConfig = config;
|
|
158
|
+
const airportLat = String((_c = (_b = (_a = anyConfig.airport) == null ? void 0 : _a.lat) != null ? _b : anyConfig.airportLat) != null ? _c : config.homeLat);
|
|
159
|
+
const airportLon = String((_f = (_e = (_d = anyConfig.airport) == null ? void 0 : _d.lon) != null ? _e : anyConfig.airportLon) != null ? _f : config.homeLon);
|
|
160
|
+
const airportRadiusNm = String(anyConfig.radiusNm || 15);
|
|
161
|
+
const overflightRadiusNm = String(anyConfig.overflightMaxDistanceNm || airportRadiusNm);
|
|
162
|
+
return String(url || "").replace(/\{homeLat\}/g, String(config.homeLat)).replace(/\{homeLon\}/g, String(config.homeLon)).replace(/\{airportLat\}/g, airportLat).replace(/\{airportLon\}/g, airportLon).replace(/\{radiusNm\}/g, airportRadiusNm).replace(/\{airportRadiusNm\}/g, airportRadiusNm).replace(/\{overflightRadiusNm\}/g, overflightRadiusNm);
|
|
163
|
+
}
|
|
164
|
+
function parseAircraft(body) {
|
|
165
|
+
if (!body) {
|
|
166
|
+
return [];
|
|
167
|
+
}
|
|
168
|
+
const arr = Array.isArray(body.aircraft) ? body.aircraft : Array.isArray(body.ac) ? body.ac : [];
|
|
169
|
+
return arr.map(
|
|
170
|
+
(a) => {
|
|
171
|
+
var _a, _b, _c, _d, _e, _f;
|
|
172
|
+
return {
|
|
173
|
+
hex: clean(a.hex || ""),
|
|
174
|
+
callsign: clean(a.flight || a.call || a.callsign || ""),
|
|
175
|
+
type: clean(a.t || a.type || ""),
|
|
176
|
+
registration: clean(a.r || a.reg || ""),
|
|
177
|
+
squawk: clean(a.squawk || a.squawk_code || a.squawkCode || ""),
|
|
178
|
+
emergency: clean(a.emergency || ""),
|
|
179
|
+
lat: (_a = toNumber(a.lat)) != null ? _a : 0,
|
|
180
|
+
lon: (_b = toNumber(a.lon)) != null ? _b : 0,
|
|
181
|
+
altFt: parseAltitude(a.alt_baro || a.alt_geom || a.altitude),
|
|
182
|
+
speedKt: (_c = toNumber(a.gs || a.spd || a.speed)) != null ? _c : 0,
|
|
183
|
+
trackDeg: (_d = toNumber(a.track || a.trak || a.heading)) != null ? _d : 0,
|
|
184
|
+
verticalRate: (_e = toNumber(a.baro_rate || a.geom_rate || a.vsi)) != null ? _e : 0,
|
|
185
|
+
seenSec: (_f = toNumber(a.seen || a.seen_pos || 0)) != null ? _f : 999
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
).filter(
|
|
189
|
+
(a) => Number.isFinite(a.lat) && Number.isFinite(a.lon) && a.lat !== 0 && a.lon !== 0 && Number.isFinite(a.seenSec) && a.seenSec <= 90
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
function sleep(ms) {
|
|
193
|
+
return new Promise((resolve) => {
|
|
194
|
+
setTimeout(resolve, ms);
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
function errorText(e) {
|
|
198
|
+
if (!e) {
|
|
199
|
+
return "unbekannter Fehler";
|
|
200
|
+
}
|
|
201
|
+
if (typeof e === "string") {
|
|
202
|
+
return e;
|
|
203
|
+
}
|
|
204
|
+
if (e instanceof Error) {
|
|
205
|
+
return e.message;
|
|
206
|
+
}
|
|
207
|
+
try {
|
|
208
|
+
return JSON.stringify(e);
|
|
209
|
+
} catch {
|
|
210
|
+
return String(e);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
214
|
+
0 && (module.exports = {
|
|
215
|
+
fetchAdsb,
|
|
216
|
+
parseAircraft
|
|
217
|
+
});
|
|
218
|
+
//# sourceMappingURL=adsb.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lib/adsb.ts"],
|
|
4
|
+
"sourcesContent": ["import type { Aircraft, JetFrameConfig, AdapterLike } from './types';\n\n/** HTTP helper type: fetches a URL and returns the parsed JSON body. */\nexport type HttpJsonRaw = (url: string) => Promise<unknown>;\n\nconst ADSB_ERROR_STATE: Record<string, { count: number; lastWarn: number }> = {};\n\nconst ADSB_503_STATE: Record<string, { count: number; lastWarn: number }> = {};\n\nfunction clean(v: unknown): string {\n\treturn String(v || '').trim();\n}\n\nfunction toNumber(v: unknown): number | null {\n\tif (v === null || v === undefined || v === '') {\n\t\treturn null;\n\t}\n\tconst n = Number(v);\n\treturn Number.isFinite(n) ? n : null;\n}\n\nfunction parseAltitude(v: unknown): number {\n\tif (v === null || v === undefined) {\n\t\treturn 0;\n\t}\n\n\tif (typeof v === 'string') {\n\t\tif (v.toLowerCase() === 'ground') {\n\t\t\treturn 0;\n\t\t}\n\t\tconst n = Number(v);\n\t\treturn Number.isFinite(n) ? n : 0;\n\t}\n\n\tconst n = Number(v);\n\treturn Number.isFinite(n) ? n : 0;\n}\n\n/**\n *\n * @param config\n * @param httpJsonRaw\n * @param logWarn\n */\nexport async function fetchAdsb(\n\tconfig: JetFrameConfig,\n\thttpJsonRaw: HttpJsonRaw,\n\tlogWarn: (msg: string) => void,\n\tlogDebug?: (msg: string) => void,\n): Promise<any> {\n\tconst urls = buildAdsbUrls(config);\n\n\tconst aircraftByKey: Record<string, any> = {};\n\n\tfor (const primaryUrl of urls) {\n\t\tconst sources: Array<{ name: string; url: string }> = [{ name: 'adsb.lol', url: primaryUrl }];\n\n\t\tconst fallbackUrl = buildAdsbFiFallbackUrl(primaryUrl);\n\n\t\tif (fallbackUrl) {\n\t\t\tsources.push({ name: 'adsb.fi', url: fallbackUrl });\n\t\t}\n\n\t\tlet body: any = null;\n\t\tlet usedSource = '';\n\n\t\tfor (const source of sources) {\n\t\t\tconst maxAttempts = source.name === 'adsb.lol' ? 1 : 2;\n\n\t\t\tif (source.name !== 'adsb.lol') {\n\t\t\t\tlogDebug?.(`ADSB adsb.lol fehlgeschlagen \u2013 versuche ${source.name} Fallback`);\n\t\t\t}\n\n\t\t\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\t\t\ttry {\n\t\t\t\t\tbody = await httpJsonRaw(source.url);\n\t\t\t\t\tusedSource = source.name;\n\n\t\t\t\t\tif (source.name !== 'adsb.lol') {\n\t\t\t\t\t\tlogDebug?.(`ADSB Fallback aktiv: ${source.name}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlogDebug?.(`ADSB Quelle: ${source.name}`);\n\n\t\t\t\t\tbreak;\n\t\t\t\t} catch (e) {\n\t\t\t\t\tconst errText = errorText(e);\n\t\t\t\t\tconst isSoftAdsbError =\n\t\t\t\t\t\terrText.includes('HTTP 502') ||\n\t\t\t\t\t\terrText.includes('HTTP 503') ||\n\t\t\t\t\t\terrText.toLowerCase().includes('timeout') ||\n\t\t\t\t\t\terrText.includes('HTML statt JSON');\n\n\t\t\t\t\tconst key = `${source.name}:${source.url}`;\n\t\t\t\t\tconst now = Date.now();\n\t\t\t\t\tconst st = ADSB_ERROR_STATE[key] || { count: 0, lastWarn: 0 };\n\n\t\t\t\t\tst.count++;\n\n\t\t\t\t\tif (!isSoftAdsbError || now - st.lastWarn > 300000) {\n\t\t\t\t\t\tif (isSoftAdsbError) {\n\t\t\t\t\t\t\tlogDebug?.(`ADSB ${source.name} tempor\u00E4r nicht erreichbar (${errText})`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlogDebug?.(`ADSB ${source.name} Fehler Versuch ${attempt}: ${errText}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tst.lastWarn = now;\n\t\t\t\t\t}\n\n\t\t\t\t\tADSB_ERROR_STATE[key] = st;\n\n\t\t\t\t\tif (attempt < maxAttempts) {\n\t\t\t\t\t\tawait sleep(1500);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (body) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (!body) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (usedSource) {\n\t\t\tlogDebug?.(`ADSB Daten empfangen \u00FCber ${usedSource}`);\n\t\t}\n\n\t\tconst arr = Array.isArray(body?.aircraft) ? body.aircraft : Array.isArray(body?.ac) ? body.ac : [];\n\n\t\tfor (const item of arr) {\n\t\t\tconst key = clean(\n\t\t\t\titem.hex ||\n\t\t\t\t\titem.icao ||\n\t\t\t\t\titem.flight ||\n\t\t\t\t\titem.call ||\n\t\t\t\t\titem.callsign ||\n\t\t\t\t\t`${item.lat}_${item.lon}_${item.alt_baro || item.alt_geom || ''}`,\n\t\t\t).toLowerCase();\n\n\t\t\tif (!key) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\taircraftByKey[key] = item;\n\t\t}\n\t}\n\n\treturn {\n\t\taircraft: Object.values(aircraftByKey),\n\t};\n}\n\nfunction buildAdsbUrls(config: JetFrameConfig): string[] {\n\tconst anyConfig = config as any;\n\n\tconst customUrl = clean(anyConfig.adsbCustomUrl || anyConfig.customAdsbUrl || '');\n\n\tif (customUrl) {\n\t\treturn [replaceAdsbUrlTokens(customUrl, config)];\n\t}\n\n\tconst airportLat = Number(anyConfig.airport?.lat ?? anyConfig.airportLat ?? config.homeLat);\n\n\tconst airportLon = Number(anyConfig.airport?.lon ?? anyConfig.airportLon ?? config.homeLon);\n\n\tconst airportRadiusNm = Math.max(Number(anyConfig.radiusNm || 0), 1);\n\n\tconst urls = [`https://api.adsb.lol/v2/lat/${airportLat}/lon/${airportLon}/dist/${airportRadiusNm}`];\n\n\tif (anyConfig.overflightEnabled || anyConfig.overflightOnly) {\n\t\tconst homeRadiusNm = Math.max(Number(anyConfig.overflightMaxDistanceNm || 0), 1);\n\n\t\tconst homeUrl =\n\t\t\t`https://api.adsb.lol/v2/lat/${config.homeLat}` + `/lon/${config.homeLon}` + `/dist/${homeRadiusNm}`;\n\n\t\tif (!urls.includes(homeUrl)) {\n\t\t\turls.push(homeUrl);\n\t\t}\n\t}\n\n\treturn urls;\n}\n\nfunction buildAdsbFiFallbackUrl(url: string): string {\n\tconst m = String(url || '').match(/\\/lat\\/([^/]+)\\/lon\\/([^/]+)\\/dist\\/([^/?#]+)/);\n\n\tif (!m) {\n\t\treturn '';\n\t}\n\n\tconst lat = m[1];\n\tconst lon = m[2];\n\tconst dist = m[3];\n\n\tif (!lat || !lon || !dist) {\n\t\treturn '';\n\t}\n\n\treturn `https://opendata.adsb.fi/api/v3/lat/${lat}/lon/${lon}/dist/${dist}`;\n}\n\nfunction replaceAdsbUrlTokens(url: string, config: JetFrameConfig): string {\n\tconst anyConfig = config as any;\n\n\tconst airportLat = String(anyConfig.airport?.lat ?? anyConfig.airportLat ?? config.homeLat);\n\n\tconst airportLon = String(anyConfig.airport?.lon ?? anyConfig.airportLon ?? config.homeLon);\n\n\tconst airportRadiusNm = String(anyConfig.radiusNm || 15);\n\n\tconst overflightRadiusNm = String(anyConfig.overflightMaxDistanceNm || airportRadiusNm);\n\n\treturn String(url || '')\n\t\t.replace(/\\{homeLat\\}/g, String(config.homeLat))\n\t\t.replace(/\\{homeLon\\}/g, String(config.homeLon))\n\t\t.replace(/\\{airportLat\\}/g, airportLat)\n\t\t.replace(/\\{airportLon\\}/g, airportLon)\n\t\t.replace(/\\{radiusNm\\}/g, airportRadiusNm)\n\t\t.replace(/\\{airportRadiusNm\\}/g, airportRadiusNm)\n\t\t.replace(/\\{overflightRadiusNm\\}/g, overflightRadiusNm);\n}\n\n/**\n *\n * @param body\n */\nexport function parseAircraft(body: any): Aircraft[] {\n\tif (!body) {\n\t\treturn [];\n\t}\n\n\tconst arr = Array.isArray(body.aircraft) ? body.aircraft : Array.isArray(body.ac) ? body.ac : [];\n\n\treturn arr\n\t\t.map(\n\t\t\t(a: any): Aircraft => ({\n\t\t\t\thex: clean(a.hex || ''),\n\t\t\t\tcallsign: clean(a.flight || a.call || a.callsign || ''),\n\t\t\t\ttype: clean(a.t || a.type || ''),\n\t\t\t\tregistration: clean(a.r || a.reg || ''),\n\n\t\t\t\tsquawk: clean(a.squawk || a.squawk_code || a.squawkCode || ''),\n\t\t\t\temergency: clean(a.emergency || ''),\n\n\t\t\t\tlat: toNumber(a.lat) ?? 0,\n\t\t\t\tlon: toNumber(a.lon) ?? 0,\n\n\t\t\t\taltFt: parseAltitude(a.alt_baro || a.alt_geom || a.altitude),\n\t\t\t\tspeedKt: toNumber(a.gs || a.spd || a.speed) ?? 0,\n\t\t\t\ttrackDeg: toNumber(a.track || a.trak || a.heading) ?? 0,\n\t\t\t\tverticalRate: toNumber(a.baro_rate || a.geom_rate || a.vsi) ?? 0,\n\n\t\t\t\tseenSec: toNumber(a.seen || a.seen_pos || 0) ?? 999,\n\t\t\t}),\n\t\t)\n\t\t.filter(\n\t\t\t(a: Aircraft) =>\n\t\t\t\tNumber.isFinite(a.lat) &&\n\t\t\t\tNumber.isFinite(a.lon) &&\n\t\t\t\ta.lat !== 0 &&\n\t\t\t\ta.lon !== 0 &&\n\t\t\t\tNumber.isFinite(a.seenSec) &&\n\t\t\t\ta.seenSec <= 90,\n\t\t);\n}\n\nfunction sleep(ms: number): Promise<void> {\n\treturn new Promise(resolve => {\n\t\tsetTimeout(resolve, ms);\n\t});\n}\n\nfunction errorText(e: unknown): string {\n\tif (!e) {\n\t\treturn 'unbekannter Fehler';\n\t}\n\tif (typeof e === 'string') {\n\t\treturn e;\n\t}\n\tif (e instanceof Error) {\n\t\treturn e.message;\n\t}\n\n\ttry {\n\t\treturn JSON.stringify(e);\n\t} catch {\n\t\treturn String(e);\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["n"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var airportNamesDe_exports = {};
|
|
30
|
+
__export(airportNamesDe_exports, {
|
|
31
|
+
loadGermanIataNames: () => loadGermanIataNames
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(airportNamesDe_exports);
|
|
34
|
+
var https = __toESM(require("https"));
|
|
35
|
+
const IATA_WIKI_DE_BASE = "https://de.wikipedia.org/wiki/Liste_der_IATA-Codes/";
|
|
36
|
+
async function loadGermanIataNames(logDebug) {
|
|
37
|
+
const result = {};
|
|
38
|
+
const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
|
|
39
|
+
for (const letter of letters) {
|
|
40
|
+
try {
|
|
41
|
+
const url = IATA_WIKI_DE_BASE + letter;
|
|
42
|
+
logDebug == null ? void 0 : logDebug(`Lade IATA-DE Namen ${letter}...`, 2);
|
|
43
|
+
const html = await downloadText(url);
|
|
44
|
+
const parsed = parseGermanIataPage(html);
|
|
45
|
+
for (const [iata, city] of Object.entries(parsed)) {
|
|
46
|
+
if (!result[iata] && city) {
|
|
47
|
+
result[iata] = city;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
} catch {
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
function parseGermanIataPage(html) {
|
|
56
|
+
const result = {};
|
|
57
|
+
const rows = String(html || "").match(/<tr[\s\S]*?<\/tr>/gi) || [];
|
|
58
|
+
for (const row of rows) {
|
|
59
|
+
const cells = row.match(/<t[dh][\s\S]*?<\/t[dh]>/gi) || [];
|
|
60
|
+
if (cells.length < 4) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const texts = cells.map(cleanWikiText).filter(Boolean);
|
|
64
|
+
const iata = texts.find((t) => /^[A-Z]{3}$/.test(t));
|
|
65
|
+
if (!iata) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const city = normalizeGermanCity(texts[3] || "");
|
|
69
|
+
if (city) {
|
|
70
|
+
result[iata] = city;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
function cleanWikiText(html) {
|
|
76
|
+
return decodeHtml(
|
|
77
|
+
String(html || "").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<sup[\s\S]*?<\/sup>/gi, " ").replace(/<br\s*\/?>/gi, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim()
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
function normalizeGermanCity(value) {
|
|
81
|
+
return String(value || "").replace(/\s*\[[^\]]+\]/g, "").replace(/\s+/g, " ").replace(/^–$/, "").trim();
|
|
82
|
+
}
|
|
83
|
+
function decodeHtml(s) {
|
|
84
|
+
return String(s || "").replace(/&/g, "&").replace(/ /g, " ").replace(/"/g, '"').replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">").replace(/ü/g, "\xFC").replace(/Ü/g, "\xDC").replace(/ö/g, "\xF6").replace(/Ö/g, "\xD6").replace(/ä/g, "\xE4").replace(/Ä/g, "\xC4").replace(/ß/g, "\xDF");
|
|
85
|
+
}
|
|
86
|
+
function downloadText(url, redirects = 0) {
|
|
87
|
+
return new Promise((resolve, reject) => {
|
|
88
|
+
const req = https.get(
|
|
89
|
+
url,
|
|
90
|
+
{
|
|
91
|
+
timeout: 2e4,
|
|
92
|
+
headers: {
|
|
93
|
+
"User-Agent": "Mozilla/5.0 JetFrame",
|
|
94
|
+
Accept: "text/html,text/plain,*/*"
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
(res) => {
|
|
98
|
+
if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
99
|
+
if (redirects >= 5) {
|
|
100
|
+
reject(new Error("Zu viele Redirects"));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const nextUrl = res.headers.location.startsWith("http") ? res.headers.location : new URL(res.headers.location, url).toString();
|
|
104
|
+
resolve(downloadText(nextUrl, redirects + 1));
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (res.statusCode && res.statusCode >= 400) {
|
|
108
|
+
reject(new Error(`HTTP ${res.statusCode}`));
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
let body = "";
|
|
112
|
+
res.setEncoding("utf8");
|
|
113
|
+
res.on("data", (chunk) => {
|
|
114
|
+
body += chunk;
|
|
115
|
+
});
|
|
116
|
+
res.on("end", () => {
|
|
117
|
+
resolve(String(body || "").trim());
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
req.on("timeout", () => {
|
|
122
|
+
req.destroy(new Error("Download Timeout"));
|
|
123
|
+
});
|
|
124
|
+
req.on("error", reject);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
128
|
+
0 && (module.exports = {
|
|
129
|
+
loadGermanIataNames
|
|
130
|
+
});
|
|
131
|
+
//# sourceMappingURL=airportNamesDe.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lib/airportNamesDe.ts"],
|
|
4
|
+
"sourcesContent": ["import * as https from 'https';\n\nconst IATA_WIKI_DE_BASE = 'https://de.wikipedia.org/wiki/Liste_der_IATA-Codes/';\n\nexport async function loadGermanIataNames(\n\tlogDebug?: (msg: string, level?: number) => void,\n): Promise<Record<string, string>> {\n\tconst result: Record<string, string> = {};\n\n\tconst letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');\n\n\tfor (const letter of letters) {\n\t\ttry {\n\t\t\tconst url = IATA_WIKI_DE_BASE + letter;\n\n\t\t\tlogDebug?.(`Lade IATA-DE Namen ${letter}...`, 2);\n\n\t\t\tconst html = await downloadText(url);\n\n\t\t\tconst parsed = parseGermanIataPage(html);\n\n\t\t\tfor (const [iata, city] of Object.entries(parsed)) {\n\t\t\t\tif (!result[iata] && city) {\n\t\t\t\t\tresult[iata] = city;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// ignore single page\n\t\t}\n\t}\n\n\treturn result;\n}\n\nfunction parseGermanIataPage(html: string): Record<string, string> {\n\tconst result: Record<string, string> = {};\n\n\tconst rows = String(html || '').match(/<tr[\\s\\S]*?<\\/tr>/gi) || [];\n\n\tfor (const row of rows) {\n\t\tconst cells = row.match(/<t[dh][\\s\\S]*?<\\/t[dh]>/gi) || [];\n\n\t\tif (cells.length < 4) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst texts = cells.map(cleanWikiText).filter(Boolean);\n\n\t\tconst iata = texts.find(t => /^[A-Z]{3}$/.test(t));\n\n\t\tif (!iata) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Typischer Aufbau:\n\t\t// IATA | ICAO | Flughafen | Ort | Land\n\n\t\tconst city = normalizeGermanCity(texts[3] || '');\n\n\t\tif (city) {\n\t\t\tresult[iata] = city;\n\t\t}\n\t}\n\n\treturn result;\n}\n\nfunction cleanWikiText(html: string): string {\n\treturn decodeHtml(\n\t\tString(html || '')\n\t\t\t.replace(/<style[\\s\\S]*?<\\/style>/gi, ' ')\n\t\t\t.replace(/<script[\\s\\S]*?<\\/script>/gi, ' ')\n\t\t\t.replace(/<sup[\\s\\S]*?<\\/sup>/gi, ' ')\n\t\t\t.replace(/<br\\s*\\/?>/gi, ' ')\n\t\t\t.replace(/<[^>]+>/g, ' ')\n\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t.trim(),\n\t);\n}\n\nfunction normalizeGermanCity(value: string): string {\n\treturn String(value || '')\n\t\t.replace(/\\s*\\[[^\\]]+\\]/g, '')\n\t\t.replace(/\\s+/g, ' ')\n\t\t.replace(/^\u2013$/, '')\n\t\t.trim();\n}\n\nfunction decodeHtml(s: string): string {\n\treturn String(s || '')\n\t\t.replace(/&/g, '&')\n\t\t.replace(/ /g, ' ')\n\t\t.replace(/"/g, '\"')\n\t\t.replace(/'/g, \"'\")\n\t\t.replace(/</g, '<')\n\t\t.replace(/>/g, '>')\n\t\t.replace(/ü/g, '\u00FC')\n\t\t.replace(/Ü/g, '\u00DC')\n\t\t.replace(/ö/g, '\u00F6')\n\t\t.replace(/Ö/g, '\u00D6')\n\t\t.replace(/ä/g, '\u00E4')\n\t\t.replace(/Ä/g, '\u00C4')\n\t\t.replace(/ß/g, '\u00DF');\n}\n\nfunction downloadText(url: string, redirects = 0): Promise<string> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst req = https.get(\n\t\t\turl,\n\t\t\t{\n\t\t\t\ttimeout: 20000,\n\t\t\t\theaders: {\n\t\t\t\t\t'User-Agent': 'Mozilla/5.0 JetFrame',\n\t\t\t\t\tAccept: 'text/html,text/plain,*/*',\n\t\t\t\t},\n\t\t\t},\n\t\t\tres => {\n\t\t\t\tif (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {\n\t\t\t\t\tif (redirects >= 5) {\n\t\t\t\t\t\treject(new Error('Zu viele Redirects'));\n\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst nextUrl = res.headers.location.startsWith('http')\n\t\t\t\t\t\t? res.headers.location\n\t\t\t\t\t\t: new URL(res.headers.location, url).toString();\n\n\t\t\t\t\tresolve(downloadText(nextUrl, redirects + 1));\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (res.statusCode && res.statusCode >= 400) {\n\t\t\t\t\treject(new Error(`HTTP ${res.statusCode}`));\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet body = '';\n\n\t\t\t\tres.setEncoding('utf8');\n\n\t\t\t\tres.on('data', chunk => {\n\t\t\t\t\tbody += chunk;\n\t\t\t\t});\n\n\t\t\t\tres.on('end', () => {\n\t\t\t\t\tresolve(String(body || '').trim());\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t\treq.on('timeout', () => {\n\t\t\treq.destroy(new Error('Download Timeout'));\n\t\t});\n\n\t\treq.on('error', reject);\n\t});\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|