@atmosx/event-product-parser 3.0.621 → 3.1.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 (200) hide show
  1. package/.github/CHANGELOGS.md +52 -0
  2. package/.github/CODE_OF_CONDUCT.md +24 -1
  3. package/.github/CONTRIBUTING.md +22 -3
  4. package/.github/FUNDING.yaml +3 -0
  5. package/.github/LICENSE +24 -1
  6. package/.github/SECURITY.md +25 -6
  7. package/.github/docs/chapters/general-configurations.md +109 -0
  8. package/.github/docs/chapters/sources-and-attributes.md +219 -0
  9. package/README.md +56 -146
  10. package/dist/index.cjs +25333 -0
  11. package/package.json +17 -11
  12. package/pnpm-workspace.yaml +4 -0
  13. package/src/bootstrap.ts +67 -52
  14. package/src/components/audio/GenerateAudioMessage.ts +149 -0
  15. package/src/{@modules/@eas → components/audio/components}/GetCleanDescription.ts +2 -2
  16. package/src/{@modules/@eas → components/audio/components}/GetFloatPCM16.ts +2 -2
  17. package/src/{@modules/@eas → components/audio/components}/GetMergedPCM16.ts +2 -2
  18. package/src/{@modules/@eas → components/audio/components}/GetPCM16.ts +13 -8
  19. package/src/{@modules/@eas → components/audio/components}/GetPCMToFloat.ts +2 -2
  20. package/src/{@modules/@eas → components/audio/components}/GetSampledPCM16.ts +14 -8
  21. package/src/{@modules/@eas → components/audio/components}/GetTTS.ts +17 -10
  22. package/src/{@modules/@eas → components/audio/components}/GetWavPCM16.ts +7 -7
  23. package/src/{@modules/@eas → components/audio/components}/SetAFSK.ts +13 -8
  24. package/src/{@modules/@eas → components/audio/components}/SetAsciiToBits.ts +2 -2
  25. package/src/{@modules/@eas → components/audio/components}/SetAttentionTone.ts +11 -6
  26. package/src/{@modules/@eas → components/audio/components}/SetNoise.ts +12 -7
  27. package/src/{@modules/@eas → components/audio/components}/SetRadioEffect.ts +12 -7
  28. package/src/{@modules/@eas → components/audio/components}/SetSameHeader.ts +22 -14
  29. package/src/components/database/CreateQuery.ts +39 -0
  30. package/src/components/database/InitializeDatabase.ts +71 -0
  31. package/src/components/database/imports/Boundaires.ts +168 -0
  32. package/src/{@modules/@database/ImportBroadcastify.ts → components/database/imports/Broadcastify.ts} +15 -25
  33. package/src/components/database/imports/Census.ts +87 -0
  34. package/src/{@modules/@database/ImportShapefiles.ts → components/database/imports/Shapefiles.ts} +24 -27
  35. package/src/{@modules/@database/ImportStanza.ts → components/database/imports/Stanza.ts} +15 -19
  36. package/src/components/events/CreateEvents.ts +88 -0
  37. package/src/components/events/FilterEvents.ts +149 -0
  38. package/src/{@building/CreateEvent.ts → components/events/ProcessStanza.ts} +22 -24
  39. package/src/components/events/RemoveEvents.ts +74 -0
  40. package/src/{@building → components/events/components}/GetCleanedEvent.ts +2 -2
  41. package/src/{@building → components/events/components}/GetEventAttachments.ts +14 -12
  42. package/src/components/events/components/GetEventDirection.ts +28 -0
  43. package/src/{@building → components/events/components}/GetEventEnhancedName.ts +5 -8
  44. package/src/{@building → components/events/components}/GetEventGeometry.ts +19 -13
  45. package/src/{@building → components/events/components}/GetEventHeader.ts +13 -13
  46. package/src/components/events/components/GetEventMerged.ts +51 -0
  47. package/src/{@building → components/events/components}/GetEventNodes.ts +22 -20
  48. package/src/{@building → components/events/components}/GetEventOffice.ts +13 -13
  49. package/src/components/events/components/GetEventPopulation.ts +58 -0
  50. package/src/components/events/components/GetEventProperties.ts +106 -0
  51. package/src/{@building → components/events/components}/GetEventSignature.ts +9 -9
  52. package/src/{@building → components/events/components}/GetEventTags.ts +3 -3
  53. package/src/components/events/components/GetEventTheme.ts +26 -0
  54. package/src/components/events/components/GetEventTracking.ts +64 -0
  55. package/src/{@modules/@database → components/events/utilities}/GetCachedEvents.ts +18 -15
  56. package/src/{@manager → components/events/utilities}/SetHash.ts +18 -13
  57. package/src/{@manager → components/events/utilities}/UpdateEvents.ts +12 -12
  58. package/src/{@manager → components/events/utilities}/UpdateNode.ts +14 -14
  59. package/src/{@parsers/@text → components/formatting}/GetEmbededText.ts +14 -8
  60. package/src/{@parsers/@text → components/formatting}/GetStringText.ts +15 -11
  61. package/src/{@modules/@utilities → components/geometry}/GetShapeNearestPoint.ts +24 -19
  62. package/src/components/geometry/GetUnionPolygon.ts +36 -0
  63. package/src/components/images/GenerateGraphic.ts +242 -0
  64. package/src/components/images/components/CreateRectangle.ts +22 -0
  65. package/src/components/images/components/CreateText.ts +22 -0
  66. package/src/components/images/modules/CreateSVG.ts +37 -0
  67. package/src/components/images/modules/GetGeographicalBoundaries.ts +72 -0
  68. package/src/components/images/modules/GetGeographicalCities.ts +58 -0
  69. package/src/components/images/modules/GetGeographicalEvents.ts +48 -0
  70. package/src/components/images/modules/GetGeometryBounds.ts +82 -0
  71. package/src/components/images/modules/GetParsedBoundary.ts +58 -0
  72. package/src/components/images/modules/GetSVGPath.ts +53 -0
  73. package/src/components/images/modules/NormalizePolygon.ts +57 -0
  74. package/src/{@modules/@stanza → components/stanza}/GetAwipsType.ts +16 -17
  75. package/src/{@modules/@stanza → components/stanza}/ValidateStanza.ts +27 -15
  76. package/src/{@modules/@utilities → components/utilities}/CreateHttp.ts +26 -26
  77. package/src/components/utilities/EmitThread.ts +97 -0
  78. package/src/{@modules/@utilities → components/utilities}/GetLatestIssuance.ts +2 -2
  79. package/src/{@modules/@utilities → components/utilities}/GetMatched.ts +10 -5
  80. package/src/components/utilities/QueueManager.ts +70 -0
  81. package/src/{@modules/@utilities → components/utilities}/SetDebug.ts +13 -13
  82. package/src/components/utilities/SetEventEmit.ts +42 -0
  83. package/src/{@modules/@utilities → components/utilities}/SetSettings.ts +7 -7
  84. package/src/{@modules/@utilities → components/utilities}/SetSleep.ts +5 -5
  85. package/src/components/utilities/SetTimeoutAction.ts +64 -0
  86. package/src/components/utilities/SetWarning.ts +47 -0
  87. package/src/{@modules/@xmpp → components/xmpp}/DeployXMPP.ts +20 -20
  88. package/src/{@core/CreateListener.ts → components/xmpp/ErrorXMPP.ts} +8 -5
  89. package/src/{@modules/@xmpp → components/xmpp}/OfflineXMPP.ts +13 -13
  90. package/src/{@modules/@xmpp → components/xmpp}/OnlineXMPP.ts +18 -18
  91. package/src/components/xmpp/ReconnectXMPP.ts +64 -0
  92. package/src/{@modules/@xmpp → components/xmpp}/StanzaXMPP.ts +26 -26
  93. package/src/{@enums → enums}/AWIPS.ts +2 -2
  94. package/src/{@enums → enums}/Actions.ts +2 -2
  95. package/src/{@enums → enums}/Cancellation.ts +2 -2
  96. package/src/{@enums → enums}/Causes.ts +2 -2
  97. package/src/{@enums → enums}/Correlations.ts +2 -2
  98. package/src/{@enums → enums}/Enhanced.ts +4 -3
  99. package/src/{@enums → enums}/Events.ts +2 -2
  100. package/src/{@enums → enums}/Expressions.ts +3 -3
  101. package/src/{@enums → enums}/GlobalFilter.ts +2 -2
  102. package/src/{@enums → enums}/Hail.ts +2 -2
  103. package/src/{@enums → enums}/ICAO.ts +2 -2
  104. package/src/{@enums → enums}/Matches.ts +8 -3
  105. package/src/{@enums → enums}/Products.ts +2 -2
  106. package/src/{@enums → enums}/Records.ts +2 -2
  107. package/src/{@enums → enums}/Severity.ts +2 -2
  108. package/src/{@enums → enums}/Shapefiles.ts +2 -2
  109. package/src/{@enums → enums}/States.ts +68 -4
  110. package/src/{@enums → enums}/Status.ts +2 -2
  111. package/src/{@enums → enums}/Strings.ts +2 -2
  112. package/src/{@enums → enums}/Tags.ts +9 -4
  113. package/src/{@enums → enums}/Testing.ts +2 -2
  114. package/src/enums/Themes.ts +70 -0
  115. package/src/events/ParseAPI.ts +133 -0
  116. package/src/{@events → events}/ParseText.ts +24 -22
  117. package/src/{@events → events}/ParseUGC.ts +27 -26
  118. package/src/{@events → events}/ParseVTEC.ts +37 -36
  119. package/src/{@core → exports}/ClearEvents.ts +9 -9
  120. package/src/{@core → exports}/GetEvents.ts +4 -4
  121. package/src/exports/GetNearestCity.ts +45 -0
  122. package/src/{@core → exports}/GetNodes.ts +4 -4
  123. package/src/{@core → exports}/GetRandomEvent.ts +4 -4
  124. package/src/{@core → exports}/GetVersion.ts +4 -4
  125. package/src/exports/ManualEvent.ts +55 -0
  126. package/src/{@core → exports}/QueryStanza.ts +12 -11
  127. package/src/exports/SetNode.ts +100 -0
  128. package/src/{@core → exports}/StartService.ts +23 -22
  129. package/src/{@core → exports}/StopService.ts +10 -10
  130. package/src/index.ts +57 -37
  131. package/src/{@parsers/@hvtec → parsers/hvtec}/HVExtract.ts +7 -7
  132. package/src/{@parsers/@text → parsers/text}/GetDescriptionFromProduct.ts +20 -21
  133. package/src/parsers/text/GetPolygonFromProduct.ts +71 -0
  134. package/src/{@parsers/@text → parsers/text}/GetTextFromProduct.ts +12 -12
  135. package/src/parsers/ugc/GetCache.ts +24 -0
  136. package/src/{@parsers/@ugc → parsers/ugc}/GetExpiry.ts +2 -2
  137. package/src/{@parsers/@ugc/GetUGCHeader.ts → parsers/ugc/GetHeader.ts} +4 -4
  138. package/src/{@parsers/@ugc → parsers/ugc}/GetLocations.ts +10 -10
  139. package/src/parsers/ugc/GetZonePolygon.ts +73 -0
  140. package/src/{@parsers/@ugc → parsers/ugc}/GetZones.ts +3 -3
  141. package/src/{@parsers/@ugc → parsers/ugc}/SetCache.ts +13 -8
  142. package/src/{@parsers/@ugc → parsers/ugc}/UGCExtract.ts +14 -14
  143. package/src/{@parsers/@pvtec → parsers/vtec}/GetExpiry.ts +2 -2
  144. package/src/{@parsers/@pvtec → parsers/vtec}/VTECExtract.ts +17 -17
  145. package/src/tasks/CreateTasks.ts +116 -0
  146. package/src/tasks/TaskGenerateJSON.ts +34 -0
  147. package/src/tasks/TaskGenerateText.ts +34 -0
  148. package/src/tasks/TaskSendNTFY.ts +96 -0
  149. package/src/tasks/TaskSendWebhook.ts +107 -0
  150. package/src/{@types → types/event}/Attributes.ts +2 -3
  151. package/src/{@types → types/event}/Event.ts +8 -7
  152. package/src/{@types → types/event}/HVTEC.ts +2 -2
  153. package/src/{@types → types/event}/Properties.ts +17 -3
  154. package/src/{@types → types/event}/Stanza.ts +2 -2
  155. package/src/{@types → types/event}/VTEC.ts +8 -8
  156. package/src/{@types → types/standard}/Actions.ts +3 -3
  157. package/src/{@types → types/standard}/Hash.ts +5 -5
  158. package/src/{@modules/@utilities/GetSettings.ts → types/standard/Nodes.ts} +15 -7
  159. package/src/{@types → types/standard}/Settings.ts +19 -12
  160. package/src/{@types → types/standard}/StanzaCompiled.ts +15 -15
  161. package/src/{@types → types/standard}/UGC.ts +5 -5
  162. package/tools/build.js +32 -0
  163. package/tsconfig.json +32 -1
  164. package/.github/SUPPORTED_EVENTS.md +0 -370
  165. package/.github/docs/docs-functions.md +0 -30
  166. package/.github/docs/docs-general-configurations.md +0 -209
  167. package/.github/docs/docs-integrations.md +0 -37
  168. package/.github/docs/docs-listeners.md +0 -28
  169. package/.github/docs/docs-source-configuration.md +0 -218
  170. package/.github/docs/docs-technical.md +0 -50
  171. package/.github/logo.png +0 -0
  172. package/.github/samples/SAMPLE_EAS_GENERATION.wav +0 -0
  173. package/.github/samples/SAMPLE_GEOJSON.json +0 -204
  174. package/.github/samples/SAMPLE_TEXT_PRODUCT.txt +0 -119
  175. package/dist/cjs/index.cjs +0 -8005
  176. package/dist/esm/index.mjs +0 -7985
  177. package/src/@building/GetEventProperties.ts +0 -96
  178. package/src/@building/GetEventTracking.ts +0 -68
  179. package/src/@core/ManualEvent.ts +0 -56
  180. package/src/@core/SetNode.ts +0 -81
  181. package/src/@events/ParseAPI.ts +0 -117
  182. package/src/@manager/MakeEvents.ts +0 -106
  183. package/src/@manager/RemoveEvent.ts +0 -70
  184. package/src/@manager/Tasks.ts +0 -246
  185. package/src/@manager/ValidateEvents.ts +0 -142
  186. package/src/@modules/@database/InitializeDatabase.ts +0 -59
  187. package/src/@modules/@eas/GenerateEASMessage.ts +0 -144
  188. package/src/@modules/@utilities/GetFormattedTime.ts +0 -43
  189. package/src/@modules/@utilities/SetCronSchedule.ts +0 -94
  190. package/src/@modules/@utilities/SetEventEmit.ts +0 -41
  191. package/src/@modules/@utilities/SetListener.ts +0 -30
  192. package/src/@modules/@utilities/SetTimeoutAction.ts +0 -64
  193. package/src/@modules/@utilities/SetWarning.ts +0 -34
  194. package/src/@modules/@xmpp/ErrorXMPP.ts +0 -27
  195. package/src/@modules/@xmpp/ReconnectXMPP.ts +0 -64
  196. package/src/@parsers/@text/GetPolygonFromProduct.ts +0 -53
  197. package/src/@parsers/@text/GetXML.ts +0 -61
  198. package/src/@parsers/@ugc/GetCache.ts +0 -24
  199. package/src/@parsers/@ugc/GetZonePolygon.ts +0 -111
  200. package/tsup.config.ts +0 -16
@@ -1,246 +0,0 @@
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 { TypeSettings } from "../@types/Settings";
21
- import { TypeEvent } from "../@types/Event";
22
- import { TypeActions } from "../@types/Actions";
23
- import { bootstrap } from "../bootstrap"
24
- import { GenerateEASMessage } from "../@modules/@eas/GenerateEASMessage"
25
- import { SetTimeoutAction } from "../@modules/@utilities/SetTimeoutAction";
26
- import { GetEmebedText } from "../@parsers/@text/GetEmbededText";
27
- import { GetStringText } from "../@parsers/@text/GetStringText";
28
- import { GetCleanedEvent } from "../@building/GetCleanedEvent"
29
- import { CreateHttp } from "../@modules/@utilities/CreateHttp";
30
- import { SetDebug } from "../@modules/@utilities/SetDebug";
31
- import { GetMatched } from "../@modules/@utilities/GetMatched";
32
- import { mkdir, writeFile, readFile, appendFile } from "fs/promises";
33
-
34
- export const Tasks = async (events: TypeEvent[]): Promise<void> => {
35
- const tick = performance.now()
36
- const settings = bootstrap.settings as TypeSettings;
37
- const notifyServer = settings.NotifyServer;
38
- const actions = settings.ActionSettings as TypeActions[];
39
- for (const event of events) {
40
- const properties = event.properties;
41
- const hasActions = Array.isArray(actions) && actions.length > 0;
42
- if (!hasActions) {
43
- SetDebug({ title: `Tasks`, message: `${Math.round(performance.now() - tick)}ms` });
44
- return;
45
- }
46
- const metadata = {
47
- text: null,
48
- eas: null,
49
- json: null,
50
- name: properties.event,
51
- status: properties.status,
52
- description: properties.description,
53
- tracking: properties.metadata.tracking,
54
- header: properties.metadata.header,
55
- raw: properties.metadata.raw,
56
- expired: properties.status_metadata.is_expired,
57
- attachments: properties.metadata.attachments
58
- }
59
-
60
- const archiveSettings = settings.GlobalSettings?.ArchiveSettings;
61
- const textArchiveDir = archiveSettings?.TextDirectory;
62
- const jsonArchiveDir = archiveSettings?.JSONDirectory;
63
- const eventBaseName = `${metadata.name}_${metadata.tracking}`;
64
- const easTitle = `${metadata.name}_${metadata.status}_${metadata.tracking}`;
65
- const cleanedEventText = JSON.stringify(GetCleanedEvent(event), null, 2);
66
- const stringText = GetStringText(event);
67
- const embedText = GetEmebedText(event);
68
-
69
- for (const action of actions) {
70
- const events = action?.Events;
71
- const webhook = action?.Webhook;
72
- const notify = action?.NotificationServer;
73
- const uploads = action?.Uploads
74
- const isMatched = GetMatched(events ?? [], metadata.name)
75
-
76
- if (events?.length == 0 || isMatched) {
77
- const t = performance.now()
78
-
79
- if (uploads?.EAS && !metadata.eas) {
80
- metadata.eas = await GenerateEASMessage({
81
- title: easTitle,
82
- message: metadata.description,
83
- header: metadata.header
84
- });
85
- SetDebug({
86
- title: "Tasks/EAS",
87
- message: `${Math.round(performance.now() - t)}ms`
88
- });
89
- }
90
-
91
- if (uploads?.TEXT && metadata.text === null) {
92
- const t = performance.now()
93
- if (textArchiveDir) {
94
- const file = (`${textArchiveDir}/${eventBaseName}.txt`).replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
95
- await mkdir(textArchiveDir, { recursive: true });
96
- await appendFile(file, `${metadata.raw}${"\n".repeat(5)}`);
97
- SetDebug({
98
- title: "Tasks/TEXT",
99
- message: `${Math.round(performance.now() - t)}ms`
100
- });
101
- }
102
- metadata.text = metadata.raw;
103
- }
104
-
105
- if (uploads?.JSON && metadata.json === null) {
106
- const t = performance.now()
107
- if (jsonArchiveDir) {
108
- const file = (`${jsonArchiveDir}/${eventBaseName}.json`).replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
109
- await mkdir(jsonArchiveDir, { recursive: true });
110
- await writeFile(file, cleanedEventText);
111
- SetDebug({
112
- title: "Tasks/JSON",
113
- message: `${Math.round(performance.now() - t)}ms`
114
- });
115
- }
116
- metadata.json = cleanedEventText;
117
- }
118
-
119
- if (notifyServer?.Enabled && notify?.Enabled && notify?.Topic) {
120
- let buttons = [];
121
- const t = performance.now()
122
- const auth = notifyServer?.Credentials?.Username && notifyServer?.Credentials?.Password ? { username: notifyServer?.Credentials?.Username, password: notifyServer?.Credentials?.Password } : undefined;
123
- const image = metadata.attachments?.find(a => a.name === "Image: Graphic");
124
-
125
-
126
- if (notifyServer?.MediaStorage?.EAS) {
127
- if (metadata.eas) {
128
- buttons.push({
129
- "action": "view",
130
- "label": "Listen",
131
- "url": `${notifyServer?.MediaStorage?.EAS}/${metadata.name}_${metadata.status}_${metadata.tracking}.wav`,
132
- })
133
- }
134
- }
135
- if (metadata.json) {
136
- buttons.push({
137
- "action": "view",
138
- "label": "View JSON",
139
- "url": `${notifyServer?.MediaStorage?.JSON}/${metadata.name}_${metadata.tracking}.json`,
140
- })
141
- }
142
- if (metadata.text) {
143
- buttons.push({
144
- "action": "view",
145
- "label": "View Text",
146
- "url": `${notifyServer?.MediaStorage?.TEXT}/${metadata.name}_${metadata.tracking}.txt`,
147
- })
148
- }
149
- if (image) {
150
- buttons.push({
151
- "action": "view",
152
- "label": "View Image",
153
- "url": image.link,
154
- })
155
- }
156
- await CreateHttp({
157
- url: `${notifyServer?.Server?.replace(/\/$/, "")}/${notify.Topic}`,
158
- timeout: 15_000,
159
- method: "PUT",
160
- ...(auth && { auth }),
161
- headers: {
162
- "Title": `${metadata.name} (${metadata.status})`,
163
- "Tags": properties.parameters.tags?.join(",") ?? "N/A",
164
- "Priority": notify?.Priority ?? "5",
165
- ... (buttons.length > 0 && { "Actions": JSON.stringify(buttons) }),
166
- },
167
- body: stringText
168
- })
169
- SetDebug({
170
- title: "Tasks/NTFY",
171
- message: `${Math.round(performance.now() - t)}ms`
172
- });
173
- }
174
-
175
- if (webhook?.Enabled && webhook?.Destination) {
176
- const t = performance.now()
177
- const isRatelimited = SetTimeoutAction({ identifier: webhook.Destination, interval: (webhook.Ratelimit ?? 2) * 2, max: (webhook.Ratelimit ?? 2), addTime: true })
178
- const form = new FormData();
179
- const embed = {
180
- title: `${metadata.name} (${metadata.status})`,
181
- description: embedText,
182
- fields: [],
183
- color: 16711680,
184
- timestamp: new Date().toISOString(),
185
- footer: { text: webhook.Title ?? `AtmosphericX` }
186
- };
187
-
188
- if (isRatelimited.limited) { return }
189
-
190
-
191
- if (metadata.description && !metadata.expired) {
192
- const description = metadata.description.length > 900
193
- ? metadata.description.substring(0, 900) + "\n\n[Message truncated due to length]"
194
- : metadata.description;
195
- embed.fields.push({
196
- name: "Description",
197
- value: description ? '```' + '\n' + description.split('\n').map(l => l.trim()).filter(Boolean).join('\n') + '\n' + '```' : ""
198
- });
199
- }
200
-
201
-
202
- if (metadata.attachments?.length > 0) {
203
- const attachments = metadata.attachments.slice(0, 5);
204
- embed.fields.push({
205
- name: "Attachments",
206
- value: attachments.map(attachment => `- [${attachment.name.length > 45 ? attachment.name.substring(0, 45) + '...' : attachment.name}](${attachment.link})`).join('\n')
207
- });
208
- }
209
-
210
- if (uploads?.TEXT) {
211
- form.append("fUpload", new Blob([Buffer.from(metadata.text)], {type: "application/text"}), `${properties.event}_${properties.status}_${properties.metadata.tracking}.txt`)
212
- }
213
-
214
- if (uploads?.JSON) {
215
- form.append("fUpload2", new Blob([Buffer.from(metadata.json)], {type: "application/json"}), `${properties.event}_${properties.status}_${properties.metadata.tracking}.json`)
216
- }
217
-
218
- if (uploads?.EAS) {
219
- if (metadata.eas) {
220
- const file = await readFile(metadata.eas);
221
- form.append("fEas", new Blob([Buffer.from(file)], { type: "audio/mpeg" }), `${properties.event}_${properties.status}_${properties.metadata.tracking}_eas.mp3`)
222
- }
223
- }
224
-
225
- form.append("payload_json", JSON.stringify({
226
- username: webhook.Title ?? "AtmosphericX",
227
- content: webhook.Message ?? "",
228
- embeds: [embed]
229
- }));
230
-
231
- await CreateHttp({
232
- url: webhook.Destination,
233
- timeout: 15e3,
234
- method: `POST`,
235
- body: form
236
- })
237
- SetDebug({
238
- title: "Tasks/Webhook",
239
- message: `${Math.round(performance.now() - t)}ms`
240
- });
241
- }
242
- }
243
- }
244
- }
245
- SetDebug({ title: `Tasks`, message: `${Math.round(performance.now() - tick)}ms` })
246
- }
@@ -1,142 +0,0 @@
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 { TypeEvent } from "../@types/Event";
21
- import { TypeSettings } from "../@types/Settings";
22
- import { bootstrap } from "../bootstrap"
23
- import { GetEventEnhancedName } from "../@building/GetEventEnhancedName";
24
- import { GetEventSignature } from "../@building/GetEventSignature"
25
- import { MakeEvents } from "./MakeEvents";
26
- import { RemoveEvent } from "./RemoveEvent";
27
- import { GetEventAttachments } from "../@building/GetEventAttachments";
28
- import { SetEventEmit } from "../@modules/@utilities/SetEventEmit";
29
- import { SetDebug } from "../@modules/@utilities/SetDebug";
30
- import { GetMatched } from "../@modules/@utilities/GetMatched";
31
- import { GetEventGeometry } from "../@building/GetEventGeometry";
32
- import { createHash } from "crypto"
33
-
34
- export const ValidateEvents = async (events: TypeEvent[]): Promise<void> => {
35
- const tick = performance.now();
36
- if (events.length === 0) return
37
- const configurations = bootstrap.settings as TypeSettings
38
- const sets = {} as Record<string, Set<string>>;
39
- const bools = {} as Record<string, boolean>;
40
- const megered = {...configurations.GlobalSettings, ...configurations.GlobalSettings.EventFiltering}
41
- for (const key in megered) {
42
- const setting = megered[key];
43
- if (Array.isArray(setting)) { sets[key] = new Set(setting.map(item => item.toLowerCase())); }
44
- if (typeof setting === 'boolean') { bools[key] = setting; }
45
- }
46
-
47
- const isFiltered = (define: TypeEvent): boolean => {
48
- const properties = define.properties;
49
- const zones = properties.geocode.ugc;
50
- const icao = properties.geocode.office.office
51
-
52
- if (properties.status_metadata.is_test) {
53
- SetEventEmit({ event: `onTestProduct`, metadata: define })
54
- if (bools?.IgnoreTestProducts) return true;
55
- }
56
-
57
- if (properties.status_metadata.is_expired) {
58
- SetEventEmit({ event: `onExpiredProduct`, metadata: define })
59
- RemoveEvent(define, false)
60
- return true;
61
- }
62
-
63
- if (properties.metadata?.vtec?.is_watch && properties.metadata.source != `events.api`) {
64
- const isSPC = properties.metadata?.vtec?.prediction_center;
65
- SetEventEmit({ event: isSPC ? `onStormPredictionWatch` : `onNonStormPredictionWatch`, metadata: define })
66
- if (bools?.SPCWatchesOnly && !isSPC) {
67
- return true;
68
- }
69
- if ((!bools?.SPCWatchesOnly) && isSPC) {
70
- return true
71
- }
72
- }
73
-
74
- for (const key in sets) {
75
- const setting = sets[key]
76
- const values = [...setting];
77
- if (key === 'ListeningEvents' && setting.size > 0 && !GetMatched(values, define.properties.event)) {
78
- SetEventEmit({
79
- event: `onFilteredEvent`,
80
- metadata: define
81
- });
82
- return true
83
- }
84
- if (key === 'IgnoredEvents' && setting.size > 0 && GetMatched(values, define.properties.event)) {
85
- SetEventEmit({
86
- event: `onIgnoredEvent`,
87
- metadata: define
88
- });
89
- return true
90
- }
91
- if (key === 'ListeningICAO' && setting.size > 0 && icao != null && !setting.has(icao.toLowerCase())) {
92
- SetEventEmit({
93
- event: `onFilteredICAO`,
94
- metadata: define
95
- });
96
- return true
97
- }
98
- if (key === 'IgnoredICAO' && setting.size > 0 && icao != null && setting.has(icao.toLowerCase())) {
99
- SetEventEmit({
100
- event: `onIgnoredICAO`,
101
- metadata: define
102
- });
103
- return true
104
- }
105
- if (key === 'ListeningUGC' && setting.size > 0 && zones.length > 0 && !zones.some((ugc: string) => setting.has(ugc.toLowerCase()))) {
106
- SetEventEmit({
107
- event: `onFilteredUGC`,
108
- metadata: define
109
- });
110
- return true
111
- }
112
- if (key === 'ListeningStates' && setting.size > 0 && zones.length > 0 && !zones.some((ugc: string) => setting.has(ugc.substring(0, 2).toLowerCase()))) {
113
- SetEventEmit({
114
- event: `onFilteredState`,
115
- metadata: define
116
- });
117
- return true
118
- }
119
- }
120
- return false
121
- }
122
-
123
- const filtering = events.filter((event: TypeEvent) => {
124
- bootstrap.cache.processed = bootstrap.cache.processed.filter((e) => e !== event);
125
- const define = GetEventSignature(event) as TypeEvent;
126
- const pre = {...define,properties: {...define.properties, metadata: {...define.properties.metadata }}};
127
- const properties = define.properties; delete pre.properties.metadata.ms; delete pre.properties.metadata.header;
128
- const enhanced = properties.event = GetEventEnhancedName(event)
129
- const filtered = isFiltered(define)
130
- if (!filtered) {
131
- event.geometry = !bools?.DisableGeometryParsing ? GetEventGeometry(event) : null;
132
- properties.metadata.attachments = GetEventAttachments(event)
133
- }
134
- properties.metadata.hash = createHash("sha256").update(JSON.stringify(pre)).digest("hex")
135
- SetEventEmit({ event: `onProductType${enhanced.replace(/\s+/g, '')}`, metadata: define });
136
- return !filtered
137
- })
138
-
139
- SetDebug({ title: `ValidateEvents (PRE) (${filtering.length}/${events.length})`, message: `${Math.round(performance.now() - tick)}ms` })
140
- await MakeEvents(filtering)
141
- SetDebug({ title: `MakeEvents (${filtering.length}/${events.length})`, message: `${Math.round(performance.now() - tick)}ms` })
142
- }
@@ -1,59 +0,0 @@
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
-
21
- import { TypeSettings } from "../../@types/Settings"
22
- import { bootstrap } from "../../bootstrap"
23
- import { SetWarning } from '../@utilities/SetWarning'
24
- import { ImportShapefiles } from './ImportShapefiles'
25
- import { ImportBroadcastify } from "./ImportBroadcastify"
26
- import { existsSync, writeFileSync } from "fs"
27
- import sqlite3 from 'better-sqlite3'
28
-
29
- export const InitializeDatabase = async (): Promise<void> => {
30
- const settings = bootstrap.settings as TypeSettings;
31
- try {
32
- if (!existsSync(settings.Database)) {
33
- writeFileSync(settings.Database, '')
34
- SetWarning({ message: `Creating new database at ${settings.Database}` })
35
- }
36
- bootstrap.database = new sqlite3(settings.Database);
37
- bootstrap.database
38
- .prepare(`CREATE TABLE IF NOT EXISTS stanzas ( id INTEGER PRIMARY KEY AUTOINCREMENT, type TEXT, issued TEXT, stanza TEXT )`)
39
- .run();
40
- bootstrap.database
41
- .prepare(`CREATE TABLE IF NOT EXISTS shapefiles (id TEXT PRIMARY KEY, location TEXT, geometry TEXT)`)
42
- .run();
43
- const isNeedingShapefiles = bootstrap.database
44
- .prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='shapefiles';`)
45
- .get();
46
- const isNeedingBroadcastify = bootstrap.database
47
- .prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='broadcastify';`)
48
- .get();
49
-
50
- if (!isNeedingShapefiles || !isNeedingBroadcastify) {
51
- 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.` })
52
- await ImportBroadcastify();
53
- await ImportShapefiles();
54
- SetWarning({ message: `Building has completed, you can now continue or close the terminal`})
55
- }
56
- } catch (error) {
57
- SetWarning({ message: `An error occurred while initializing the database: ${error.message}` })
58
- }
59
- }
@@ -1,144 +0,0 @@
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 { TypeSettings } from "../../@types/Settings";
21
- import { bootstrap } from "../../bootstrap";
22
- import { SetWarning } from "../@utilities/SetWarning";
23
- import { GetWavPCM16 } from "./GetWavPCM16";
24
- import { GetSampledPCM16 } from "./GetSampledPCM16";
25
- import { SetRadioEffect } from "./SetRadioEffect";
26
- import { SetSameHeader } from "./SetSameHeader";
27
- import { SetAttentionTone } from "./SetAttentionTone";
28
- import { GetMergedPCM16 } from "./GetMergedPCM16";
29
- import { SetNoise } from "./SetNoise";
30
- import { GetPCM16 } from "./GetPCM16";
31
- import { GetTTS } from "./GetTTS";
32
- import { GetCleanDescription } from "./GetCleanDescription";
33
- import { SetDebug } from "../@utilities/SetDebug";
34
- import { join } from 'path'
35
- import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from 'fs'
36
- import { execSync } from 'child_process'
37
- import { platform } from 'os'
38
-
39
-
40
- interface GenerateEASMessageOptions {
41
- message: string
42
- header: string
43
- title: string
44
- }
45
-
46
- export const GenerateEASMessage = async (options: GenerateEASMessageOptions): Promise<string> => {
47
- const tick = performance.now()
48
- const settings = bootstrap.settings as TypeSettings;
49
- const directory = settings.GlobalSettings.ArchiveSettings.EasDirectory;
50
- const prefix = settings.GlobalSettings.ArchiveSettings.EasToneout;
51
- let message = options.message;
52
- let header = options.header;
53
- let title = (options.title ?? `${Math.random().toString(36).substring(2, 15)}-${header.replace(/[^a-zA-Z0-9]/g, '')}`).replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
54
- if (!message || !header) {
55
- SetWarning({
56
- title: `EAS`,
57
- message: `Message and header are required to generate an EAS tone.`
58
- })
59
- return null;
60
- }
61
- let buffTTS: Buffer;
62
- let buffRadio: any;
63
- let buffFull: any[] = [];
64
-
65
- if (!existsSync(directory)) {
66
- mkdirSync(directory, { recursive: true });
67
- }
68
- const tmpTTS = join(directory, `/${title}-tts.wav`)
69
- const outTTS = join(directory, `/${title}.wav`)
70
- const vPlatform = platform();
71
-
72
- if (vPlatform === 'darwin') {
73
- SetWarning({
74
- title: `EAS`,
75
- message: `EAS tone generation is not supported on macOS.`
76
- });
77
- return null
78
- }
79
-
80
-
81
- await new Promise<void>((resolve, reject) => {
82
- const tMsg = GetCleanDescription(message)
83
- GetTTS(tMsg, tmpTTS).then(() => {
84
- resolve();
85
- });
86
- });
87
- if (!existsSync(tmpTTS)) {
88
- return null;
89
- }
90
- buffTTS = readFileSync(tmpTTS);
91
- const vWav = GetWavPCM16(buffTTS);
92
- const vSamples = GetSampledPCM16(vWav.samples, vWav.sampleRate, 8000)
93
- const vRadio = SetRadioEffect(vSamples, 8000)
94
-
95
- if (existsSync(prefix)) {
96
- let tBuffer = readFileSync(prefix);
97
- let tWav = GetWavPCM16(tBuffer);
98
-
99
- if (tWav == null) {
100
- try {
101
- const converted = join(directory, `/${title}-tts-fixed.wav`)
102
- execSync(`ffmpeg -y -i "${prefix}" -ar 8000 -ac 1 -sample_fmt s16 "${converted}"`, { stdio: 'ignore' })
103
- if (existsSync(converted)) {
104
- tBuffer = readFileSync(converted)
105
- tWav = GetWavPCM16(tBuffer)
106
- try { unlinkSync(converted) } catch {}
107
- }
108
- } catch (e) {}
109
- }
110
-
111
- if (tWav == null) {
112
- SetWarning({ title: `EAS`, message: `Intro tone isn't a valid .WAV file or isn't in PCM 16-bit format. Converted attempt failed; please convert it then try again.` })
113
- return null;
114
- }
115
-
116
- const tSamples = (tWav.sampleRate != 8000 ? GetSampledPCM16(tWav.samples, tWav.sampleRate, 8000) : tWav.samples)
117
- buffRadio = SetRadioEffect(tSamples, 8000)
118
- }
119
-
120
- buffFull = buffRadio != null ? [buffRadio, new Int16Array(Math.floor(0.5 * 8000))] : [];
121
- buffFull.push(
122
- SetSameHeader(header, 3, 8000, {
123
- preMarkSec: 1.1,
124
- gapSec: 0.5,
125
- }),
126
- new Int16Array(Math.floor(0.5 * 8000)),
127
- SetAttentionTone(8, 8000),
128
- new Int16Array(Math.floor(0.5 * 8000)),
129
- vRadio
130
- )
131
- for (let i = 0; i < 3; i++) {
132
- buffFull.push(SetSameHeader(header, 1, 8000, { preMarkSec: 0.5, gapSec: 0.1 }))
133
- buffFull.push(new Int16Array(Math.floor(0.5 * 8000)));
134
- }
135
- const aSamples = GetMergedPCM16(buffFull);
136
- const aFinal = SetNoise(aSamples, 0.002);
137
- const aBuffer = GetPCM16(Array.from(aFinal).map(v => ({ value: v })), 8000);
138
- writeFileSync(outTTS, aBuffer)
139
- try{ unlinkSync(tmpTTS) } catch {}
140
- SetDebug({ title: `GenerateEASMessage`, message: `${Math.round(performance.now() - tick)}ms` })
141
- return outTTS;
142
- }
143
-
144
-
@@ -1,43 +0,0 @@
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
-
21
- export const GetFormattedTime = (date: string): string => {
22
- const now = Date.now();
23
- const then = typeof date === "number" ? date : new Date(date).getTime()
24
- const seconds = Math.floor((now - then) / 1000);
25
- const absSeconds = Math.abs(seconds);
26
- const isPast = seconds > 0;
27
- const units: [string, number][] = [
28
- ["year", 31536000], ["month", 2592000],
29
- ["day", 86400], ["hour", 3600],
30
- ["minute", 60], ["second", 1],
31
- ];
32
- for (const [name, value] of units) {
33
- const interval = Math.floor(absSeconds / value);
34
- if (interval >= 1) {
35
- return isPast
36
- ? `${interval} ${name}${interval > 1 ? "s" : ""} ago`
37
- : `in ${interval} ${name}${interval > 1 ? "s" : ""}`;
38
- }
39
- }
40
- return "just now";
41
- }
42
-
43
-