@atmosx/event-product-parser 3.0.6 → 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.
- package/.github/docs/docs-functions.md +2 -2
- package/.github/docs/docs-general-configurations.md +2 -12
- package/.github/docs/docs-integrations.md +4 -3
- package/.github/docs/docs-listeners.md +1 -1
- package/.github/docs/docs-source-configuration.md +1 -1
- package/.github/docs/docs-technical.md +1 -1
- package/{.github/README.md → README.md} +15 -9
- package/dist/cjs/index.cjs +24073 -7018
- package/dist/esm/index.mjs +24035 -6983
- package/package.json +56 -47
- package/pnpm-workspace.yaml +4 -0
- package/src/bootstrap.ts +64 -48
- package/src/{@building → building}/CreateEvent.ts +22 -24
- package/src/{@building → building}/GetCleanedEvent.ts +2 -2
- package/src/{@building → building}/GetEventAttachments.ts +14 -12
- package/src/building/GetEventDirection.ts +28 -0
- package/src/{@building → building}/GetEventEnhancedName.ts +5 -8
- package/src/{@building → building}/GetEventGeometry.ts +19 -13
- package/src/{@building → building}/GetEventHeader.ts +13 -13
- package/src/{@building → building}/GetEventNodes.ts +21 -19
- package/src/{@building → building}/GetEventOffice.ts +13 -13
- package/src/building/GetEventProperties.ts +105 -0
- package/src/{@building → building}/GetEventSignature.ts +9 -9
- package/src/{@building → building}/GetEventTags.ts +3 -3
- package/src/building/GetEventTheme.ts +26 -0
- package/src/building/GetEventTracking.ts +64 -0
- package/src/components/audio/GenerateAudioMessage.ts +149 -0
- package/src/{@modules/@eas → components/audio/components}/GetCleanDescription.ts +2 -2
- package/src/{@modules/@eas → components/audio/components}/GetFloatPCM16.ts +2 -2
- package/src/{@modules/@eas → components/audio/components}/GetMergedPCM16.ts +2 -2
- package/src/{@modules/@eas → components/audio/components}/GetPCM16.ts +13 -8
- package/src/{@modules/@eas → components/audio/components}/GetPCMToFloat.ts +2 -2
- package/src/{@modules/@eas → components/audio/components}/GetSampledPCM16.ts +14 -8
- package/src/{@modules/@eas → components/audio/components}/GetTTS.ts +17 -10
- package/src/{@modules/@eas → components/audio/components}/GetWavPCM16.ts +7 -7
- package/src/{@modules/@eas → components/audio/components}/SetAFSK.ts +13 -8
- package/src/{@modules/@eas → components/audio/components}/SetAsciiToBits.ts +2 -2
- package/src/{@modules/@eas → components/audio/components}/SetAttentionTone.ts +11 -6
- package/src/{@modules/@eas → components/audio/components}/SetNoise.ts +12 -7
- package/src/{@modules/@eas → components/audio/components}/SetRadioEffect.ts +12 -7
- package/src/{@modules/@eas → components/audio/components}/SetSameHeader.ts +22 -14
- package/src/{@modules/@utilities/SetWarning.ts → components/database/CreateQuery.ts} +18 -13
- package/src/{@modules/@database → components/database}/GetCachedEvents.ts +18 -15
- package/src/components/database/ImportBoundaries.ts +168 -0
- package/src/{@modules/@database → components/database}/ImportBroadcastify.ts +14 -24
- package/src/components/database/ImportCities.ts +87 -0
- package/src/{@modules/@database → components/database}/ImportShapefiles.ts +23 -26
- package/src/{@modules/@database → components/database}/ImportStanza.ts +15 -19
- package/src/components/database/InitializeDatabase.ts +71 -0
- package/src/components/images/GenerateGraphic.ts +234 -0
- package/src/components/images/components/CreateRectangle.ts +22 -0
- package/src/components/images/components/CreateText.ts +22 -0
- package/src/components/images/modules/CreateSVG.ts +37 -0
- package/src/components/images/modules/GetGeographicalBoundaries.ts +72 -0
- package/src/components/images/modules/GetGeographicalCities.ts +58 -0
- package/src/components/images/modules/GetGeographicalEvents.ts +48 -0
- package/src/components/images/modules/GetGeometryBounds.ts +82 -0
- package/src/components/images/modules/GetParsedBoundary.ts +58 -0
- package/src/components/images/modules/GetSVGPath.ts +53 -0
- package/src/components/images/modules/NormalizePolygon.ts +57 -0
- package/src/{@modules/@stanza → components/stanza}/GetAwipsType.ts +16 -17
- package/src/{@modules/@stanza → components/stanza}/ValidateStanza.ts +27 -15
- package/src/{@modules/@utilities → components/utilities}/CreateHttp.ts +26 -26
- package/src/{@modules/@utilities → components/utilities}/GetFormattedTime.ts +2 -2
- package/src/{@modules/@utilities → components/utilities}/GetLatestIssuance.ts +2 -2
- package/src/{@modules/@utilities → components/utilities}/GetMatched.ts +10 -5
- package/src/{@modules/@utilities → components/utilities}/GetShapeNearestPoint.ts +24 -19
- package/src/components/utilities/GetUnionPolygon.ts +36 -0
- package/src/components/utilities/QueueManager.ts +70 -0
- package/src/{@modules/@utilities → components/utilities}/SetCronSchedule.ts +29 -25
- package/src/{@modules/@utilities → components/utilities}/SetDebug.ts +12 -12
- package/src/components/utilities/SetEventEmit.ts +42 -0
- package/src/{@modules/@utilities → components/utilities}/SetSettings.ts +7 -7
- package/src/{@modules/@utilities → components/utilities}/SetSleep.ts +5 -5
- package/src/components/utilities/SetTimeoutAction.ts +64 -0
- package/src/components/utilities/SetWarning.ts +47 -0
- package/src/{@modules/@xmpp → components/xmpp}/DeployXMPP.ts +20 -20
- package/src/{@core/CreateListener.ts → components/xmpp/ErrorXMPP.ts} +8 -5
- package/src/{@modules/@xmpp → components/xmpp}/OfflineXMPP.ts +13 -13
- package/src/{@modules/@xmpp → components/xmpp}/OnlineXMPP.ts +18 -18
- package/src/components/xmpp/ReconnectXMPP.ts +64 -0
- package/src/{@modules/@xmpp → components/xmpp}/StanzaXMPP.ts +25 -25
- package/src/{@core → core}/ClearEvents.ts +9 -9
- package/src/{@core → core}/GetEvents.ts +4 -4
- package/src/{@core → core}/GetNodes.ts +4 -4
- package/src/{@core → core}/GetRandomEvent.ts +4 -4
- package/src/{@core → core}/GetVersion.ts +4 -4
- package/src/{@core → core}/ManualEvent.ts +23 -24
- package/src/{@core → core}/QueryStanza.ts +12 -11
- package/src/core/SetNode.ts +87 -0
- package/src/{@core → core}/StartService.ts +21 -20
- package/src/{@core → core}/StopService.ts +10 -10
- package/src/{@enums → enums}/AWIPS.ts +2 -2
- package/src/{@enums → enums}/Actions.ts +2 -2
- package/src/{@enums → enums}/Cancellation.ts +2 -2
- package/src/{@enums → enums}/Causes.ts +2 -2
- package/src/{@enums → enums}/Correlations.ts +2 -2
- package/src/{@enums → enums}/Enhanced.ts +2 -2
- package/src/{@enums → enums}/Events.ts +2 -2
- package/src/{@enums → enums}/Expressions.ts +3 -3
- package/src/{@enums → enums}/GlobalFilter.ts +2 -2
- package/src/{@enums → enums}/Hail.ts +2 -2
- package/src/{@enums → enums}/ICAO.ts +2 -2
- package/src/{@enums → enums}/Matches.ts +8 -3
- package/src/{@enums → enums}/Products.ts +2 -2
- package/src/{@enums → enums}/Records.ts +2 -2
- package/src/{@enums → enums}/Severity.ts +2 -2
- package/src/{@enums → enums}/Shapefiles.ts +2 -2
- package/src/{@enums → enums}/States.ts +68 -4
- package/src/{@enums → enums}/Status.ts +2 -2
- package/src/{@enums → enums}/Strings.ts +2 -2
- package/src/{@enums → enums}/Tags.ts +9 -4
- package/src/{@enums → enums}/Testing.ts +2 -2
- package/src/enums/Themes.ts +70 -0
- package/src/events/ParseAPI.ts +129 -0
- package/src/{@events → events}/ParseText.ts +24 -22
- package/src/{@events → events}/ParseUGC.ts +27 -26
- package/src/{@events → events}/ParseVTEC.ts +38 -37
- package/src/index.ts +57 -37
- package/src/manager/MakeEvents.ts +110 -0
- package/src/manager/RemoveEvent.ts +74 -0
- package/src/{@manager → manager}/SetHash.ts +18 -13
- package/src/{@manager → manager}/UpdateEvents.ts +12 -12
- package/src/{@manager → manager}/UpdateNode.ts +14 -14
- package/src/{@building → manager}/ValidateEvents.ts +47 -57
- package/src/{@parsers/@hvtec → parsers/hvtec}/HVExtract.ts +11 -11
- package/src/{@parsers/@text → parsers/text}/GetDescriptionFromProduct.ts +20 -21
- package/src/{@parsers/@text → parsers/text}/GetEmbededText.ts +7 -6
- package/src/parsers/text/GetPolygonFromProduct.ts +71 -0
- package/src/{@parsers/@text → parsers/text}/GetStringText.ts +9 -9
- package/src/{@parsers/@text → parsers/text}/GetTextFromProduct.ts +12 -12
- package/src/parsers/ugc/GetCache.ts +24 -0
- package/src/{@parsers/@ugc → parsers/ugc}/GetExpiry.ts +2 -2
- package/src/{@parsers/@ugc/GetUGCHeader.ts → parsers/ugc/GetHeader.ts} +4 -4
- package/src/{@parsers/@ugc → parsers/ugc}/GetLocations.ts +10 -10
- package/src/parsers/ugc/GetZonePolygon.ts +73 -0
- package/src/{@parsers/@ugc → parsers/ugc}/GetZones.ts +3 -3
- package/src/{@parsers/@ugc → parsers/ugc}/SetCache.ts +13 -8
- package/src/{@parsers/@ugc → parsers/ugc}/UGCExtract.ts +14 -14
- package/src/{@parsers/@pvtec → parsers/vtec}/GetExpiry.ts +2 -2
- package/src/parsers/vtec/VTECExtract.ts +49 -0
- package/src/{@types → static}/Attributes.ts +2 -3
- package/src/{@types → static}/Event.ts +8 -7
- package/src/{@types → static}/Properties.ts +7 -3
- package/src/{@types → static}/Stanza.ts +2 -2
- package/src/tasks/CreateTasks.ts +123 -0
- package/src/tasks/TaskGenerateJSON.ts +34 -0
- package/src/tasks/TaskGenerateText.ts +34 -0
- package/src/tasks/TaskSendNTFY.ts +97 -0
- package/src/tasks/TaskSendWebhook.ts +107 -0
- package/src/{@types → types}/Actions.ts +3 -3
- package/src/{@types → types}/HVTEC.ts +6 -6
- package/src/{@types → types}/Hash.ts +5 -5
- package/src/types/Nodes.ts +29 -0
- package/src/{@types → types}/Settings.ts +16 -8
- package/src/{@types → types}/StanzaCompiled.ts +15 -15
- package/src/{@types → types}/UGC.ts +5 -5
- package/src/{@modules/@utilities/GetSettings.ts → types/VTEC.ts} +12 -7
- package/tools/build.js +47 -0
- package/tsconfig.json +28 -1
- package/src/@building/GetEventProperties.ts +0 -96
- package/src/@building/GetEventTracking.ts +0 -68
- package/src/@core/SetNode.ts +0 -81
- package/src/@events/ParseAPI.ts +0 -117
- package/src/@manager/CreateActions.ts +0 -213
- package/src/@manager/MakeEvent.ts +0 -99
- package/src/@manager/RemoveEvent.ts +0 -70
- package/src/@modules/@database/InitializeDatabase.ts +0 -59
- package/src/@modules/@eas/GenerateEASMessage.ts +0 -144
- package/src/@modules/@utilities/SetEventEmit.ts +0 -41
- package/src/@modules/@utilities/SetListener.ts +0 -30
- package/src/@modules/@utilities/SetTimeoutAction.ts +0 -64
- package/src/@modules/@xmpp/ErrorXMPP.ts +0 -27
- package/src/@modules/@xmpp/ReconnectXMPP.ts +0 -64
- package/src/@parsers/@pvtec/VTECExtract.ts +0 -49
- package/src/@parsers/@text/GetPolygonFromProduct.ts +0 -53
- package/src/@parsers/@text/GetXML.ts +0 -61
- package/src/@parsers/@ugc/GetCache.ts +0 -24
- package/src/@parsers/@ugc/GetZonePolygon.ts +0 -111
- package/src/@types/VTEC.ts +0 -30
- package/tsup.config.ts +0 -16
|
@@ -11,18 +11,18 @@
|
|
|
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:
|
|
14
|
+
Documentation: https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Independent Package: @atmosx/event-product-parser
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
interface getWavPCM16Response {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
Samples: Int16Array
|
|
23
|
+
SampleRate: number
|
|
24
|
+
Channels: number
|
|
25
|
+
BitsPerSample: number
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export const GetWavPCM16 = (buffer: Buffer): getWavPCM16Response => {
|
|
@@ -46,7 +46,7 @@ export const GetWavPCM16 = (buffer: Buffer): getWavPCM16Response => {
|
|
|
46
46
|
const bitsPerSample = fmt.readUInt16LE(14);
|
|
47
47
|
if (audioFormat !== 1 || bitsPerSample !== 16 || channels !== 1) { return null; }
|
|
48
48
|
const samples = new Int16Array(data.buffer, data.byteOffset, data.length / 2);
|
|
49
|
-
return {
|
|
49
|
+
return { Samples: new Int16Array(samples), SampleRate: sampleRate, Channels: channels, BitsPerSample: bitsPerSample };
|
|
50
50
|
}
|
|
51
51
|
|
|
52
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:
|
|
14
|
+
Documentation: https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Independent Package: @atmosx/event-product-parser
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
interface SetAFSKOptions {
|
|
22
|
+
Bits: number[]
|
|
23
|
+
SampleRate: number
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const SetAFSK = ({ Bits, SampleRate }: SetAFSKOptions): Int16Array => {
|
|
22
27
|
const baud = 520.83;
|
|
23
28
|
const markFreq = 2083.3;
|
|
24
29
|
const spaceFreq = 1562.5;
|
|
@@ -27,20 +32,20 @@ export const SetAFSK = (bits: number[], sampleRate: number): Int16Array => {
|
|
|
27
32
|
const result = [];
|
|
28
33
|
let phase = 0;
|
|
29
34
|
let frac = 0;
|
|
30
|
-
for (let b = 0; b <
|
|
31
|
-
const bit =
|
|
35
|
+
for (let b = 0; b < Bits.length; b++) {
|
|
36
|
+
const bit = Bits[b];
|
|
32
37
|
const freq = bit ? markFreq : spaceFreq;
|
|
33
|
-
const samplesPerBit =
|
|
38
|
+
const samplesPerBit = SampleRate / baud + frac;
|
|
34
39
|
const n = Math.round(samplesPerBit);
|
|
35
40
|
frac = samplesPerBit - n;
|
|
36
|
-
const inc = twoPi * freq /
|
|
41
|
+
const inc = twoPi * freq / SampleRate;
|
|
37
42
|
for (let i = 0; i < n; i++) {
|
|
38
43
|
result.push(Math.round(Math.sin(phase) * amplitude * 32767));
|
|
39
44
|
phase += inc;
|
|
40
45
|
if (phase > twoPi) phase -= twoPi;
|
|
41
46
|
}
|
|
42
47
|
}
|
|
43
|
-
const fadeSamples = Math.floor(
|
|
48
|
+
const fadeSamples = Math.floor(SampleRate * 0.002);
|
|
44
49
|
for (let i = 0; i < fadeSamples; i++) {
|
|
45
50
|
const gain = i / fadeSamples;
|
|
46
51
|
result[i] = Math.round(result[i] * gain);
|
|
@@ -11,9 +11,9 @@
|
|
|
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:
|
|
14
|
+
Documentation: https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Independent Package: @atmosx/event-product-parser
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
*/
|
|
@@ -11,23 +11,28 @@
|
|
|
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:
|
|
14
|
+
Documentation: https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Independent Package: @atmosx/event-product-parser
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
interface SetAttentionToneOptions {
|
|
22
|
+
MS: number
|
|
23
|
+
SampleRate: number
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const SetAttentionTone = ({ MS, SampleRate }: SetAttentionToneOptions): Int16Array => {
|
|
27
|
+
const len = Math.floor(MS * SampleRate);
|
|
23
28
|
const out = new Int16Array(len);
|
|
24
29
|
const f1 = 853;
|
|
25
30
|
const f2 = 960;
|
|
26
31
|
const twoPi = Math.PI * 2;
|
|
27
32
|
const amp = 0.1;
|
|
28
|
-
const fadeLen = Math.floor(
|
|
33
|
+
const fadeLen = Math.floor(SampleRate * 0.00);
|
|
29
34
|
for (let i = 0; i < len; i++) {
|
|
30
|
-
const t = i /
|
|
35
|
+
const t = i / SampleRate;
|
|
31
36
|
const s = Math.sin(twoPi * f1 * t) + Math.sin(twoPi * f2 * t);
|
|
32
37
|
let gain = 1;
|
|
33
38
|
if (i < fadeLen) gain = i / fadeLen;
|
|
@@ -11,19 +11,24 @@
|
|
|
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:
|
|
14
|
+
Documentation: https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Independent Package: @atmosx/event-product-parser
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
import { GetPCMToFloat } from "
|
|
22
|
-
import { GetFloatPCM16 } from "
|
|
21
|
+
import { GetPCMToFloat } from "@AudioComponents/GetPCMToFloat"
|
|
22
|
+
import { GetFloatPCM16 } from "@AudioComponents/GetFloatPCM16"
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
interface SetNoiseOptions {
|
|
25
|
+
Int16: Int16Array
|
|
26
|
+
NoiseLevel?: number
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const SetNoise = ({ Int16, NoiseLevel }: SetNoiseOptions): Int16Array => {
|
|
30
|
+
const x = GetPCMToFloat(Int16);
|
|
31
|
+
for (let i = 0; i < x.length; i++) x[i] += (Math.random() * 2 - 1) * (NoiseLevel ?? 0.02);
|
|
27
32
|
let peak = 0;
|
|
28
33
|
for (let i = 0; i < x.length; i++) peak = Math.max(peak, Math.abs(x[i]));
|
|
29
34
|
if (peak > 1) for (let i = 0; i < x.length; i++) x[i] *= 0.98 / peak;
|
|
@@ -11,21 +11,26 @@
|
|
|
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:
|
|
14
|
+
Documentation: https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Independent Package: @atmosx/event-product-parser
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
import { GetPCMToFloat } from "
|
|
22
|
-
import { GetFloatPCM16 } from "
|
|
21
|
+
import { GetPCMToFloat } from "@AudioComponents/GetPCMToFloat"
|
|
22
|
+
import { GetFloatPCM16 } from "@AudioComponents/GetFloatPCM16"
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
interface SetRadioEffectOptions {
|
|
25
|
+
Int16: Int16Array
|
|
26
|
+
SampleRate: number
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const SetRadioEffect = ({ Int16, SampleRate }: SetRadioEffectOptions): Int16Array => {
|
|
25
30
|
const hpCut = 3555;
|
|
26
31
|
const lpCut = 1600;
|
|
27
|
-
const x = GetPCMToFloat(
|
|
28
|
-
const dt = 1 /
|
|
32
|
+
const x = GetPCMToFloat(Int16);
|
|
33
|
+
const dt = 1 / SampleRate;
|
|
29
34
|
const rcHP = 1 / (2 * Math.PI * hpCut);
|
|
30
35
|
const aHP = rcHP / (rcHP + dt);
|
|
31
36
|
let yHP = 0, xPrev = 0;
|
|
@@ -11,33 +11,41 @@
|
|
|
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:
|
|
14
|
+
Documentation: https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Independent Package: @atmosx/event-product-parser
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
import { SetAFSK } from "
|
|
22
|
-
import { SetAsciiToBits } from "
|
|
23
|
-
import { GetMergedPCM16 } from "
|
|
21
|
+
import { SetAFSK } from "@AudioComponents/SetAFSK"
|
|
22
|
+
import { SetAsciiToBits } from "@AudioComponents/SetAsciiToBits"
|
|
23
|
+
import { GetMergedPCM16 } from "@AudioComponents/GetMergedPCM16"
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
interface SetSameHeaderOptions {
|
|
26
|
+
VTEC: string
|
|
27
|
+
Repeats: number
|
|
28
|
+
SampleRate?: number
|
|
29
|
+
PreMarkSec?: number
|
|
30
|
+
GapSec?: number
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const SetSameHeader = ({ VTEC, Repeats, SampleRate, PreMarkSec, GapSec }: SetSameHeaderOptions): Int16Array => {
|
|
34
|
+
const preMarkSec = PreMarkSec ?? 0.3;
|
|
35
|
+
const gapSec = GapSec ?? 0.1;
|
|
28
36
|
const bursts = [];
|
|
29
|
-
const gap = new Int16Array(Math.floor(gapSec *
|
|
30
|
-
for (let i = 0; i <
|
|
31
|
-
const bodyBits = SetAsciiToBits(
|
|
32
|
-
const body = SetAFSK(bodyBits,
|
|
33
|
-
const extendedBodyDuration = Math.round(preMarkSec *
|
|
37
|
+
const gap = new Int16Array(Math.floor(gapSec * SampleRate));
|
|
38
|
+
for (let i = 0; i < Repeats; i++) {
|
|
39
|
+
const bodyBits = SetAsciiToBits(VTEC);
|
|
40
|
+
const body = SetAFSK({ Bits: bodyBits, SampleRate: SampleRate});
|
|
41
|
+
const extendedBodyDuration = Math.round(preMarkSec * SampleRate);
|
|
34
42
|
const extendedBody = new Int16Array(extendedBodyDuration + gap.length);
|
|
35
43
|
for (let j = 0; j < extendedBodyDuration; j++) {
|
|
36
44
|
extendedBody[j] = Math.round(body[j % body.length] * 0.2);
|
|
37
45
|
}
|
|
38
46
|
extendedBody.set(gap, extendedBodyDuration);
|
|
39
47
|
bursts.push(extendedBody);
|
|
40
|
-
if (i !==
|
|
48
|
+
if (i !== Repeats - 1) bursts.push(gap);
|
|
41
49
|
}
|
|
42
50
|
return GetMergedPCM16(bursts);
|
|
43
51
|
}
|
|
@@ -11,24 +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:
|
|
14
|
+
Documentation: https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Independent Package: @atmosx/event-product-parser
|
|
17
17
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
20
|
+
import { Bootstrap } from "@Bootstrap"
|
|
21
|
+
import { SetWarning } from "@Utilities/SetWarning"
|
|
22
22
|
|
|
23
|
-
interface
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
interface CreateQueryOptions {
|
|
24
|
+
Query: string
|
|
25
|
+
Parameters?: unknown[]
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
export const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
export const CreateQuery = function({ Query, Parameters }: CreateQueryOptions): any {
|
|
29
|
+
try {
|
|
30
|
+
const parameters = Array.isArray(Parameters) ? Parameters : [];
|
|
31
|
+
const statement = Bootstrap.Database.prepare(Query);
|
|
32
|
+
return /^\s*select/i.test(Query)
|
|
33
|
+
? statement.all(...parameters)
|
|
34
|
+
: statement.run(...parameters);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
SetWarning({Message: `Database Query Error: ${error instanceof Error ? error.stack ?? error.message : String(error)}`})
|
|
37
|
+
throw error;
|
|
33
38
|
}
|
|
34
|
-
}
|
|
39
|
+
};
|
|
@@ -11,26 +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:
|
|
14
|
+
Documentation: https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Independent Package: @atmosx/event-product-parser
|
|
17
17
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { TypeSettings } from "
|
|
21
|
-
import {
|
|
22
|
-
import { SetWarning } from
|
|
23
|
-
import { CreateEvent } from
|
|
24
|
-
import {
|
|
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 { CreateQuery } from "@Database/CreateQuery"
|
|
25
25
|
|
|
26
26
|
export const GetCachedEvents = async (): Promise<void> => {
|
|
27
27
|
try {
|
|
28
|
-
const settings =
|
|
28
|
+
const settings = Bootstrap.Settings as TypeSettings;
|
|
29
29
|
const tick = performance.now();
|
|
30
30
|
if (settings.NOAAWeatherWireServiceSettings.CacheSettings.Enabled) {
|
|
31
31
|
const max = settings.NOAAWeatherWireServiceSettings.CacheSettings.MaxRetentionHistory ?? 500;
|
|
32
|
-
const get = await
|
|
33
|
-
|
|
32
|
+
const get = await CreateQuery({
|
|
33
|
+
Query: `SELECT * FROM stanzas ORDER BY rowid DESC LIMIT ?`,
|
|
34
|
+
Parameters: [max]
|
|
35
|
+
}) as { rowid: number; stanza: string }[];
|
|
36
|
+
SetWarning({ Message: `Fetched ${get.length} cached stanzas from the database in ${Math.floor(performance.now() - tick)} ms` })
|
|
34
37
|
let events = get.map((row) => JSON.parse(row.stanza))
|
|
35
38
|
.filter(stanza => {
|
|
36
39
|
if (!stanza) { return }
|
|
@@ -40,11 +43,11 @@ export const GetCachedEvents = async (): Promise<void> => {
|
|
|
40
43
|
return !isSkippable
|
|
41
44
|
});
|
|
42
45
|
events = events.sort((a, b) => b.issued - a.issued)
|
|
43
|
-
await Promise.all(events.map(event => CreateEvent(event
|
|
44
|
-
SetWarning({
|
|
45
|
-
await ValidateEvents(bootstrap.cache.processed)
|
|
46
|
+
await Promise.all(events.map(event => CreateEvent(event)))
|
|
47
|
+
SetWarning({ Message: `Processed ${events.length} cached stanzas in ${Math.floor(performance.now() - tick)} ms` })
|
|
46
48
|
}
|
|
47
|
-
} catch (error) {
|
|
48
|
-
|
|
49
|
+
} catch (error: unknown) {
|
|
50
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
51
|
+
SetWarning({ Message: `An error occurred while fetching cached stanzas: ${message}` })
|
|
49
52
|
}
|
|
50
53
|
}
|
|
@@ -0,0 +1,168 @@
|
|
|
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 { EnumStateFIPS } from "@Enums/States"
|
|
21
|
+
import { Bootstrap } from "@Bootstrap"
|
|
22
|
+
import { CreateHttp } from "@Utilities/CreateHttp"
|
|
23
|
+
import { CreateQuery } from "@Database/CreateQuery"
|
|
24
|
+
import { SetWarning } from "@Utilities/SetWarning"
|
|
25
|
+
import { feature } from "topojson-client"
|
|
26
|
+
|
|
27
|
+
type BoundaryRow = {
|
|
28
|
+
id: string
|
|
29
|
+
type: `state` | `county`
|
|
30
|
+
state: string
|
|
31
|
+
name: string
|
|
32
|
+
geometry: string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const ImportBoundaries = async (): Promise<void> => {
|
|
36
|
+
try {
|
|
37
|
+
const existing = CreateQuery({ Query: `SELECT type, COUNT(*) AS count FROM boundaries GROUP BY type`}) as { type: string, count: number }[]
|
|
38
|
+
const existingStates = existing.find(row => row.type === `state`)?.count ?? 0
|
|
39
|
+
const existingCounties = existing.find(row => row.type === `county`)?.count ?? 0
|
|
40
|
+
|
|
41
|
+
if (existingStates > 0 || existingCounties > 0) {
|
|
42
|
+
SetWarning({ Message: `Boundary database already contains ${existingStates} states and ${existingCounties} counties, skipping import` })
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const boundaries = await CreateHttp({
|
|
47
|
+
URL: Bootstrap.Settings.BoundarySettings.BoundaryDatabase,
|
|
48
|
+
Timeout: 5000
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
if (boundaries.error || !boundaries.message) {
|
|
52
|
+
SetWarning({ Message: `Failed to download boundary database` })
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let database: any
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
database = JSON.parse(boundaries.message)
|
|
60
|
+
} catch {
|
|
61
|
+
SetWarning({ Message: `Failed to parse boundary database` })
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (database?.type !== `Topology` || !database?.objects?.states || !database?.objects?.counties) {
|
|
66
|
+
SetWarning({ Message: `Boundary database is missing states or counties` })
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
let states: any
|
|
71
|
+
let counties: any
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
states = feature(database, database.objects.states)
|
|
75
|
+
counties = feature(database, database.objects.counties)
|
|
76
|
+
} catch (error: unknown) {
|
|
77
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
78
|
+
SetWarning({ Message: `Failed to convert boundary database: ${message}` })
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (!Array.isArray(states?.features) || !Array.isArray(counties?.features)) {
|
|
83
|
+
SetWarning({ Message: `Boundary database contains invalid state or county data` })
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const insert = `INSERT OR REPLACE INTO boundaries (id, type, state, name, geometry) VALUES (?, ?, ?, ?, ?)`
|
|
88
|
+
const stateRows: BoundaryRow[] = []
|
|
89
|
+
const countyRows: BoundaryRow[] = []
|
|
90
|
+
let skippedStates = 0
|
|
91
|
+
let skippedCounties = 0
|
|
92
|
+
|
|
93
|
+
for (const state of states.features) {
|
|
94
|
+
if (!state?.geometry || state.id === undefined || state.id === null) {
|
|
95
|
+
skippedStates++
|
|
96
|
+
continue
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const fips = String(state.id).padStart(2, `0`)
|
|
100
|
+
const abbreviation = EnumStateFIPS[fips]
|
|
101
|
+
|
|
102
|
+
if (!abbreviation) {
|
|
103
|
+
skippedStates++
|
|
104
|
+
continue
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
stateRows.push({
|
|
108
|
+
id: fips,
|
|
109
|
+
type: `state`,
|
|
110
|
+
state: abbreviation,
|
|
111
|
+
name: state.properties?.name ?? abbreviation,
|
|
112
|
+
geometry: JSON.stringify(state.geometry)
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
for (const county of counties.features) {
|
|
117
|
+
if (!county?.geometry || county.id === undefined || county.id === null) {
|
|
118
|
+
skippedCounties++
|
|
119
|
+
continue
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const fips = String(county.id).padStart(5, `0`)
|
|
123
|
+
const stateFIPS = fips.slice(0, 2)
|
|
124
|
+
const abbreviation = EnumStateFIPS[stateFIPS]
|
|
125
|
+
|
|
126
|
+
if (!abbreviation) {
|
|
127
|
+
skippedCounties++
|
|
128
|
+
continue
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
countyRows.push({
|
|
132
|
+
id: fips,
|
|
133
|
+
type: `county`,
|
|
134
|
+
state: abbreviation,
|
|
135
|
+
name: county.properties?.name ?? fips,
|
|
136
|
+
geometry: JSON.stringify(county.geometry)
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
SetWarning({ Message: `Importing ${stateRows.length} states and ${countyRows.length} counties` })
|
|
141
|
+
|
|
142
|
+
const transaction = Bootstrap.Database.transaction((rows: BoundaryRow[]) => {
|
|
143
|
+
for (const row of rows) {
|
|
144
|
+
CreateQuery({
|
|
145
|
+
Query: insert,
|
|
146
|
+
Parameters: [row.id, row.type, row.state, row.name, row.geometry]
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
transaction(stateRows)
|
|
152
|
+
transaction(countyRows)
|
|
153
|
+
|
|
154
|
+
const imported = CreateQuery({ Query: `SELECT type, COUNT(*) AS count FROM boundaries GROUP BY type`}) as { type: string, count: number }[]
|
|
155
|
+
const importedStates = imported.find(row => row.type === `state`)?.count ?? 0
|
|
156
|
+
const importedCounties = imported.find(row => row.type === `county`)?.count ?? 0
|
|
157
|
+
|
|
158
|
+
if (importedStates !== stateRows.length || importedCounties !== countyRows.length) {
|
|
159
|
+
SetWarning({ Message: `Boundary import verification failed: ${importedStates} states and ${importedCounties} counties` })
|
|
160
|
+
return
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
SetWarning({ Message: `Imported ${importedStates} states and ${importedCounties} counties` })
|
|
164
|
+
} catch (error: unknown) {
|
|
165
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
166
|
+
SetWarning({ Message: `An error occurred while importing boundaries: ${message}` })
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -11,44 +11,34 @@
|
|
|
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:
|
|
14
|
+
Documentation: https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Independent Package: @atmosx/event-product-parser
|
|
17
17
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import {
|
|
21
|
-
import { CreateHttp } from
|
|
22
|
-
import { SetWarning } from "
|
|
20
|
+
import { Bootstrap } from "@Bootstrap"
|
|
21
|
+
import { CreateHttp } from "@Utilities/CreateHttp"
|
|
22
|
+
import { SetWarning } from "@Utilities/SetWarning"
|
|
23
|
+
import { CreateQuery } from "@Database/CreateQuery";
|
|
23
24
|
|
|
24
25
|
export const ImportBroadcastify = async (): Promise<void> => {
|
|
25
|
-
const settings =
|
|
26
|
-
|
|
27
|
-
const isBroadcastifyImported = bootstrap.database
|
|
28
|
-
.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='broadcastify';`)
|
|
29
|
-
.get();
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (!settings.BroadcastifySettings.BroadcastifyAttachments) { return }
|
|
33
|
-
if (isBroadcastifyImported) { return }
|
|
34
|
-
|
|
26
|
+
const settings = Bootstrap.Settings;
|
|
35
27
|
const broadcastify = await CreateHttp({
|
|
36
|
-
|
|
37
|
-
|
|
28
|
+
URL: settings.BroadcastifySettings.BroadcastifyDatabase,
|
|
29
|
+
Timeout: 5000,
|
|
38
30
|
});
|
|
39
31
|
if (!broadcastify.error) {
|
|
40
|
-
bootstrap.database.prepare(`CREATE TABLE broadcastify ( state TEXT, county TEXT, feed TEXT, type TEXT, link TEXT);`)
|
|
41
|
-
.run();
|
|
42
32
|
const states = JSON.parse(broadcastify.message);
|
|
43
|
-
const insert =
|
|
44
|
-
const transaction =
|
|
33
|
+
const insert = `INSERT INTO broadcastify (state, county, feed, type, link) VALUES (?, ?, ?, ?, ?)`;
|
|
34
|
+
const transaction = Bootstrap.Database.transaction((rows: any[]) => {
|
|
45
35
|
for (const row of rows) {
|
|
46
|
-
insert
|
|
36
|
+
CreateQuery({ Query: insert, Parameters: row });
|
|
47
37
|
}
|
|
48
38
|
});
|
|
49
39
|
const batch: any[] = [];
|
|
50
40
|
for (const state of states) {
|
|
51
|
-
SetWarning({
|
|
41
|
+
SetWarning({ Message: `Importing ${state.counties.length} counties from ${state.state} for Broadcastify` });
|
|
52
42
|
for (const county of state.counties) {
|
|
53
43
|
const countyName = county.county;
|
|
54
44
|
for (const feed of county.feeds) {
|
|
@@ -65,6 +55,6 @@ export const ImportBroadcastify = async (): Promise<void> => {
|
|
|
65
55
|
transaction(batch);
|
|
66
56
|
}
|
|
67
57
|
if (broadcastify.error) {
|
|
68
|
-
SetWarning({
|
|
58
|
+
SetWarning({ Message: `Error importing Broadcastify data: ${broadcastify.message}` });
|
|
69
59
|
}
|
|
70
60
|
};
|