@atmosx/event-product-parser 3.0.4 → 3.0.7

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 (212) hide show
  1. package/{CONTRIBUTING.md → .github/CONTRIBUTING.md} +1 -1
  2. package/.github/SUPPORTED_EVENTS.md +370 -0
  3. package/.github/docs/docs-functions.md +30 -0
  4. package/.github/docs/docs-general-configurations.md +199 -0
  5. package/.github/docs/docs-integrations.md +38 -0
  6. package/.github/docs/docs-listeners.md +28 -0
  7. package/.github/docs/docs-source-configuration.md +218 -0
  8. package/.github/docs/docs-technical.md +50 -0
  9. package/.github/logo.png +0 -0
  10. package/.github/samples/SAMPLE_EAS_GENERATION.wav +0 -0
  11. package/.github/samples/SAMPLE_GEOJSON.json +204 -0
  12. package/.github/samples/SAMPLE_TEXT_PRODUCT.txt +119 -0
  13. package/README.md +157 -337
  14. package/dist/cjs/index.cjs +24125 -15815
  15. package/dist/esm/index.mjs +24144 -15839
  16. package/package.json +56 -53
  17. package/pnpm-workspace.yaml +4 -0
  18. package/src/bootstrap.ts +83 -43
  19. package/src/building/CreateEvent.ts +54 -0
  20. package/src/{@building/building.clean.ts → building/GetCleanedEvent.ts} +4 -4
  21. package/src/building/GetEventAttachments.ts +88 -0
  22. package/src/building/GetEventDirection.ts +28 -0
  23. package/src/{@building/building.enhance.ts → building/GetEventEnhancedName.ts} +13 -17
  24. package/src/{@building/building.geometry.ts → building/GetEventGeometry.ts} +19 -13
  25. package/src/{@building/building.headers.ts → building/GetEventHeader.ts} +13 -13
  26. package/src/{@building/building.polygon.ts → building/GetEventNodes.ts} +26 -22
  27. package/src/{@building/building.office.ts → building/GetEventOffice.ts} +14 -14
  28. package/src/building/GetEventProperties.ts +105 -0
  29. package/src/{@building/building.signature.ts → building/GetEventSignature.ts} +16 -17
  30. package/src/{@core/core.createListener.ts → building/GetEventTags.ts} +11 -6
  31. package/src/building/GetEventTheme.ts +26 -0
  32. package/src/building/GetEventTracking.ts +64 -0
  33. package/src/components/audio/GenerateAudioMessage.ts +149 -0
  34. package/src/components/audio/components/GetCleanDescription.ts +91 -0
  35. package/src/{@modules/@eas/eas.getFloatPCM16.ts → components/audio/components/GetFloatPCM16.ts} +3 -3
  36. package/src/{@modules/@eas/eas.getMergedPCM16.ts → components/audio/components/GetMergedPCM16.ts} +3 -3
  37. package/src/{@modules/@eas/eas.getPCM16.ts → components/audio/components/GetPCM16.ts} +13 -8
  38. package/src/{@modules/@eas/eas.getPCMToFloat.ts → components/audio/components/GetPCMToFloat.ts} +3 -3
  39. package/src/{@modules/@eas/eas.getSampledPCM16.ts → components/audio/components/GetSampledPCM16.ts} +14 -8
  40. package/src/components/audio/components/GetTTS.ts +61 -0
  41. package/src/{@modules/@eas/eas.getWavPCM16.ts → components/audio/components/GetWavPCM16.ts} +8 -8
  42. package/src/{@modules/@eas/eas.setAFSK.ts → components/audio/components/SetAFSK.ts} +12 -8
  43. package/src/{@modules/@eas/eas.setAsciiToBits.ts → components/audio/components/SetAsciiToBits.ts} +3 -4
  44. package/src/{@modules/@eas/eas.setAttentionTone.ts → components/audio/components/SetAttentionTone.ts} +11 -6
  45. package/src/{@modules/@eas/eas.setNoise.ts → components/audio/components/SetNoise.ts} +14 -8
  46. package/src/{@modules/@eas/eas.setRadioEffect.ts → components/audio/components/SetRadioEffect.ts} +14 -8
  47. package/src/{@modules/@eas/eas.setSameHeader.ts → components/audio/components/SetSameHeader.ts} +22 -15
  48. package/src/{@modules/@utilities/utilities.setWarning.ts → components/database/CreateQuery.ts} +18 -13
  49. package/src/{@modules/@database/database.cache.ts → components/database/GetCachedEvents.ts} +19 -14
  50. package/src/components/database/ImportBoundaries.ts +168 -0
  51. package/src/components/database/ImportBroadcastify.ts +60 -0
  52. package/src/components/database/ImportCities.ts +87 -0
  53. package/src/{@modules/@database/database.shapefiles.ts → components/database/ImportShapefiles.ts} +31 -37
  54. package/src/components/database/ImportStanza.ts +43 -0
  55. package/src/components/database/InitializeDatabase.ts +71 -0
  56. package/src/components/images/GenerateGraphic.ts +234 -0
  57. package/src/components/images/components/CreateRectangle.ts +22 -0
  58. package/src/components/images/components/CreateText.ts +22 -0
  59. package/src/components/images/modules/CreateSVG.ts +37 -0
  60. package/src/components/images/modules/GetGeographicalBoundaries.ts +72 -0
  61. package/src/components/images/modules/GetGeographicalCities.ts +58 -0
  62. package/src/components/images/modules/GetGeographicalEvents.ts +48 -0
  63. package/src/components/images/modules/GetGeometryBounds.ts +82 -0
  64. package/src/components/images/modules/GetParsedBoundary.ts +58 -0
  65. package/src/components/images/modules/GetSVGPath.ts +53 -0
  66. package/src/components/images/modules/NormalizePolygon.ts +57 -0
  67. package/src/{@modules/@stanza/stanza.getAwipsType.ts → components/stanza/GetAwipsType.ts} +19 -18
  68. package/src/components/stanza/ValidateStanza.ts +62 -0
  69. package/src/components/utilities/CreateHttp.ts +83 -0
  70. package/src/{@modules/@utilities/utilities.getFormattedTime.ts → components/utilities/GetFormattedTime.ts} +3 -3
  71. package/src/components/utilities/GetLatestIssuance.ts +32 -0
  72. package/src/components/utilities/GetMatched.ts +38 -0
  73. package/src/{@modules/@utilities/utilities.getShapeNearestPoint.ts → components/utilities/GetShapeNearestPoint.ts} +24 -19
  74. package/src/components/utilities/GetUnionPolygon.ts +36 -0
  75. package/src/components/utilities/QueueManager.ts +70 -0
  76. package/src/components/utilities/SetCronSchedule.ts +98 -0
  77. package/src/{@core/core.clearEvents.ts → components/utilities/SetDebug.ts} +17 -12
  78. package/src/components/utilities/SetEventEmit.ts +42 -0
  79. package/src/{@modules/@utilities/utilities.setSettings.ts → components/utilities/SetSettings.ts} +7 -7
  80. package/src/{@modules/@utilities/utilities.setSleep.ts → components/utilities/SetSleep.ts} +5 -5
  81. package/src/components/utilities/SetTimeoutAction.ts +64 -0
  82. package/src/components/utilities/SetWarning.ts +47 -0
  83. package/src/{@modules/@xmpp/xmpp.xDeploy.ts → components/xmpp/DeployXMPP.ts} +26 -27
  84. package/src/components/xmpp/ErrorXMPP.ts +27 -0
  85. package/src/{@modules/@xmpp/xmpp.xError.ts → components/xmpp/OfflineXMPP.ts} +17 -9
  86. package/src/{@modules/@xmpp/xmpp.xOnline.ts → components/xmpp/OnlineXMPP.ts} +21 -20
  87. package/src/components/xmpp/ReconnectXMPP.ts +64 -0
  88. package/src/components/xmpp/StanzaXMPP.ts +63 -0
  89. package/src/{@building/building.tags.ts → core/ClearEvents.ts} +12 -5
  90. package/src/{@core/core.getVersion.ts → core/GetEvents.ts} +5 -6
  91. package/src/core/GetNodes.ts +24 -0
  92. package/src/{@core/core.getNodes.ts → core/GetRandomEvent.ts} +5 -6
  93. package/src/core/GetVersion.ts +24 -0
  94. package/src/core/ManualEvent.ts +55 -0
  95. package/src/core/QueryStanza.ts +40 -0
  96. package/src/core/SetNode.ts +87 -0
  97. package/src/core/StartService.ts +62 -0
  98. package/src/core/StopService.ts +32 -0
  99. package/src/enums/AWIPS.ts +366 -0
  100. package/src/{@dictionaries/dictionaries.eventActions.ts → enums/Actions.ts} +3 -3
  101. package/src/{@dictionaries/dictionaries.eventCancelMessages.ts → enums/Cancellation.ts} +4 -3
  102. package/src/{@dictionaries/dictionaries.eventCauses.ts → enums/Causes.ts} +3 -3
  103. package/src/{@dictionaries/dictionaries.statusCorrelationText.ts → enums/Correlations.ts} +3 -3
  104. package/src/enums/Enhanced.ts +70 -0
  105. package/src/{@dictionaries/dictionaries.eventTypes.ts → enums/Events.ts} +3 -3
  106. package/src/{@dictionaries/dictionaries.regExp.ts → enums/Expressions.ts} +5 -4
  107. package/src/{@core/core.getEvents.ts → enums/GlobalFilter.ts} +7 -8
  108. package/src/{@dictionaries/dictionaries.hailStrings.ts → enums/Hail.ts} +9 -4
  109. package/src/{@dictionaries/dictionaries.officeICAOs.ts → enums/ICAO.ts} +5 -3
  110. package/src/enums/Matches.ts +60 -0
  111. package/src/{@dictionaries/dictionaries.eventProducts.ts → enums/Products.ts} +3 -3
  112. package/src/{@dictionaries/dictionaries.eventRecords.ts → enums/Records.ts} +3 -3
  113. package/src/{@dictionaries/dictionaries.eventSeverity.ts → enums/Severity.ts} +3 -3
  114. package/src/{@dictionaries/dictionaries.shapefileLinks.ts → enums/Shapefiles.ts} +3 -3
  115. package/src/enums/States.ts +136 -0
  116. package/src/{@dictionaries/dictionaries.eventStatus.ts → enums/Status.ts} +3 -3
  117. package/src/enums/Strings.ts +22 -0
  118. package/src/enums/Tags.ts +172 -0
  119. package/src/{@dictionaries/dictionaries.testSignatures.ts → enums/Testing.ts} +5 -4
  120. package/src/enums/Themes.ts +70 -0
  121. package/src/events/ParseAPI.ts +129 -0
  122. package/src/{@events/events.text.ts → events/ParseText.ts} +32 -23
  123. package/src/{@events/events.ugc.ts → events/ParseUGC.ts} +36 -26
  124. package/src/events/ParseVTEC.ts +88 -0
  125. package/src/index.ts +60 -38
  126. package/src/manager/MakeEvents.ts +110 -0
  127. package/src/manager/RemoveEvent.ts +74 -0
  128. package/src/{@manager/manager.setHash.ts → manager/SetHash.ts} +19 -15
  129. package/src/manager/UpdateEvents.ts +35 -0
  130. package/src/manager/UpdateNode.ts +62 -0
  131. package/src/manager/ValidateEvents.ts +144 -0
  132. package/src/{@parsers/@hvtec/hvtec.extract.ts → parsers/hvtec/HVExtract.ts} +13 -13
  133. package/src/parsers/text/GetDescriptionFromProduct.ts +59 -0
  134. package/src/parsers/text/GetEmbededText.ts +57 -0
  135. package/src/parsers/text/GetPolygonFromProduct.ts +71 -0
  136. package/src/parsers/text/GetStringText.ts +58 -0
  137. package/src/{@parsers/@text/text.getTextFromProduct.ts → parsers/text/GetTextFromProduct.ts} +12 -12
  138. package/src/parsers/ugc/GetCache.ts +24 -0
  139. package/src/{@parsers/@ugc/ugc.expiry.ts → parsers/ugc/GetExpiry.ts} +3 -3
  140. package/src/{@parsers/@ugc/ugc.header.ts → parsers/ugc/GetHeader.ts} +6 -6
  141. package/src/parsers/ugc/GetLocations.ts +57 -0
  142. package/src/parsers/ugc/GetZonePolygon.ts +73 -0
  143. package/src/{@parsers/@ugc/ugc.zones.ts → parsers/ugc/GetZones.ts} +3 -3
  144. package/src/{@modules/@utilities/utilities.setListener.ts → parsers/ugc/SetCache.ts} +13 -10
  145. package/src/{@parsers/@ugc/ugc.extract.ts → parsers/ugc/UGCExtract.ts} +15 -15
  146. package/src/{@parsers/@pvtec/pvtec.expires.ts → parsers/vtec/GetExpiry.ts} +3 -3
  147. package/src/parsers/vtec/VTECExtract.ts +49 -0
  148. package/src/{@types/types.attributes.ts → static/Attributes.ts} +2 -3
  149. package/src/{@types/type.event.ts → static/Event.ts} +11 -8
  150. package/src/{@types/type.properties.ts → static/Properties.ts} +17 -10
  151. package/src/{@types/types.stanza.ts → static/Stanza.ts} +2 -2
  152. package/src/tasks/CreateTasks.ts +123 -0
  153. package/src/{@core/core.stop.ts → tasks/TaskGenerateJSON.ts} +14 -12
  154. package/src/tasks/TaskGenerateText.ts +34 -0
  155. package/src/tasks/TaskSendNTFY.ts +97 -0
  156. package/src/tasks/TaskSendWebhook.ts +107 -0
  157. package/src/types/Actions.ts +37 -0
  158. package/src/{@types/types.hvtec.ts → types/HVTEC.ts} +6 -6
  159. package/src/{@types/types.hash.ts → types/Hash.ts} +5 -5
  160. package/src/types/Nodes.ts +29 -0
  161. package/src/{@types/types.settings.ts → types/Settings.ts} +42 -10
  162. package/src/{@types/types.compiled.ts → types/StanzaCompiled.ts} +15 -14
  163. package/src/{@types/types.ugc.ts → types/UGC.ts} +5 -5
  164. package/src/{@modules/@utilities/utilities.getSettings.ts → types/VTEC.ts} +12 -7
  165. package/tools/build.js +47 -0
  166. package/tsconfig.json +28 -1
  167. package/dist/index.d.mts +0 -239
  168. package/dist/index.d.ts +0 -239
  169. package/src/@building/building.create.ts +0 -42
  170. package/src/@building/building.properties.ts +0 -89
  171. package/src/@building/building.tracking.ts +0 -68
  172. package/src/@building/building.validate.ts +0 -147
  173. package/src/@core/core.getRandomEvent.ts +0 -25
  174. package/src/@core/core.setNode.ts +0 -81
  175. package/src/@core/core.start.ts +0 -61
  176. package/src/@dictionaries/dictionaries.betterEventNames.ts +0 -99
  177. package/src/@dictionaries/dictionaries.eventAwipAbreviations.ts +0 -364
  178. package/src/@dictionaries/dictionaries.eventTags.ts +0 -93
  179. package/src/@dictionaries/dictionaries.eventsMatchText.ts +0 -36
  180. package/src/@dictionaries/dictionaries.transcribedMessageReplacements.ts +0 -68
  181. package/src/@events/events.api.ts +0 -113
  182. package/src/@events/events.vtec.ts +0 -87
  183. package/src/@manager/manager.mkEvent.ts +0 -96
  184. package/src/@manager/manager.rmEvent.ts +0 -49
  185. package/src/@manager/manager.updateEvents.ts +0 -35
  186. package/src/@manager/manager.updateNodes.ts +0 -55
  187. package/src/@manager/manager.updateWebhooks.ts +0 -50
  188. package/src/@modules/@database/database.init.ts +0 -45
  189. package/src/@modules/@database/database.stanza.ts +0 -48
  190. package/src/@modules/@eas/eas.setEasTone.ts +0 -137
  191. package/src/@modules/@stanza/stanza.validate.ts +0 -50
  192. package/src/@modules/@utilities/utilities.createHttp.ts +0 -85
  193. package/src/@modules/@utilities/utilities.createWebhook.ts +0 -115
  194. package/src/@modules/@utilities/utilities.setCronSchedule.ts +0 -65
  195. package/src/@modules/@utilities/utilities.setEventEmit.ts +0 -41
  196. package/src/@modules/@utilities/utilities.setTimeoutAction.ts +0 -59
  197. package/src/@modules/@xmpp/xmpp.xOffline.ts +0 -38
  198. package/src/@modules/@xmpp/xmpp.xReconnect.ts +0 -64
  199. package/src/@modules/@xmpp/xmpp.xStanza.ts +0 -63
  200. package/src/@parsers/@pvtec/pvtec.extract.ts +0 -49
  201. package/src/@parsers/@text/text.getDescriptionFromProduct.ts +0 -53
  202. package/src/@parsers/@text/text.getPolygonFromProduct.ts +0 -32
  203. package/src/@parsers/@text/text.getXML.ts +0 -61
  204. package/src/@parsers/@ugc/ugc.coordinates.ts +0 -110
  205. package/src/@parsers/@ugc/ugc.locations.ts +0 -29
  206. package/src/@types/types.pvtec.ts +0 -30
  207. package/src/@types/types.webhook.ts +0 -27
  208. package/test.js +0 -91
  209. package/tsup.config.ts +0 -16
  210. /package/{CODE_OF_CONDUCT.md → .github/CODE_OF_CONDUCT.md} +0 -0
  211. /package/{LICENSE → .github/LICENSE} +0 -0
  212. /package/{SECURITY.md → .github/SECURITY.md} +0 -0
@@ -11,17 +11,16 @@
11
11
  Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
12
  Discord: https://atmosphericx-discord.scriptkitty.cafe
13
13
  Ko-Fi: https://ko-fi.com/k3yomi
14
- Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
14
+ Documentation: https://atmosphericx.scriptkitty.cafe/documentation
15
15
 
16
- Internal Package: @atmosx/event-product-parser
16
+ Independent Package: @atmosx/event-product-parser
17
17
 
18
18
  */
19
19
 
20
-
21
- import { TypeEvent } from "../@types/type.event"
22
- import { getEventGeometry } from "./building.geometry"
23
- import { bootstrap } from "../bootstrap"
24
- import { getShapeNearestPoint } from "../@modules/@utilities/utilities.getShapeNearestPoint"
20
+ import { TypeEvent } from "StaticTypes/Event"
21
+ import { Bootstrap } from "@Bootstrap"
22
+ import { GetEventGeometry } from "@Building/GetEventGeometry"
23
+ import { GetShapeNearestPoint } from "@Utilities/GetShapeNearestPoint"
25
24
 
26
25
  interface GetEventNodesResponse {
27
26
  nodes: {
@@ -36,32 +35,37 @@ interface GetEventNodesResponse {
36
35
  updated: number
37
36
  }
38
37
 
39
- export const getEventNodes = async (event: TypeEvent): Promise<GetEventNodesResponse> => {
40
- const metadata = { nodes: [], proximity: false, filtered: false }
41
- const geometry = await getEventGeometry(event);
38
+ export const GetEventNodes = async (event: TypeEvent): Promise<GetEventNodesResponse> => {
39
+ const nodes = Bootstrap.Cache.Nodes.features;
40
+ if (!nodes || nodes.length === 0) {
41
+ return { nodes: [], filtered: false, updated: Date.now() };
42
+ }
43
+ const metadata = { nodes: [] as GetEventNodesResponse['nodes'], proximity: false, filtered: false };
44
+ const geometry = await GetEventGeometry({ Event: event });;
42
45
  if (!geometry || !geometry.coordinates) {
43
46
  return { nodes: [], filtered: false, updated: Date.now() }
44
47
  }
45
- const nodes = bootstrap.cache.nodes.features;
46
48
  for (const node of nodes) {
47
- const [longitude, latitude] = node.geometry.coordinates;
48
- const getPoint = getShapeNearestPoint(geometry.coordinates, [longitude, latitude])
49
- const miles = getPoint.distance ?? null;
50
- const kilometers = Number((miles * 1.609344).toFixed(3));
49
+ const [longitude, latitude] = (node?.geometry?.coordinates ?? []) as [number, number];
50
+
51
+ const getPoint = GetShapeNearestPoint({ Coordinates: geometry.coordinates, Point: [longitude, latitude] });
52
+ const miles = getPoint.Distance ?? null;
53
+ const kilometers = miles != null ? Number((miles * 1.609344).toFixed(3)) : null;
51
54
 
52
55
  const info = {
53
56
  id: node.properties?.identifier,
54
- coordinates: [longitude, latitude],
55
- nearest: getPoint.point,
57
+ coordinates: [longitude, latitude] as [number, number],
58
+ nearest: getPoint.Point as [number, number],
56
59
  miles,
57
60
  kilometers,
58
- proximity: getPoint.proximity
59
- }
60
- metadata.nodes.push(info)
61
- if (bootstrap.settings.GlobalSettings.EventFiltering.NodeLocationFiltering && miles < bootstrap.settings.GlobalSettings.NodeMinDistance) {
62
- metadata.proximity = true;
61
+ proximity: false
62
+ };
63
+
64
+ if (miles != null && (miles < Bootstrap.Settings.GlobalSettings.NodeMaxDistance)) {
63
65
  info.proximity = true;
66
+ metadata.proximity = true;
64
67
  }
68
+ metadata.nodes.push(info);
65
69
  }
66
70
  return {
67
71
  nodes: metadata.nodes,
@@ -11,20 +11,20 @@
11
11
  Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
12
  Discord: https://atmosphericx-discord.scriptkitty.cafe
13
13
  Ko-Fi: https://ko-fi.com/k3yomi
14
- Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
14
+ Documentation: https://atmosphericx.scriptkitty.cafe/documentation
15
15
 
16
- Internal Package: @atmosx/event-product-parser
16
+ Independent Package: @atmosx/event-product-parser
17
17
 
18
18
  */
19
19
 
20
- import { TypeAttributes } from "../@types/types.attributes";
21
- import { TypePVTEC } from "../@types/types.pvtec";
22
- import { officeICAOs } from "../@dictionaries/dictionaries.officeICAOs";
20
+ import { TypeAttributes } from "StaticTypes/Attributes"
21
+ import { TypeVTEC } from "Types/VTEC"
22
+ import { EnumICAO } from "@Enums/ICAO"
23
23
 
24
24
  interface GetOfficeOptions {
25
- attributes: TypeAttributes
26
- organization: string
27
- pVtec: TypePVTEC
25
+ Attributes: TypeAttributes
26
+ Organization: string
27
+ VTEC: TypeVTEC
28
28
  }
29
29
 
30
30
  interface GetOfficeResponse {
@@ -32,12 +32,12 @@ interface GetOfficeResponse {
32
32
  name: string | null
33
33
  }
34
34
 
35
- export const getEventOffice = (options: GetOfficeOptions): GetOfficeResponse => {
36
- const office = options.pVtec != null
37
- ? options.pVtec?.tracking?.split(`-`)[0] : (options.attributes?.cccc ||
38
- (options.organization != null ?
39
- (Array.isArray(options.organization) ? options.organization?.[0] : options.organization)
35
+ export const GetEventOffice = ({ Attributes, Organization, VTEC }: GetOfficeOptions): GetOfficeResponse => {
36
+ const office = VTEC != null
37
+ ? VTEC?.Tracking?.split(`.`)[0] : (Attributes?.cccc ??
38
+ (Organization != null ?
39
+ (Array.isArray(Organization) ? Organization?.[0] : Organization)
40
40
  : null));
41
- const name = officeICAOs?.[office] ?? null;
41
+ const name = EnumICAO?.[office] ?? null;
42
42
  return { office, name };
43
43
  }
@@ -0,0 +1,105 @@
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: https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Independent Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ import { TypeEventProperties } from "StaticTypes/Properties"
21
+ import { TypeAttributes } from "StaticTypes/Attributes"
22
+ import { TypeUGC } from "Types/UGC"
23
+ import { TypeVTEC } from "Types/VTEC"
24
+ import { EnumExpressions } from "@Enums/Expressions"
25
+ import { GetDescriptionFromProduct } from "@ParsingText/GetDescriptionFromProduct"
26
+ import { GetPolygonFromProduct } from "@ParsingText/GetPolygonFromProduct"
27
+ import { GetTextFromProduct } from "@ParsingText/GetTextFromProduct"
28
+ import { GetEventOffice } from "@Building/GetEventOffice"
29
+ import { GetEventTags } from "@Building/GetEventTags"
30
+ import { GetEventDirection } from "@Building/GetEventDirection"
31
+
32
+ interface GetEventPropertiesOptions {
33
+ Message: string
34
+ Attributes: TypeAttributes
35
+ UGC?: TypeUGC
36
+ VTEC?: TypeVTEC
37
+ }
38
+
39
+ export const GetEventProperties = ({ Message, Attributes, UGC, VTEC }: GetEventPropertiesOptions): TypeEventProperties => {
40
+ const organization = Message.match(EnumExpressions.wmo)?.[0] ?? null
41
+ const polygons = GetPolygonFromProduct(Message)
42
+ const properties = {
43
+ locations: UGC?.Locations?.join(`; `) ?? null,
44
+ locations_array: UGC?.Locations ?? [],
45
+ regions: [...new Set(
46
+ UGC?.Zones
47
+ ?.map((location: string) => location.match(/^([A-Z]{2})[CZ](\d{3})$/)?.[1])
48
+ .filter(Boolean) ?? []
49
+ )],
50
+ regions_string: (() => {
51
+ const abbrs = [...new Set(UGC?.Zones?.map((l: string) => l.match(/^([A-Z]{2})[CZ](\d{3})$/)?.[1]).filter(Boolean) ?? [])];
52
+ return abbrs.length ? abbrs.join(`-`) : null;
53
+ })(),
54
+ description: GetDescriptionFromProduct({ Message: Message, Handle: VTEC?.Raw ?? null }),
55
+ attributes: Attributes,
56
+ geocode: {
57
+ office: GetEventOffice({ Attributes: Attributes, Organization: organization, VTEC: VTEC }),
58
+ organization: organization,
59
+ ugc: UGC?.Zones ?? [],
60
+ polygon: polygons.length > 0 ? Buffer.from(JSON.stringify([polygons])).toString('base64') : null,
61
+ polygon_generated: polygons.length > 0 ? true : false
62
+ },
63
+ parameters: {
64
+ tags: GetEventTags(Message),
65
+ instructions: GetTextFromProduct({ Message: Message, Find: [`For your protection`, `do not`, `use extreme caution`], Append: `...`, Removal: [`.`]}) ?? null,
66
+ source: GetTextFromProduct({ Message: Message, Find: [`SOURCE...`], Removal: [`.`]}) ?? null,
67
+ hazards: GetTextFromProduct({ Message: Message, Find: [`HAZARD...`], Removal: [`.`]}) ?? null,
68
+ impacts: GetTextFromProduct({ Message: Message, Find: [`IMPACT...`], Removal: [`.`]}) ?? null,
69
+ estimated_hail_size: GetTextFromProduct({ Message: Message, Find: [`MAX HAIL SIZE...`, `HAIL...`], Removal: ['in']}) ?? null,
70
+ estimated_wind_gusts: GetTextFromProduct({ Message: Message, Find: [`MAX WIND GUST...`, `WIND...`]}) ?? null,
71
+ direction: GetEventDirection(Message) ?? null,
72
+ damage_threat: GetTextFromProduct({ Message: Message, Find: [`DAMAGE THREAT...`], Removal: []}) ?? null,
73
+ tornado_threat: GetTextFromProduct({ Message: Message, Find: [`TORNADO...`, `WATERSPOUT...`] }) ?? null,
74
+ flood_threat: GetTextFromProduct({ Message: Message, Find: [`FLASH FLOOD...`]}) ?? null,
75
+ wind_threat: GetTextFromProduct({ Message: Message, Find: [`WIND THREAT...`]}) ?? null,
76
+ hail_threat: GetTextFromProduct({ Message: Message, Find: [`HAIL THREAT...`], Removal: []}) ?? null,
77
+ },
78
+ discussion_parameters: {
79
+ discussion_number: GetTextFromProduct({ Message: Message, Find: [`Mesoscale Discussion `], Removal: [`Mesoscale Discussion`, `Number`, `...`] })?.toString()?.padStart(4, "0") ?? null,
80
+ discussion_concerning: GetTextFromProduct({ Message: Message, Find: [`Concerning...`] }) ?? null,
81
+ discussion_max_tornado: GetTextFromProduct({ Message: Message, Find: [`MOST PROBABLE PEAK TORNADO INTENSITY...`] }) ?? null,
82
+ discussion_max_hail: GetTextFromProduct({ Message: Message, Find: [`MOST PROBABLE PEAK HAIL SIZE...`] }) ?? null,
83
+ discussion_max_wind: GetTextFromProduct({ Message: Message, Find: [`MOST PROBABLE PEAK WIND GUST...`] }) ?? null,
84
+ discussion_watch_issuance: GetTextFromProduct({ Message: Message, Find: [`Probability of Watch Issuance...`], Removal: [`percent`]}) ?? null,
85
+ },
86
+ watch_parameters: {
87
+ watch_number: VTEC?.Watch ? ( GetTextFromProduct({ Message: Message, Find: [`ITIES FOR`, `UPDATE FOR`, `Watch Number `], Removal: [`%`, `<`, `:`] })?.replace(/(WT|WS|)/g, '')?.trim()?.toString()?.padStart(4, "0") ?? VTEC?.Tracking?.slice(-4)?.toString()?.padStart(4, "0") ?? null) : null,
88
+ watch_type: Message.includes(`TORNADO WATCH`) ? `Tornado` : Message.includes(`SEVERE`) ? `Severe` : null,
89
+ additional_tornadoes_probability: GetTextFromProduct({ Message: Message, Find: [`PROB OF 2 OR MORE TORNADOES`], Removal: [`%`, `<`, `:`] }) ?? null,
90
+ strong_tornadoes_probability: GetTextFromProduct({ Message: Message, Find: [`PROB OF 1 OR MORE STRONG /EF2-EF5/ TORNADOES`], Removal: [`%`, `<`, `:`] }) ?? null,
91
+ severe_wind_probability: GetTextFromProduct({ Message: Message, Find: [`PROB OF 10 OR MORE SEVERE WIND EVENTS`], Removal: [`%`, `<`, `:`] }) ?? null,
92
+ severe_hail_probability: GetTextFromProduct({ Message: Message, Find: [`PROB OF 10 OR MORE SEVERE HAIL EVENTS`], Removal: [`%`, `<`, `:`] }) ?? null,
93
+ hail_2in_probability: GetTextFromProduct({ Message: Message, Find: [`PROB OF 1 OR MORE HAIL EVENTS >= 2 INCHES`], Removal: [`%`, `<`, `:`] }) ?? null,
94
+ combined_hail_wind_probability: GetTextFromProduct({ Message: Message, Find: [`PROB OF 6 OR MORE COMBINED SEVERE HAIL/WIND EVENTS`], Removal: [`%`, `<`, `:`] }) ?? null,
95
+ max_hail_in: GetTextFromProduct({ Message: Message, Find: [`MAX HAIL /INCHES/`], Removal: [`%`, `<`, `:`] }) ?? null,
96
+ max_wind_surface: GetTextFromProduct({ Message: Message, Find: [`MAX WIND GUSTS SURFACE /KNOTS/`], Removal: [`%`, `<`, `:`] }) ?? null,
97
+ max_tops_x100feet: GetTextFromProduct({ Message: Message, Find: [`MAX TOPS /X 100 FEET/`], Removal: [`%`, `<`, `:`] }) ?? null,
98
+ pds_watch: (GetTextFromProduct({ Message: Message, Find: [`PARTICULARLY DANGEROUS SITUATION`], Removal: [`%`, `<`, `:`] }) === `YES` ? true : null)
99
+ }
100
+ }
101
+ if (isNaN(Number(properties.watch_parameters.watch_number))) {
102
+ properties.watch_parameters.watch_number = null
103
+ }
104
+ return properties;
105
+ }
@@ -11,30 +11,29 @@
11
11
  Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
12
  Discord: https://atmosphericx-discord.scriptkitty.cafe
13
13
  Ko-Fi: https://ko-fi.com/k3yomi
14
- Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
14
+ Documentation: https://atmosphericx.scriptkitty.cafe/documentation
15
15
 
16
- Internal Package: @atmosx/event-product-parser
16
+ Independent Package: @atmosx/event-product-parser
17
17
 
18
18
  */
19
19
 
20
- import { TypeEvent } from "../@types/type.event";
21
- import { statusCorrelationText } from "../@dictionaries/dictionaries.statusCorrelationText";
22
- import { eventCancelMessages } from "../@dictionaries/dictionaries.eventCancelMessages";
23
- import { testSignatures} from "../@dictionaries/dictionaries.testSignatures"
24
- import { eventProducts } from "../@dictionaries/dictionaries.eventProducts";
25
- import { hailStrings } from "../@dictionaries/dictionaries.hailStrings"
20
+ import { TypeEvent } from "StaticTypes/Event"
21
+ import { EnumCorrelations } from "@Enums/Correlations"
22
+ import { EnumCancellation } from "@Enums/Cancellation"
23
+ import { EnumTesting} from "@Enums/Testing"
24
+ import { EnumProducts } from "@Enums/Products"
25
+ import { EnumHail } from "@Enums/Hail"
26
26
 
27
-
28
- export const getEventSignature = (event: TypeEvent): TypeEvent => {
27
+ export const GetEventSignature = (event: TypeEvent): TypeEvent => {
29
28
  const properties = event?.properties;
30
29
  const vtec = event?.properties?.metadata?.vtec
31
- const status = statusCorrelationText
30
+ const status = EnumCorrelations
32
31
  .find((c: { type: string }) => c.type === properties?.status);
33
- const csig = eventCancelMessages.find(sig => properties.description.toLowerCase().includes(sig.toLowerCase()));
32
+ const csig = EnumCancellation.find(sig => properties.description.toLowerCase().includes(sig.toLowerCase()));
34
33
  properties.status_metadata = { ...properties.status_metadata, is_issued: true, is_test: false};
35
34
 
36
- if (properties.parameters.estimated_hail_size) {
37
- properties.parameters.estimated_hail_size += ` (${hailStrings[properties.parameters.estimated_hail_size] ?? '--'})`
35
+ if (properties?.parameters?.estimated_hail_size) {
36
+ properties.parameters.estimated_hail_size += ` (${EnumHail[properties?.parameters?.estimated_hail_size] ?? '--'})`
38
37
  }
39
38
 
40
39
  if (status) {
@@ -45,9 +44,9 @@ export const getEventSignature = (event: TypeEvent): TypeEvent => {
45
44
  properties.status_metadata = { ...properties.status_metadata, is_expired: true };
46
45
  }
47
46
 
48
- const getProduct = vtec?.vtec?.split(`.`)[0]?.replace(`/`, ``)
49
- const isTestProduct = eventProducts[getProduct] == `Test Product`
50
- if (isTestProduct || testSignatures.some(sig => properties.description?.toLowerCase().includes(sig.toLowerCase()) || properties?.parameters?.instructions?.toLowerCase().includes(sig.toLowerCase()))) {
47
+ const getProduct = vtec?.Raw?.split(`.`)[0]?.replace(`/`, ``)
48
+ const isTestProduct = EnumProducts[getProduct] == `Test Product`
49
+ if (isTestProduct || EnumTesting.some(sig => properties.description?.toLowerCase().includes(sig.toLowerCase()) ?? properties?.parameters?.instructions?.toLowerCase().includes(sig.toLowerCase()))) {
51
50
  properties.status_metadata = { ...properties.status_metadata, is_test: true }
52
51
  }
53
52
 
@@ -11,14 +11,19 @@
11
11
  Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
12
  Discord: https://atmosphericx-discord.scriptkitty.cafe
13
13
  Ko-Fi: https://ko-fi.com/k3yomi
14
- Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
14
+ Documentation: https://atmosphericx.scriptkitty.cafe/documentation
15
15
 
16
- Internal Package: @atmosx/event-product-parser
16
+ Independent Package: @atmosx/event-product-parser
17
17
 
18
18
  */
19
19
 
20
- import { setListener } from "../@modules/@utilities/utilities.setListener";
20
+ import { EnumTags } from "@Enums/Tags"
21
21
 
22
- export const createListener = (event: string, callback: () => void) => {
23
- setListener({event, callback})
24
- }
22
+ export const GetEventTags = (message: string): string[] => {
23
+ if (!message) return [];
24
+ return [...new Set(Object.values(EnumTags)
25
+ .flat()
26
+ .filter(({ match }) => match.test(message))
27
+ .map(({ tag }) => tag)
28
+ )];
29
+ };
@@ -0,0 +1,26 @@
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: https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Independent Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ import { Bootstrap } from "@Bootstrap";
21
+ import { EnumThemes } from "@Enums/Themes"
22
+ import { GetMatched } from "@Utilities/GetMatched";
23
+
24
+ export const GetEventTheme = (Event: string): string => {
25
+ return Bootstrap.Settings.GlobalSettings.Themes.find(theme => GetMatched({Strings: [theme.Event], String: Event}))?.RGB ?? EnumThemes.find(theme => theme.Event === `Default`)?.RGB ?? `rgb(56, 72, 88)`;
26
+ };
@@ -0,0 +1,64 @@
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: https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Independent Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ import { TypeAttributes } from "StaticTypes/Attributes"
21
+ import { TypeEventProperties } from "StaticTypes/Properties"
22
+ import { TypeStanzaCompiled } from "Types/StanzaCompiled"
23
+ import { TypeVTEC } from "Types/VTEC"
24
+
25
+ interface GetTrackingOptions {
26
+ Type: `RAW` | `VTEC` | `API`
27
+ Stanza?: TypeStanzaCompiled
28
+ Attributes?: TypeAttributes
29
+ Properties?: TypeEventProperties
30
+ WMO?: {
31
+ Identifier: string
32
+ ID: string
33
+ }
34
+ VTEC?: TypeVTEC
35
+ }
36
+
37
+ export const GetEventTracking = ({ Type, Stanza, Attributes, Properties, WMO, VTEC }: GetTrackingOptions): string => {
38
+ if (Type === `RAW`) {
39
+ const getWatchNumber = Properties?.watch_parameters?.watch_number ?? null
40
+ if (getWatchNumber) {
41
+ return `${Properties.geocode.office.office}.${Stanza.Type.Prefix}.A.${getWatchNumber}`
42
+ }
43
+ return `${Properties.geocode.office.office}.${Attributes.ttaaii}.${Attributes.id.slice(-4).replace(`.`, ``) ?? '0'}`
44
+ }
45
+ if (Type === `VTEC`) {
46
+ return VTEC?.Tracking;
47
+ }
48
+ if (Type === `API`) {
49
+ if (VTEC) {
50
+ const vtecValue = Array.isArray(VTEC)
51
+ ? VTEC[0].vtec : VTEC?.Raw;
52
+ const splitVTEC = vtecValue.split('.');
53
+ return `${splitVTEC[2]}.${splitVTEC[3]}.${splitVTEC[4]}.${splitVTEC[5]}`;
54
+ }
55
+ const wmoMatch = WMO?.Identifier?.match(/([A-Z]{4}\d{2})\s+([A-Z]{4})/);
56
+ const station = wmoMatch?.[2] ?? '---';
57
+ if (WMO?.ID) {
58
+ const idMatch = WMO?.ID.match(/([a-f0-9]+)\.(\d+)\.(\d+)$/);
59
+ return `${station}.${idMatch?.[0]?.replace(/\./g, '') ?? '---'}`;
60
+ }
61
+ const id = wmoMatch?.[1] ?? '---';
62
+ return `${station}.${id?.replace(/\./g, '') ?? '---'}`;
63
+ }
64
+ }
@@ -0,0 +1,149 @@
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: https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Independent Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ import { TypeSettings } from "Types/Settings"
21
+ import { Bootstrap } from "@Bootstrap"
22
+ import { GetWavPCM16 } from "@AudioComponents/GetWavPCM16"
23
+ import { GetSampledPCM16 } from "@AudioComponents/GetSampledPCM16"
24
+ import { SetRadioEffect } from "@AudioComponents/SetRadioEffect"
25
+ import { SetSameHeader } from "@AudioComponents/SetSameHeader"
26
+ import { SetAttentionTone } from "@AudioComponents/SetAttentionTone"
27
+ import { GetMergedPCM16 } from "@AudioComponents/GetMergedPCM16"
28
+ import { SetNoise } from "@AudioComponents/SetNoise"
29
+ import { GetPCM16 } from "@AudioComponents/GetPCM16"
30
+ import { GetTTS } from "@AudioComponents/GetTTS"
31
+ import { GetCleanDescription } from "@AudioComponents/GetCleanDescription"
32
+ import { SetWarning } from "@Utilities/SetWarning"
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
+ interface GenerateAudioMessageOptions {
40
+ Message: string
41
+ Header: string
42
+ Directory?: string
43
+ Title: string
44
+ }
45
+
46
+ export const GenerateAudioMessage = async ({ Message, Directory, Header, Title }: GenerateAudioMessageOptions): Promise<string> => {
47
+ const tick = performance.now()
48
+ const settings = Bootstrap.Settings as TypeSettings;
49
+ const prefix = settings.GlobalSettings.ArchiveSettings.AudioToneout;
50
+ let title = (Title ?? `${Math.random().toString(36).substring(2, 15)}-${Header.replace(/[^a-zA-Z0-9]/g, '')}`).replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
51
+ if (!Message || !Header) {
52
+ SetWarning({
53
+ Title: `Audio`,
54
+ Message: `Message and header are required to generate an audio message.`
55
+ })
56
+ return null;
57
+ }
58
+ let buffTTS: Buffer;
59
+ let buffRadio: any;
60
+ let buffFull: any[] = [];
61
+
62
+ if (!Directory) {
63
+ SetWarning({
64
+ Title: `Audio`,
65
+ Message: `Audio directory is not set in the settings. Please set it to generate audio messages.`
66
+ });
67
+ return null;
68
+ }
69
+
70
+ if (!existsSync(Directory)) {
71
+ mkdirSync(Directory, { recursive: true });
72
+ }
73
+ const tmpTTS = join(Directory, `/${title}-tts.wav`)
74
+ const outTTS = join(Directory, `/${title}.wav`)
75
+ const vPlatform = platform();
76
+
77
+ if (vPlatform === 'darwin') {
78
+ SetWarning({
79
+ Title: `Audio`,
80
+ Message: `Audio tone generation is not supported on macOS.`
81
+ });
82
+ return null
83
+ }
84
+
85
+
86
+ await new Promise<void>((resolve, reject) => {
87
+ const tMsg = GetCleanDescription(Message)
88
+ GetTTS({Text: tMsg, OutputPath: tmpTTS}).then(() => {
89
+ resolve();
90
+ });
91
+ });
92
+ if (!existsSync(tmpTTS)) {
93
+ return null;
94
+ }
95
+ buffTTS = readFileSync(tmpTTS);
96
+ const vWav = GetWavPCM16(buffTTS);
97
+ const vSamples = GetSampledPCM16({Int16: vWav.Samples, OriginalRate: vWav.SampleRate, TargetRate: 8000})
98
+ const vRadio = SetRadioEffect({Int16: vSamples, SampleRate: 8000});
99
+
100
+ if (existsSync(prefix)) {
101
+ let tBuffer = readFileSync(prefix);
102
+ let tWav = GetWavPCM16(tBuffer);
103
+
104
+ if (tWav == null) {
105
+ try {
106
+ const converted = join(Directory, `/${title}-tts-fixed.wav`)
107
+ execSync(`ffmpeg -y -i "${prefix}" -ar 8000 -ac 1 -sample_fmt s16 "${converted}"`, { stdio: 'ignore' })
108
+ if (existsSync(converted)) {
109
+ tBuffer = readFileSync(converted)
110
+ tWav = GetWavPCM16(tBuffer)
111
+ try { unlinkSync(converted) } catch {}
112
+ }
113
+ } catch (e) {}
114
+ }
115
+
116
+ if (tWav == null) {
117
+ SetWarning({
118
+ Title: `EAS`,
119
+ 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.`
120
+ })
121
+ return null;
122
+ }
123
+
124
+ const tSamples = (tWav.SampleRate != 8000 ? GetSampledPCM16({Int16: tWav.Samples, OriginalRate: tWav.SampleRate, TargetRate: 8000}) : tWav.Samples)
125
+ buffRadio = SetRadioEffect({Int16: tSamples, SampleRate: 8000})
126
+ }
127
+
128
+ buffFull = buffRadio != null ? [buffRadio, new Int16Array(Math.floor(0.5 * 8000))] : [];
129
+ buffFull.push(
130
+ SetSameHeader({ VTEC: Header, Repeats: 3, SampleRate: 8000, PreMarkSec: 1.1, GapSec: 0.5 }),
131
+ new Int16Array(Math.floor(0.5 * 8000)),
132
+ SetAttentionTone({ MS: 8, SampleRate: 8000 }),
133
+ new Int16Array(Math.floor(0.5 * 8000)),
134
+ vRadio
135
+ )
136
+ for (let i = 0; i < 3; i++) {
137
+ buffFull.push(SetSameHeader({ VTEC: Header, Repeats: 1, SampleRate: 8000, PreMarkSec: 0.5, GapSec: 0.1 }))
138
+ buffFull.push(new Int16Array(Math.floor(0.5 * 8000)));
139
+ }
140
+ const aSamples = GetMergedPCM16(buffFull);
141
+ const aFinal = SetNoise({ Int16: aSamples, NoiseLevel: 0.002 });
142
+ const aBuffer = GetPCM16({ Samples: Array.from(aFinal).map(v => ({ value: v })), SampleRate: 8000 });
143
+ writeFileSync(outTTS, aBuffer)
144
+ try{ unlinkSync(tmpTTS) } catch {}
145
+ SetDebug({ Title: `GenerateEASMessage`, Message: `${Math.round(performance.now() - tick)}ms` })
146
+ return outTTS;
147
+ }
148
+
149
+
@@ -0,0 +1,91 @@
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: https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Independent Package: @atmosx/event-product-parser
17
+
18
+
19
+ */
20
+
21
+ export const GetCleanDescription = (message: string): string => {
22
+ const patches: { regex: RegExp, replacement: string }[] = [
23
+ { regex: /\.{3,}/g, replacement: ". " },
24
+ { regex: /\bUTC\b/g, replacement: 'Coordinated Universal Time' },
25
+ { regex: /\bGMT\b/g, replacement: 'Greenwich Mean Time' },
26
+ { regex: /\bEST\b(?!\w)/g, replacement: 'Eastern Standard Time' },
27
+ { regex: /\bEDT\b(?!\w)/g, replacement: 'Eastern Daylight Time' },
28
+ { regex: /\bCST\b(?!\w)/g, replacement: 'Central Standard Time' },
29
+ { regex: /\bCDT\b(?!\w)/g, replacement: 'Central Daylight Time' },
30
+ { regex: /\bMST\b(?!\w)/g, replacement: 'Mountain Standard Time' },
31
+ { regex: /\bMDT\b(?!\w)/g, replacement: 'Mountain Daylight Time' },
32
+ { regex: /\bPST\b(?!\w)/g, replacement: 'Pacific Standard Time' },
33
+ { regex: /\bPDT\b(?!\w)/g, replacement: 'Pacific Daylight Time' },
34
+ { regex: /\bAKST\b(?!\w)/g, replacement: 'Alaska Standard Time' },
35
+ { regex: /\bAKDT\b(?!\w)/g, replacement: 'Alaska Daylight Time' },
36
+ { regex: /\bHST\b(?!\w)/g, replacement: 'Hawaii Standard Time' },
37
+ { regex: /\bHDT\b(?!\w)/g, replacement: 'Hawaii Daylight Time' },
38
+ { regex: /\bmph\b(?!\w)/g, replacement: 'miles per hour' },
39
+ { regex: /\bkm\/h\b(?!\w)/g, replacement: 'kilometers per hour' },
40
+ { regex: /\bkmh\b(?!\w)/g, replacement: 'kilometers per hour' },
41
+ { regex: /\bkt\b(?!\w)/g, replacement: 'knots' },
42
+ { regex: /\bNE\b(?!\w)/g, replacement: 'northeast' },
43
+ { regex: /\bNW\b(?!\w)/g, replacement: 'northwest' },
44
+ { regex: /\bSE\b(?!\w)/g, replacement: 'southeast' },
45
+ { regex: /\bSW\b(?!\w)/g, replacement: 'southwest' },
46
+ { regex: /\bNM\b(?!\w)/g, replacement: 'nautical miles' },
47
+ { regex: /\bdeg\b(?!\w)/g, replacement: 'degrees' },
48
+ { regex: /\btstm\b(?!\w)/g, replacement: 'thunderstorm' },
49
+ { regex: /\bmm\b(?!\w)/g, replacement: 'millimeters' },
50
+ { regex: /\bcm\b(?!\w)/g, replacement: 'centimeters' },
51
+ { regex: /\bin.\b(?!\w)/g, replacement: 'inches' },
52
+ { regex: /\bft\b(?!\w)/g, replacement: 'feet' },
53
+ { regex: /\bmi\b(?!\w)/g, replacement: 'miles' },
54
+ { regex: /\bhr\b(?!\w)/g, replacement: 'hour' },
55
+ { regex: /\bhourly\b(?!\w)/g, replacement: 'per hour' },
56
+ { regex: /\bkg\b(?!\w)/g, replacement: 'kilograms' },
57
+ { regex: /\bg\/kg\b(?!\w)/g, replacement: 'grams per kilogram' },
58
+ { regex: /\bmb\b(?!\w)/g, replacement: 'millibars' },
59
+ { regex: /\bhPa\b(?!\w)/g, replacement: 'hectopascals' },
60
+ { regex: /\bPa\b(?!\w)/g, replacement: 'pascals' },
61
+ { regex: /\bKPa\b(?!\w)/g, replacement: 'kilopascals' },
62
+ { regex: /\bC\/hr\b(?!\w)/g, replacement: 'degrees Celsius per hour' },
63
+ { regex: /\bF\/hr\b(?!\w)/g, replacement: 'degrees Fahrenheit per hour' },
64
+ { regex: /\bC\/min\b(?!\w)/g, replacement: 'degrees Celsius per minute' },
65
+ { regex: /\bF\/min\b(?!\w)/g, replacement: 'degrees Fahrenheit per minute' },
66
+ { regex: /\bC\b(?!\w)/g, replacement: 'degrees Celsius' },
67
+ { regex: /\bF\b(?!\w)/g, replacement: 'degrees Fahrenheit' },
68
+ ]
69
+ const hours: Record<number, string> = {
70
+ 0: "twelve", 1: "one", 2: "two", 3: "three", 4: "four",
71
+ 5: "five", 6: "six", 7: "seven", 8: "eight", 9: "nine",
72
+ 10: "ten", 11: "eleven", 12: "twelve",
73
+ };
74
+ const minWord = (m: number) => m === 0 ? "o'clock" : m < 10 ? `oh ${m}` : `${m}`;
75
+ const fmt = (h: number, m: number, ap: string) => `${hours[h % 12]} ${minWord(m)} ${ap}`;
76
+ for (const {regex, replacement} of patches) {
77
+ message = message.replace(regex, replacement)
78
+ }
79
+ return message
80
+ .replace(/'/g, "''")
81
+ .replace(/\b(\d{1,2}):(\d{2})\s*(AM|PM)\b/gi, (_, h, m, ap) => fmt(+h, +m, ap.toUpperCase()))
82
+ .replace(/\b(\d{1,2})\s+(\d{2})\s+(AM|PM)\b/gi, (_, h, m, ap) => fmt(+h, +m, ap.toUpperCase()))
83
+ .replace(/\b(\d{2})(\d{2})\s+(AM|PM)\b/gi, (_, hh, mm, ap) => fmt(+hh, +mm, ap.toUpperCase()))
84
+ .replace(/\b(\d{1,2})\s+(AM|PM)\b/gi, (_, h, ap) => fmt(+h, 0, ap.toUpperCase()))
85
+ .replace(/\*+/g, " ")
86
+ .replace(/-/g, " ")
87
+ .replace(/\n/g, " ")
88
+ .trim();
89
+ }
90
+
91
+