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.
Files changed (107) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +357 -0
  3. package/admin/SF-Pro.ttf +0 -0
  4. package/admin/admin.d.ts +65 -0
  5. package/admin/frame.html +982 -0
  6. package/admin/frame.html.bak-aircraft-card-real-row-20260518-1608 +1236 -0
  7. package/admin/frame.html.bak-aircraft-card-structure-20260518-1517 +1236 -0
  8. package/admin/frame.html.bak-aircraft-logo-id-fix-20260518-1639 +1239 -0
  9. package/admin/frame.html.bak-shortcut-test +1236 -0
  10. package/admin/frame.html.bak-tablet-class-20260518-1729 +1239 -0
  11. package/admin/heatmap.html +216 -0
  12. package/admin/index.html +268 -0
  13. package/admin/index_m.html +1749 -0
  14. package/admin/jetframe.css +1260 -0
  15. package/admin/jetframe.css.bak-airbus-landscape-fix +4630 -0
  16. package/admin/jetframe.css.bak-aircraft-card-clean-equal-20260518-1438 +4899 -0
  17. package/admin/jetframe.css.bak-aircraft-card-real-row-20260518-1608 +4814 -0
  18. package/admin/jetframe.css.bak-aircraft-card-row-left-20260518-1525 +4604 -0
  19. package/admin/jetframe.css.bak-aircraft-card-slim-equal-20260518-1446 +4647 -0
  20. package/admin/jetframe.css.bak-aircraft-card-structure-20260518-1517 +4646 -0
  21. package/admin/jetframe.css.bak-aircraft-inline-final-20260518-1527 +4654 -0
  22. package/admin/jetframe.css.bak-aircraft-row-compact-fix-20260518-1639 +4763 -0
  23. package/admin/jetframe.css.bak-before-aircrafttype-purge +4818 -0
  24. package/admin/jetframe.css.bak-before-cleanup +4670 -0
  25. package/admin/jetframe.css.bak-before-remove-tablet-only-20260518-1711 +4896 -0
  26. package/admin/jetframe.css.bak-before-tablet-layout-rework-20260518-1650 +4914 -0
  27. package/admin/jetframe.css.bak-clean-duplicate-fonts-20260518-1340 +4975 -0
  28. package/admin/jetframe.css.bak-clean-old-index-fix-20260518-1937 +5167 -0
  29. package/admin/jetframe.css.bak-hardleft-airbus +4751 -0
  30. package/admin/jetframe.css.bak-index-iphone-landscape-20260518-1931 +5030 -0
  31. package/admin/jetframe.css.bak-index-landscape-final-20260518-1941 +5167 -0
  32. package/admin/jetframe.css.bak-index-landscape-real-20260518-1936 +5186 -0
  33. package/admin/jetframe.css.bak-landscape-compact-jumbo-bold-20260518-1343 +4802 -0
  34. package/admin/jetframe.css.bak-logo-align-final +4551 -0
  35. package/admin/jetframe.css.bak-logo-final2 +4551 -0
  36. package/admin/jetframe.css.bak-narrowbody-font-fix +4992 -0
  37. package/admin/jetframe.css.bak-nuke-airbus-align +4790 -0
  38. package/admin/jetframe.css.bak-pill-balance-20260518-1603 +4773 -0
  39. package/admin/jetframe.css.bak-pill-balance-fix +4910 -0
  40. package/admin/jetframe.css.bak-radar-fix-fonts +4710 -0
  41. package/admin/jetframe.css.bak-shortcut-test +4899 -0
  42. package/admin/jetframe.css.bak-smaller-aircraft-card-fonts-20260518-1345 +4897 -0
  43. package/admin/jetframe.css.bak-tablet-fix-real-20260518-1748 +4945 -0
  44. package/admin/jetframe.css.bak-tablet-fullscreen-fix-20260518-1804 +4972 -0
  45. package/admin/jetframe.css.bak-tablet-landscape-layout-20260518-1645 +4802 -0
  46. package/admin/jetframe.css.bak-tablet-layout-final-20260518-1839 +4802 -0
  47. package/admin/jetframe.css.bak-tablet-layout-v3-20260518-1729 +4802 -0
  48. package/admin/jetframe.css.bak-tablet-layout-v4-20260518-1801 +4957 -0
  49. package/admin/jetframe.css.bak-tablet-layout-v5-20260518-1843 +4970 -0
  50. package/admin/jetframe.css.bak-tablet-layout-v6-20260518-1848 +4958 -0
  51. package/admin/jetframe.css.bak-tablet-layout-v7-20260518-1909 +4985 -0
  52. package/admin/jetframe.css.bak-tablet-only-landscape-v2-20260518-1707 +4802 -0
  53. package/admin/jetframe.css.bak-tablet-pages-final-20260519-1857 +5188 -0
  54. package/admin/jetframe.css.bak-tablet-pages-final-20260519-1859 +5347 -0
  55. package/admin/jetframe.css.bak-tablet-pages-v2-20260519-190807 +5349 -0
  56. package/admin/jetframe.css.bak-typography-align-final +4818 -0
  57. package/admin/jetframe.png +0 -0
  58. package/admin/manifest.webmanifest +15 -0
  59. package/admin/src/app.tsx +58 -0
  60. package/admin/src/components/settings.tsx +97 -0
  61. package/admin/src/i18n/de.json +11 -0
  62. package/admin/src/i18n/en.json +11 -0
  63. package/admin/src/i18n/es.json +11 -0
  64. package/admin/src/i18n/fr.json +11 -0
  65. package/admin/src/i18n/i18n.d.ts +28 -0
  66. package/admin/src/i18n/it.json +11 -0
  67. package/admin/src/i18n/nl.json +11 -0
  68. package/admin/src/i18n/pl.json +11 -0
  69. package/admin/src/i18n/pt.json +11 -0
  70. package/admin/src/i18n/ru.json +11 -0
  71. package/admin/src/i18n/uk.json +11 -0
  72. package/admin/src/i18n/zh-cn.json +11 -0
  73. package/admin/src/index.tsx +25 -0
  74. package/admin/stats.html +228 -0
  75. package/admin/style.css +32 -0
  76. package/admin/tsconfig.json +11 -0
  77. package/admin/words.js +46 -0
  78. package/build/lib/adsb.js +218 -0
  79. package/build/lib/adsb.js.map +7 -0
  80. package/build/lib/airportNamesDe.js +131 -0
  81. package/build/lib/airportNamesDe.js.map +7 -0
  82. package/build/lib/airports.js +281 -0
  83. package/build/lib/airports.js.map +7 -0
  84. package/build/lib/classify.js +339 -0
  85. package/build/lib/classify.js.map +7 -0
  86. package/build/lib/config.js +103 -0
  87. package/build/lib/config.js.map +7 -0
  88. package/build/lib/flightInfo.js +1409 -0
  89. package/build/lib/flightInfo.js.map +7 -0
  90. package/build/lib/geo.js +84 -0
  91. package/build/lib/geo.js.map +7 -0
  92. package/build/lib/images.js +422 -0
  93. package/build/lib/images.js.map +7 -0
  94. package/build/lib/specialLiveries.js +342 -0
  95. package/build/lib/specialLiveries.js.map +7 -0
  96. package/build/lib/states.js +971 -0
  97. package/build/lib/states.js.map +7 -0
  98. package/build/lib/staticFiles.js +73 -0
  99. package/build/lib/staticFiles.js.map +7 -0
  100. package/build/lib/types.js +17 -0
  101. package/build/lib/types.js.map +7 -0
  102. package/build/lib/visConfig.js +52 -0
  103. package/build/lib/visConfig.js.map +7 -0
  104. package/build/main.js +1454 -0
  105. package/build/main.js.map +7 -0
  106. package/io-package.json +169 -0
  107. package/package.json +82 -0
@@ -0,0 +1,342 @@
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 specialLiveries_exports = {};
30
+ __export(specialLiveries_exports, {
31
+ parseSpecialLiveriesHtml: () => parseSpecialLiveriesHtml,
32
+ updateSpecialLiveries: () => updateSpecialLiveries
33
+ });
34
+ module.exports = __toCommonJS(specialLiveries_exports);
35
+ var https = __toESM(require("https"));
36
+ var http = __toESM(require("http"));
37
+ const SPECIAL_LIVERIES_URL = "https://airportwebcams.net/special-liveries/";
38
+ async function updateSpecialLiveries(adapter, logDebug, logWarn) {
39
+ try {
40
+ logDebug == null ? void 0 : logDebug("Lade Special-Liveries Datenbank...", 1);
41
+ const html = await downloadText(SPECIAL_LIVERIES_URL);
42
+ logDebug == null ? void 0 : logDebug(`Special-Liveries HTML L\xE4nge: ${html.length}`, 1);
43
+ const liveries = parseSpecialLiveriesHtml(html);
44
+ logDebug == null ? void 0 : logDebug(`Special-Liveries parsed: ${liveries.length}`, 1);
45
+ await adapter.setForeignStateAsync(`${adapter.namespace}.specialLiveries`, JSON.stringify(liveries), true);
46
+ await adapter.setForeignStateAsync(
47
+ `${adapter.namespace}.specialLiveriesLastUpdate`,
48
+ (/* @__PURE__ */ new Date()).toISOString(),
49
+ true
50
+ );
51
+ logDebug == null ? void 0 : logDebug(`Special-Liveries DB aktualisiert: ${liveries.length} Eintr\xE4ge`, 1);
52
+ } catch (e) {
53
+ logWarn == null ? void 0 : logWarn(`Special-Liveries DB Fehler: ${errorText(e)}`);
54
+ }
55
+ }
56
+ function parseSpecialLiveriesHtml(html) {
57
+ const fromTable = parseFromHtmlTable(html);
58
+ if (fromTable.length) {
59
+ return uniqueAndSort(fromTable);
60
+ }
61
+ const text = htmlToText(html);
62
+ return uniqueAndSort(parseFromPlainText(text));
63
+ }
64
+ function parseFromHtmlTable(html) {
65
+ const rows = extractTableRows(html);
66
+ const result = [];
67
+ for (const row of rows) {
68
+ const cells = extractTableCells(row);
69
+ if (cells.length < 5) {
70
+ continue;
71
+ }
72
+ const item = buildEntry(cells[0], cells[1], cells[2], cells[3], cells.slice(4).join(" "));
73
+ if (item) {
74
+ result.push(item);
75
+ }
76
+ }
77
+ return result;
78
+ }
79
+ function parseFromPlainText(text) {
80
+ const result = [];
81
+ const startMarker = "Country Airline Aircraft Type Registration Description";
82
+ const start = text.indexOf(startMarker);
83
+ if (start < 0) {
84
+ return [];
85
+ }
86
+ const data = text.substring(start + startMarker.length);
87
+ const regRe = /\b([A-Z0-9]{1,3}-[A-Z0-9]{3,5}|[A-Z]{1,2}\d{3,5}[A-Z]?|[A-Z]{2}-[A-Z0-9]{3}|N\d{1,5}[A-Z]{0,2}|JA\d{3,4}[A-Z]|B-\d{4}|C-[A-Z0-9]{4}|VH-[A-Z0-9]{3}|OE-[A-Z0-9]{3}|OO-[A-Z0-9]{3}|D-[A-Z0-9]{4})\b/g;
88
+ let m;
89
+ const hits = [];
90
+ while ((m = regRe.exec(data)) !== null) {
91
+ hits.push({
92
+ reg: cleanRegistration(m[1]),
93
+ index: m.index
94
+ });
95
+ }
96
+ for (let i = 0; i < hits.length; i++) {
97
+ const hit = hits[i];
98
+ const next = hits[i + 1];
99
+ const beforeStart = Math.max(0, hit.index - 140);
100
+ const afterEnd = next ? next.index : Math.min(data.length, hit.index + 180);
101
+ const before = clean(data.substring(beforeStart, hit.index));
102
+ const after = clean(data.substring(hit.index + hit.reg.length, afterEnd));
103
+ const parts = before.split(" ");
104
+ if (parts.length < 3) {
105
+ continue;
106
+ }
107
+ const country = parts[0];
108
+ const airline = parts.slice(1, -2).join(" ");
109
+ const aircraft = parts.slice(-2).join(" ");
110
+ const description = after.replace(/^[-–—: ]+/, "").trim();
111
+ const item = buildEntry(country, airline, aircraft, hit.reg, description);
112
+ if (item) {
113
+ result.push(item);
114
+ }
115
+ }
116
+ return result;
117
+ }
118
+ function buildEntry(countryRaw, airlineRaw, aircraftRaw, registrationRaw, descriptionRaw) {
119
+ const country = clean(countryRaw);
120
+ const airline = clean(airlineRaw);
121
+ const aircraft = clean(aircraftRaw);
122
+ const registration = cleanRegistration(registrationRaw);
123
+ const description = clean(descriptionRaw);
124
+ if (!isRegistration(registration)) {
125
+ return null;
126
+ }
127
+ if (!airline || !description) {
128
+ return null;
129
+ }
130
+ return {
131
+ registration,
132
+ country,
133
+ airline,
134
+ aircraft,
135
+ type: guessType(description),
136
+ title: guessTitle(description),
137
+ description,
138
+ emoji: guessEmoji(description),
139
+ source: "airportwebcams"
140
+ };
141
+ }
142
+ function uniqueAndSort(items) {
143
+ const unique = [];
144
+ const seen = /* @__PURE__ */ new Set();
145
+ for (const item of items) {
146
+ if (seen.has(item.registration)) {
147
+ continue;
148
+ }
149
+ seen.add(item.registration);
150
+ unique.push(item);
151
+ }
152
+ unique.sort((a, b) => a.registration.localeCompare(b.registration));
153
+ return unique;
154
+ }
155
+ function extractTableRows(html) {
156
+ const rows = [];
157
+ const re = /<tr[\s\S]*?<\/tr>/gi;
158
+ let m;
159
+ while ((m = re.exec(html)) !== null) {
160
+ rows.push(m[0]);
161
+ }
162
+ return rows;
163
+ }
164
+ function extractTableCells(row) {
165
+ const cells = [];
166
+ const re = /<t[dh][^>]*>([\s\S]*?)<\/t[dh]>/gi;
167
+ let m;
168
+ while ((m = re.exec(row)) !== null) {
169
+ cells.push(htmlToText(m[1]));
170
+ }
171
+ return cells;
172
+ }
173
+ function htmlToText(html) {
174
+ return decodeHtml(
175
+ String(html || "").replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<br\s*\/?>/gi, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim()
176
+ );
177
+ }
178
+ function decodeHtml(s) {
179
+ return String(s || "").replace(/&amp;/g, "&").replace(/&nbsp;/g, " ").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&uuml;/g, "\xFC").replace(/&ouml;/g, "\xF6").replace(/&auml;/g, "\xE4").replace(/&Uuml;/g, "\xDC").replace(/&Ouml;/g, "\xD6").replace(/&Auml;/g, "\xC4").replace(/&szlig;/g, "\xDF");
180
+ }
181
+ function clean(v) {
182
+ return String(v || "").replace(/\s+/g, " ").trim();
183
+ }
184
+ function cleanRegistration(v) {
185
+ return clean(v).toUpperCase().replace(/[^A-Z0-9-]/g, "");
186
+ }
187
+ function isRegistration(v) {
188
+ if (!v) {
189
+ return false;
190
+ }
191
+ if (v.length < 4 || v.length > 8) {
192
+ return false;
193
+ }
194
+ if (!/[A-Z]/.test(v)) {
195
+ return false;
196
+ }
197
+ if (!/[0-9A-Z]/.test(v)) {
198
+ return false;
199
+ }
200
+ return true;
201
+ }
202
+ function guessTitle(description) {
203
+ const d = clean(description);
204
+ return d.replace(/\s+Livery$/i, "").replace(/\s+Special Livery$/i, "").trim();
205
+ }
206
+ function guessType(description) {
207
+ const d = description.toLowerCase();
208
+ if (d.includes("star alliance")) {
209
+ return "Alliance Livery";
210
+ }
211
+ if (d.includes("oneworld")) {
212
+ return "Alliance Livery";
213
+ }
214
+ if (d.includes("skyteam")) {
215
+ return "Alliance Livery";
216
+ }
217
+ if (d.includes("retro")) {
218
+ return "Retro Livery";
219
+ }
220
+ if (d.includes("football") || d.includes("fanhansa") || d.includes("real madrid")) {
221
+ return "Sports Livery";
222
+ }
223
+ if (d.includes("pokemon") || d.includes("pikachu")) {
224
+ return "Pokemon Livery";
225
+ }
226
+ if (d.includes("star wars")) {
227
+ return "Movie Livery";
228
+ }
229
+ if (d.includes("anniversary") || d.includes("years") || d.includes("100")) {
230
+ return "Anniversary Livery";
231
+ }
232
+ if (d.includes("disney")) {
233
+ return "Disney Livery";
234
+ }
235
+ if (d.includes("sustainable") || d.includes("green")) {
236
+ return "Eco Livery";
237
+ }
238
+ return "Special Livery";
239
+ }
240
+ function guessEmoji(description) {
241
+ const d = description.toLowerCase();
242
+ if (d.includes("star alliance") || d.includes("oneworld") || d.includes("skyteam")) {
243
+ return "\u2B50";
244
+ }
245
+ if (d.includes("retro")) {
246
+ return "\u{1F3A8}";
247
+ }
248
+ if (d.includes("football") || d.includes("fanhansa") || d.includes("real madrid")) {
249
+ return "\u26BD";
250
+ }
251
+ if (d.includes("pokemon") || d.includes("pikachu")) {
252
+ return "\u26A1";
253
+ }
254
+ if (d.includes("star wars")) {
255
+ return "\u{1F916}";
256
+ }
257
+ if (d.includes("anniversary") || d.includes("years") || d.includes("100")) {
258
+ return "\u{1F389}";
259
+ }
260
+ if (d.includes("disney")) {
261
+ return "\u{1F3F0}";
262
+ }
263
+ if (d.includes("sustainable") || d.includes("green")) {
264
+ return "\u{1F331}";
265
+ }
266
+ if (d.includes("tintin")) {
267
+ return "\u{1F680}";
268
+ }
269
+ if (d.includes("retro")) {
270
+ return "\u{1F6E9}\uFE0F";
271
+ }
272
+ return "\u{1F3A8}";
273
+ }
274
+ function downloadText(url, redirects = 0) {
275
+ return new Promise((resolve, reject) => {
276
+ const client = url.startsWith("https") ? https : http;
277
+ const req = client.get(
278
+ url,
279
+ {
280
+ timeout: 25e3,
281
+ headers: {
282
+ "User-Agent": "Mozilla/5.0 JetFrame",
283
+ Accept: "text/html,application/xhtml+xml,text/plain,*/*"
284
+ }
285
+ },
286
+ (res) => {
287
+ if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
288
+ if (redirects >= 5) {
289
+ reject(new Error("Zu viele Redirects bei Special-Liveries"));
290
+ return;
291
+ }
292
+ const nextUrl = res.headers.location.startsWith("http") ? res.headers.location : new URL(res.headers.location, url).toString();
293
+ resolve(downloadText(nextUrl, redirects + 1));
294
+ return;
295
+ }
296
+ if (res.statusCode && res.statusCode >= 400) {
297
+ reject(new Error(`HTTP ${res.statusCode}`));
298
+ return;
299
+ }
300
+ let body = "";
301
+ res.setEncoding("utf8");
302
+ res.on("data", (chunk) => {
303
+ body += chunk;
304
+ });
305
+ res.on("end", () => {
306
+ const text = String(body || "").trim();
307
+ if (!text) {
308
+ reject(new Error("Special-Liveries HTML leer"));
309
+ return;
310
+ }
311
+ resolve(text);
312
+ });
313
+ }
314
+ );
315
+ req.on("timeout", () => {
316
+ req.destroy(new Error("Special-Liveries Download Timeout"));
317
+ });
318
+ req.on("error", reject);
319
+ });
320
+ }
321
+ function errorText(e) {
322
+ if (!e) {
323
+ return "unbekannter Fehler";
324
+ }
325
+ if (typeof e === "string") {
326
+ return e;
327
+ }
328
+ if (e instanceof Error) {
329
+ return e.message;
330
+ }
331
+ try {
332
+ return JSON.stringify(e);
333
+ } catch {
334
+ return String(e);
335
+ }
336
+ }
337
+ // Annotate the CommonJS export names for ESM import in node:
338
+ 0 && (module.exports = {
339
+ parseSpecialLiveriesHtml,
340
+ updateSpecialLiveries
341
+ });
342
+ //# sourceMappingURL=specialLiveries.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/lib/specialLiveries.ts"],
4
+ "sourcesContent": ["import type { AdapterLike } from './types';\nimport * as https from 'https';\nimport * as http from 'http';\n\n/**\n *\n */\nexport interface SpecialLiveryEntry {\n\t/**\n\t *\n\t */\n\tregistration: string;\n\t/**\n\t *\n\t */\n\tcountry: string;\n\t/**\n\t *\n\t */\n\tairline: string;\n\t/**\n\t *\n\t */\n\taircraft: string;\n\t/**\n\t *\n\t */\n\ttype: string;\n\t/**\n\t *\n\t */\n\ttitle: string;\n\t/**\n\t *\n\t */\n\tdescription: string;\n\t/**\n\t *\n\t */\n\temoji: string;\n\t/**\n\t *\n\t */\n\tsource: string;\n}\n\nconst SPECIAL_LIVERIES_URL = 'https://airportwebcams.net/special-liveries/';\n\n/**\n *\n */\nexport async function updateSpecialLiveries(\n\tadapter: AdapterLike,\n\tlogDebug?: (msg: string, level?: number) => void,\n\tlogWarn?: (msg: string) => void,\n): Promise<void> {\n\ttry {\n\t\tlogDebug?.('Lade Special-Liveries Datenbank...', 1);\n\n\t\tconst html = await downloadText(SPECIAL_LIVERIES_URL);\n\t\tlogDebug?.(`Special-Liveries HTML L\u00E4nge: ${html.length}`, 1);\n\n\t\tconst liveries = parseSpecialLiveriesHtml(html);\n\t\tlogDebug?.(`Special-Liveries parsed: ${liveries.length}`, 1);\n\n\t\tawait adapter.setForeignStateAsync(`${adapter.namespace}.specialLiveries`, JSON.stringify(liveries), true);\n\n\t\tawait adapter.setForeignStateAsync(\n\t\t\t`${adapter.namespace}.specialLiveriesLastUpdate`,\n\t\t\tnew Date().toISOString(),\n\t\t\ttrue,\n\t\t);\n\n\t\tlogDebug?.(`Special-Liveries DB aktualisiert: ${liveries.length} Eintr\u00E4ge`, 1);\n\t} catch (e) {\n\t\tlogWarn?.(`Special-Liveries DB Fehler: ${errorText(e)}`);\n\t}\n}\n\n/**\n *\n */\nexport function parseSpecialLiveriesHtml(html: string): SpecialLiveryEntry[] {\n\tconst fromTable = parseFromHtmlTable(html);\n\n\tif (fromTable.length) {\n\t\treturn uniqueAndSort(fromTable);\n\t}\n\n\tconst text = htmlToText(html);\n\n\treturn uniqueAndSort(parseFromPlainText(text));\n}\n\nfunction parseFromHtmlTable(html: string): SpecialLiveryEntry[] {\n\tconst rows = extractTableRows(html);\n\tconst result: SpecialLiveryEntry[] = [];\n\n\tfor (const row of rows) {\n\t\tconst cells = extractTableCells(row);\n\n\t\tif (cells.length < 5) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst item = buildEntry(cells[0], cells[1], cells[2], cells[3], cells.slice(4).join(' '));\n\n\t\tif (item) {\n\t\t\tresult.push(item);\n\t\t}\n\t}\n\n\treturn result;\n}\n\nfunction parseFromPlainText(text: string): SpecialLiveryEntry[] {\n\tconst result: SpecialLiveryEntry[] = [];\n\n\tconst startMarker = 'Country Airline Aircraft Type Registration Description';\n\tconst start = text.indexOf(startMarker);\n\n\tif (start < 0) {\n\t\treturn [];\n\t}\n\n\tconst data = text.substring(start + startMarker.length);\n\n\tconst regRe =\n\t\t/\\b([A-Z0-9]{1,3}-[A-Z0-9]{3,5}|[A-Z]{1,2}\\d{3,5}[A-Z]?|[A-Z]{2}-[A-Z0-9]{3}|N\\d{1,5}[A-Z]{0,2}|JA\\d{3,4}[A-Z]|B-\\d{4}|C-[A-Z0-9]{4}|VH-[A-Z0-9]{3}|OE-[A-Z0-9]{3}|OO-[A-Z0-9]{3}|D-[A-Z0-9]{4})\\b/g;\n\n\tlet m: RegExpExecArray | null;\n\tconst hits: Array<{ reg: string; index: number }> = [];\n\n\twhile ((m = regRe.exec(data)) !== null) {\n\t\thits.push({\n\t\t\treg: cleanRegistration(m[1]),\n\t\t\tindex: m.index,\n\t\t});\n\t}\n\n\tfor (let i = 0; i < hits.length; i++) {\n\t\tconst hit = hits[i];\n\t\tconst next = hits[i + 1];\n\n\t\tconst beforeStart = Math.max(0, hit.index - 140);\n\t\tconst afterEnd = next ? next.index : Math.min(data.length, hit.index + 180);\n\n\t\tconst before = clean(data.substring(beforeStart, hit.index));\n\t\tconst after = clean(data.substring(hit.index + hit.reg.length, afterEnd));\n\n\t\tconst parts = before.split(' ');\n\n\t\tif (parts.length < 3) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst country = parts[0];\n\t\tconst airline = parts.slice(1, -2).join(' ');\n\t\tconst aircraft = parts.slice(-2).join(' ');\n\n\t\tconst description = after.replace(/^[-\u2013\u2014: ]+/, '').trim();\n\n\t\tconst item = buildEntry(country, airline, aircraft, hit.reg, description);\n\n\t\tif (item) {\n\t\t\tresult.push(item);\n\t\t}\n\t}\n\n\treturn result;\n}\n\nfunction buildEntry(\n\tcountryRaw: unknown,\n\tairlineRaw: unknown,\n\taircraftRaw: unknown,\n\tregistrationRaw: unknown,\n\tdescriptionRaw: unknown,\n): SpecialLiveryEntry | null {\n\tconst country = clean(countryRaw);\n\tconst airline = clean(airlineRaw);\n\tconst aircraft = clean(aircraftRaw);\n\tconst registration = cleanRegistration(registrationRaw);\n\tconst description = clean(descriptionRaw);\n\n\tif (!isRegistration(registration)) {\n\t\treturn null;\n\t}\n\tif (!airline || !description) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tregistration,\n\t\tcountry,\n\t\tairline,\n\t\taircraft,\n\t\ttype: guessType(description),\n\t\ttitle: guessTitle(description),\n\t\tdescription,\n\t\temoji: guessEmoji(description),\n\t\tsource: 'airportwebcams',\n\t};\n}\n\nfunction uniqueAndSort(items: SpecialLiveryEntry[]): SpecialLiveryEntry[] {\n\tconst unique: SpecialLiveryEntry[] = [];\n\tconst seen = new Set<string>();\n\n\tfor (const item of items) {\n\t\tif (seen.has(item.registration)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tseen.add(item.registration);\n\t\tunique.push(item);\n\t}\n\n\tunique.sort((a, b) => a.registration.localeCompare(b.registration));\n\n\treturn unique;\n}\n\nfunction extractTableRows(html: string): string[] {\n\tconst rows: string[] = [];\n\tconst re = /<tr[\\s\\S]*?<\\/tr>/gi;\n\n\tlet m: RegExpExecArray | null;\n\n\twhile ((m = re.exec(html)) !== null) {\n\t\trows.push(m[0]);\n\t}\n\n\treturn rows;\n}\n\nfunction extractTableCells(row: string): string[] {\n\tconst cells: string[] = [];\n\tconst re = /<t[dh][^>]*>([\\s\\S]*?)<\\/t[dh]>/gi;\n\n\tlet m: RegExpExecArray | null;\n\n\twhile ((m = re.exec(row)) !== null) {\n\t\tcells.push(htmlToText(m[1]));\n\t}\n\n\treturn cells;\n}\n\nfunction htmlToText(html: string): string {\n\treturn decodeHtml(\n\t\tString(html || '')\n\t\t\t.replace(/<script[\\s\\S]*?<\\/script>/gi, ' ')\n\t\t\t.replace(/<style[\\s\\S]*?<\\/style>/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 decodeHtml(s: string): string {\n\treturn String(s || '')\n\t\t.replace(/&amp;/g, '&')\n\t\t.replace(/&nbsp;/g, ' ')\n\t\t.replace(/&quot;/g, '\"')\n\t\t.replace(/&#39;/g, \"'\")\n\t\t.replace(/&lt;/g, '<')\n\t\t.replace(/&gt;/g, '>')\n\t\t.replace(/&uuml;/g, '\u00FC')\n\t\t.replace(/&ouml;/g, '\u00F6')\n\t\t.replace(/&auml;/g, '\u00E4')\n\t\t.replace(/&Uuml;/g, '\u00DC')\n\t\t.replace(/&Ouml;/g, '\u00D6')\n\t\t.replace(/&Auml;/g, '\u00C4')\n\t\t.replace(/&szlig;/g, '\u00DF');\n}\n\nfunction clean(v: unknown): string {\n\treturn String(v || '')\n\t\t.replace(/\\s+/g, ' ')\n\t\t.trim();\n}\n\nfunction cleanRegistration(v: unknown): string {\n\treturn clean(v)\n\t\t.toUpperCase()\n\t\t.replace(/[^A-Z0-9-]/g, '');\n}\n\nfunction isRegistration(v: string): boolean {\n\tif (!v) {\n\t\treturn false;\n\t}\n\tif (v.length < 4 || v.length > 8) {\n\t\treturn false;\n\t}\n\tif (!/[A-Z]/.test(v)) {\n\t\treturn false;\n\t}\n\tif (!/[0-9A-Z]/.test(v)) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nfunction guessTitle(description: string): string {\n\tconst d = clean(description);\n\n\treturn d\n\t\t.replace(/\\s+Livery$/i, '')\n\t\t.replace(/\\s+Special Livery$/i, '')\n\t\t.trim();\n}\n\nfunction guessType(description: string): string {\n\tconst d = description.toLowerCase();\n\n\tif (d.includes('star alliance')) {\n\t\treturn 'Alliance Livery';\n\t}\n\tif (d.includes('oneworld')) {\n\t\treturn 'Alliance Livery';\n\t}\n\tif (d.includes('skyteam')) {\n\t\treturn 'Alliance Livery';\n\t}\n\tif (d.includes('retro')) {\n\t\treturn 'Retro Livery';\n\t}\n\tif (d.includes('football') || d.includes('fanhansa') || d.includes('real madrid')) {\n\t\treturn 'Sports Livery';\n\t}\n\tif (d.includes('pokemon') || d.includes('pikachu')) {\n\t\treturn 'Pokemon Livery';\n\t}\n\tif (d.includes('star wars')) {\n\t\treturn 'Movie Livery';\n\t}\n\tif (d.includes('anniversary') || d.includes('years') || d.includes('100')) {\n\t\treturn 'Anniversary Livery';\n\t}\n\tif (d.includes('disney')) {\n\t\treturn 'Disney Livery';\n\t}\n\tif (d.includes('sustainable') || d.includes('green')) {\n\t\treturn 'Eco Livery';\n\t}\n\n\treturn 'Special Livery';\n}\n\nfunction guessEmoji(description: string): string {\n\tconst d = description.toLowerCase();\n\n\tif (d.includes('star alliance') || d.includes('oneworld') || d.includes('skyteam')) {\n\t\treturn '\u2B50';\n\t}\n\tif (d.includes('retro')) {\n\t\treturn '\uD83C\uDFA8';\n\t}\n\tif (d.includes('football') || d.includes('fanhansa') || d.includes('real madrid')) {\n\t\treturn '\u26BD';\n\t}\n\tif (d.includes('pokemon') || d.includes('pikachu')) {\n\t\treturn '\u26A1';\n\t}\n\tif (d.includes('star wars')) {\n\t\treturn '\uD83E\uDD16';\n\t}\n\tif (d.includes('anniversary') || d.includes('years') || d.includes('100')) {\n\t\treturn '\uD83C\uDF89';\n\t}\n\tif (d.includes('disney')) {\n\t\treturn '\uD83C\uDFF0';\n\t}\n\tif (d.includes('sustainable') || d.includes('green')) {\n\t\treturn '\uD83C\uDF31';\n\t}\n\tif (d.includes('tintin')) {\n\t\treturn '\uD83D\uDE80';\n\t}\n\tif (d.includes('retro')) {\n\t\treturn '\uD83D\uDEE9\uFE0F';\n\t}\n\n\treturn '\uD83C\uDFA8';\n}\n\nfunction downloadText(url: string, redirects = 0): Promise<string> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst client = url.startsWith('https') ? https : http;\n\n\t\tconst req = client.get(\n\t\t\turl,\n\t\t\t{\n\t\t\t\ttimeout: 25000,\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,application/xhtml+xml,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 bei Special-Liveries'));\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\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\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\tconst text = String(body || '').trim();\n\n\t\t\t\t\tif (!text) {\n\t\t\t\t\t\treject(new Error('Special-Liveries HTML leer'));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tresolve(text);\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('Special-Liveries Download Timeout'));\n\t\t});\n\n\t\treq.on('error', reject);\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": []
7
+ }