@atmosx/event-product-parser 3.0.46 → 3.0.48
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/README.md +12 -1
- package/dist/cjs/index.cjs +354 -9620
- package/dist/esm/index.mjs +354 -9620
- package/dist/index.d.mts +12 -1
- package/dist/index.d.ts +12 -1
- package/package.json +4 -5
- package/src/@building/building.attachments.ts +49 -8
- package/src/@building/building.properties.ts +1 -0
- package/src/@building/building.signature.ts +1 -1
- package/src/@core/core.createEvent.ts +1 -0
- package/src/@dictionaries/dictionaries.cancellation.ts +1 -0
- package/src/@dictionaries/dictionaries.expressions.ts +1 -0
- package/src/@dictionaries/dictionaries.states.ts +72 -0
- package/src/@events/events.api.ts +1 -0
- package/src/@manager/manager.updateListener.ts +102 -66
- package/src/@modules/@database/database.broadcastify.ts +67 -0
- package/src/@modules/@database/database.init.ts +14 -1
- package/src/@modules/@database/database.shapefiles.ts +1 -4
- package/src/@modules/@utilities/utilities.createHttp.ts +40 -55
- package/src/@modules/@utilities/utilities.setCronSchedule.ts +2 -1
- package/src/@modules/@xmpp/xmpp.xReconnect.ts +1 -1
- package/src/@parsers/@text/text.getEmbed.ts +0 -2
- package/src/@types/type.event.ts +1 -1
- package/src/@types/type.listener.ts +1 -1
- package/src/@types/type.properties.ts +1 -0
- package/src/@types/type.settings.ts +7 -1
- package/src/bootstrap.ts +7 -1
- package/test.js +12 -4
- /package/src/@dictionaries/{dictionaries.test.ts → dictionaries.testing.ts} +0 -0
package/dist/index.d.mts
CHANGED
|
@@ -10,6 +10,7 @@ type TypeListener = {
|
|
|
10
10
|
uploads?: {
|
|
11
11
|
file?: boolean;
|
|
12
12
|
eas?: boolean;
|
|
13
|
+
event?: boolean;
|
|
13
14
|
};
|
|
14
15
|
};
|
|
15
16
|
|
|
@@ -42,6 +43,11 @@ type TypeSettings = {
|
|
|
42
43
|
CallbackInterval: number;
|
|
43
44
|
EventsEndpoint: string;
|
|
44
45
|
};
|
|
46
|
+
BroadcastifySettings: {
|
|
47
|
+
BroadcastifyAttachments: boolean;
|
|
48
|
+
BroadcastifyDatabase: string;
|
|
49
|
+
BroadcastifyTags: string[];
|
|
50
|
+
};
|
|
45
51
|
GlobalSettings: {
|
|
46
52
|
EventManagement: boolean;
|
|
47
53
|
BetterEventNames: boolean;
|
|
@@ -64,6 +70,7 @@ type TypeSettings = {
|
|
|
64
70
|
};
|
|
65
71
|
ArchiveSettings: {
|
|
66
72
|
TTL: number;
|
|
73
|
+
EventDirectory: string;
|
|
67
74
|
TextDirectory: string;
|
|
68
75
|
EasDirectory: string;
|
|
69
76
|
EasToneout: string;
|
|
@@ -84,6 +91,7 @@ type TypeAttributes = {
|
|
|
84
91
|
|
|
85
92
|
type TypeEventProperties = {
|
|
86
93
|
locations: string;
|
|
94
|
+
locations_array: string[];
|
|
87
95
|
description: string;
|
|
88
96
|
attributes?: TypeAttributes;
|
|
89
97
|
geocode: {
|
|
@@ -200,7 +208,10 @@ type TypeEvent = {
|
|
|
200
208
|
issued: string;
|
|
201
209
|
status: string;
|
|
202
210
|
}[];
|
|
203
|
-
attachments?:
|
|
211
|
+
attachments?: {
|
|
212
|
+
name: string;
|
|
213
|
+
link: string;
|
|
214
|
+
}[];
|
|
204
215
|
raw: string;
|
|
205
216
|
};
|
|
206
217
|
} & TypeEventProperties;
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ type TypeListener = {
|
|
|
10
10
|
uploads?: {
|
|
11
11
|
file?: boolean;
|
|
12
12
|
eas?: boolean;
|
|
13
|
+
event?: boolean;
|
|
13
14
|
};
|
|
14
15
|
};
|
|
15
16
|
|
|
@@ -42,6 +43,11 @@ type TypeSettings = {
|
|
|
42
43
|
CallbackInterval: number;
|
|
43
44
|
EventsEndpoint: string;
|
|
44
45
|
};
|
|
46
|
+
BroadcastifySettings: {
|
|
47
|
+
BroadcastifyAttachments: boolean;
|
|
48
|
+
BroadcastifyDatabase: string;
|
|
49
|
+
BroadcastifyTags: string[];
|
|
50
|
+
};
|
|
45
51
|
GlobalSettings: {
|
|
46
52
|
EventManagement: boolean;
|
|
47
53
|
BetterEventNames: boolean;
|
|
@@ -64,6 +70,7 @@ type TypeSettings = {
|
|
|
64
70
|
};
|
|
65
71
|
ArchiveSettings: {
|
|
66
72
|
TTL: number;
|
|
73
|
+
EventDirectory: string;
|
|
67
74
|
TextDirectory: string;
|
|
68
75
|
EasDirectory: string;
|
|
69
76
|
EasToneout: string;
|
|
@@ -84,6 +91,7 @@ type TypeAttributes = {
|
|
|
84
91
|
|
|
85
92
|
type TypeEventProperties = {
|
|
86
93
|
locations: string;
|
|
94
|
+
locations_array: string[];
|
|
87
95
|
description: string;
|
|
88
96
|
attributes?: TypeAttributes;
|
|
89
97
|
geocode: {
|
|
@@ -200,7 +208,10 @@ type TypeEvent = {
|
|
|
200
208
|
issued: string;
|
|
201
209
|
status: string;
|
|
202
210
|
}[];
|
|
203
|
-
attachments?:
|
|
211
|
+
attachments?: {
|
|
212
|
+
name: string;
|
|
213
|
+
link: string;
|
|
214
|
+
}[];
|
|
204
215
|
raw: string;
|
|
205
216
|
};
|
|
206
217
|
} & TypeEventProperties;
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atmosx/event-product-parser",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.48",
|
|
4
4
|
"description": "NOAA Weather Wire & NWS API Parser - Built for standalone and Project AtmosphericX Integration.",
|
|
5
5
|
"main": "dist/cjs/index.cjs",
|
|
6
6
|
"module": "dist/esm/index.mjs",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "git+https://github.com/AtmosphericX/event-product-parser",
|
|
10
|
-
"branch": "beta"
|
|
10
|
+
"branch": "v3-beta-branch"
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
13
|
"start": "cd ./test && node ./index.js",
|
|
@@ -33,14 +33,13 @@
|
|
|
33
33
|
},
|
|
34
34
|
"homepage": "https://github.com/AtmosphericX/event-product-parser#readme",
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"express-ws": "5.0.2",
|
|
37
|
-
"express": "5.2.1",
|
|
38
36
|
"@xmpp/client": "0.14.0",
|
|
39
37
|
"better-sqlite3": "12.9.0",
|
|
40
38
|
"croner": "10.0.1",
|
|
39
|
+
"express": "5.2.1",
|
|
40
|
+
"express-ws": "5.0.2",
|
|
41
41
|
"jszip": "3.10.1",
|
|
42
42
|
"polygon-clipping": "0.15.7",
|
|
43
|
-
"request": "2.88.2",
|
|
44
43
|
"say": "0.16.0",
|
|
45
44
|
"shapefile": "0.6.6",
|
|
46
45
|
"typescript": "5.9.3",
|
|
@@ -17,15 +17,33 @@
|
|
|
17
17
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
+
import { bootstrap } from "../bootstrap"
|
|
20
21
|
import { TypeEvent } from "../@types/type.event"
|
|
21
22
|
import { getLatestIssuance } from "../@modules/@utilities/utilities.getLatestIssuance";
|
|
23
|
+
import { dict_states } from "../@dictionaries/dictionaries.states"
|
|
24
|
+
import { dict_expressions } from "../@dictionaries/dictionaries.expressions"
|
|
22
25
|
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
interface GetEventAttachmentsResponse {
|
|
27
|
+
name: string
|
|
28
|
+
link: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
type BroadcastifyResponse = {
|
|
32
|
+
state: string
|
|
33
|
+
county: string
|
|
34
|
+
feed: string
|
|
35
|
+
type: string
|
|
36
|
+
link: string
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const getEventAttachments = (event: TypeEvent): GetEventAttachmentsResponse[] | null => {
|
|
40
|
+
let attachments = [];
|
|
41
|
+
const issuanceTime = getLatestIssuance();
|
|
25
42
|
const spcNumber = event?.properties?.discussion_parameters?.discussion_number;
|
|
26
43
|
const watchNumber = event?.properties?.watch_parameters?.watch_number;
|
|
27
|
-
const
|
|
28
|
-
|
|
44
|
+
const locations = event?.properties?.locations_array;
|
|
45
|
+
const events = [
|
|
46
|
+
{ target: "Day 1", attachment: `https://www.spc.noaa.gov/products/outlook/day1otlk_${issuanceTime}.png` },
|
|
29
47
|
{ target: "Day 2", attachment: `https://www.spc.noaa.gov/products/outlook/day2otlk.png` },
|
|
30
48
|
{ target: "Day 3", attachment: `https://www.spc.noaa.gov/products/outlook/day3otlk.png` },
|
|
31
49
|
{ target: "Mesoscale Discussion", attachment: `https://www.spc.noaa.gov/products/md/mcd${spcNumber}.png` },
|
|
@@ -34,9 +52,32 @@ export const getEventAttachments = (event: TypeEvent): string[] | null => {
|
|
|
34
52
|
{ target: "Severe Thunderstorm Watch", attachment: `https://www.spc.noaa.gov/products/watch/ww${watchNumber}_radar_big.gif` },
|
|
35
53
|
{ target: "PDS Severe Thunderstorm Watch", attachment: `https://www.spc.noaa.gov/products/watch/ww${watchNumber}_radar_big.gif` }
|
|
36
54
|
]
|
|
37
|
-
|
|
38
|
-
if (
|
|
39
|
-
|
|
55
|
+
|
|
56
|
+
if (events.find((e) => e.target === event.properties.event)) {
|
|
57
|
+
attachments.push({ name: `Image: Graphic`, link: events.find((e) => e.target === event.properties.event).attachment });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
for (const location of locations) {
|
|
61
|
+
if (dict_expressions.location.test(location)) {
|
|
62
|
+
const lines = [`Northern`, `Southern`, `Eastern`, `Western`, `Inland`, `Costal`, `County`]
|
|
63
|
+
const county = location?.split(',')[0]?.trim().replace(new RegExp(`^(${lines.join('|')}) `), '')
|
|
64
|
+
const state = dict_states[location?.split(',')[1]?.trim()]
|
|
65
|
+
const feeds = bootstrap.database.prepare(`SELECT * FROM broadcastify WHERE state = ? AND county = ?`).all(state, county).sort((a, b) => {
|
|
66
|
+
const typeOrder = ['Other', 'Public Safety'];
|
|
67
|
+
const indexA = typeOrder.indexOf(a.type);
|
|
68
|
+
const indexB = typeOrder.indexOf(b.type);
|
|
69
|
+
return indexA - indexB;
|
|
70
|
+
});
|
|
71
|
+
const tags = bootstrap.settings.BroadcastifySettings.BroadcastifyTags;
|
|
72
|
+
const filtered = feeds.filter((feed: BroadcastifyResponse) => tags.includes(feed.type));
|
|
73
|
+
if (filtered.length > 0) {
|
|
74
|
+
filtered.map((filtered: BroadcastifyResponse) => {
|
|
75
|
+
if (!attachments.some((a) => a.link === filtered.link)) {
|
|
76
|
+
attachments.push({ name: `${filtered.type}: ${filtered.feed}`, link: filtered.link });
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
40
81
|
}
|
|
41
|
-
return
|
|
82
|
+
return attachments;
|
|
42
83
|
}
|
|
@@ -42,6 +42,7 @@ export const properties = (options: GetPropertiesOptions): TypeEventProperties =
|
|
|
42
42
|
const polygons = getPolygonFromProduct(options.message)
|
|
43
43
|
const properties = {
|
|
44
44
|
locations: options?.ugc?.locations?.join(`; `) ?? null,
|
|
45
|
+
locations_array: options?.ugc?.locations ?? [],
|
|
45
46
|
description: getDescriptionFromProduct({ message: options.message, handle: options?.pVtec?.vtec ?? null }),
|
|
46
47
|
attributes: options.attributes,
|
|
47
48
|
geocode: {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
import { TypeEvent } from "../@types/type.event";
|
|
21
21
|
import { dict_correlations } from "../@dictionaries/dictionaries.correlations";
|
|
22
22
|
import { dict_cancellation } from "../@dictionaries/dictionaries.cancellation";
|
|
23
|
-
import { dict_testing} from "../@dictionaries/dictionaries.
|
|
23
|
+
import { dict_testing} from "../@dictionaries/dictionaries.testing"
|
|
24
24
|
import { dict_products } from "../@dictionaries/dictionaries.products";
|
|
25
25
|
import { dict_hail } from "../@dictionaries/dictionaries.hail"
|
|
26
26
|
|
|
@@ -45,6 +45,7 @@ export const createEvent = (options: CreateEventOptions): void => {
|
|
|
45
45
|
issued: options.issued.toISOString(),
|
|
46
46
|
expires: options.expires.toISOString(),
|
|
47
47
|
locations: options.locations,
|
|
48
|
+
locations_array: options.locations ? options.locations.split(';') : [],
|
|
48
49
|
description: options.description,
|
|
49
50
|
geocode: {
|
|
50
51
|
office: {
|
|
@@ -21,6 +21,7 @@ export const dict_cancellation: string[] = [
|
|
|
21
21
|
"has been cancelled",
|
|
22
22
|
"subsided sufficiently for the advisory to be cancelled",
|
|
23
23
|
"has been cancelled",
|
|
24
|
+
"no tsunami threat from a nearby earthquake",
|
|
24
25
|
"will be allowed to expire",
|
|
25
26
|
"has diminished",
|
|
26
27
|
"and no longer",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
export const dict_expressions: { [key: string]: RegExp } = {
|
|
21
|
+
location: new RegExp(/^([A-Za-z.\-' ]+),\s*([A-Z]{2})$/),
|
|
21
22
|
pvtec: new RegExp(`[OTEX].(NEW|CON|EXT|EXA|EXB|UPG|CAN|EXP|COR|ROU).[A-Z]{4}.[A-Z]{2}.[WAYSFON].[0-9]{4}.[0-9]{6}T[0-9]{4}Z-[0-9]{6}T[0-9]{4}Z`, "g"),
|
|
22
23
|
hvtec: new RegExp(`[a-zA-Z0-9]{4}.[A-Z0-9].[A-Z]{2}.[0-9]{6}T[0-9]{4}Z.[0-9]{6}T[0-9]{4}Z.[0-9]{6}T[0-9]{4}Z.[A-Z]{2}`, "imu"),
|
|
23
24
|
wmo: new RegExp(`[A-Z0-9]{6}\\s[A-Z]{4}\\s\\d{6}`, "imu"),
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export const dict_states: Record<string, string> = {
|
|
21
|
+
"AL": "Alabama",
|
|
22
|
+
"AK": "Alaska",
|
|
23
|
+
"AZ": "Arizona",
|
|
24
|
+
"AR": "Arkansas",
|
|
25
|
+
"CA": "California",
|
|
26
|
+
"CO": "Colorado",
|
|
27
|
+
"CT": "Connecticut",
|
|
28
|
+
"DE": "Delaware",
|
|
29
|
+
"FL": "Florida",
|
|
30
|
+
"GA": "Georgia",
|
|
31
|
+
"HI": "Hawaii",
|
|
32
|
+
"ID": "Idaho",
|
|
33
|
+
"IL": "Illinois",
|
|
34
|
+
"IN": "Indiana",
|
|
35
|
+
"IA": "Iowa",
|
|
36
|
+
"KS": "Kansas",
|
|
37
|
+
"KY": "Kentucky",
|
|
38
|
+
"LA": "Louisiana",
|
|
39
|
+
"ME": "Maine",
|
|
40
|
+
"MD": "Maryland",
|
|
41
|
+
"MA": "Massachusetts",
|
|
42
|
+
"MI": "Michigan",
|
|
43
|
+
"MN": "Minnesota",
|
|
44
|
+
"MS": "Mississippi",
|
|
45
|
+
"MO": "Missouri",
|
|
46
|
+
"MT": "Montana",
|
|
47
|
+
"NE": "Nebraska",
|
|
48
|
+
"NV": "Nevada",
|
|
49
|
+
"NH": "New Hampshire",
|
|
50
|
+
"NJ": "New Jersey",
|
|
51
|
+
"NM": "New Mexico",
|
|
52
|
+
"NY": "New York",
|
|
53
|
+
"NC": "North Carolina",
|
|
54
|
+
"ND": "North Dakota",
|
|
55
|
+
"OH": "Ohio",
|
|
56
|
+
"OK": "Oklahoma",
|
|
57
|
+
"OR": "Oregon",
|
|
58
|
+
"PA": "Pennsylvania",
|
|
59
|
+
"RI": "Rhode Island",
|
|
60
|
+
"SC": "South Carolina",
|
|
61
|
+
"SD": "South Dakota",
|
|
62
|
+
"TN": "Tennessee",
|
|
63
|
+
"TX": "Texas",
|
|
64
|
+
"UT": "Utah",
|
|
65
|
+
"VT": "Vermont",
|
|
66
|
+
"VA": "Virginia",
|
|
67
|
+
"WA": "Washington",
|
|
68
|
+
"WV": "West Virginia",
|
|
69
|
+
"WI": "Wisconsin",
|
|
70
|
+
"WY": "Wyoming",
|
|
71
|
+
"DC": "District of Columbia"
|
|
72
|
+
};
|
|
@@ -47,6 +47,7 @@ export const api = async (stanza: TypeStanzaCompiled): Promise<void> => {
|
|
|
47
47
|
issued: feature?.properties?.sent ? new Date(feature?.properties?.sent).toISOString() : null,
|
|
48
48
|
expires: feature?.properties?.expires ? new Date(feature?.properties?.expires).toISOString() : null,
|
|
49
49
|
locations: feature?.properties?.areaDesc ?? null,
|
|
50
|
+
locations_array: feature?.properties?.areaDesc ? feature?.properties?.areaDesc.split(';') : [],
|
|
50
51
|
description: feature?.properties?.description ?? null,
|
|
51
52
|
attributes: feature?.properties?.attributes ?? {},
|
|
52
53
|
geocode: {
|
|
@@ -24,9 +24,10 @@ import { bootstrap } from "../bootstrap"
|
|
|
24
24
|
import { setEasTone } from "../@modules/@eas/eas.setEasTone"
|
|
25
25
|
import { setTimeoutAction } from "../@modules/@utilities/utilities.setTimeoutAction";
|
|
26
26
|
import { getEmebed } from "../@parsers/@text/text.getEmbed";
|
|
27
|
+
import { getCleanedEvent } from "../@building/building.clean"
|
|
27
28
|
import { createHttp } from "../@modules/@utilities/utilities.createHttp";
|
|
28
29
|
import { existsSync, mkdirSync, writeFileSync, readFileSync, appendFileSync } from "fs";
|
|
29
|
-
import
|
|
30
|
+
import { setWarning } from "../@modules/@utilities/utilities.setWarning";
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
|
|
@@ -35,90 +36,125 @@ export const updateListener = async (event: TypeEvent): Promise<void> => {
|
|
|
35
36
|
const settings = bootstrap.settings;
|
|
36
37
|
const listeners = settings.ListenerSettings as TypeListener[];
|
|
37
38
|
const properties = event.properties;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
const metadata = {
|
|
40
|
+
file: null,
|
|
41
|
+
eas: null,
|
|
42
|
+
name: properties.event,
|
|
43
|
+
status: properties.status,
|
|
44
|
+
description: properties.description,
|
|
45
|
+
tracking: properties.metadata.tracking,
|
|
46
|
+
header: properties.metadata.header,
|
|
47
|
+
raw: properties.metadata.raw,
|
|
48
|
+
expired: properties.status_metadata.is_expired,
|
|
49
|
+
attachments: properties.metadata.attachments
|
|
50
|
+
}
|
|
43
51
|
|
|
44
|
-
|
|
52
|
+
for (const listener of listeners) {
|
|
53
|
+
const events = listener?.events;
|
|
54
|
+
const webhook = listener?.webhook;
|
|
55
|
+
const uploads = listener?.uploads
|
|
56
|
+
const isMatched = events.some(pattern => {
|
|
45
57
|
if (!pattern) return false;
|
|
46
|
-
if (pattern === "*" || pattern ===
|
|
58
|
+
if (pattern === "*" || pattern === metadata.name) return true;
|
|
47
59
|
if (pattern.includes("*")) {
|
|
48
60
|
const regex = "^" +
|
|
49
61
|
pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*") + "$";
|
|
50
|
-
return new RegExp(regex).test(
|
|
62
|
+
return new RegExp(regex).test(metadata.name);
|
|
51
63
|
}
|
|
52
64
|
return false;
|
|
53
65
|
});
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
message: properties.description,
|
|
62
|
-
header: properties.metadata.header
|
|
66
|
+
|
|
67
|
+
if (events?.length == 0 || isMatched) {
|
|
68
|
+
if (uploads?.eas) {
|
|
69
|
+
metadata.eas = await setEasTone({
|
|
70
|
+
title: `${metadata.name}_${metadata.status}_${metadata.tracking}`,
|
|
71
|
+
message: metadata.description,
|
|
72
|
+
header: metadata.header
|
|
63
73
|
});
|
|
64
74
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (existsSync(
|
|
70
|
-
|
|
75
|
+
|
|
76
|
+
if (uploads?.file) {
|
|
77
|
+
const fDestination = settings.GlobalSettings.ArchiveSettings.TextDirectory;
|
|
78
|
+
if (fDestination) {
|
|
79
|
+
if (!existsSync(fDestination)) { mkdirSync(fDestination, { recursive: true }); }
|
|
80
|
+
if (existsSync(`${fDestination}/${metadata.name}_${metadata.status}_${metadata.tracking}.txt`)) {
|
|
81
|
+
appendFileSync(`${fDestination}/${metadata.name}_${metadata.status}_${metadata.tracking}.txt`, metadata.raw);
|
|
71
82
|
} else {
|
|
72
|
-
writeFileSync(`${
|
|
83
|
+
writeFileSync(`${fDestination}/${metadata.name}_${metadata.status}_${metadata.tracking}.txt`, metadata.raw);
|
|
73
84
|
}
|
|
74
85
|
}
|
|
75
|
-
file =
|
|
86
|
+
metadata.file = metadata.raw;
|
|
76
87
|
}
|
|
77
88
|
|
|
78
|
-
if (
|
|
79
|
-
const
|
|
80
|
-
if (
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
89
|
+
if (uploads?.event) {
|
|
90
|
+
const eDestination = settings.GlobalSettings.ArchiveSettings.EventDirectory;
|
|
91
|
+
if (eDestination) {
|
|
92
|
+
if (!existsSync(eDestination)) { mkdirSync(eDestination, { recursive: true }); }
|
|
93
|
+
writeFileSync(`${eDestination}/${metadata.name}_${metadata.status}_${metadata.tracking}.json`, JSON.stringify(getCleanedEvent(event), null, 2));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (webhook.enabled && webhook.destination) {
|
|
98
|
+
const ratelimit = setTimeoutAction({ identifier: webhook.destination, interval: webhook.ratelimit * 2, max: webhook.ratelimit, addTime: true })
|
|
99
|
+
const form = new FormData();
|
|
100
|
+
const embed = {
|
|
101
|
+
title: `${metadata.name} (${metadata.status})`,
|
|
102
|
+
description: getEmebed(event),
|
|
103
|
+
fields: [],
|
|
104
|
+
color: 16711680,
|
|
105
|
+
timestamp: new Date().toISOString(),
|
|
106
|
+
footer: { text: webhook.title ?? `AtmosphericX` }
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
if (ratelimit.limited) { return }
|
|
87
110
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
title: `${properties.event} (${properties.status})`,
|
|
93
|
-
description: body,
|
|
94
|
-
color: 16711680,
|
|
95
|
-
timestamp: new Date().toISOString(),
|
|
96
|
-
image: {},
|
|
97
|
-
footer: { text: sWebhook.title ?? `AtmosphericX` }
|
|
98
|
-
};
|
|
99
|
-
form.append("payload_json", JSON.stringify({
|
|
100
|
-
username: sWebhook.title ?? "AtmosphericX",
|
|
101
|
-
content: sWebhook.message ?? "",
|
|
102
|
-
embeds: [embed]
|
|
103
|
-
}));
|
|
104
|
-
if (sUploads?.file) {
|
|
105
|
-
form.append("fUpload", Buffer.from(file), { filename: `${properties.event}_${properties.status}_${properties.metadata.tracking}.txt`, contentType: "application/text" });
|
|
111
|
+
|
|
112
|
+
if (metadata.description && !metadata.expired) {
|
|
113
|
+
if (metadata.description.length > 900) {
|
|
114
|
+
metadata.description = metadata.description.substring(0, 900) + "\n\n[Message truncated due to length]";
|
|
106
115
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
116
|
+
embed.fields.push({
|
|
117
|
+
name: "Description",
|
|
118
|
+
value: metadata.description ? '```' + '\n' + metadata.description.split('\n').map(l => l.trim()).filter(Boolean).join('\n') + '\n' + '```' : ""
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
if (metadata.attachments?.length > 0) {
|
|
124
|
+
metadata.attachments = metadata.attachments.slice(0, 5);
|
|
125
|
+
embed.fields.push({
|
|
126
|
+
name: "Attachments",
|
|
127
|
+
value: metadata.attachments.map(attachment => `- [${attachment.name.length > 45 ? attachment.name.substring(0, 45) + '...' : attachment.name}](${attachment.link})`).join('\n')
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (uploads?.file) {
|
|
132
|
+
form.append("fUpload", new Blob([Buffer.from(metadata.file)], {type: "application/text"}), `${properties.event}_${properties.status}_${properties.metadata.tracking}.txt`)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (uploads?.eas) {
|
|
136
|
+
if (metadata.eas) {
|
|
137
|
+
const file = readFileSync(metadata.eas)
|
|
138
|
+
form.append("fEas", new Blob([Buffer.from(file)], { type: "audio/mpeg" }), `${properties.event}_${properties.status}_${properties.metadata.tracking}_eas.mp3`)
|
|
112
139
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
form.append("payload_json", JSON.stringify({
|
|
143
|
+
username: webhook.title ?? "AtmosphericX",
|
|
144
|
+
content: webhook.message ?? "",
|
|
145
|
+
embeds: [embed]
|
|
146
|
+
}));
|
|
147
|
+
|
|
148
|
+
const a = await createHttp({
|
|
149
|
+
url: webhook.destination,
|
|
150
|
+
timeout: 5000,
|
|
151
|
+
method: `POST`,
|
|
152
|
+
body: form
|
|
153
|
+
})
|
|
154
|
+
if (a.error) {
|
|
155
|
+
setWarning({ message: `Failed to send webhook: ${a.error.message}` })
|
|
120
156
|
}
|
|
121
157
|
}
|
|
122
158
|
}
|
|
123
159
|
}
|
|
124
|
-
}
|
|
160
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { bootstrap } from "../../bootstrap"
|
|
21
|
+
import { createHttp } from '../@utilities/utilities.createHttp'
|
|
22
|
+
import { setWarning } from "../@utilities/utilities.setWarning";
|
|
23
|
+
|
|
24
|
+
export const importBroadcastify = async (): Promise<void> => {
|
|
25
|
+
const settings = bootstrap.settings;
|
|
26
|
+
|
|
27
|
+
const isBroadcastifyImported = bootstrap.database
|
|
28
|
+
.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='broadcastify';`)
|
|
29
|
+
.get();
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
if (!settings.BroadcastifySettings.BroadcastifyAttachments) { return }
|
|
33
|
+
if (isBroadcastifyImported) { return }
|
|
34
|
+
|
|
35
|
+
const broadcastify = await createHttp({
|
|
36
|
+
url: settings.BroadcastifySettings.BroadcastifyDatabase,
|
|
37
|
+
timeout: 5000,
|
|
38
|
+
});
|
|
39
|
+
if (!broadcastify.error) {
|
|
40
|
+
bootstrap.database.prepare(`CREATE TABLE broadcastify ( state TEXT, county TEXT, feed TEXT, type TEXT, link TEXT);`)
|
|
41
|
+
.run();
|
|
42
|
+
const states = JSON.parse(broadcastify.message);
|
|
43
|
+
const insert = bootstrap.database.prepare(`INSERT INTO broadcastify (state, county, feed, type, link) VALUES (?, ?, ?, ?, ?)`);
|
|
44
|
+
const transaction = bootstrap.database.transaction((rows: any[]) => {
|
|
45
|
+
for (const row of rows) {
|
|
46
|
+
insert.run(row);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
const batch: any[] = [];
|
|
50
|
+
for (const state of states) {
|
|
51
|
+
setWarning({ message: `Importing ${state.counties.length} counties from ${state.state} for Broadcastify` });
|
|
52
|
+
for (const county of state.counties) {
|
|
53
|
+
const countyName = county.county;
|
|
54
|
+
for (const feed of county.feeds) {
|
|
55
|
+
batch.push([
|
|
56
|
+
state.state,
|
|
57
|
+
countyName,
|
|
58
|
+
feed.name,
|
|
59
|
+
feed.type,
|
|
60
|
+
feed.link
|
|
61
|
+
]);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
transaction(batch);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
@@ -23,6 +23,7 @@ import { TypeSettings } from "../../@types/type.settings"
|
|
|
23
23
|
import { bootstrap } from "../../bootstrap"
|
|
24
24
|
import { setWarning } from '../@utilities/utilities.setWarning'
|
|
25
25
|
import { importShapefiles } from './database.shapefiles'
|
|
26
|
+
import { importBroadcastify } from "./database.broadcastify"
|
|
26
27
|
|
|
27
28
|
export const initializeDatabase = async (): Promise<void> => {
|
|
28
29
|
const settings = bootstrap.settings as TypeSettings;
|
|
@@ -38,7 +39,19 @@ export const initializeDatabase = async (): Promise<void> => {
|
|
|
38
39
|
bootstrap.database
|
|
39
40
|
.prepare(`CREATE TABLE IF NOT EXISTS shapefiles (id TEXT PRIMARY KEY, location TEXT, geometry TEXT)`)
|
|
40
41
|
.run();
|
|
41
|
-
|
|
42
|
+
const isNeedingShapefiles = bootstrap.database
|
|
43
|
+
.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='shapefiles';`)
|
|
44
|
+
.get();
|
|
45
|
+
const isNeedingBroadcastify = bootstrap.database
|
|
46
|
+
.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='broadcastify';`)
|
|
47
|
+
.get();
|
|
48
|
+
|
|
49
|
+
if (!isNeedingShapefiles || !isNeedingBroadcastify) {
|
|
50
|
+
setWarning({message: `Required database tables are currently building, please ${bootstrap.ansi_colors.RED}DO NOT${bootstrap.ansi_colors.RESET} close your terminal. The building will not finish and will remain incomplete. If you do mess up, you will need to delete ${settings.Database} and restart the application.` })
|
|
51
|
+
await importBroadcastify();
|
|
52
|
+
await importShapefiles();
|
|
53
|
+
setWarning({ message: `Building has completed, you can now continue or close the terminal`})
|
|
54
|
+
}
|
|
42
55
|
} catch (error) {
|
|
43
56
|
setWarning({ message: `An error occurred while initializing the database: ${error.message}` })
|
|
44
57
|
}
|