@atmosx/event-product-parser 3.0.62 → 3.0.63

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 (112) hide show
  1. package/README.md +6 -4
  2. package/dist/cjs/index.cjs +21216 -6908
  3. package/dist/esm/index.mjs +21207 -6900
  4. package/package.json +49 -47
  5. package/pnpm-workspace.yaml +4 -0
  6. package/src/@building/CreateEvent.ts +20 -22
  7. package/src/@building/GetEventAttachments.ts +8 -8
  8. package/src/@building/GetEventEnhancedName.ts +2 -4
  9. package/src/@building/GetEventGeometry.ts +5 -5
  10. package/src/@building/GetEventHeader.ts +11 -11
  11. package/src/@building/GetEventNodes.ts +12 -12
  12. package/src/@building/GetEventOffice.ts +11 -11
  13. package/src/@building/GetEventProperties.ts +60 -55
  14. package/src/@building/GetEventSignature.ts +7 -7
  15. package/src/@building/GetEventTags.ts +1 -1
  16. package/src/@building/GetEventTracking.ts +28 -32
  17. package/src/@core/ClearEvents.ts +7 -7
  18. package/src/@core/CreateListener.ts +2 -2
  19. package/src/@core/GetEvents.ts +2 -2
  20. package/src/@core/GetNodes.ts +2 -2
  21. package/src/@core/GetRandomEvent.ts +2 -2
  22. package/src/@core/GetVersion.ts +2 -2
  23. package/src/@core/ManualEvent.ts +20 -21
  24. package/src/@core/QueryStanza.ts +7 -7
  25. package/src/@core/SetNode.ts +32 -26
  26. package/src/@core/StartService.ts +18 -18
  27. package/src/@core/StopService.ts +8 -8
  28. package/src/@enums/Expressions.ts +1 -1
  29. package/src/@enums/Tags.ts +1 -1
  30. package/src/@events/ParseAPI.ts +44 -39
  31. package/src/@events/ParseText.ts +19 -19
  32. package/src/@events/ParseUGC.ts +21 -21
  33. package/src/@events/ParseVTEC.ts +32 -33
  34. package/src/@manager/MakeEvents.ts +33 -30
  35. package/src/@manager/RemoveEvent.ts +38 -34
  36. package/src/@manager/SetHash.ts +16 -11
  37. package/src/@manager/UpdateEvents.ts +10 -10
  38. package/src/@manager/UpdateNode.ts +13 -13
  39. package/src/@manager/ValidateEvents.ts +36 -37
  40. package/src/@modules/@database/GetCachedEvents.ts +10 -12
  41. package/src/@modules/@database/ImportBroadcastify.ts +12 -13
  42. package/src/@modules/@database/ImportShapefiles.ts +17 -18
  43. package/src/@modules/@database/ImportStanza.ts +11 -11
  44. package/src/@modules/@database/InitializeDatabase.ts +16 -16
  45. package/src/@modules/@eas/GenerateEASMessage.ts +53 -47
  46. package/src/@modules/@eas/GetPCM16.ts +11 -6
  47. package/src/@modules/@eas/GetSampledPCM16.ts +12 -6
  48. package/src/@modules/@eas/GetTTS.ts +12 -7
  49. package/src/@modules/@eas/GetWavPCM16.ts +5 -5
  50. package/src/@modules/@eas/SetAFSK.ts +11 -6
  51. package/src/@modules/@eas/SetAttentionTone.ts +9 -4
  52. package/src/@modules/@eas/SetNoise.ts +10 -5
  53. package/src/@modules/@eas/SetRadioEffect.ts +10 -5
  54. package/src/@modules/@eas/SetSameHeader.ts +20 -12
  55. package/src/@modules/@stanza/GetAwipsType.ts +14 -15
  56. package/src/@modules/@stanza/ValidateStanza.ts +25 -13
  57. package/src/@modules/@utilities/CreateHttp.ts +24 -24
  58. package/src/@modules/@utilities/GetMatched.ts +8 -3
  59. package/src/@modules/@utilities/GetSettings.ts +3 -3
  60. package/src/@modules/@utilities/GetShapeNearestPoint.ts +22 -17
  61. package/src/@modules/@utilities/QueueManager.ts +70 -0
  62. package/src/@modules/@utilities/SetCronSchedule.ts +20 -20
  63. package/src/@modules/@utilities/SetDebug.ts +10 -10
  64. package/src/@modules/@utilities/SetEventEmit.ts +15 -15
  65. package/src/@modules/@utilities/SetListener.ts +6 -6
  66. package/src/@modules/@utilities/SetSettings.ts +5 -5
  67. package/src/@modules/@utilities/SetSleep.ts +3 -3
  68. package/src/@modules/@utilities/SetTimeoutAction.ts +25 -25
  69. package/src/@modules/@utilities/SetWarning.ts +8 -8
  70. package/src/@modules/@xmpp/DeployXMPP.ts +16 -16
  71. package/src/@modules/@xmpp/ErrorXMPP.ts +4 -4
  72. package/src/@modules/@xmpp/OfflineXMPP.ts +11 -11
  73. package/src/@modules/@xmpp/OnlineXMPP.ts +16 -16
  74. package/src/@modules/@xmpp/ReconnectXMPP.ts +27 -27
  75. package/src/@modules/@xmpp/StanzaXMPP.ts +23 -23
  76. package/src/@parsers/@hvtec/HVExtract.ts +9 -9
  77. package/src/@parsers/@text/GetDescriptionFromProduct.ts +18 -19
  78. package/src/@parsers/@text/GetEmbededText.ts +3 -3
  79. package/src/@parsers/@text/GetStringText.ts +6 -6
  80. package/src/@parsers/@text/GetTextFromProduct.ts +10 -10
  81. package/src/@parsers/@text/GetXML.ts +5 -5
  82. package/src/@parsers/@ugc/GetCache.ts +2 -2
  83. package/src/@parsers/@ugc/{GetUGCHeader.ts → GetHeader.ts} +2 -2
  84. package/src/@parsers/@ugc/GetLocations.ts +5 -5
  85. package/src/@parsers/@ugc/GetZonePolygon.ts +10 -10
  86. package/src/@parsers/@ugc/GetZones.ts +1 -1
  87. package/src/@parsers/@ugc/SetCache.ts +11 -6
  88. package/src/@parsers/@ugc/UGCExtract.ts +10 -10
  89. package/src/@parsers/{@pvtec → @vtec}/VTECExtract.ts +19 -19
  90. package/src/@tasks/CreateTasks.ts +110 -0
  91. package/src/@tasks/TaskGenerateAudio.ts +34 -0
  92. package/src/@tasks/TaskGenerateJSON.ts +34 -0
  93. package/src/@tasks/TaskGenerateText.ts +34 -0
  94. package/src/@tasks/TaskSendNTFY.ts +91 -0
  95. package/src/@tasks/TaskSendWebhook.ts +100 -0
  96. package/src/@types/HVTEC.ts +4 -4
  97. package/src/@types/Hash.ts +3 -3
  98. package/src/@types/Settings.ts +1 -1
  99. package/src/@types/StanzaCompiled.ts +13 -13
  100. package/src/@types/UGC.ts +3 -3
  101. package/src/@types/VTEC.ts +10 -10
  102. package/src/{@types → @types-lower}/Event.ts +4 -4
  103. package/src/{@types → @types-lower}/Properties.ts +2 -1
  104. package/src/{@types → @types-lower}/Stanza.ts +1 -1
  105. package/src/bootstrap.ts +26 -26
  106. package/src/index.ts +30 -27
  107. package/tools/build.js +45 -0
  108. package/tsconfig.json +21 -1
  109. package/src/@manager/Tasks.ts +0 -246
  110. package/tsup.config.ts +0 -16
  111. /package/src/@parsers/{@pvtec → @vtec}/GetExpiry.ts +0 -0
  112. /package/src/{@types → @types-lower}/Attributes.ts +0 -0
@@ -17,24 +17,24 @@
17
17
 
18
18
  */
19
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";
20
+ import { TypeEvent } from "types-lower/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 "@manager/MakeEvents"
26
+ import { RemoveEvent } from "@manager/RemoveEvent"
27
+ import { GetEventAttachments } from "@building/GetEventAttachments"
28
+ import { SetEventEmit } from "@utilities/SetEventEmit"
29
+ import { SetDebug } from "@utilities/SetDebug"
30
+ import { GetMatched } from "@utilities/GetMatched"
31
+ import { GetEventGeometry } from "@building/GetEventGeometry"
32
32
  import { createHash } from "crypto"
33
33
 
34
34
  export const ValidateEvents = async (events: TypeEvent[]): Promise<void> => {
35
35
  const tick = performance.now();
36
36
  if (events.length === 0) return
37
- const configurations = bootstrap.settings as TypeSettings
37
+ const configurations = Bootstrap.Settings as TypeSettings
38
38
  const sets = {} as Record<string, Set<string>>;
39
39
  const bools = {} as Record<string, boolean>;
40
40
  const megered = {...configurations.GlobalSettings, ...configurations.GlobalSettings.EventFiltering}
@@ -50,19 +50,19 @@ export const ValidateEvents = async (events: TypeEvent[]): Promise<void> => {
50
50
  const icao = properties.geocode.office.office
51
51
 
52
52
  if (properties.status_metadata.is_test) {
53
- SetEventEmit({ event: `onTestProduct`, metadata: define })
53
+ SetEventEmit({ Event: `onTestProduct`, Metadata: define })
54
54
  if (bools?.IgnoreTestProducts) return true;
55
55
  }
56
56
 
57
57
  if (properties.status_metadata.is_expired) {
58
- SetEventEmit({ event: `onExpiredProduct`, metadata: define })
59
- RemoveEvent(define, false)
58
+ SetEventEmit({ Event: `onExpiredProduct`, Metadata: define })
59
+ RemoveEvent({ Event: define, IsTimeBasedExpiration: false })
60
60
  return true;
61
61
  }
62
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 })
63
+ if (properties.metadata?.vtec?.Watch && properties.metadata.source != `events.api`) {
64
+ const isSPC = properties.metadata?.vtec?.PredictionCenter;
65
+ SetEventEmit({ Event: isSPC ? `onStormPredictionWatch` : `onNonStormPredictionWatch`, Metadata: define })
66
66
  if (bools?.SPCWatchesOnly && !isSPC) {
67
67
  return true;
68
68
  }
@@ -74,45 +74,45 @@ export const ValidateEvents = async (events: TypeEvent[]): Promise<void> => {
74
74
  for (const key in sets) {
75
75
  const setting = sets[key]
76
76
  const values = [...setting];
77
- if (key === 'ListeningEvents' && setting.size > 0 && !GetMatched(values, define.properties.event)) {
77
+ if (key === 'ListeningEvents' && setting.size > 0 && !GetMatched({ Strings: values, String: define.properties.event })) {
78
78
  SetEventEmit({
79
- event: `onFilteredEvent`,
80
- metadata: define
79
+ Event: `onFilteredEvent`,
80
+ Metadata: define
81
81
  });
82
82
  return true
83
83
  }
84
- if (key === 'IgnoredEvents' && setting.size > 0 && GetMatched(values, define.properties.event)) {
84
+ if (key === 'IgnoredEvents' && setting.size > 0 && GetMatched({ Strings: values, String: define.properties.event })) {
85
85
  SetEventEmit({
86
- event: `onIgnoredEvent`,
87
- metadata: define
86
+ Event: `onIgnoredEvent`,
87
+ Metadata: define
88
88
  });
89
89
  return true
90
90
  }
91
91
  if (key === 'ListeningICAO' && setting.size > 0 && icao != null && !setting.has(icao.toLowerCase())) {
92
92
  SetEventEmit({
93
- event: `onFilteredICAO`,
94
- metadata: define
93
+ Event: `onFilteredICAO`,
94
+ Metadata: define
95
95
  });
96
96
  return true
97
97
  }
98
98
  if (key === 'IgnoredICAO' && setting.size > 0 && icao != null && setting.has(icao.toLowerCase())) {
99
99
  SetEventEmit({
100
- event: `onIgnoredICAO`,
101
- metadata: define
100
+ Event: `onIgnoredICAO`,
101
+ Metadata: define
102
102
  });
103
103
  return true
104
104
  }
105
105
  if (key === 'ListeningUGC' && setting.size > 0 && zones.length > 0 && !zones.some((ugc: string) => setting.has(ugc.toLowerCase()))) {
106
106
  SetEventEmit({
107
- event: `onFilteredUGC`,
108
- metadata: define
107
+ Event: `onFilteredUGC`,
108
+ Metadata: define
109
109
  });
110
110
  return true
111
111
  }
112
112
  if (key === 'ListeningStates' && setting.size > 0 && zones.length > 0 && !zones.some((ugc: string) => setting.has(ugc.substring(0, 2).toLowerCase()))) {
113
113
  SetEventEmit({
114
- event: `onFilteredState`,
115
- metadata: define
114
+ Event: `onFilteredState`,
115
+ Metadata: define
116
116
  });
117
117
  return true
118
118
  }
@@ -121,7 +121,7 @@ export const ValidateEvents = async (events: TypeEvent[]): Promise<void> => {
121
121
  }
122
122
 
123
123
  const filtering = events.filter((event: TypeEvent) => {
124
- bootstrap.cache.processed = bootstrap.cache.processed.filter((e) => e !== event);
124
+ Bootstrap.Cache.Parsed = Bootstrap.Cache.Parsed.filter((e) => e !== event);
125
125
  const define = GetEventSignature(event) as TypeEvent;
126
126
  const pre = {...define,properties: {...define.properties, metadata: {...define.properties.metadata }}};
127
127
  const properties = define.properties; delete pre.properties.metadata.ms; delete pre.properties.metadata.header;
@@ -132,11 +132,10 @@ export const ValidateEvents = async (events: TypeEvent[]): Promise<void> => {
132
132
  properties.metadata.attachments = GetEventAttachments(event)
133
133
  }
134
134
  properties.metadata.hash = createHash("sha256").update(JSON.stringify(pre)).digest("hex")
135
- SetEventEmit({ event: `onProductType${enhanced.replace(/\s+/g, '')}`, metadata: define });
135
+ SetEventEmit({ Event: `onProductType${enhanced.replace(/\s+/g, '')}`, Metadata: define });
136
136
  return !filtered
137
137
  })
138
138
 
139
- SetDebug({ title: `ValidateEvents (PRE) (${filtering.length}/${events.length})`, message: `${Math.round(performance.now() - tick)}ms` })
139
+ SetDebug({ Title: `ValidateEvents (${filtering.length}/${events.length})`, Message: `${Math.round(performance.now() - tick)}ms` })
140
140
  await MakeEvents(filtering)
141
- SetDebug({ title: `MakeEvents (${filtering.length}/${events.length})`, message: `${Math.round(performance.now() - tick)}ms` })
142
141
  }
@@ -17,20 +17,19 @@
17
17
 
18
18
  */
19
19
 
20
- import { TypeSettings } from "../../@types/Settings"
21
- import { bootstrap } from '../../bootstrap'
22
- import { SetWarning } from '../@utilities/SetWarning';
23
- import { CreateEvent } from '../../@building/CreateEvent';
24
- import { ValidateEvents } from "../../@manager/ValidateEvents";
20
+ import { TypeSettings } from "types/Settings"
21
+ import { Bootstrap } from "@bootstrap"
22
+ import { SetWarning } from "@utilities/SetWarning"
23
+ import { CreateEvent } from "@building/CreateEvent"
25
24
 
26
25
  export const GetCachedEvents = async (): Promise<void> => {
27
26
  try {
28
- const settings = bootstrap.settings as TypeSettings;
27
+ const settings = Bootstrap.Settings as TypeSettings;
29
28
  const tick = performance.now();
30
29
  if (settings.NOAAWeatherWireServiceSettings.CacheSettings.Enabled) {
31
30
  const max = settings.NOAAWeatherWireServiceSettings.CacheSettings.MaxRetentionHistory ?? 500;
32
- const get = await bootstrap.database.prepare(`SELECT * FROM stanzas ORDER BY rowid DESC LIMIT ?`).all(max) as { rowid: number; stanza: string }[];
33
- SetWarning({ message: `Fetched ${get.length} cached stanzas from the database in ${Math.floor(performance.now() - tick)} ms` })
31
+ const get = await Bootstrap.Database.prepare(`SELECT * FROM stanzas ORDER BY rowid DESC LIMIT ?`).all(max) as { rowid: number; stanza: string }[];
32
+ SetWarning({ Message: `Fetched ${get.length} cached stanzas from the database in ${Math.floor(performance.now() - tick)} ms` })
34
33
  let events = get.map((row) => JSON.parse(row.stanza))
35
34
  .filter(stanza => {
36
35
  if (!stanza) { return }
@@ -40,11 +39,10 @@ export const GetCachedEvents = async (): Promise<void> => {
40
39
  return !isSkippable
41
40
  });
42
41
  events = events.sort((a, b) => b.issued - a.issued)
43
- await Promise.all(events.map(event => CreateEvent(event, true)))
44
- SetWarning({ message: `Processed ${events.length} cached stanzas in ${Math.floor(performance.now() - tick)} ms` })
45
- await ValidateEvents(bootstrap.cache.processed)
42
+ await Promise.all(events.map(event => CreateEvent(event)))
43
+ SetWarning({ Message: `Processed ${events.length} cached stanzas in ${Math.floor(performance.now() - tick)} ms` })
46
44
  }
47
45
  } catch (error) {
48
- SetWarning({ message: `An error occurred while fetching cached stanzas: ${error.message} -> ${error.stack}` })
46
+ SetWarning({ Message: `An error occurred while fetching cached stanzas: ${error.message} -> ${error.stack}` })
49
47
  }
50
48
  }
@@ -17,38 +17,37 @@
17
17
 
18
18
  */
19
19
 
20
- import { bootstrap } from "../../bootstrap"
21
- import { CreateHttp } from '../@utilities/CreateHttp'
22
- import { SetWarning } from "../@utilities/SetWarning";
20
+ import { Bootstrap } from "@bootstrap"
21
+ import { CreateHttp } from "@utilities/CreateHttp"
22
+ import { SetWarning } from "@utilities/SetWarning"
23
23
 
24
24
  export const ImportBroadcastify = async (): Promise<void> => {
25
- const settings = bootstrap.settings;
25
+ const settings = Bootstrap.Settings;
26
26
 
27
- const isBroadcastifyImported = bootstrap.database
27
+ const isBroadcastifyImported = Bootstrap.Database
28
28
  .prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='broadcastify';`)
29
29
  .get();
30
30
 
31
-
32
31
  if (!settings.BroadcastifySettings.BroadcastifyAttachments) { return }
33
32
  if (isBroadcastifyImported) { return }
34
33
 
35
34
  const broadcastify = await CreateHttp({
36
- url: settings.BroadcastifySettings.BroadcastifyDatabase,
37
- timeout: 5000,
35
+ URL: settings.BroadcastifySettings.BroadcastifyDatabase,
36
+ Timeout: 5000,
38
37
  });
39
38
  if (!broadcastify.error) {
40
- bootstrap.database.prepare(`CREATE TABLE broadcastify ( state TEXT, county TEXT, feed TEXT, type TEXT, link TEXT);`)
39
+ Bootstrap.Database.prepare(`CREATE TABLE broadcastify ( state TEXT, county TEXT, feed TEXT, type TEXT, link TEXT);`)
41
40
  .run();
42
41
  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[]) => {
42
+ const insert = Bootstrap.Database.prepare(`INSERT INTO broadcastify (state, county, feed, type, link) VALUES (?, ?, ?, ?, ?)`);
43
+ const transaction = Bootstrap.Database.transaction((rows: any[]) => {
45
44
  for (const row of rows) {
46
45
  insert.run(row);
47
46
  }
48
47
  });
49
48
  const batch: any[] = [];
50
49
  for (const state of states) {
51
- SetWarning({ message: `Importing ${state.counties.length} counties from ${state.state} for Broadcastify` });
50
+ SetWarning({ Message: `Importing ${state.counties.length} counties from ${state.state} for Broadcastify` });
52
51
  for (const county of state.counties) {
53
52
  const countyName = county.county;
54
53
  for (const feed of county.feeds) {
@@ -65,6 +64,6 @@ export const ImportBroadcastify = async (): Promise<void> => {
65
64
  transaction(batch);
66
65
  }
67
66
  if (broadcastify.error) {
68
- SetWarning({ message: `Error importing Broadcastify data: ${broadcastify.message}` });
67
+ SetWarning({ Message: `Error importing Broadcastify data: ${broadcastify.message}` });
69
68
  }
70
69
  };
@@ -17,29 +17,28 @@
17
17
 
18
18
  */
19
19
 
20
- import { TypeSettings } from "../../@types/Settings"
21
- import { EnumShapefiles } from '../../@enums/Shapefiles'
22
- import { bootstrap } from "../../bootstrap"
23
- import { SetSleep } from '../@utilities/SetSleep'
24
- import { SetWarning } from '../@utilities/SetWarning'
20
+ import { TypeSettings } from "types/Settings"
21
+ import { EnumShapefiles } from "@enums/Shapefiles"
22
+ import { Bootstrap } from "@bootstrap"
23
+ import { SetSleep } from "@utilities/SetSleep"
24
+ import { SetWarning } from "@utilities/SetWarning"
25
25
  import { existsSync, mkdirSync, writeFileSync, unlinkSync, rm } from "fs"
26
- import { resolve, extname} from 'path'
27
- import { loadAsync } from 'jszip'
28
- import { read } from 'shapefile'
26
+ import { resolve, extname} from "path"
27
+ import { loadAsync } from "jszip"
28
+ import { read } from "shapefile"
29
29
 
30
30
  export const ImportShapefiles = async (): Promise<void> => {
31
- const settings = bootstrap.settings as TypeSettings;
32
31
  try {
33
- const tShapefiles = bootstrap.database
32
+ const tShapefiles = Bootstrap.Database
34
33
  .prepare(`SELECT COUNT(*) AS count FROM shapefiles`)
35
34
  .get().count;
36
35
  if (tShapefiles === 0) {
37
- await SetSleep({timeout: 1e3});
36
+ await SetSleep({Timeout: 1e3});
38
37
  for (const shapefile of EnumShapefiles) {
39
38
  const response = await fetch(shapefile.link);
40
39
  const arrayBuff = await response.arrayBuffer();
41
40
  const content = await loadAsync(arrayBuff);
42
- const directory = resolve(__dirname, `../../shapefiles`);
41
+ const directory = resolve(__dirname, `shapefiles`);
43
42
  if (!existsSync(directory)) {
44
43
  mkdirSync(directory, { recursive: true });
45
44
  }
@@ -50,15 +49,15 @@ export const ImportShapefiles = async (): Promise<void> => {
50
49
  writeFileSync(output, data)
51
50
  }
52
51
  }
53
- const filepath = resolve(__dirname, '../../shapefiles', shapefile.name + '_' + shapefile.id)
52
+ const filepath = resolve(__dirname, 'shapefiles', shapefile.name + '_' + shapefile.id)
54
53
  const { features } = await read(
55
54
  filepath,
56
55
  filepath,
57
56
  );
58
- SetWarning({ message: `Importing ${features.length} features from ${shapefile.name}_${shapefile.id} for Shapefiles` })
59
- const insert = bootstrap.database
57
+ SetWarning({ Message: `Importing ${features.length} features from ${shapefile.name}_${shapefile.id} for Shapefiles` })
58
+ const insert = Bootstrap.Database
60
59
  .prepare(`INSERT OR REPLACE INTO shapefiles (id, location, geometry) VALUES (?, ?, ?)`)
61
- const transaction = bootstrap.database.transaction((entries: any[]) => {
60
+ const transaction = Bootstrap.Database.transaction((entries: any[]) => {
62
61
  for (const entry of entries) {
63
62
  const { properties, geometry } = entry;
64
63
  let final: string, location: string;
@@ -85,9 +84,9 @@ export const ImportShapefiles = async (): Promise<void> => {
85
84
  unlinkSync(`${filepath}.dbf`)
86
85
  transaction(features)
87
86
  }
88
- rm(resolve(__dirname, '../../shapefiles'), { recursive: true, force: true }, () => {});
87
+ rm(resolve(__dirname, 'shapefiles'), { recursive: true, force: true }, () => {});
89
88
  }
90
89
  } catch (error) {
91
- SetWarning( {message: `An error occurred while compiling shapefiles: ${error.message}` })
90
+ SetWarning( {Message: `An error occurred while compiling shapefiles: ${error.message}` })
92
91
  }
93
92
  }
@@ -17,31 +17,31 @@
17
17
 
18
18
  */
19
19
 
20
- import { TypeSettings } from "../../@types/Settings"
21
- import { TypeStanzaCompiled } from '../../@types/StanzaCompiled';
22
- import { bootstrap } from '../../bootstrap'
23
- import { SetWarning } from '../@utilities/SetWarning';
20
+ import { TypeSettings } from "types/Settings"
21
+ import { TypeStanzaCompiled } from "types/StanzaCompiled"
22
+ import { Bootstrap } from "@bootstrap"
23
+ import { SetWarning } from "@utilities/SetWarning"
24
24
 
25
- export const ImportStanza = async (stanza: TypeStanzaCompiled): Promise<void> => {
26
- const settings = bootstrap.settings as TypeSettings;
25
+ export const ImportStanza = async (Stanza: TypeStanzaCompiled): Promise<void> => {
26
+ const settings = Bootstrap.Settings as TypeSettings;
27
27
  try {
28
28
  if (!settings.NOAAWeatherWireServiceSettings.CacheSettings.Enabled) { return }
29
- bootstrap.database
29
+ Bootstrap.Database
30
30
  .prepare(`INSERT OR IGNORE INTO stanzas (type, stanza, issued) VALUES (?, ?, ?)`)
31
- .run(stanza.getType.type, JSON.stringify(stanza), stanza.attributes.issue)
32
- const count = bootstrap.database
31
+ .run(Stanza.Type.Type, JSON.stringify(Stanza), Stanza.Attributes.issue)
32
+ const count = Bootstrap.Database
33
33
  .prepare(`SELECT COUNT(*) as total FROM stanzas`)
34
34
  .get() as { total: number }
35
35
  const max = settings.NOAAWeatherWireServiceSettings.CacheSettings.MaxDatabaseHistory;
36
36
  if (count.total > max) {
37
37
  const toDelete = count.total - max;
38
38
  if (toDelete > 0) {
39
- bootstrap.database
39
+ Bootstrap.Database
40
40
  .prepare(`DELETE FROM stanzas WHERE id IN (SELECT id FROM stanzas ORDER BY issued ASC LIMIT ?)`)
41
41
  .run(toDelete);
42
42
  }
43
43
  }
44
44
  } catch (error) {
45
- SetWarning({ message: `An error occurred while importing stanza: ${error.message}` })
45
+ SetWarning({ Message: `An error occurred while importing stanza: ${error.message}` })
46
46
  }
47
47
  }
@@ -18,42 +18,42 @@
18
18
  */
19
19
 
20
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"
21
+ import { TypeSettings } from "types/Settings"
22
+ import { Bootstrap } from "@bootstrap"
23
+ import { SetWarning } from "@utilities/SetWarning"
24
+ import { ImportShapefiles } from "@database/ImportShapefiles"
25
+ import { ImportBroadcastify } from "@database/ImportBroadcastify"
26
26
  import { existsSync, writeFileSync } from "fs"
27
- import sqlite3 from 'better-sqlite3'
27
+ import sqlite3 from "better-sqlite3"
28
28
 
29
29
  export const InitializeDatabase = async (): Promise<void> => {
30
- const settings = bootstrap.settings as TypeSettings;
30
+ const settings = Bootstrap.Settings as TypeSettings;
31
31
  try {
32
32
  if (!existsSync(settings.Database)) {
33
33
  writeFileSync(settings.Database, '')
34
- SetWarning({ message: `Creating new database at ${settings.Database}` })
34
+ SetWarning({ Message: `Creating new database at ${settings.Database}` })
35
35
  }
36
- bootstrap.database = new sqlite3(settings.Database);
37
- bootstrap.database
36
+ Bootstrap.Database = new sqlite3(settings.Database);
37
+ Bootstrap.Database
38
38
  .prepare(`CREATE TABLE IF NOT EXISTS stanzas ( id INTEGER PRIMARY KEY AUTOINCREMENT, type TEXT, issued TEXT, stanza TEXT )`)
39
39
  .run();
40
- bootstrap.database
40
+ Bootstrap.Database
41
41
  .prepare(`CREATE TABLE IF NOT EXISTS shapefiles (id TEXT PRIMARY KEY, location TEXT, geometry TEXT)`)
42
42
  .run();
43
- const isNeedingShapefiles = bootstrap.database
43
+ const isNeedingShapefiles = Bootstrap.Database
44
44
  .prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='shapefiles';`)
45
45
  .get();
46
- const isNeedingBroadcastify = bootstrap.database
46
+ const isNeedingBroadcastify = Bootstrap.Database
47
47
  .prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='broadcastify';`)
48
48
  .get();
49
49
 
50
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.` })
51
+ SetWarning({Message: `Required database tables are currently building, please ${Bootstrap.Colors.Red}DO NOT${Bootstrap.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
52
  await ImportBroadcastify();
53
53
  await ImportShapefiles();
54
- SetWarning({ message: `Building has completed, you can now continue or close the terminal`})
54
+ SetWarning({ Message: `Building has completed, you can now continue or close the terminal`})
55
55
  }
56
56
  } catch (error) {
57
- SetWarning({ message: `An error occurred while initializing the database: ${error.message}` })
57
+ SetWarning({ Message: `An error occurred while initializing the database: ${error.message}` })
58
58
  }
59
59
  }
@@ -17,44 +17,42 @@
17
17
 
18
18
  */
19
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'
20
+ import { TypeSettings } from "types/Settings"
21
+ import { Bootstrap } from "@bootstrap"
22
+ import { GetWavPCM16 } from "@eas/GetWavPCM16"
23
+ import { GetSampledPCM16 } from "@eas/GetSampledPCM16"
24
+ import { SetRadioEffect } from "@eas/SetRadioEffect"
25
+ import { SetSameHeader } from "@eas/SetSameHeader"
26
+ import { SetAttentionTone } from "@eas/SetAttentionTone"
27
+ import { GetMergedPCM16 } from "@eas/GetMergedPCM16"
28
+ import { SetNoise } from "@eas/SetNoise"
29
+ import { GetPCM16 } from "@eas/GetPCM16"
30
+ import { GetTTS } from "@eas/GetTTS"
31
+ import { GetCleanDescription } from "@eas/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
38
 
39
39
 
40
40
  interface GenerateEASMessageOptions {
41
- message: string
42
- header: string
43
- title: string
41
+ Message: string
42
+ Header: string
43
+ Title: string
44
44
  }
45
45
 
46
- export const GenerateEASMessage = async (options: GenerateEASMessageOptions): Promise<string> => {
46
+ export const GenerateEASMessage = async ({ Message, Header, Title }: GenerateEASMessageOptions): Promise<string> => {
47
47
  const tick = performance.now()
48
- const settings = bootstrap.settings as TypeSettings;
48
+ const settings = Bootstrap.Settings as TypeSettings;
49
49
  const directory = settings.GlobalSettings.ArchiveSettings.EasDirectory;
50
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) {
51
+ let title = (Title ?? `${Math.random().toString(36).substring(2, 15)}-${Header.replace(/[^a-zA-Z0-9]/g, '')}`).replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
52
+ if (!Message || !Header) {
55
53
  SetWarning({
56
- title: `EAS`,
57
- message: `Message and header are required to generate an EAS tone.`
54
+ Title: `EAS`,
55
+ Message: `Message and header are required to generate an EAS tone.`
58
56
  })
59
57
  return null;
60
58
  }
@@ -62,6 +60,14 @@ export const GenerateEASMessage = async (options: GenerateEASMessageOptions): Pr
62
60
  let buffRadio: any;
63
61
  let buffFull: any[] = [];
64
62
 
63
+ if (!directory) {
64
+ SetWarning({
65
+ Title: `EAS`,
66
+ Message: `EAS directory is not set in the settings. Please set it to generate EAS tones.`
67
+ });
68
+ return null;
69
+ }
70
+
65
71
  if (!existsSync(directory)) {
66
72
  mkdirSync(directory, { recursive: true });
67
73
  }
@@ -71,16 +77,16 @@ export const GenerateEASMessage = async (options: GenerateEASMessageOptions): Pr
71
77
 
72
78
  if (vPlatform === 'darwin') {
73
79
  SetWarning({
74
- title: `EAS`,
75
- message: `EAS tone generation is not supported on macOS.`
80
+ Title: `EAS`,
81
+ Message: `EAS tone generation is not supported on macOS.`
76
82
  });
77
83
  return null
78
84
  }
79
85
 
80
86
 
81
87
  await new Promise<void>((resolve, reject) => {
82
- const tMsg = GetCleanDescription(message)
83
- GetTTS(tMsg, tmpTTS).then(() => {
88
+ const tMsg = GetCleanDescription(Message)
89
+ GetTTS({Text: tMsg, OutputPath: tmpTTS}).then(() => {
84
90
  resolve();
85
91
  });
86
92
  });
@@ -89,8 +95,8 @@ export const GenerateEASMessage = async (options: GenerateEASMessageOptions): Pr
89
95
  }
90
96
  buffTTS = readFileSync(tmpTTS);
91
97
  const vWav = GetWavPCM16(buffTTS);
92
- const vSamples = GetSampledPCM16(vWav.samples, vWav.sampleRate, 8000)
93
- const vRadio = SetRadioEffect(vSamples, 8000)
98
+ const vSamples = GetSampledPCM16({Int16: vWav.Samples, OriginalRate: vWav.SampleRate, TargetRate: 8000})
99
+ const vRadio = SetRadioEffect({Int16: vSamples, SampleRate: 8000});
94
100
 
95
101
  if (existsSync(prefix)) {
96
102
  let tBuffer = readFileSync(prefix);
@@ -109,35 +115,35 @@ export const GenerateEASMessage = async (options: GenerateEASMessageOptions): Pr
109
115
  }
110
116
 
111
117
  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.` })
118
+ SetWarning({
119
+ Title: `EAS`,
120
+ 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.`
121
+ })
113
122
  return null;
114
123
  }
115
124
 
116
- const tSamples = (tWav.sampleRate != 8000 ? GetSampledPCM16(tWav.samples, tWav.sampleRate, 8000) : tWav.samples)
117
- buffRadio = SetRadioEffect(tSamples, 8000)
125
+ const tSamples = (tWav.SampleRate != 8000 ? GetSampledPCM16({Int16: tWav.Samples, OriginalRate: tWav.SampleRate, TargetRate: 8000}) : tWav.Samples)
126
+ buffRadio = SetRadioEffect({Int16: tSamples, SampleRate: 8000})
118
127
  }
119
128
 
120
129
  buffFull = buffRadio != null ? [buffRadio, new Int16Array(Math.floor(0.5 * 8000))] : [];
121
130
  buffFull.push(
122
- SetSameHeader(header, 3, 8000, {
123
- preMarkSec: 1.1,
124
- gapSec: 0.5,
125
- }),
131
+ SetSameHeader({ VTEC: Header, Repeats: 3, SampleRate: 8000, PreMarkSec: 1.1, GapSec: 0.5 }),
126
132
  new Int16Array(Math.floor(0.5 * 8000)),
127
- SetAttentionTone(8, 8000),
133
+ SetAttentionTone({ MS: 8, SampleRate: 8000 }),
128
134
  new Int16Array(Math.floor(0.5 * 8000)),
129
135
  vRadio
130
136
  )
131
137
  for (let i = 0; i < 3; i++) {
132
- buffFull.push(SetSameHeader(header, 1, 8000, { preMarkSec: 0.5, gapSec: 0.1 }))
138
+ buffFull.push(SetSameHeader({ VTEC: Header, Repeats: 1, SampleRate: 8000, PreMarkSec: 0.5, GapSec: 0.1 }))
133
139
  buffFull.push(new Int16Array(Math.floor(0.5 * 8000)));
134
140
  }
135
141
  const aSamples = GetMergedPCM16(buffFull);
136
- const aFinal = SetNoise(aSamples, 0.002);
137
- const aBuffer = GetPCM16(Array.from(aFinal).map(v => ({ value: v })), 8000);
142
+ const aFinal = SetNoise({ Int16: aSamples, NoiseLevel: 0.002 });
143
+ const aBuffer = GetPCM16({ Samples: Array.from(aFinal).map(v => ({ value: v })), SampleRate: 8000 });
138
144
  writeFileSync(outTTS, aBuffer)
139
145
  try{ unlinkSync(tmpTTS) } catch {}
140
- SetDebug({ title: `GenerateEASMessage`, message: `${Math.round(performance.now() - tick)}ms` })
146
+ SetDebug({ Title: `GenerateEASMessage`, Message: `${Math.round(performance.now() - tick)}ms` })
141
147
  return outTTS;
142
148
  }
143
149
 
@@ -18,12 +18,17 @@
18
18
 
19
19
  */
20
20
 
21
- export const GetPCM16 = (samples: Record<string, number>[], sampleRate: number): Buffer => {
21
+ interface GetPCM16Options {
22
+ Samples: Record<string, number>[]
23
+ SampleRate: number
24
+ }
25
+
26
+ export const GetPCM16 = ({ Samples, SampleRate }: GetPCM16Options): Buffer => {
22
27
  let o = 0;
23
28
  const bytesPerSample = 2;
24
29
  const blockAlign = 1 * bytesPerSample;
25
- const byteRate = sampleRate * blockAlign;
26
- const subchunk2Size = samples.length * bytesPerSample;
30
+ const byteRate = SampleRate * blockAlign;
31
+ const subchunk2Size = Samples.length * bytesPerSample;
27
32
  const chunkSize = 36 + subchunk2Size;
28
33
  const buffer = Buffer.alloc(44 + subchunk2Size);
29
34
 
@@ -35,7 +40,7 @@ export const GetPCM16 = (samples: Record<string, number>[], sampleRate: number):
35
40
  buffer.writeUInt32LE(16, o); o += 4;
36
41
  buffer.writeUInt16LE(1, o); o += 2;
37
42
  buffer.writeUInt16LE(1, o); o += 2;
38
- buffer.writeUInt32LE(sampleRate, o); o += 4;
43
+ buffer.writeUInt32LE(SampleRate, o); o += 4;
39
44
  buffer.writeUInt32LE(byteRate, o); o += 4;
40
45
  buffer.writeUInt16LE(blockAlign, o); o += 2;
41
46
  buffer.writeUInt16LE(16, o); o += 2;
@@ -43,8 +48,8 @@ export const GetPCM16 = (samples: Record<string, number>[], sampleRate: number):
43
48
  buffer.write("data", o); o += 4;
44
49
  buffer.writeUInt32LE(subchunk2Size, o); o += 4;
45
50
 
46
- for (let i = 0; i < samples.length; i++, o += 2) {
47
- buffer.writeInt16LE(samples[i].value, o);
51
+ for (let i = 0; i < Samples.length; i++, o += 2) {
52
+ buffer.writeInt16LE(Samples[i].value, o);
48
53
  }
49
54
  return buffer;
50
55
  }