diff --git a/README.md b/README.md
index 2a2f273..e44dda7 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,50 @@
-# SharpENDEC
\ No newline at end of file
+# SharpENDEC
+
+### Credits
+```
+BunnyTub - Main Developer
+ApatheticDELL - Logo Designer
+Google Translate / Microsoft Translator - Translations
+```
+
+### Libraries
+```
+Costura.Fody
+Fody
+NAudio
+Newtonsoft.Json
+```
+
+> [!NOTE]
+> Although SharpENDEC is meant to replicate an ENDEC, it is **not** meant to be a complete ENDEC replacement.
+> Physical hardware is usually more stable, and more capable in terms of processing.
+
+## What is it anyway?
+SharpENDEC is a Canadian software CAP (Common Alerting Protocol) receiver for alerting.
+If you're a little confused, imagine something similar to a physical ENDEC, but based in software.
+
+## How do I install it?
+Well, it's simple! You don't need to. Simply put the executable into a directory of your choice, then run it. If you run into a problem, or you're on an older version of Windows, you'll most likely need to [install .NET Framework 4.8.1](https://dotnet.microsoft.com/en-us/download/dotnet-framework/net481), or fully update Windows. Once you've done that, there isn't anything else that you will need to install or change.
+
+## How do I set it up?
+Well, you don't have to. But you should! There's a lot of stuff that could be of use. But... you should look over [this PDF document from Pelmorex (2021/06)](https://alerts.pelmorex.com/wp-content/uploads/2021/06/NAADS-LMD-User-Guide-R10.0.pdf) for some more knowledge on how Canada's public alerting system works, and its CAP-CP XML data. Once you have a little bit of a better understanding of the system, even just a little bit, come back here!
+
+Here's something, configurations! You might want to change some default settings, especially if they don't fit for your scenario. If you want to change your settings, press ```C``` during startup. To reset them to factory defaults, press ```R``` instead. I'll let you explore them for yourself! Although... if you can't find any CAP-GP geocodes for use in filtering, you can use [this Excel spreadsheet](https://www.publicsafety.gc.ca/cnt/rsrcs/pblctns/capcp-lctn-rfrncs/capcp-lctn-rfrncs-annex-a-201708.xlsx), which contains the most recent list of geocodes.
+
+One last thing. If you want to grab the text produced for use in automation, you can use ```static-text.txt``` if you need the newest text. If you want the file to be empty when it is inactive, use ```active-text.txt```. For the opposite, you can use ```inactive-text.txt``` instead.
+
+## How can I change the audio?
+Audio can be added and changed easily! Simply add in files and swap as you please.
+
+```in.wav``` This sound is used as the lead-in, and is played before all other sounds. It will simply be ignored if it does not exist.
+
+```attn.wav``` This sound is used as the attention tone for alerts marked as severe and above. The built-in copy will be extracted if it does not exist.
+
+```attn-minor.wav``` This sound is used as the attention tone for alerts marked as minor and below. It will fallback to **attn.wav** if it does not exist.
+
+```audio.wav``` This sound is reserved for the program's internal use. Modifying the file should not have any effect, and will be overwritten.
+
+```out.wav``` This sound is used as the lead-out, and is played after all other sounds. It will simply be ignored if it does not exist.
+
+## Is there anything else I need to know?
+Nope! That's about it. There's nothing else to know here. Thanks ApatheticDELL for this application idea, it worked out really well, and you were also awesome for helping me figure out these things. SharpENDEC (C#) was originally ported from QuantumENDEC (Python), and that was uh, really hard, and annoying to figure out. I did not like translating Python, but once it got going well, everything fit into place, and overall, felt good enough, then later on, I made it better.
diff --git a/SharpENDEC/App.config b/SharpENDEC/App.config
index cd01b0e..560f8b5 100644
--- a/SharpENDEC/App.config
+++ b/SharpENDEC/App.config
@@ -1,13 +1,13 @@
-
+
-
-
-
+
+
+
-
+
@@ -39,10 +39,10 @@
True
- False
+ True
- False
+ True
True
@@ -62,13 +62,13 @@
- en
+ english
-1
- Tom
+ Ava
False
@@ -84,6 +84,14 @@
+
+ 120
+
+
+
+
+
+
@@ -133,12 +141,12 @@
-
+
-
+
@@ -146,4 +154,4 @@
-
\ No newline at end of file
+
diff --git a/SharpENDEC/ConsoleForm.Designer.cs b/SharpENDEC/ConsoleForm.Designer.cs
new file mode 100644
index 0000000..58b3234
--- /dev/null
+++ b/SharpENDEC/ConsoleForm.Designer.cs
@@ -0,0 +1,67 @@
+namespace SharpENDEC
+{
+ partial class ConsoleForm
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.textBox1 = new System.Windows.Forms.TextBox();
+ this.SuspendLayout();
+ //
+ // textBox1
+ //
+ this.textBox1.BackColor = System.Drawing.Color.Black;
+ this.textBox1.BorderStyle = System.Windows.Forms.BorderStyle.None;
+ this.textBox1.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.textBox1.Font = new System.Drawing.Font("Comic Sans MS", 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.textBox1.ForeColor = System.Drawing.Color.Lime;
+ this.textBox1.Location = new System.Drawing.Point(0, 0);
+ this.textBox1.Multiline = true;
+ this.textBox1.Name = "textBox1";
+ this.textBox1.ReadOnly = true;
+ this.textBox1.Size = new System.Drawing.Size(978, 494);
+ this.textBox1.TabIndex = 0;
+ //
+ // ConsoleForm
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(978, 494);
+ this.Controls.Add(this.textBox1);
+ this.Name = "ConsoleForm";
+ this.Text = "Quick & Dirty Console Window";
+ this.Load += new System.EventHandler(this.ConsoleForm_Load);
+ this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ConsoleForm_KeyDown);
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.TextBox textBox1;
+ }
+}
\ No newline at end of file
diff --git a/SharpENDEC/ConsoleForm.cs b/SharpENDEC/ConsoleForm.cs
new file mode 100644
index 0000000..2736e33
--- /dev/null
+++ b/SharpENDEC/ConsoleForm.cs
@@ -0,0 +1,184 @@
+using System;
+using System.Drawing;
+using System.IO;
+using System.Text;
+using System.Windows.Forms;
+
+namespace SharpENDEC
+{
+ public partial class ConsoleForm : Form
+ {
+ public ConsoleForm()
+ {
+ InitializeComponent();
+ }
+
+ private void ConsoleForm_Load(object sender, EventArgs e)
+ {
+ Console.SetOut(new TextBoxOutWriter(textBox1));
+ Console.SetError(new TextBoxErrorWriter(textBox1));
+ }
+
+ public class TextBoxOutWriter : TextWriter
+ {
+ private readonly TextBox _textBox;
+ private readonly StringBuilder _buffer;
+
+ public TextBoxOutWriter(TextBox textBox)
+ {
+ _textBox = textBox;
+ _buffer = new StringBuilder();
+ _textBox.Multiline = true;
+ _textBox.ScrollBars = ScrollBars.Vertical;
+ }
+
+ public override void Write(char value)
+ {
+ _buffer.Append(value);
+ if (_buffer.Length >= 2)
+ {
+ Flush();
+ }
+ }
+
+ public override void Write(string value)
+ {
+ _buffer.Append(value);
+ if (_buffer.Length >= 2)
+ {
+ Flush();
+ }
+ }
+
+ public override Encoding Encoding => Encoding.UTF8;
+
+ public override void Flush()
+ {
+ if (_buffer.Length > 0)
+ {
+ _textBox.Invoke((MethodInvoker)delegate {
+ _textBox.AppendText(_buffer.ToString());
+ _textBox.ForeColor = Color.Lime;
+ });
+ _buffer.Clear();
+ }
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Flush();
+ }
+ base.Dispose(disposing);
+ }
+ }
+
+ public class TextBoxInReader : TextReader
+ {
+ private TextBox _inputTextBox;
+ private TextBox _outputTextBox;
+ private string _inputBuffer;
+
+ public TextBoxInReader(TextBox inputTextBox, TextBox outputTextBox)
+ {
+ _inputTextBox = inputTextBox;
+ _outputTextBox = outputTextBox;
+
+ // Capture Enter key press in the input TextBox
+ _inputTextBox.KeyPress += new KeyPressEventHandler(OnEnterKeyPress);
+ }
+
+ private void OnEnterKeyPress(object sender, KeyPressEventArgs e)
+ {
+ if (e.KeyChar == (char)Keys.Enter)
+ {
+ e.Handled = true; // Prevent the beep sound
+
+ // Capture the input
+ _inputBuffer = _inputTextBox.Text;
+
+ // Clear input box and append to output box for feedback
+ _inputTextBox.Clear();
+ _outputTextBox.AppendText(_inputBuffer + Environment.NewLine);
+ }
+ }
+
+ public override string ReadLine()
+ {
+ // Wait until the Enter key is pressed (simulate input waiting)
+ while (string.IsNullOrEmpty(_inputBuffer))
+ {
+ Application.DoEvents(); // Allows processing of other UI events
+ }
+
+ string result = _inputBuffer;
+ _inputBuffer = null; // Clear the buffer after use
+
+ return result;
+ }
+
+ public Encoding Encoding => Encoding.UTF8;
+ }
+
+ public class TextBoxErrorWriter : TextWriter
+ {
+ private readonly TextBox _textBox;
+ private readonly StringBuilder _buffer;
+
+ public TextBoxErrorWriter(TextBox textBox)
+ {
+ _textBox = textBox;
+ _buffer = new StringBuilder();
+ _textBox.Multiline = true;
+ _textBox.ScrollBars = ScrollBars.Vertical;
+ }
+
+ public override void Write(char value)
+ {
+ _buffer.Append(value);
+ if (_buffer.Length >= 0)
+ {
+ Flush();
+ }
+ }
+
+ public override void Write(string value)
+ {
+ _buffer.Append(value);
+ if (_buffer.Length >= 0)
+ {
+ Flush();
+ }
+ }
+
+ public override Encoding Encoding => Encoding.UTF8;
+
+ public override void Flush()
+ {
+ if (_buffer.Length > 0)
+ {
+ _textBox.Invoke((MethodInvoker)delegate {
+ _textBox.AppendText(_buffer.ToString());
+ _textBox.ForeColor = Color.Red;
+ });
+ _buffer.Clear();
+ }
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Flush();
+ }
+ base.Dispose(disposing);
+ }
+ }
+
+ private void ConsoleForm_KeyDown(object sender, KeyEventArgs e)
+ {
+
+ }
+ }
+}
diff --git a/SharpENDEC/ConsoleForm.resx b/SharpENDEC/ConsoleForm.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/SharpENDEC/ConsoleForm.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/SharpENDEC/EASfusionLogo.ico b/SharpENDEC/EASfusionLogo.ico
deleted file mode 100644
index 2c6d158..0000000
Binary files a/SharpENDEC/EASfusionLogo.ico and /dev/null differ
diff --git a/SharpENDEC/ENDEC/AlertProcessor.cs b/SharpENDEC/ENDEC/AlertProcessor.cs
new file mode 100644
index 0000000..255838c
--- /dev/null
+++ b/SharpENDEC/ENDEC/AlertProcessor.cs
@@ -0,0 +1,244 @@
+using SharpENDEC.Properties;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace SharpENDEC
+{
+ public static partial class ENDEC
+ {
+ public static List SharpAlertQueue = new List();
+
+ public static void AlertProcessor()
+ {
+ while (true)
+ {
+ if (SharpAlertQueue.Count != 0)
+ {
+ SharpDataItem alert;
+ lock (SharpAlertQueue)
+ {
+ alert = SharpAlertQueue[0];
+ SharpAlertQueue.Remove(alert);
+ }
+ ProcessAlertItem(alert);
+ }
+ Thread.Sleep(100);
+ }
+ }
+
+ public static void ProcessAlertItem(SharpDataItem relayItem)
+ {
+ bool IsUI = Settings.Default.WirelessAlertMode;
+ foreach (Match match in Regex.Matches(relayItem.Data, @"([^<]+)\s*([^<]+)", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline))
+ {
+ if (match.Groups[1].Value == "layer:SOREM:2.0:WirelessText")
+ {
+ if (!string.IsNullOrWhiteSpace(match.Groups[2].Value))
+ {
+ IsUI = true;
+ break;
+ }
+ }
+
+ //ConsoleExt.WriteLine($"valueName: {match.Groups[1].Value}");
+ //ConsoleExt.WriteLine($"value: {match.Groups[2].Value}");
+ }
+
+ Match sentMatch = Regex.Match(relayItem.Data, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
+ Match statusMatch = Regex.Match(relayItem.Data, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
+ Match messageTypeMatch = Regex.Match(relayItem.Data, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
+ MatchCollection broadcastImmediatelyMatches = Regex.Matches(relayItem.Data, @"layer:SOREM:1.0:Broadcast_Immediately\s*\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
+ MatchCollection urgencyMatches = Regex.Matches(relayItem.Data, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
+ MatchCollection severityMatches = Regex.Matches(relayItem.Data, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
+
+ bool final = false;
+
+ for (int i = 0; i < severityMatches.Count; i++)
+ {
+ if (Check.Config(relayItem.Data, statusMatch.Groups[1].Value, messageTypeMatch.Groups[1].Value, severityMatches[i].Groups[1].Value, urgencyMatches[i].Groups[1].Value, broadcastImmediatelyMatches[i].Groups[1].Value))
+ {
+ final = true;
+ break;
+ }
+ }
+
+ if (!final)
+ {
+ ConsoleExt.WriteLine($"[Alert Processor] {LanguageStrings.AlertIgnoredDueToPreferences(Settings.Default.CurrentLanguage)}", ConsoleColor.DarkGray);
+ return;
+ }
+
+ MatchCollection infoMatches = Regex.Matches(relayItem.Data, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
+ int infoProc = 0;
+
+ foreach (Match infoMatch in infoMatches)
+ {
+ infoProc++;
+ ConsoleExt.WriteLine($"[Alert Processor] {LanguageStrings.GenericProcessingValueOfValue(Settings.Default.CurrentLanguage, infoProc, infoMatches.Count)}");
+ string infoEN = $"{infoMatch.Groups[1].Value}";
+ string lang = "en";
+ if (Regex.Match(infoEN, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value == "fr-CA")
+ {
+ lang = "fr";
+ }
+ if (lang != "en")
+ {
+ continue;
+ }
+
+ string Status = statusMatch.Groups[1].Value;
+ string MsgType = messageTypeMatch.Groups[1].Value;
+ string EventType = Regex.Match(infoEN, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value;
+ string urgency = Regex.Match(infoEN, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value;
+ string severity = Regex.Match(infoEN, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value;
+ //string when = Regex.Match(@"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value;
+ string broadcastImmediately;
+ Match broadcastImmediatelyMatch = Regex.Match(infoEN, @"layer:SOREM:1.0:Broadcast_Immediately\s*\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
+ if (broadcastImmediatelyMatch.Success)
+ {
+ broadcastImmediately = broadcastImmediatelyMatch.Groups[1].Value;
+ }
+ else
+ {
+ broadcastImmediately = "No";
+ }
+
+ EventDetails EventInfo = GetEventDetails(EventType);
+
+ ConsoleExt.WriteLine(Status, ConsoleColor.DarkGray);
+ ConsoleExt.WriteLine(MsgType, ConsoleColor.DarkGray);
+ ConsoleExt.WriteLine($"{EventType} | {EventInfo.FriendlyName}", ConsoleColor.DarkGray);
+ ConsoleExt.WriteLine(urgency, ConsoleColor.DarkGray);
+ ConsoleExt.WriteLine(severity, ConsoleColor.DarkGray);
+ ConsoleExt.WriteLine(broadcastImmediately, ConsoleColor.DarkGray);
+ ConsoleExt.WriteLine(sentMatch.Groups[1].Value, ConsoleColor.DarkGray);
+
+ bool Stop = false;
+
+ if (Check.Config(infoEN, statusMatch.Groups[1].Value, MsgType, severity, urgency, broadcastImmediately))
+ {
+ foreach (string EventName in Settings.Default.EnforceEventBlacklist)
+ {
+ if (EventType.ToLower() == EventName.ToLower())
+ {
+ Stop = true;
+ }
+ }
+
+ if (Stop)
+ {
+ ConsoleExt.WriteLine($"[Alert Processor] {LanguageStrings.AlertIgnoredDueToBlacklist(Settings.Default.CurrentLanguage)}", ConsoleColor.DarkGray);
+ continue;
+ }
+
+ ConsoleExt.WriteLine($"[Alert Processor] {LanguageStrings.GeneratingProductText(Settings.Default.CurrentLanguage)}");
+
+ Generate gen = new Generate(infoEN, MsgType, sentMatch.Groups[1].Value);
+
+ var info = gen.BroadcastInfo(lang);
+
+ //if (true) //(!string.IsNullOrWhiteSpace(info.BroadcastText))
+ {
+ //ConsoleExt.WriteLine($"[Alert Processor] {LanguageStrings.GeneratingProductAudio}");
+ File.WriteAllText($"{AssemblyDirectory}\\inactive-text.txt", string.Empty);
+ File.WriteAllText($"{AssemblyDirectory}\\active-text.txt", $"{info.BroadcastText}\x20");
+ File.WriteAllText($"{AssemblyDirectory}\\static-text.txt", $"{info.BroadcastText}\x20");
+
+ ConsoleExt.WriteLine($"[Alert Processor] -> {info.BroadcastText}", ConsoleColor.Magenta);
+
+ gen.GenerateAudio(info.BroadcastText, lang);
+
+ if (IsUI)
+ {
+ Color BackColor;
+ Color ForeColor;
+
+ switch (severity.ToLower())
+ {
+ case "extreme":
+ BackColor = Color.Red;
+ ForeColor = Color.Yellow;
+ break;
+ case "severe":
+ BackColor = Color.OrangeRed;
+ ForeColor = Color.Black;
+ break;
+ case "moderate":
+ BackColor = Color.Gold;
+ ForeColor = Color.Black;
+ break;
+ case "minor":
+ BackColor = Color.LightGreen;
+ ForeColor = Color.Black;
+ break;
+ case "unknown":
+ default:
+ BackColor = Color.White;
+ ForeColor = Color.Black;
+ break;
+ }
+
+ //Task.Run(() =>
+ //{
+ // AlertForm af = new AlertForm
+ // {
+ // PlayAudio = () => Play($"{AudioDirectory}\\audio.wav"),
+ // EventBackColor = BackColor,
+ // EventForeColor = ForeColor,
+ // EventTextContent = EventInfo.FriendlyName
+ // };
+ // af.Show();
+ //}).Wait(30000);
+
+ Task.Run(() =>
+ {
+ NotifyOverlay no = new NotifyOverlay
+ {
+ EventShortInfoText = $"{EventInfo.FriendlyName}",
+ EventLongInfoText = $"{info.BroadcastText}",
+ EventTypeText = $"{EventInfo.FriendlyName}"
+ };
+ no.ShowDialog();
+ }).Wait(30000);
+ }
+ else
+ {
+ ConsoleExt.WriteLine($"[Alert Processor] {LanguageStrings.PlayingAudio(Settings.Default.CurrentLanguage)}");
+ ConsoleExt.WriteLine($"[Alert Processor] {Play($"{AudioDirectory}\\in.wav").AudioLength.TotalMilliseconds} millisecond(s) played");
+ if (EventInfo.Severity.Contains("Severe") || EventInfo.Severity.Contains("Extreme"))
+ ConsoleExt.WriteLine($"[Alert Processor] {Play($"{AudioDirectory}\\attn.wav").AudioLength.TotalMilliseconds} millisecond(s) played.");
+ else
+ {
+ var (FilePlayed, AudioLength) = Play($"{AudioDirectory}\\attn-minor.wav");
+ if (FilePlayed)
+ ConsoleExt.WriteLine($"[Alert Processor] {Play($"{AudioDirectory}\\attn-minor.wav").AudioLength.TotalMilliseconds} millisecond(s) played.");
+ else
+ ConsoleExt.WriteLine($"[Alert Processor] {Play($"{AudioDirectory}\\attn.wav").AudioLength.TotalMilliseconds} millisecond(s) played.");
+ }
+ //ConsoleExt.WriteLine($"[Alert Processor] Attention tone not played because the alert severity is not severe or extreme.");
+ ConsoleExt.WriteLine($"[Alert Processor] {Play($"{AudioDirectory}\\audio.wav").AudioLength.TotalMilliseconds} millisecond(s) played.");
+ ConsoleExt.WriteLine($"[Alert Processor] {Play($"{AudioDirectory}\\out.wav").AudioLength.TotalMilliseconds} millisecond(s) played.");
+ }
+
+ File.WriteAllText($"{AssemblyDirectory}\\active-text.txt", string.Empty);
+ File.WriteAllText($"{AssemblyDirectory}\\inactive-text.txt", $"{info.BroadcastText}\x20");
+ }
+ //else
+ //{
+ // ConsoleExt.WriteLine($"[Alert Processor] {LanguageStrings.GeneratedProductEmpty(Settings.Default.CurrentLanguage)}");
+ //}
+ }
+ else
+ {
+ ConsoleExt.WriteLine($"[Alert Processor] {LanguageStrings.AlertIgnoredDueToPreferences(Settings.Default.CurrentLanguage)}", ConsoleColor.DarkGray);
+ }
+ }
+ //ConsoleExt.WriteLine("[Alert Processor] Processed all available entries.", ConsoleColor.DarkGray);
+ }
+ }
+}
diff --git a/SharpENDEC/ENDEC/BatteryMonitor.cs b/SharpENDEC/ENDEC/BatteryMonitor.cs
new file mode 100644
index 0000000..ce367bc
--- /dev/null
+++ b/SharpENDEC/ENDEC/BatteryMonitor.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Threading;
+using System.Windows.Forms;
+
+namespace SharpENDEC
+{
+ public static partial class ENDEC
+ {
+ public class BatteryMonitor
+ {
+ public void Monitor()
+ {
+ // TODO: Add setting to enable and disable battery monitoring
+ while (true)
+ {
+ try
+ {
+ PowerStatus powerStatus = SystemInformation.PowerStatus;
+ BatteryChargeStatus chargeStatus = powerStatus.BatteryChargeStatus;
+
+ if (!(powerStatus.BatteryLifePercent > 0.20))
+ {
+ ConsoleExt.WriteLine($"[Battery] The battery percentage is currently at {powerStatus.BatteryLifePercent}.");
+ }
+ ConsoleExt.WriteLine($"Battery Status: {chargeStatus}");
+
+ if ((chargeStatus & BatteryChargeStatus.Charging) == BatteryChargeStatus.Charging)
+ {
+ ConsoleExt.WriteLine("The system is currently charging.");
+ }
+ else if (chargeStatus == BatteryChargeStatus.NoSystemBattery)
+ {
+ ConsoleExt.WriteLine("No battery is installed.");
+ }
+ else
+ {
+ ConsoleExt.WriteLine("The system is not charging.");
+ }
+ }
+ catch (Exception)
+ {
+
+ }
+ Thread.Sleep(30000);
+ }
+ }
+ }
+ }
+}
diff --git a/SharpENDEC/ENDEC/DataProcessor.cs b/SharpENDEC/ENDEC/DataProcessor.cs
new file mode 100644
index 0000000..88fbb28
--- /dev/null
+++ b/SharpENDEC/ENDEC/DataProcessor.cs
@@ -0,0 +1,663 @@
+using NAudio.Wave.SampleProviders;
+using NAudio.Wave;
+using SharpENDEC.Properties;
+using System;
+using System.Drawing;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Net.Http;
+using System.Speech.Synthesis;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
+using NAudio.Utils;
+using System.Collections.Generic;
+
+namespace SharpENDEC
+{
+ public static partial class ENDEC
+ {
+ public static void DataProcessor()
+ {
+ //try
+ {
+ while (true)
+ {
+ SharpDataItem relayItem = Check.WatchForItemsInList();
+ ConsoleExt.WriteLine($"[Data Processor] {LanguageStrings.CapturedFromFileWatcher(Settings.Default.CurrentLanguage)}", ConsoleColor.Cyan);
+
+ lock (SharpDataHistory) SharpDataHistory.Add(relayItem);
+ lock (SharpDataQueue) SharpDataQueue.Remove(relayItem);
+
+ if (relayItem.Data.Contains("NAADS-Heartbeat"))
+ {
+ ConsoleExt.WriteLine($"[Data Processor] {LanguageStrings.HeartbeatDetected(Settings.Default.CurrentLanguage)}", ConsoleColor.Green);
+ Match referencesMatch = Regex.Match(relayItem.Data, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
+ if (referencesMatch.Success)
+ {
+ string references = referencesMatch.Groups[1].Value;
+ //ConsoleExt.WriteLine(referencesMatch.Groups[0].Value);
+ //ConsoleExt.WriteLine(referencesMatch.Groups[1].Value);
+ Check.Heartbeat(references);
+ }
+ }
+ else
+ {
+ lock (SharpAlertQueue) SharpAlertQueue.Add(relayItem);
+ ConsoleExt.WriteLine(LanguageStrings.AlertQueued(Settings.Default.CurrentLanguage));
+ }
+
+ ConsoleExt.WriteLine($"[Data Processor] {LanguageStrings.LastDataReceived(Settings.Default.CurrentLanguage)} {DateTime.Now:yyyy-MM-dd HH:mm:ss}.");
+ }
+ }
+ //catch (ThreadAbortException)
+ //{
+ // ConsoleExt.WriteLine($"{LanguageStrings.ThreadShutdown(Settings.Default.CurrentLanguage, $"Data Processor")}");
+ //}
+ }
+
+ private static (bool FilePlayed, TimeSpan AudioLength) Play(string filePath, float volume = 1, bool DefaultDevice = false)
+ {
+ if (File.Exists(filePath))
+ {
+ using (var audioFile = new AudioFileReader(filePath))
+ using (var outputDevice = new WaveOutEvent
+ {
+ Volume = volume
+ })
+ {
+ if (!DefaultDevice) outputDevice.DeviceNumber = Settings.Default.SoundDevice;
+ outputDevice.Init(audioFile);
+ outputDevice.Play();
+ ConsoleExt.WriteLine($"[Data Processor] -> {filePath}.");
+ while (outputDevice.PlaybackState == PlaybackState.Playing)
+ {
+ if (SkipPlayback)
+ {
+ outputDevice.Stop();
+ SkipPlayback = false;
+ }
+ if (outputDevice.GetPositionTimeSpan() >= TimeSpan.FromSeconds(Settings.Default.EnforceMaximumTime)
+ && Settings.Default.EnforceMaximumTime != -1)
+ outputDevice.Stop();
+ Thread.Sleep(100);
+ }
+ return (true, outputDevice.GetPositionTimeSpan());
+ }
+ }
+ else return (false, TimeSpan.Zero);
+ }
+
+ public static class Check
+ {
+ public static bool Config(string InfoX, string Status, string MsgType,
+ string Severity, string Urgency, string BroadcastImmediately)
+ {
+ bool Final = false;
+
+ // Status:
+ // Test
+ // Actual
+
+ switch (Status.ToLower())
+ {
+ case "test":
+ if (!Settings.Default.statusTest) return false;
+ break;
+ case "actual":
+ if (!Settings.Default.statusActual) return false;
+ break;
+ default:
+ break;
+ }
+
+ // MsgType:
+ // Alert
+ // Update
+ // Cancel
+
+ if (BroadcastImmediately.ToLower().Contains("yes"))
+ {
+ Final = true;
+ }
+ else
+ {
+ try
+ {
+ bool var1; // Severity
+ bool var2; // Urgency
+ bool var3; // MsgType
+
+ switch (Severity.ToLower())
+ {
+ case "extreme":
+ var1 = Settings.Default.severityExtreme;
+ break;
+ case "severe":
+ var1 = Settings.Default.severitySevere;
+ break;
+ case "moderate":
+ var1 = Settings.Default.severityModerate;
+ break;
+ case "minor":
+ var1 = Settings.Default.severityMinor;
+ break;
+ case "unknown":
+ var1 = Settings.Default.severityUnknown;
+ break;
+ default:
+ var1 = Settings.Default.severityUnknown;
+ break;
+ }
+
+ switch (Urgency.ToLower())
+ {
+ case "immediate":
+ var2 = Settings.Default.urgencyImmediate;
+ break;
+ case "expected":
+ var2 = Settings.Default.urgencyExpected;
+ break;
+ case "future":
+ var2 = Settings.Default.urgencyFuture;
+ break;
+ case "past":
+ var2 = Settings.Default.urgencyPast;
+ break;
+ default:
+ var2 = false;
+ break;
+ }
+
+ switch (MsgType.ToLower())
+ {
+ case "alert":
+ var3 = Settings.Default.messageTypeAlert;
+ break;
+ case "update":
+ var3 = Settings.Default.messageTypeUpdate;
+ break;
+ case "cancel":
+ var3 = Settings.Default.messageTypeCancel;
+ break;
+ case "test":
+ var3 = Settings.Default.messageTypeTest;
+ break;
+ default:
+ var3 = false;
+ break;
+
+ }
+
+ if (var1 && var2 && var3)
+ {
+ Final = true;
+ }
+ }
+ catch
+ {
+ Final = false;
+ }
+ }
+
+ if (Final)
+ {
+ if (Settings.Default.AllowedLocations_Geocodes.Count == 0)
+ {
+
+ }
+ else
+ {
+ try
+ {
+ MatchCollection matches = Regex.Matches(InfoX,
+ @"\s*profile:CAP-CP:Location:0.3\s*\s*(.*?)\s*",
+ RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
+ bool GeoMatch = false;
+ foreach (Match match in matches)
+ {
+ string geocode = match.Groups[1].Value;
+ if (Settings.Default.AllowedLocations_Geocodes.Contains(geocode))
+ {
+ GeoMatch = true;
+ break;
+ }
+ }
+ if (!GeoMatch)
+ {
+ return false;
+ }
+ }
+ catch (Exception ex)
+ {
+ ConsoleExt.WriteLine($"[Data Processor] {ex.Message}", ConsoleColor.Red);
+ return false;
+ }
+ }
+ }
+ return Final;
+ }
+
+ public static DateTime LastHeartbeat = DateTime.Now;
+
+ private static readonly HttpClient client = new HttpClient
+ {
+ Timeout = TimeSpan.FromSeconds(3)
+ };
+
+ public static void Heartbeat(string References)
+ {
+ ConsoleExt.WriteLine($"[Heartbeat] {LanguageStrings.DownloadingFiles(Settings.Default.CurrentLanguage)}", ConsoleColor.DarkYellow);
+ string[] RefList = References.Split(' ');
+ int DataMatched = 0;
+ int Total = 0;
+ foreach (string i in RefList)
+ {
+ Total++;
+ ConsoleExt.WriteLine($"[Heartbeat] {LanguageStrings.GenericProcessingValueOfValue(Settings.Default.CurrentLanguage, Total, RefList.Length)}", ConsoleColor.DarkYellow);
+ string filename = string.Empty;
+ string[] k = i.Split(',');
+ string sentDTFull = k[2].Replace("-", "_").Replace(":", "_").Replace("+", "p");
+ string sentDT = sentDTFull.Substring(0, 10).Replace("_", "-");
+ filename += sentDTFull;
+ filename += "I" + k[1].Replace("-", "_").Replace(":", "_");
+ filename += ".xml";
+ //string filenameShort = sentDTFull.Replace("_", "-");
+
+ string Dom1 = "capcp1.naad-adna.pelmorex.com";
+ string Dom2 = "capcp2.naad-adna.pelmorex.com";
+
+ if (SharpDataQueue.Any(x => x.Name == filename) || SharpDataHistory.Any(x => x.Name == filename))
+ {
+ ConsoleExt.WriteLine($"[Heartbeat] {LanguageStrings.DataPreviouslyProcessed(Settings.Default.CurrentLanguage)}", ConsoleColor.Yellow);
+ DataMatched++;
+ }
+ else
+ {
+ ConsoleExt.WriteLine($"[Heartbeat] {filename}...", ConsoleColor.Yellow);
+ string url1 = $"http://{Dom1}/{sentDT}/{filename}";
+ string url2 = $"http://{Dom2}/{sentDT}/{filename}";
+
+ try
+ {
+ ConsoleExt.WriteLine($"-> {url1}", ConsoleColor.Yellow);
+ Task xml = client.GetStringAsync(url1);
+ xml.Wait();
+ lock (SharpDataQueue) SharpDataQueue.Add(new SharpDataItem(filename, xml.Result));
+ xml.Dispose();
+ }
+ catch (Exception e1)
+ {
+ try
+ {
+ ConsoleExt.WriteLine($"[Heartbeat] {e1.Message}", ConsoleColor.Red);
+ ConsoleExt.WriteLine($"[Heartbeat] {filename}...", ConsoleColor.Yellow);
+ ConsoleExt.WriteLine($"-> {url2}", ConsoleColor.Yellow);
+ Task xml = client.GetStringAsync(url2);
+ xml.Wait();
+ lock (SharpDataQueue) SharpDataQueue.Add(new SharpDataItem(filename, xml.Result));
+ xml.Dispose();
+ }
+ catch (Exception e2)
+ {
+ ConsoleExt.WriteLine($"[Heartbeat] {e2.Message}", ConsoleColor.Red);
+ ConsoleExt.WriteLine($"[Heartbeat] {LanguageStrings.DownloadFailure(Settings.Default.CurrentLanguage)}", ConsoleColor.Red);
+ }
+ }
+ }
+ }
+ if (DataMatched != 0) ConsoleExt.WriteLine($"[Heartbeat] {LanguageStrings.DataIgnoredDueToMatchingPairs(Settings.Default.CurrentLanguage, DataMatched)}", ConsoleColor.Blue);
+ LastHeartbeat = DateTime.Now;
+ }
+
+ public static SharpDataItem WatchForItemsInList()
+ {
+ //ConsoleExt.WriteLine($"[Data Processor] Watching for new strings in FileStringListTempName.");
+ while (true)
+ {
+ if (SharpDataQueue.Count != 0)
+ {
+ lock (SharpDataQueue)
+ {
+ SharpDataItem data = SharpDataQueue.First();
+ return data;
+ }
+ }
+ Thread.Sleep(50);
+ }
+ return null;
+ }
+ }
+
+ public class Generate
+ {
+ private readonly string InfoData;
+ private readonly string MsgType;
+ private readonly string Sent;
+
+ public Generate(string InfoDataZ, string MsgTypeZ, string SentDate)
+ {
+ InfoData = InfoDataZ;
+ MsgType = MsgTypeZ;
+ Sent = SentDate;
+ }
+
+ public (string BroadcastText, bool) BroadcastInfo(string lang)
+ {
+ string BroadcastText = "";
+
+ Match match = Regex.Match(InfoData, @"layer:SOREM:1.0:Broadcast_Text\s*\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
+ if (match.Success)
+ {
+ BroadcastText = match.Groups[1].Value.Replace("\r\n", " ").Replace("\n", " ").Replace(" ", " ").Trim();
+ }
+ else
+ {
+ string issue, update, cancel;
+ if (lang == "fr")
+ {
+ issue = "émis";
+ update = "mis à jour";
+ cancel = "annulé";
+ }
+ else
+ {
+ issue = "issued";
+ update = "updated";
+ cancel = "cancelled";
+ }
+
+ string MsgPrefix;
+ switch (MsgType.ToLower())
+ {
+ case "alert":
+ MsgPrefix = issue;
+ break;
+ case "update":
+ MsgPrefix = update;
+ break;
+ case "cancel":
+ MsgPrefix = cancel;
+ break;
+ default:
+ MsgPrefix = "issued";
+ break;
+ }
+
+ DateTime sentDate;
+ try
+ {
+ // .ToUniversalTime()
+ sentDate = DateTime.Parse(Sent, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
+ }
+ catch (Exception e)
+ {
+ ConsoleExt.WriteLine(e.Message);
+ sentDate = DateTime.Now;
+ }
+
+ //DateTime sentDate = DateTime.Parse(Sent, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToUniversalTime();
+
+ string SentFormatted = lang == "fr" ? $"{sentDate:HH}'{sentDate:h}'{sentDate:mm zzz}." : $"{sentDate:HH:mm z}, {sentDate:MMMM dd}, {sentDate:yyyy}.";
+
+ string EventType;
+ try
+ {
+ EventType = Regex.Match(InfoData, @"layer:EC-MSC-SMC:1.0:Alert_Name\s*\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value;
+ }
+ catch (Exception)
+ {
+ EventType = Regex.Match(InfoData, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value;
+ EventType = lang == "fr" ? $"alerte {EventType}" : $"{EventType} alert";
+ }
+
+ string Coverage;
+ try
+ {
+ Coverage = Regex.Match(InfoData, @"layer:EC-MSC-SMC:1.0:Alert_Coverage\s*\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value;
+ Coverage = lang == "fr" ? $"en {Coverage} pour:" : $"in {Coverage} for:";
+ }
+ catch (Exception)
+ {
+ Coverage = lang == "fr" ? "pour:" : "for:";
+ }
+
+ string[] areaDescMatches = Regex.Matches(InfoData, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline)
+ .Cast()
+ .Select(m => m.Groups[1].Value)
+ .ToArray();
+
+ string AreaDesc = string.Join(", ", areaDescMatches) + ".";
+
+ string SenderName;
+
+ try
+ {
+ SenderName = Regex.Match(InfoData, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value;
+ }
+ catch (Exception)
+ {
+ SenderName = "an alert issuer";
+ }
+
+ string Description;
+
+ try
+ {
+ Description = Regex.Match(InfoData, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value.Replace("\n", " ");
+ if (!Description.EndsWith(".")) Description += ".";
+ }
+ catch (Exception)
+ {
+ Description = "";
+ }
+
+ string Instruction;
+
+ try
+ {
+ Instruction = Regex.Match(InfoData, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value.Replace("\n", " ");
+ if (!Instruction.EndsWith(".")) Instruction += ".";
+ }
+ catch (Exception)
+ {
+ Instruction = "";
+ }
+
+ string Effective;
+
+ try
+ {
+ Effective = Regex.Match(InfoData, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value.Replace("\n", " ");
+ DateTime.Parse(Effective, CultureInfo.InvariantCulture);
+ }
+ catch (Exception)
+ {
+ Effective = "currently";
+ }
+
+ string Expires;
+
+ try
+ {
+ Expires = Regex.Match(InfoData, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value.Replace("\n", " ");
+ DateTime.Parse(Expires, CultureInfo.InvariantCulture);
+ }
+ catch (Exception)
+ {
+ Expires = "soon";
+ }
+
+ // Effective {Effective}, and expiring {Expires}.
+
+ BroadcastText = lang == "fr" ?
+ $"À {SentFormatted} {SenderName} a {MsgPrefix} une {EventType} {Coverage} {AreaDesc}. {Description} {Instruction}".Replace("###", "").Replace(" ", " ").Trim() :
+ $"At {SentFormatted} {SenderName} has {MsgPrefix} a {EventType} {Coverage} {AreaDesc}. {Description} {Instruction}".Replace("###", "").Replace(" ", " ").Trim();
+ }
+
+ if (BroadcastText.EndsWith("\x20.")) BroadcastText = BroadcastText.TrimEnd('\x20', '.');
+ if (BroadcastText.EndsWith(".")) BroadcastText = BroadcastText.TrimEnd('.');
+ if (!BroadcastText.EndsWith(".") || !BroadcastText.EndsWith("!")) BroadcastText += ".";
+
+ //if (Debugger.IsAttached) BroadcastText += "\x20| Debugging in progress";
+
+ return (BroadcastText, true);
+ }
+
+ public bool GetAudio(string audioLink, string output, int decodeType)
+ {
+ if (decodeType == 1)
+ {
+ ConsoleExt.WriteLine("Decoding audio from Base64.");
+ try
+ {
+ byte[] audioData = Convert.FromBase64String(audioLink);
+ File.WriteAllBytes(output, audioData);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ ConsoleExt.WriteLine($"Decoder failed: {ex.Message}");
+ return false;
+ }
+ }
+ else if (decodeType == 0)
+ {
+ ConsoleExt.WriteLine("Downloading audio.");
+ try
+ {
+ using (HttpClient webClient = new HttpClient())
+ {
+ File.WriteAllBytes(output, webClient.GetByteArrayAsync(audioLink).Result);
+ }
+ return true;
+ }
+ catch (Exception ex)
+ {
+ ConsoleExt.WriteLine($"Downloader failed: {ex.Message}");
+ }
+ return false;
+ }
+ else
+ {
+ ConsoleExt.WriteLine("Invalid DecodeType specified.");
+ return false;
+ }
+ }
+
+ private readonly SpeechSynthesizer engine = new SpeechSynthesizer();
+
+ public void GenerateAudio(string text, string lang)
+ {
+ try
+ {
+ Match Resource = Regex.Match(InfoData, @"\s*(.*?)\s*\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
+ if (!Resource.Success) throw new Exception("Audio field not found. TTS will be generated instead.");
+ string broadcastAudioResource = Resource.Groups[1].Value;
+ string audioLink = string.Empty;
+ string audioType = string.Empty;
+ int decode = -1;
+
+ if (broadcastAudioResource.Contains(""))
+ {
+ Match Link = Regex.Match(broadcastAudioResource, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
+ Match Type = Regex.Match(broadcastAudioResource, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
+ decode = 1;
+ if (Link.Success && Type.Success)
+ {
+ audioLink = Link.Groups[1].Value;
+ audioType = Type.Groups[1].Value;
+ }
+ }
+ else
+ {
+ Match Link = Regex.Match(broadcastAudioResource, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
+ Match Type = Regex.Match(broadcastAudioResource, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
+ decode = 0;
+ if (Link.Success && Type.Success)
+ {
+ audioLink = Link.Groups[1].Value;
+ audioType = Type.Groups[1].Value;
+ }
+ }
+
+ ConsoleExt.WriteLine(audioLink);
+ //Thread.Sleep(5000);
+
+ string audioFile;
+ switch (audioType)
+ {
+ case "audio/mpeg":
+ audioFile = "PreAudio.mp3";
+ break;
+ case "audio/x-ms-wma":
+ audioFile = "PreAudio.wma";
+ break;
+ default:
+ audioFile = "PreAudio.wav";
+ break;
+ }
+
+ if (File.Exists($"{AudioDirectory}\\{audioFile}")) File.Delete($"{AudioDirectory}\\{audioFile}");
+ if (File.Exists($"{AudioDirectory}\\audio.wav")) File.Delete($"{AudioDirectory}\\audio.wav");
+
+ if (GetAudio(audioLink, audioFile, decode))
+ {
+ using (var audioFileReader = new AudioFileReader(audioFile))
+ {
+ var volumeSampleProvider = new VolumeSampleProvider(audioFileReader.ToSampleProvider())
+ {
+ Volume = 2.5f,
+ };
+ WaveFileWriter.CreateWaveFile16($"{AudioDirectory}\\audio.wav", volumeSampleProvider);
+ }
+
+ if (!File.Exists($"{AudioDirectory}\\audio.wav"))
+ {
+ ConsoleExt.WriteLine("Post processing failed.");
+ File.Move(audioFile, $"{AudioDirectory}\\audio.wav");
+ }
+
+ //string ffmpegCmd = $"{AssemblyDirectory}\\ffmpeg.exe -y -i {audioFile} -filter:a volume=2.5 {AssemblyDirectory.Replace("\\", "/")}/Audio/audio.wav";
+ //Process p = Process.Start("cmd.exe", $"/c {ffmpegCmd}");
+ //p.WaitForExit(12000);
+ //if (p.ExitCode != 0 || !File.Exists($"{AssemblyDirectory}\\Audio\\audio.wav"))
+ //{
+ // ConsoleExt.WriteLine("Post processing failed. Please make sure ffmpeg is in the program folder.");
+ // File.Move(audioFile, $"{AssemblyDirectory}\\Audio\\audio.wav");
+ //}
+ //new SoundPlayer($"{AssemblyDirectory}\\Audio\\audio.wav").PlaySync();
+ }
+ else
+ {
+ throw new Exception();
+ }
+ }
+ catch (Exception ex)
+ {
+ ConsoleExt.WriteLine(ex.Message);
+
+ //ConsoleExt.WriteLine(lang);
+ foreach (var voice in engine.GetInstalledVoices())
+ {
+ //ConsoleExt.WriteLine(voice.VoiceInfo.Culture.TwoLetterISOLanguageName.ToLower());
+ if (voice.VoiceInfo.Name.Contains(Settings.Default.SpeechVoice) && voice.VoiceInfo.Culture.TwoLetterISOLanguageName.ToLower() == lang)
+ {
+ //ConsoleExt.WriteLine(voice.VoiceInfo.Name, ConsoleColor.Magenta);
+ engine.SelectVoice(voice.VoiceInfo.Name);
+ break;
+ }
+ }
+
+ text = text.Replace("#", "hashtag\x20");
+ text = text.Replace("*", "star\x20");
+
+ engine.SetOutputToWaveFile($"{AudioDirectory}\\audio.wav");
+ engine.Speak(text);
+ engine.Dispose();
+ }
+ }
+ }
+ }
+}
diff --git a/SharpENDEC/ENDEC/EventDetails.cs b/SharpENDEC/ENDEC/EventDetails.cs
new file mode 100644
index 0000000..0924a7a
--- /dev/null
+++ b/SharpENDEC/ENDEC/EventDetails.cs
@@ -0,0 +1,69 @@
+using System.Collections.Generic;
+
+namespace SharpENDEC
+{
+ public static partial class ENDEC
+ {
+ public static EventDetails GetEventDetails(string eventCode)
+ {
+ var eventDetailsDictionary = new Dictionary
+ {
+ { "airQuality", new EventDetails("Air Quality", "Severe or Extreme", "Observed") },
+ { "civilEmerg", new EventDetails("Civil Emergency", "Severe or Extreme", "Observed") },
+ { "terrorism", new EventDetails("Terrorism", "Severe or Extreme", "Observed") },
+ { "animalDang", new EventDetails("Dangerous Animal", "Severe or Extreme", "Observed") },
+ { "wildFire", new EventDetails("Wildfire", "Severe or Extreme", "Likely or Observed") },
+ { "industryFire", new EventDetails("Industrial Fire", "Severe or Extreme", "Observed") },
+ { "urbanFire", new EventDetails("Urban Fire", "Severe or Extreme", "Observed") },
+ { "forestFire", new EventDetails("Forest Fire", "Severe or Extreme", "Likely or Observed") },
+ { "stormSurge", new EventDetails("Storm Surge", "Severe or Extreme", "Likely or Observed") },
+ { "flashFlood", new EventDetails("Flash Flood", "Severe or Extreme", "Likely or Observed") },
+ { "damOverflow", new EventDetails("Dam Overflow", "Severe or Extreme", "Likely or Observed") },
+ { "earthquake", new EventDetails("Earthquake", "Severe or Extreme", "Likely or Observed") },
+ { "magnetStorm", new EventDetails("Magnetic Storm", "Severe or Extreme", "Likely or Observed") },
+ { "landslide", new EventDetails("Landslide", "Severe or Extreme", "Likely or Observed") },
+ { "meteor", new EventDetails("Meteor", "Severe or Extreme", "Likely or Observed") },
+ { "tsunami", new EventDetails("Tsunami", "Severe or Extreme", "Likely or Observed") },
+ { "lahar", new EventDetails("Lahar", "Severe or Extreme", "Likely or Observed") },
+ { "pyroclasticS", new EventDetails("Pyroclastic Surge", "Severe or Extreme", "Likely or Observed") },
+ { "pyroclasticF", new EventDetails("Pyroclastic Flow", "Severe or Extreme", "Likely or Observed") },
+ { "volcanicAsh", new EventDetails("Volcanic Ash", "Severe or Extreme", "Likely or Observed") },
+ { "chemical", new EventDetails("Chemical", "Severe or Extreme", "Observed") },
+ { "biological", new EventDetails("Biological", "Severe or Extreme", "Observed") },
+ { "radiological", new EventDetails("Radiological", "Severe or Extreme", "Observed") },
+ { "explosives", new EventDetails("Explosives", "Severe or Extreme", "Likely or Observed") },
+ { "fallObject", new EventDetails("Falling Object", "Severe or Extreme", "Observed") },
+ { "drinkingWate", new EventDetails("Drinking Water", "Severe or Extreme", "Observed") },
+ { "amber", new EventDetails("Amber Alert", "Severe or Extreme", "Observed") },
+ { "hurricane", new EventDetails("Hurricane", "Severe or Extreme", "Observed") },
+ { "thunderstorm", new EventDetails("Thunderstorm", "Severe or Extreme", "Observed") },
+ { "tornado", new EventDetails("Tornado", "Severe or Extreme", "Likely or Observed") },
+ { "testMessage", new EventDetails("Test Message", "Minor", "Observed") },
+ { "911Service", new EventDetails("911 Service", "Severe or Extreme", "Observed") }
+ };
+
+ if (eventDetailsDictionary.TryGetValue(eventCode, out EventDetails eventDetails))
+ {
+ return eventDetails;
+ }
+ else
+ {
+ return new EventDetails(eventCode, "Unknown Severity", "Unknown Certainty");
+ }
+ }
+
+ public class EventDetails
+ {
+ public string FriendlyName { get; }
+ public string Severity { get; }
+ public string Certainty { get; }
+
+ public EventDetails(string friendlyName, string severity, string certainty)
+ {
+ FriendlyName = friendlyName;
+ Severity = severity;
+ Certainty = certainty;
+ }
+ }
+ }
+}
diff --git a/SharpENDEC/ENDEC/FeedCapture.cs b/SharpENDEC/ENDEC/FeedCapture.cs
new file mode 100644
index 0000000..b7c04ee
--- /dev/null
+++ b/SharpENDEC/ENDEC/FeedCapture.cs
@@ -0,0 +1,207 @@
+using SharpENDEC.Properties;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net.Sockets;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading;
+
+namespace SharpENDEC
+{
+ public static partial class ENDEC
+ {
+ public static List SharpDataQueue = new List();
+ public static List SharpDataHistory = new List();
+
+ public class SharpDataItem
+ {
+ public string Name { get; set; }
+ public string Data { get; set; }
+
+ public SharpDataItem(string name, string data)
+ {
+ Name = name;
+ Data = data;
+ }
+ }
+
+ public class FeedCapture
+ {
+ public bool ShutdownCapture = false;
+
+ private void Receive(string host, int port, string delimiter)
+ {
+ try
+ {
+ using (TcpClient client = new TcpClient())
+ {
+ client.Connect(host, port);
+ NetworkStream stream = client.GetStream();
+ stream.ReadTimeout = 2500;
+ ConsoleExt.WriteLine($"[{host}:{port}] {LanguageStrings.ConnectedToServer(Settings.Default.CurrentLanguage, host, port)}", ConsoleColor.Green);
+
+ // FOR DEBUGGING --- REMOVE --- FOR DEBUGGING --- REMOVE
+ //while (true) Check.LastHeartbeat = DateTime.Now;
+ // FOR DEBUGGING --- REMOVE --- FOR DEBUGGING --- REMOVE
+
+ string dataReceived = string.Empty;
+
+ List data = new List();
+
+ while (true)
+ {
+ if (ShutdownCapture)
+ {
+ ConsoleExt.WriteLine($"{LanguageStrings.ThreadShutdown(Settings.Default.CurrentLanguage, $"Stream Processing ({host}:{port})")}");
+ }
+ while (!stream.DataAvailable)
+ {
+ try
+ {
+ stream.WriteByte(0);
+ }
+ catch (IOException e)
+ {
+ ConsoleExt.WriteLine($"[{host}:{port}] {e.Message}", ConsoleColor.Red);
+ return;
+ }
+ Thread.Sleep(1000);
+ }
+ data.Clear();
+ DateTime now = DateTime.Now;
+ ConsoleExt.WriteLine($"[{host}:{port}] {LanguageStrings.ProcessingStream(Settings.Default.CurrentLanguage)}");
+
+ while (stream.DataAvailable)
+ {
+ int bit = stream.ReadByte();
+ if (bit != -1)
+ {
+ data.Add((byte)bit);
+ // The Math.Pow is here to intentionally slow down the TCP stream download,
+ // because it's simply too fast, and we can sometimes continue early without it.
+ // Although we may not need it.
+ //Math.Pow(bit, bit);
+ }
+ }
+
+ string chunk = Encoding.UTF8.GetString(data.ToArray(), 0, data.Count);
+
+ dataReceived += chunk;
+
+ if (chunk.Contains(delimiter))
+ {
+ ConsoleExt.WriteLine($"[{host}:{port}] {LanguageStrings.ProcessedStream(Settings.Default.CurrentLanguage, data.Count, now)}");
+ string capturedSent = Regex.Match(dataReceived, @"\s*(.*?)\s*", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline).Groups[1].Value.Replace("-", "_").Replace("+", "p").Replace(":", "_");
+ string capturedIdent = Regex.Match(dataReceived, @"\s*(.*?)\s*", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline).Groups[1].Value.Replace("-", "_").Replace("+", "p").Replace(":", "_");
+ string filename = $"{capturedSent}I{capturedIdent}.xml";
+
+ if (SharpDataQueue.Any(x => x.Name == filename) || SharpDataHistory.Any(x => x.Name == filename))
+ {
+ ConsoleExt.WriteLine($"[{host}:{port}] {LanguageStrings.DataPreviouslyProcessed(Settings.Default.CurrentLanguage)}", ConsoleColor.DarkGray);
+ }
+ else
+ {
+ SharpDataQueue.Add(new SharpDataItem(filename, dataReceived));
+ ConsoleExt.WriteLine($"[{host}:{port}] {LanguageStrings.FileDownloaded(Settings.Default.CurrentLanguage, host)}");
+ }
+ dataReceived = string.Empty;
+ }
+ else
+ {
+ if (data.Count > 10000000)
+ {
+ throw new Exception($"[{host}:{port}] The data exceeds the 10 MB limit. The server may be malfunctioning.");
+ }
+ else ConsoleExt.WriteLine($"[{host}:{port}] {data.Count} bytes total including the current chunk.");
+ }
+ }
+ }
+ }
+ catch (SocketException e)
+ {
+ ConsoleExt.WriteLine($"[{host}:{port}] {e.Message}");
+ Thread.Sleep(1000);
+ return;
+ }
+ catch (TimeoutException)
+ {
+ ConsoleExt.WriteLine($"[{host}:{port}] {LanguageStrings.HostTimedOut(Settings.Default.CurrentLanguage, host)}");
+ return;
+ }
+ catch (ThreadAbortException)
+ {
+ ShutdownCapture = true;
+ //ConsoleExt.WriteLine($"{LanguageStrings.ThreadShutdown(Settings.Default.CurrentLanguage, $"Stream Processing ({host}:{port})")}");
+ return;
+ }
+ }
+
+ public bool Main()
+ {
+ SharpDataQueue = new List();
+ SharpDataHistory = new List();
+
+ void StartServerConnection()
+ {
+ foreach (string server in Settings.Default.CanadianServers)
+ {
+ Thread thread = new Thread(() => Receive(server, 8080, ""));
+ thread.Start();
+ ClientThreads.Add(thread);
+ ConsoleExt.WriteLine($"{LanguageStrings.StartingConnection(Settings.Default.CurrentLanguage, server, 8080)}", ConsoleColor.DarkGray);
+ Thread.Sleep(250);
+ }
+ }
+
+ StartServerConnection();
+
+ try
+ {
+ while (true)
+ {
+ for (int i = 0; i < ClientThreads.Count; i++)
+ {
+ if (!ClientThreads[i].IsAlive)
+ {
+ if (!ShutdownCapture)
+ {
+ ConsoleExt.WriteLine($"{LanguageStrings.RestartingAfterException(Settings.Default.CurrentLanguage)}");
+ string server = Settings.Default.CanadianServers[i];
+ Thread newThread = new Thread(() => Receive(server, 8080, ""));
+ newThread.Start();
+ ClientThreads[i] = newThread;
+ }
+ }
+ }
+
+ if (ShutdownCapture)
+ {
+ lock (ClientThreads)
+ foreach (var thread in ClientThreads)
+ {
+ try
+ {
+ if (thread.IsAlive) thread.Join();
+ }
+ catch (Exception)
+ {
+
+ }
+ }
+ ShutdownCapture = false;
+ return true;
+ }
+
+ Thread.Sleep(1000);
+ }
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+ }
+ }
+ }
+}
diff --git a/SharpENDEC/InternalExtensions/ConsoleExt.cs b/SharpENDEC/InternalExtensions/ConsoleExt.cs
new file mode 100644
index 0000000..8708c42
--- /dev/null
+++ b/SharpENDEC/InternalExtensions/ConsoleExt.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace SharpENDEC
+{
+ public static class ConsoleExt
+ {
+ public static ConsoleColor og = ConsoleColor.White;
+
+ public static void WriteLine(string value = "", ConsoleColor foreground = ConsoleColor.White)
+ {
+ og = Console.ForegroundColor;
+ Console.ForegroundColor = foreground;
+ Console.WriteLine(value);
+ Console.ForegroundColor = og;
+ }
+
+ public static void Write(string value = "", ConsoleColor foreground = ConsoleColor.White)
+ {
+ og = Console.ForegroundColor;
+ Console.ForegroundColor = foreground;
+ Console.Write(value);
+ Console.ForegroundColor = og;
+ }
+ }
+}
diff --git a/SharpENDEC/InternalExtensions/MainExt.cs b/SharpENDEC/InternalExtensions/MainExt.cs
new file mode 100644
index 0000000..4c54de1
--- /dev/null
+++ b/SharpENDEC/InternalExtensions/MainExt.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+using ThreadState = System.Threading.ThreadState;
+
+namespace SharpENDEC
+{
+ public static class MainExt
+ {
+ private static Exception ex = new Exception();
+
+ ///
+ /// This method is for dummy purposes, and does not perform any tasks.
+ ///
+ public static void UnknownCaller()
+ {
+ }
+
+ ///
+ /// This method is for dummy purposes, and does not perform any tasks.
+ ///
+ public static Exception UnknownException()
+ {
+ return new Exception("DummyException");
+ }
+
+ ///
+ /// Immediately shuts down all threads, writes the exception to the console and disk, then waits infinitely.
+ ///
+ /// The method that called the exception.
+ /// The exception that caused the unsafe state.
+ /// The reason why the unsafe state was invoked.
+ /// Whether or not to restart and ignore the infinite rule.
+ public static void UnsafeStateShutdown(Action caller, Exception exception, string reason, bool restart = true)
+ {
+ lock (ex)
+ {
+ if (caller.IsNull()) caller = UnknownCaller;
+ if (exception.IsNull()) exception = UnknownException();
+ if (string.IsNullOrEmpty(reason)) reason = "No reason provided.";
+
+ ex = exception;
+
+ lock (ENDEC.ClientThreads)
+ {
+ foreach (Thread thread in ENDEC.ClientThreads)
+ try { if (!thread.IsNull()) thread.Abort(ex); } catch (Exception) { }
+ ENDEC.ClientThreads.Clear();
+ }
+
+ lock (Program.MainThreads)
+ {
+ foreach (var (thread, method) in Program.MainThreads)
+ try { if (!thread.IsNull()) thread.Abort(ex); } catch (Exception) { }
+ Program.MainThreads.Clear();
+ }
+
+ ENDEC.Capture = null;
+
+ Console.Clear();
+ Console.ForegroundColor = ConsoleColor.DarkRed;
+ string full = ($"{DateTime.Now:G} | Called by {caller.Method.Name}\r\n" +
+ $"Stack Trace: {ex.StackTrace}\r\n" +
+ $"Source: {ex.Source}\r\n" +
+ $"Message: {ex.Message}\r\n" +
+ $"{reason}");
+ Console.WriteLine(full);
+ Thread.Sleep(1000);
+ Debug.Assert(false, "The program went into an unsafe state.", full);
+ Console.Clear();
+ if (restart)
+ {
+ Console.Clear();
+ new Thread(() => Program.Main()).Start();
+ }
+ else Thread.Sleep(Timeout.Infinite);
+
+ }
+ }
+
+ public static bool IsNull(this object obj)
+ {
+ if (obj == null) return true;
+ return false;
+ }
+ }
+}
diff --git a/SharpENDEC/LanguageStrings.cs b/SharpENDEC/LanguageStrings.cs
new file mode 100644
index 0000000..9454b45
--- /dev/null
+++ b/SharpENDEC/LanguageStrings.cs
@@ -0,0 +1,425 @@
+using System;
+
+namespace SharpENDEC
+{
+ public static class LanguageStrings
+ {
+ public static string RecoveredFromFailure(string lang)
+ {
+ switch (lang)
+ {
+ case "french":
+ return "Le chien de garde a récemment détecté un problème et a effacé toutes les données XML stockées.\r\n" +
+ "Les alertes précédemment relayées peuvent être relayées à nouveau lorsque le prochain battement de coeur arrive.";
+ case "inuktitut":
+ return "ᓇᐅᑦᑎᖅᓱᖅᑎ ᖃᐅᔨᓵᓚᐅᖅᑐᖅ ᐊᑲᐅᙱᓕᐅᕈᑎᒥᒃ, ᐲᔭᐃᓯᒪᓪᓗᓂᓗ ᑕᒪᐃᓐᓂᒃ XML ᑲᑎᖅᓱᖅᓯᒪᔪᓂ ᑐᖅᑯᖅᑕᐅᓯᒪᓪᓗᑎᒃ.\r\n" +
+ "ᑭᖑᓂᑦᑎᓐᓂ ᐅᖃᐅᓯᐅᖃᑦᑕᖅᓯᒪᔪᑦ ᖃᐅᔨᑎᑦᑎᔾᔪᑏᑦ ᐅᖃᐅᓯᐅᒃᑲᓐᓂᓕᕈᓐᓇᖅᐳᑦ ᑭᖑᓪᓕᕐᒥ ᐆᒻᒪᓯᕆᔪᖃᒃᑲᓐᓂᓕᖅᐸᑦ.";
+ case "english":
+ default:
+ return "The watchdog has recently detected a problem, and has cleared all XML data stored.\r\n" +
+ "Alerts previously relayed may relay again when the next heartbeat arrives.";
+ }
+ }
+
+ public static string WatchdogForcedRestartWarning(string lang)
+ {
+ switch (lang)
+ {
+ case "french":
+ return "Cela fait plus de 5 minutes depuis le dernier battement de coeur. Si aucun battement de coeur n'est détecté dans les 5 minutes supplémentaires, le programme redémarrera automatiquement.";
+ case "inuktitut":
+ return "5 ᒥᓂᑦ ᐅᖓᑖᓃᓕᖅᑐᖅ ᐆᒻᒪᑎᖓ ᑭᖑᓪᓕᖅᐸᐅᓚᐅᖅᑎᓪᓗᒍ. ᐆᒻᒪᓯᕆᔪᖅ ᖃᐅᔨᔭᐅᙱᑉᐸᑦ 5 ᒥᓂᑦᒥᑦ, ᐱᓕᕆᐊᖅ ᐱᒋᐊᑲᐅᑎᒋᓂᐊᖅᑐᖅ.";
+ case "english":
+ default:
+ return "It has been more than 5 minutes since the last heartbeat. If a heartbeat is not detected within 5 additional minutes, the program will automatically restart.";
+ }
+ }
+
+ public static string WatchdogForceRestartingProcess(string lang)
+ {
+ switch (lang)
+ {
+ case "french":
+ return "Le battement de coeur a été présumé mort. Redémarrage de tous les services dans quelques instants.";
+ case "english":
+ default:
+ return "The heartbeat has been presumed dead. Restarting all services in a few moments.";
+ }
+ }
+
+ //public static string WatchingFiles(string lang)
+ //{
+ // switch (lang)
+ // {
+ // case "french":
+ // return "Surveillance du répertoire pour les alertes.";
+ // case "english":
+ // default:
+ // return "Watching directory for alerts.";
+ // }
+ //}
+
+ public static string HeartbeatDetected(string lang)
+ {
+ switch (lang)
+ {
+ case "french":
+ return "Battement de coeur détecté.";
+ case "inuktitut":
+ return "ᐆᒻᒪᑎᒥᒃ ᖃᐅᔨᔭᐅᔪᖅ.";
+ case "english":
+ default:
+ return "Heartbeat detected.";
+ }
+ }
+
+ public static string AlertQueued(string lang)
+ {
+ switch (lang)
+ {
+ case "french":
+ return "Alerte ajoutée à la file d’attente.";
+ case "inuktitut":
+ return "ᐊᓘᑦ ᐃᓚᔭᐅᔪᖅ.";
+ case "english":
+ default:
+ return "Alert added to the queue.";
+ }
+ }
+
+ public static string ConnectedToServer(string lang, string host, int port)
+ {
+ switch (lang)
+ {
+ case "french":
+ return $"Connecté à {host} sur le port {port}.";
+ case "inuktitut":
+ return $"ᐊᑕᔪᖅ {host} ᑐᓚᒃᑕᕐᕕᖕᒥ {port}.";
+ case "english":
+ default:
+ return $"Connected to {host} on port {port}.";
+ }
+ }
+
+ public static string HostTimedOut(string lang, string host)
+ {
+ switch (lang)
+ {
+ case "french":
+ return $"{host} n'a envoyé aucune donnée dans le délai minimum.";
+ case "english":
+ default:
+ return $"{host} hasn't sent any data within the minimum time limit.";
+ }
+ }
+
+ public static string RestartingAfterException(string lang)
+ {
+ switch (lang)
+ {
+ case "french":
+ return "Le fil de capture est mort de façon inattendue. Il redémarrera automatiquement dans quelques instants.";
+ case "english":
+ default:
+ return "The capture thread has died unexpectedly. It will automatically restart in a few moments.";
+ }
+ }
+
+ public static string FileDownloaded(string lang, string host)
+ {
+ switch (lang)
+ {
+ case "french":
+ return $"Données enregistrées. | De : {host}";
+ case "inuktitut":
+ return $"ᑎᑎᕋᖅᓯᒪᔪᑦ ᖃᐅᔨᓴᖅᑕᐅᓂᑯᐃᑦ ᑐᖅᑯᖅᑕᐅᓯᒪᔪᑦ. | ᐅᕙᙵᑦ: {host}";
+ case "english":
+ default:
+ return $"Data saved. | From: {host}";
+ }
+ }
+
+ public static string DownloadingFiles(string lang)
+ {
+ switch (lang)
+ {
+ case "french":
+ return "Téléchargement de fichiers à partir du signal cardiaque reçu.";
+ case "inuktitut":
+ return "ᖃᕆᑕᐅᔭᒃᑯᑦ ᐱᓗᒋᑦ ᑎᑎᖅᑲᑦ ᐱᔭᐅᔪᓂᒃ ᐆᒻᒪᑎᐅᑉ ᕐᑳᖓᓂ.";
+ case "english":
+ default:
+ return "Downloading files from received heartbeat.";
+ }
+ }
+
+ public static string FileIgnoredDueToMatchingPair(string lang)
+ {
+ switch (lang)
+ {
+ case "french":
+ return "Paire correspondante détectée. Les données ne seront pas traitées.";
+ case "inuktitut":
+ return "ᐊᔾᔨᒌᓂᒃ ᐃᓚᒌᖕᓂᒃ ᖃᐅᔨᔪᖃᓚᐅᖅᑐᖅ. ᑎᑎᕋᖅᓯᒪᔪᑦ ᖃᐅᔨᓴᖅᑕᐅᓂᑯᐃᑦ ᐱᓕᕆᐊᖑᔾᔮᖏᑦᑐᑦ.";
+ case "english":
+ default:
+ return "Matching pair detected. The data won't be processed.";
+ }
+ }
+
+ public static string DataIgnoredDueToMatchingPairs(string lang, int count)
+ {
+ switch (lang)
+ {
+ case "french":
+ return $"{count} chaîne(s) avaient des paires correspondantes et n'ont pas été traités.";
+ case "inuktitut":
+ return $"{count} ᐊᒃᖢᓇᐅᔭᑦ ᐊᔾᔨᒌᓂᒃ ᐱᖃᑎᒌᓚᐅᖅᐳᑦ, ᐱᓕᕆᐊᖑᓚᐅᙱᖦᖢᑎᒡᓗ.";
+ case "english":
+ default:
+ return $"{count} string(s) had matching pairs, and were not processed.";
+ }
+ }
+
+ public static string AlertIgnoredDueToPreferences(string lang)
+ {
+ switch (lang)
+ {
+ case "french":
+ return "Cette alerte ne sera pas traitée en raison des préférences de l'utilisateur.";
+ case "inuktitut":
+ return "ᑖᓐᓇ ᖃᐅᔨᓴᕈᑎ ᐱᓕᕆᐊᖑᔾᔮᙱᑦᑐᖅ ᐊᑐᖅᑎᑦ ᓂᕈᐊᕆᔭᖏᑦ ᐱᔾᔪᑎᒋᓪᓗᒋᑦ.";
+ case "english":
+ default:
+ return "This alert won't be processed due to the user preferences.";
+ }
+ }
+
+ public static string GeneratingProductText(string lang)
+ {
+ switch (lang)
+ {
+ case "french":
+ return "Génération de texte en cours.";
+ case "inuktitut":
+ return "ᐊᐅᓚᔪᑦ ᑎᑎᖅᑲᐃᑦ.";
+ case "english":
+ default:
+ return "Generating text.";
+ }
+ }
+
+ public static string GeneratingProductAudio(string lang)
+ {
+ switch (lang)
+ {
+ case "french":
+ return "Génération audio en cours.";
+ case "inuktitut":
+ return "ᓂᐱᖃᐅᑎᓕᐅᕐᓗᓂ.";
+ case "english":
+ default:
+ return "Generating audio.";
+ }
+ }
+
+ public static string GeneratedProductEmpty(string lang)
+ {
+ switch (lang)
+ {
+ case "french":
+ return "Il n’y avait rien à générer.";
+ case "inuktitut":
+ return "ᐱᑕᖃᓚᐅᖏᑦᑐᖅ ᐊᐅᓚᔾᔭᒋᐊᕐᓂᕐᒧᑦ.";
+ case "english":
+ default:
+ return "There was nothing to generate.";
+ }
+ }
+
+ public static string PlayingAudio(string lang)
+ {
+ switch (lang)
+ {
+ case "french":
+ return "La lecture audio a commencé.";
+ case "inuktitut":
+ return "ᓂᐱᖃᐅᑎᒃᑯᑦ ᐱᙳᐊᕐᓂᖅ ᐱᒋᐊᓚᐅᖅᑐᖅ.";
+ case "english":
+ default:
+ return "Audio playback started.";
+ }
+ }
+
+ public static string CapturedFromFileWatcher(string lang)
+ {
+ switch (lang)
+ {
+ case "french":
+ return "De nouvelles données ont été saisies.";
+ case "inuktitut":
+ return "ᓄᑖᑦ ᓈᓴᐅᑏᑦ/ᑎᑎᖅᑲᐃᑦ ᐱᔭᐅᓚᐅᖅᑐᑦ.";
+ case "english":
+ default:
+ return "New data was captured.";
+ }
+ }
+
+ public static string ProcessingStream(string lang)
+ {
+ switch (lang)
+ {
+ case "french":
+ return "Flux de données de traitement.";
+ case "inuktitut":
+ return "ᐱᓕᕆᐊᖃᕐᓂᖅ ᓈᓴᐅᑎᓂᒃ/ᑎᑎᖅᑲᓂᒃ.";
+ case "english":
+ default:
+ return "Processing data stream.";
+ }
+ }
+
+ public static string ProcessedStream(string lang, int total, DateTime started)
+ {
+ switch (lang)
+ {
+ case "french":
+ return $"Traité {total} dans {(DateTime.Now - started).TotalSeconds}s.";
+ case "inuktitut":
+ return $"ᐱᓕᕆᐊᖑᓪᓗᓂ {total} {(DateTime.Now - started).TotalSeconds}s.";
+ case "english":
+ default:
+ return $"Processed {total} in {(DateTime.Now - started).TotalSeconds}s.";
+ }
+ }
+
+ public static string LastDataReceived(string lang)
+ {
+ switch (lang)
+ {
+ case "french":
+ return "Dernières données reçues :";
+ case "inuktitut":
+ return "ᑭᖑᓪᓕᖅᐹᒥ ᑎᑎᕋᖅᓯᒪᔪᑦ ᐱᔭᐅᓚᐅᖅᑐᑦ:";
+ case "english":
+ default:
+ return "Last data received:";
+ }
+ }
+
+ public static string ThreadShutdown(string lang, string name)
+ {
+ switch (lang)
+ {
+ case "french":
+ return $"{name} a été arrêté.";
+ case "inuktitut":
+ return "ᑭᖑᓪᓕᖅᐹᒥ ᑎᑎᕋᖅᓯᒪᔪᑦ ᐱᔭᐅᓚᐅᖅᑐᑦ:";
+ case "english":
+ default:
+ return $"{name} was stopped.";
+ }
+ }
+
+ public static string StartingConnection(string lang, string server, int port)
+ {
+ switch (lang)
+ {
+ case "french":
+ return $"Démarrage de la connexion à {server}:{port}.";
+ case "inuktitut":
+ return $"ᐱᒋᐊᕐᓗᓂ ᑲᓱᖅᓯᒪᓂᕐᒥᑦ {server}:{port}.";
+ case "english":
+ default:
+ return $"Starting connection to {server}:{port}.";
+ }
+ }
+
+ public static string ElevationSecurityProblem(string lang)
+ {
+ switch (lang)
+ {
+ case "french":
+ return $"L’exécution de SharpENDEC elevated n’améliore pas les performances et peut poser un risque de sécurité dans certaines situations.\r\n" +
+ $"Veuillez exécuter SharpENDEC sans élévation la prochaine fois que vous l’exécuterez !";
+ case "english":
+ default:
+ return $"Running SharpENDEC elevated doesn't improve performance, and may pose a security risk in some situations.\r\n" +
+ $"Please run SharpENDEC without elevation next time you run it!";
+ }
+ }
+
+ public static string ConfigurationLossProblem(string lang)
+ {
+ switch (lang)
+ {
+ case "french":
+ return $"Vous perdrez probablement votre configuration parce que vous utilisez un compte invité." +
+ $"S’il vous plaît exécuter SharpENDEC sous un utilisateur normal pour garder votre configuration !";
+ case "inuktitut":
+ return "";
+ case "english":
+ default:
+ return $"ᐋᖅᑭᒃᓯᒪᓂᕆᔭᐃᑦ ᐊᓯᐅᔨᑐᐃᓐᓇᕆᐊᖃᖅᑕᑦ ᓲᖃᐃᒻᒪ ᐊᑐᕋᕕᑦ ᖃᐃᖁᔭᐅᓯᒪᔪᒥᒃ ᓇᓕᖅᑲᒥᒃ.\r\n" +
+ $"SharpENDEC-ᑯᑦ ᐃᖏᕐᕋᑎᖃᑦᑕᕐᓂᐊᖅᐸᑎᑦ ᐊᑐᒐᔪᒃᑕᒃᑯᑦ ᐋᖅᑭᒃᓯᒪᓂᕆᔭᐃᑦᑏᓐᓇᕋᓱᒡᓗᒍ!";
+ }
+ }
+
+ public static string DataPreviouslyProcessed(string lang)
+ {
+ switch (lang)
+ {
+ case "french":
+ return "Les données ont été ignorées car elles se trouvaient déjà dans la file d’attente ou dans l’historique.";
+ case "inuktitut":
+ return "ᑖᒃᑯᐊ ᑎᑎᕋᖅᓯᒪᔪᑦ ᐲᖅᑕᐅᑐᐃᓐᓇᓚᐅᖅᑐᑦ ᐱᔾᔪᑎᒋᓪᓗᒍ ᐱᑕᖃᕇᕐᒪᑦ ᐅᕝᕙᓘᓐᓃᑦ ᐅᐊᑦᑎᐊᕈᓐᓂᓴᕐᓂᒃ.";
+ case "english":
+ default:
+ return "The data was skipped because it's already in either the queue or history.";
+ }
+ }
+
+ public static string GenericProcessingValueOfValue(string lang, int x, int y)
+ {
+ switch (lang)
+ {
+ case "french":
+ return $"Traitement {x} de {y}.";
+ case "inuktitut":
+ return $"ᐱᓕᕆᐊᖃᕐᓂᖅ {x} ᑲᑎᖦᖢᒋᑦ {y}.";
+ case "english":
+ default:
+ return $"Processing {x} of {y}.";
+ }
+ }
+
+ public static string DownloadFailure(string lang)
+ {
+ // Failed to download the file.
+ switch (lang)
+ {
+ case "french":
+ return $"Impossible de télécharger le fichier.";
+ case "inuktitut":
+ return $"ᒥᓇᕆᙱᑕᖓ ᑎᑎᖅᑲᖓ.";
+ case "english":
+ default:
+ return $"Failed to download the file.";
+ }
+ }
+
+ public static string AlertIgnoredDueToBlacklist(string lang)
+ {
+ switch (lang)
+ {
+ case "french":
+ return "Cette alerte ne sera pas traitée en raison de la liste noire.";
+ case "inuktitut":
+ return "ᑖᓐᓇ ᖃᐅᔨᓴᕈᑎ ᐱᓕᕆᐊᖑᔾᔮᙱᑦᑐᖅ ᕿᕐᓂᖅᑕᒧᑦ.";
+ case "english":
+ default:
+ return "This alert won't be processed due to the blacklist.";
+ }
+ }
+ }
+}
diff --git a/SharpENDEC/Program.cs b/SharpENDEC/Program.cs
index a7e94b1..34a427f 100644
--- a/SharpENDEC/Program.cs
+++ b/SharpENDEC/Program.cs
@@ -1,745 +1,20 @@
-using NAudio.Utils;
-using NAudio.Wave;
-using NAudio.Wave.SampleProviders;
+using NAudio.Wave;
using SharpENDEC.Properties;
using System;
using System.Collections.Generic;
-using System.Drawing;
-using System.Globalization;
using System.IO;
-using System.Linq;
-using System.Net.Http;
-using System.Net.Sockets;
using System.Reflection;
+using System.Security.Principal;
using System.Speech.Synthesis;
-using System.Text;
-using System.Text.RegularExpressions;
using System.Threading;
-using System.Threading.Tasks;
-using System.Windows.Forms;
+using static SharpENDEC.VersionInfo;
namespace SharpENDEC
{
- public static class ENDEC
+ public static partial class ENDEC
{
public static readonly string AssemblyDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
public static readonly string AudioDirectory = $"{AssemblyDirectory}\\Audio";
- public static readonly string FileQueueDirectory = $"{AssemblyDirectory}\\FileQueue";
- public static readonly string FileHistoryDirectory = $"{AssemblyDirectory}\\FileHistory";
-
- public class Battery
- {
- public void Monitor()
- {
- // TODO: Add setting to enable and disable battery monitoring
- while (true)
- {
- try
- {
- PowerStatus powerStatus = SystemInformation.PowerStatus;
- BatteryChargeStatus chargeStatus = powerStatus.BatteryChargeStatus;
-
- if (!(powerStatus.BatteryLifePercent > 0.20))
- {
- Console.WriteLine($"[Battery] The battery percentage is currently at {powerStatus.BatteryLifePercent}.");
- }
- Console.WriteLine($"Battery Status: {chargeStatus}");
-
- if ((chargeStatus & BatteryChargeStatus.Charging) == BatteryChargeStatus.Charging)
- {
- Console.WriteLine("The system is currently charging.");
- }
- else if (chargeStatus == BatteryChargeStatus.NoSystemBattery)
- {
- Console.WriteLine("No battery is installed.");
- }
- else
- {
- Console.WriteLine("The system is not charging.");
- }
- }
- catch (Exception)
- {
-
- }
- Thread.Sleep(30000);
- }
- }
- }
-
- public class Capture
- {
- public bool ShutdownCapture = false;
-
- private void Receive(string host, int port, string delimiter)
- {
- try
- {
- using (TcpClient client = new TcpClient())
- {
- client.Connect(host, port);
- NetworkStream stream = client.GetStream();
- stream.ReadTimeout = 2500;
- Console.WriteLine($"[{host}:{port}] {SVDictionary.ConnectedToServer(Settings.Default.CurrentLanguage, host, port)}");
-
- // FOR DEBUGGING --- REMOVE --- FOR DEBUGGING --- REMOVE
- //while (true) Check.LastHeartbeat = DateTime.Now;
- // FOR DEBUGGING --- REMOVE --- FOR DEBUGGING --- REMOVE
-
- string dataReceived = string.Empty;
-
- List data = new List();
-
- while (true)
- {
- while (!stream.DataAvailable)
- {
- try
- {
- stream.WriteByte(0);
- }
- catch (IOException)
- {
- return;
- }
- Thread.Sleep(500);
- }
- data.Clear();
- DateTime now = DateTime.Now;
- Console.WriteLine($"[{host}:{port}] {SVDictionary.ProcessingStream(Settings.Default.CurrentLanguage)}");
-
- while (stream.DataAvailable)
- {
- int bit = stream.ReadByte();
- if (bit != -1)
- {
- data.Add((byte)bit);
- Math.Pow(bit, bit);
- }
- }
-
- Console.WriteLine($"[{host}:{port}] {SVDictionary.ProcessedStream(Settings.Default.CurrentLanguage, data.Count, now)}");
- string chunk = Encoding.UTF8.GetString(data.ToArray(), 0, data.Count);
-
- dataReceived += chunk;
-
- // dataReceived.StartsWith("")
-
- if (chunk.Contains(delimiter))
- {
- string capturedSent = Regex.Match(dataReceived, @"\s*(.*?)\s*", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline).Groups[1].Value.Replace("-", "_").Replace("+", "p").Replace(":", "_");
- string capturedIdent = Regex.Match(dataReceived, @"\s*(.*?)\s*", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline).Groups[1].Value.Replace("-", "_").Replace("+", "p").Replace(":", "_");
- string naadsFilename = $"{capturedSent}I{capturedIdent}.xml";
- Directory.CreateDirectory(FileQueueDirectory);
- if (!File.Exists($"{FileQueueDirectory}\\{naadsFilename}") && !File.Exists($"{FileHistoryDirectory}\\{naadsFilename}"))
- {
- File.WriteAllText($"{FileQueueDirectory}\\{naadsFilename}", dataReceived, Encoding.UTF8);
- Console.WriteLine($"[{host}:{port}] {SVDictionary.FileDownloaded(Settings.Default.CurrentLanguage, FileQueueDirectory, naadsFilename, host)}");
- }
- else
- {
- Console.WriteLine($"[{host}:{port}] The file has already been downloaded and/or processed.");
- }
- dataReceived = string.Empty;
- }
- }
- }
- }
- catch (TimeoutException)
- {
- Console.WriteLine($"[Capture] {SVDictionary.HostTimedOut(Settings.Default.CurrentLanguage, host)}");
- return;
- }
- }
-
- public bool Main()
- {
- List ClientThreads = new List();
-
- foreach (string server in Settings.Default.CanadianServers)
- {
- Thread thread = new Thread(() => Receive(server, 8080, ""));
- thread.Start();
- ClientThreads.Add(thread);
- }
-
- try
- {
- while (true)
- {
- for (int i = 0; i < ClientThreads.Count; i++)
- {
- if (!ClientThreads[i].IsAlive)
- {
- Console.WriteLine($"{SVDictionary.RestartingAfterException(Settings.Default.CurrentLanguage)}");
- string server = Settings.Default.CanadianServers[i];
- Thread newThread = new Thread(() => Receive(server, 8080, ""));
- newThread.Start();
- ClientThreads[i] = newThread;
- }
- }
-
- if (ShutdownCapture)
- {
- foreach (var thread in ClientThreads)
- {
- try
- {
- thread.Abort();
- }
- catch (Exception)
- {
-
- }
- }
- ShutdownCapture = false;
- return true;
- }
-
- Thread.Sleep(1000);
- }
- }
- catch (Exception)
- {
- return false;
- }
- }
- }
-
- public static class Check
- {
- public static bool Config(string InfoX, string Status, string MsgType,
- string Severity, string Urgency, string BroadcastImmediately)
- {
- bool Final = false;
-
- // Status:
- // Test
- // Actual
-
- switch (Status.ToLower())
- {
- case "test":
- if (!Settings.Default.statusTest) return false;
- break;
- case "actual":
- if (!Settings.Default.statusActual) return false;
- break;
- default:
- break;
- }
-
- // MsgType:
- // Alert
- // Update
- // Cancel
-
- if (BroadcastImmediately.ToLower().Contains("yes"))
- {
- Final = true;
- }
- else
- {
- try
- {
- bool var1; // Severity
- bool var2; // Urgency
- bool var3; // MsgType
-
- switch (Severity.ToLower())
- {
- case "extreme":
- var1 = Settings.Default.severityExtreme;
- break;
- case "severe":
- var1 = Settings.Default.severitySevere;
- break;
- case "moderate":
- var1 = Settings.Default.severityModerate;
- break;
- case "minor":
- var1 = Settings.Default.severityMinor;
- break;
- case "unknown":
- var1 = Settings.Default.severityUnknown;
- break;
- default:
- var1 = Settings.Default.severityUnknown;
- break;
- }
-
- switch (Urgency.ToLower())
- {
- case "immediate":
- var2 = Settings.Default.urgencyImmediate;
- break;
- case "expected":
- var2 = Settings.Default.urgencyExpected;
- break;
- case "future":
- var2 = Settings.Default.urgencyFuture;
- break;
- case "past":
- var2 = Settings.Default.urgencyPast;
- break;
- default:
- var2 = false;
- break;
- }
-
- switch (MsgType.ToLower())
- {
- case "alert":
- var3 = Settings.Default.messageTypeAlert;
- break;
- case "update":
- var3 = Settings.Default.messageTypeUpdate;
- break;
- case "cancel":
- var3 = Settings.Default.messageTypeCancel;
- break;
- case "test":
- var3 = Settings.Default.messageTypeTest;
- break;
- default:
- var3 = false;
- break;
-
- }
-
- if (var1 && var2 && var3)
- {
- Final = true;
- }
- }
- catch
- {
- Final = false;
- }
- }
-
- if (Final)
- {
- if (Settings.Default.AllowedLocations_Geocodes.Count == 0)
- {
-
- }
- else
- {
- try
- {
- MatchCollection matches = Regex.Matches(InfoX,
- @"\s*profile:CAP-CP:Location:0.3\s*\s*(.*?)\s*",
- RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
- bool GeoMatch = false;
- foreach (Match match in matches)
- {
- string geocode = match.Groups[1].Value;
- if (Settings.Default.AllowedLocations_Geocodes.Contains(geocode))
- {
- GeoMatch = true;
- break;
- }
- }
- if (!GeoMatch)
- {
- return false;
- }
- }
- catch (Exception ex)
- {
- ColorLine($"[Relayer] {ex.Message}", ConsoleColor.Red);
- return false;
- }
- }
- }
- return Final;
- }
-
- public static DateTime LastHeartbeat = DateTime.Now;
-
- private static readonly HttpClient client = new HttpClient
- {
- Timeout = TimeSpan.FromSeconds(3)
- };
-
- public static void Heartbeat(string References)
- {
- ColorLine($"[Heartbeat] {SVDictionary.DownloadingFiles(Settings.Default.CurrentLanguage)}", ConsoleColor.DarkYellow);
- string[] RefList = References.Split(' ');
- int FilesMatched = 0;
- foreach (string i in RefList)
- {
- string filename = string.Empty;
- string[] k = i.Split(',');
- string sentDTFull = k[2].Replace("-", "_").Replace(":", "_").Replace("+", "p");
- string sentDT = sentDTFull.Substring(0, 10).Replace("_", "-");
- filename += sentDTFull;
- filename += "I" + k[1].Replace("-", "_").Replace(":", "_");
- //string filenameShort = sentDTFull.Replace("_", "-");
-
- string Dom1 = "capcp1.naad-adna.pelmorex.com";
- string Dom2 = "capcp2.naad-adna.pelmorex.com";
-
- string outputfile = FileQueueDirectory + $"\\{filename}.xml";
-
- if (File.Exists(FileHistoryDirectory + $"\\{filename}.xml"))
- {
- FilesMatched++;
- continue;
- }
-
- ColorLine($"[Heartbeat] Downloading: {filename}.xml...", ConsoleColor.Yellow);
- string url1 = $"http://{Dom1}/{sentDT}/{filename}.xml";
- string url2 = $"http://{Dom2}/{sentDT}/{filename}.xml";
-
- try
- {
- ColorLine($"-> {url1}", ConsoleColor.Yellow);
- Task xml = client.GetStringAsync(url1);
- xml.Wait();
- File.WriteAllText(outputfile, xml.Result);
-
- xml.Dispose();
- }
- catch (Exception e1)
- {
- try
- {
- ColorLine($"[Heartbeat] Stage 1 failed: {e1.Message}", ConsoleColor.Red);
- ColorLine($"[Heartbeat] Downloading: {filename}.xml from backup...", ConsoleColor.Yellow);
- ColorLine($"-> {url2}", ConsoleColor.Yellow);
- Task xml = client.GetStringAsync(url2);
- xml.Wait();
- File.WriteAllText(outputfile, xml.Result);
- xml.Dispose();
- }
- catch (Exception e2)
- {
- ColorLine($"[Heartbeat] Stage 2 failed: {e2.Message}", ConsoleColor.Red);
- ColorLine($"[Heartbeat] Failed to process the file.", ConsoleColor.Red);
- }
- }
- }
- ColorLine($"[Heartbeat] {SVDictionary.FilesIgnoredDueToMatchingPairs(Settings.Default.CurrentLanguage, FilesMatched)}", ConsoleColor.Blue);
- LastHeartbeat = DateTime.Now;
- }
-
- public static string WatchNotify()
- {
- Console.WriteLine($"[Relayer] {SVDictionary.WatchingFiles(Settings.Default.CurrentLanguage)}");
-
- while (true)
- {
- if (!Directory.Exists(FileQueueDirectory)) Directory.CreateDirectory(FileQueueDirectory);
- if (!Directory.Exists(FileHistoryDirectory)) Directory.CreateDirectory(FileHistoryDirectory);
- string[] folderQueue = Directory.GetFiles(FileQueueDirectory);
- foreach (string file in folderQueue)
- {
- string fileName = Path.GetFileName(file);
- if (File.Exists(Path.Combine(FileHistoryDirectory, fileName)))
- {
- ColorLine($"[Relayer] {SVDictionary.FileIgnoredDueToMatchingPair(Settings.Default.CurrentLanguage)}", ConsoleColor.Blue);
- File.Delete(file);
- }
- else
- {
- return fileName;
- }
- }
- Thread.Sleep(100);
- }
- }
- }
-
- public class Generate
- {
- private readonly string InfoX;
- private readonly string MsgType;
- private readonly string Sent;
-
- public Generate(string InfoXML, string MsgTypeZ, string SentDate)
- {
- InfoX = InfoXML;
- MsgType = MsgTypeZ;
- Sent = SentDate;
- }
-
- public (string BroadcastText, bool) BroadcastInfo(string lang)
- {
- string BroadcastText = "";
-
- Match match = Regex.Match(InfoX, @"layer:SOREM:1.0:Broadcast_Text\s*\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
- if (match.Success)
- {
- BroadcastText = match.Groups[1].Value.Replace("\r\n", " ").Replace("\n", " ").Replace(" ", " ").Trim();
- }
- else
- {
- string issue, update, cancel;
- if (lang == "fr")
- {
- issue = "émis";
- update = "mis à jour";
- cancel = "annulé";
- }
- else
- {
- issue = "issued";
- update = "updated";
- cancel = "cancelled";
- }
-
- string MsgPrefix;
- switch (MsgType.ToLower())
- {
- case "alert":
- MsgPrefix = issue;
- break;
- case "update":
- MsgPrefix = update;
- break;
- case "cancel":
- MsgPrefix = cancel;
- break;
- default:
- MsgPrefix = "issued";
- break;
- }
-
- DateTime sentDate = DateTime.Parse(Sent, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToUniversalTime();
-
- string SentFormatted = lang == "fr" ? $"{sentDate:HH}'{sentDate:h}'{sentDate:mm zzz}." : $"{sentDate:HH:mm z}, {sentDate:MMMM dd}, {sentDate:yyyy}.";
-
- string EventType;
- try
- {
- EventType = Regex.Match(InfoX, @"layer:EC-MSC-SMC:1.0:Alert_Name\s*\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value;
- }
- catch (Exception)
- {
- EventType = Regex.Match(InfoX, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value;
- EventType = lang == "fr" ? $"alerte {EventType}" : $"{EventType} alert";
- }
-
- string Coverage;
- try
- {
- Coverage = Regex.Match(InfoX, @"layer:EC-MSC-SMC:1.0:Alert_Coverage\s*\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value;
- Coverage = lang == "fr" ? $"en {Coverage} pour:" : $"in {Coverage} for:";
- }
- catch (Exception)
- {
- Coverage = lang == "fr" ? "pour:" : "for:";
- }
-
- string[] areaDescMatches = Regex.Matches(InfoX, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline)
- .Cast()
- .Select(m => m.Groups[1].Value)
- .ToArray();
-
- string AreaDesc = string.Join(", ", areaDescMatches) + ".";
-
- string SenderName;
-
- try
- {
- SenderName = Regex.Match(InfoX, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value;
- }
- catch (Exception)
- {
- SenderName = "an alert issuer";
- }
-
- string Description;
-
- try
- {
- Description = Regex.Match(InfoX, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value.Replace("\n", " ");
- if (!Description.EndsWith(".")) Description += ".";
- }
- catch (Exception)
- {
- Description = "";
- }
-
- string Instruction;
-
- try
- {
- Instruction = Regex.Match(InfoX, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value.Replace("\n", " ");
- if (!Instruction.EndsWith(".")) Instruction += ".";
- }
- catch (Exception)
- {
- Instruction = "";
- }
-
- BroadcastText = lang == "fr" ?
- $"À {SentFormatted} {SenderName} a {MsgPrefix} une {EventType} {Coverage} {AreaDesc} {Description} {Instruction}".Replace("###", "").Replace(" ", " ").Trim() :
- $"At {SentFormatted} {SenderName} has {MsgPrefix} a {EventType} {Coverage} {AreaDesc} {Description} {Instruction}".Replace("###", "").Replace(" ", " ").Trim();
- }
-
- if (BroadcastText.EndsWith("\x20.")) BroadcastText = BroadcastText.TrimEnd('\x20', '.');
- if (!BroadcastText.EndsWith(".") || !BroadcastText.EndsWith("!")) BroadcastText += ".";
-
- //if (Debugger.IsAttached) BroadcastText += "\x20| Debugging in progress";
-
- return (BroadcastText, true);
- }
-
- public bool GetAudio(string audioLink, string output, int decodeType)
- {
- if (decodeType == 1)
- {
- Console.WriteLine("Decoding audio from Base64.");
- try
- {
- byte[] audioData = Convert.FromBase64String(audioLink);
- File.WriteAllBytes(output, audioData);
- return true;
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Decoder failed: {ex.Message}");
- return false;
- }
- }
- else if (decodeType == 0)
- {
- Console.WriteLine("Downloading audio.");
- try
- {
- using (HttpClient webClient = new HttpClient())
- {
- File.WriteAllBytes(output, webClient.GetByteArrayAsync(audioLink).Result);
- }
- return true;
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Downloader failed: {ex.Message}");
- }
- return false;
- }
- else
- {
- Console.WriteLine("Invalid DecodeType specified.");
- return false;
- }
- }
-
- private readonly SpeechSynthesizer engine = new SpeechSynthesizer();
-
- public void GenerateAudio(string text, string lang)
- {
- try
- {
- Match Resource = Regex.Match(InfoX, @"\s*(.*?)\s*\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
- if (!Resource.Success) throw new Exception("Audio field not found. TTS will be generated instead.");
- string broadcastAudioResource = Resource.Groups[1].Value;
- string audioLink = string.Empty;
- string audioType = string.Empty;
- int decode = -1;
-
- if (broadcastAudioResource.Contains(""))
- {
- Match Link = Regex.Match(broadcastAudioResource, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
- Match Type = Regex.Match(broadcastAudioResource, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
- decode = 1;
- if (Link.Success && Type.Success)
- {
- audioLink = Link.Groups[1].Value;
- audioType = Type.Groups[1].Value;
- }
- }
- else
- {
- Match Link = Regex.Match(broadcastAudioResource, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
- Match Type = Regex.Match(broadcastAudioResource, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
- decode = 0;
- if (Link.Success && Type.Success)
- {
- audioLink = Link.Groups[1].Value;
- audioType = Type.Groups[1].Value;
- }
- }
-
- Console.WriteLine(audioLink);
- Thread.Sleep(5000);
-
- string audioFile;
- switch (audioType)
- {
- case "audio/mpeg":
- audioFile = "PreAudio.mp3";
- break;
- case "audio/x-ms-wma":
- audioFile = "PreAudio.wma";
- break;
- default:
- audioFile = "PreAudio.wav";
- break;
- }
-
- if (File.Exists($"{AudioDirectory}\\{audioFile}")) File.Delete($"{AudioDirectory}\\{audioFile}");
- if (File.Exists($"{AudioDirectory}\\audio.wav")) File.Delete($"{AudioDirectory}\\audio.wav");
-
- if (GetAudio(audioLink, audioFile, decode))
- {
- using (var audioFileReader = new AudioFileReader(audioFile))
- {
- var volumeSampleProvider = new VolumeSampleProvider(audioFileReader.ToSampleProvider())
- {
- Volume = 2.5f,
- };
- WaveFileWriter.CreateWaveFile16($"{AudioDirectory}\\audio.wav", volumeSampleProvider);
- }
-
- if (!File.Exists($"{AudioDirectory}\\audio.wav"))
- {
- Console.WriteLine("Post processing failed.");
- File.Move(audioFile, $"{AudioDirectory}\\audio.wav");
- }
-
- //string ffmpegCmd = $"{AssemblyDirectory}\\ffmpeg.exe -y -i {audioFile} -filter:a volume=2.5 {AssemblyDirectory.Replace("\\", "/")}/Audio/audio.wav";
- //Process p = Process.Start("cmd.exe", $"/c {ffmpegCmd}");
- //p.WaitForExit(12000);
- //if (p.ExitCode != 0 || !File.Exists($"{AssemblyDirectory}\\Audio\\audio.wav"))
- //{
- // Console.WriteLine("Post processing failed. Please make sure ffmpeg is in the program folder.");
- // File.Move(audioFile, $"{AssemblyDirectory}\\Audio\\audio.wav");
- //}
- //new SoundPlayer($"{AssemblyDirectory}\\Audio\\audio.wav").PlaySync();
- }
- else
- {
- throw new Exception();
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex.Message);
- Console.WriteLine(lang);
- foreach (var voice in engine.GetInstalledVoices())
- {
- if (voice.VoiceInfo.Name.Contains(Settings.Default.SpeechVoice))
- {
- ColorLine(voice.VoiceInfo.Name, ConsoleColor.Magenta);
- engine.SelectVoice(voice.VoiceInfo.Name);
- break;
- }
- }
-
- text = text.Replace("#", "hashtag\x20");
- text = text.Replace("*", "star\x20");
-
- engine.SetOutputToWaveFile($"{AudioDirectory}\\audio.wav");
- engine.Speak(text);
- engine.Dispose();
- }
- }
- }
public static void CheckFolder(string folderPath, bool clear)
{
@@ -769,32 +44,62 @@ public static void ClearFolder(string directory)
}
}
+ public static bool IsAdministrator => new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator)
+ && WindowsIdentity.GetCurrent().Owner == WindowsIdentity.GetCurrent().User;
+ public static bool IsGuest => new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Guest);
+
+ public static bool SkipPlayback = false;
+
///
/// This method should only be called when the program is started or restarted.
///
public static void Init(string VersionID, bool RecoveredFromProblem)
{
- Console.WriteLine($"{VersionID}\r\n" +
- $"Ported from ApatheticDELL's QuantumENDEC 4.\r\n\r\n" +
+ Console.Title = VersionID;
+ ConsoleExt.WriteLine($"{VersionID}\r\n" +
+ $"Source code forked from QuantumENDEC 4.\r\n\r\n" +
$"Project created by BunnyTub.\r\n" +
$"Logo created by ApatheticDELL.\r\n" +
- $"Translations may not be 100% accurate due to language deviations.");
+ $"Translations may not be 100% accurate due to language deviations.\r\n");
- if (RecoveredFromProblem) ColorLine(SVDictionary.RecoveredFromFailure(Settings.Default.CurrentLanguage), ConsoleColor.DarkRed);
+ if (RecoveredFromProblem) ConsoleExt.WriteLine(LanguageStrings.RecoveredFromFailure(Settings.Default.CurrentLanguage), ConsoleColor.DarkRed);
+ if (IsAdministrator) ConsoleExt.WriteLine(LanguageStrings.ElevationSecurityProblem(Settings.Default.CurrentLanguage), ConsoleColor.Yellow);
+ if (IsGuest) ConsoleExt.WriteLine(LanguageStrings.ConfigurationLossProblem(Settings.Default.CurrentLanguage), ConsoleColor.Yellow);
- CheckFolder(FileQueueDirectory, RecoveredFromProblem);
- CheckFolder(FileHistoryDirectory, RecoveredFromProblem);
CheckFolder("Audio", false);
- if (!File.Exists("Audio\\attn.wav"))
+ if (!File.Exists($"{AudioDirectory}\\attn.wav"))
{
MemoryStream mem = new MemoryStream();
Resources.attn.CopyTo(mem);
File.WriteAllBytes("Audio\\attn.wav", mem.ToArray());
mem.Dispose();
+ ConsoleExt.WriteLine("The attention tone audio \"attn.wav\" doesn't exist. The default one will be used instead.");
}
- Thread.Sleep(2500);
+ //ConsoleExt.WriteLine();
+ ConsoleExt.WriteLine($"Press SPACE to pause for 30 seconds.");
+
+ bool alreadyPaused = false;
+
+ for (int i = 3; i > 0; i--)
+ {
+ if (alreadyPaused) break;
+ Thread.Sleep(1000);
+
+ if (Console.KeyAvailable)
+ {
+ switch (Console.ReadKey(true).Key)
+ {
+ case ConsoleKey.Spacebar:
+ ConsoleExt.WriteLine("Paused for 30 seconds.");
+ Thread.Sleep(30000);
+ alreadyPaused = true;
+ continue;
+ }
+ }
+ }
+ Console.Clear();
}
///
@@ -803,10 +108,11 @@ public static void Init(string VersionID, bool RecoveredFromProblem)
///
public static void Config()
{
- for (int i = 5; i > 0; i--)
+ Settings.Default.Upgrade();
+ for (int i = 3; i > 0; i--)
{
Console.Clear();
- Console.WriteLine($"Press C to configure settings. Press R to reset settings. Continuing otherwise in {i} second(s).");
+ ConsoleExt.WriteLine($"Press C to configure settings. Press R to reset settings. Continuing otherwise in {i} second(s).");
Thread.Sleep(1000);
@@ -820,11 +126,11 @@ public static void Config()
while (!ProgressToNextPage)
{
Console.Clear();
- Console.WriteLine($"--- Sound ---");
- Console.WriteLine($"1. SoundDevice = {Settings.Default.SoundDevice} | Use the specified sound device for audio output");
- Console.WriteLine($"2. SpeechVoice = {Settings.Default.SpeechVoice} | Use the specified voice for TTS when audio is not provided");
- Console.WriteLine();
- Console.WriteLine($"Press ENTER to go to the next page.");
+ ConsoleExt.WriteLine($"--- Sound ---");
+ ConsoleExt.WriteLine($"1. SoundDevice = {Settings.Default.SoundDevice} | Use the specified sound device for audio output");
+ ConsoleExt.WriteLine($"2. SpeechVoice = {Settings.Default.SpeechVoice} | Use the specified voice for TTS when audio is not provided");
+ ConsoleExt.WriteLine();
+ ConsoleExt.WriteLine($"Press ENTER to go to the next page.");
while (!Console.KeyAvailable) Thread.Sleep(100);
switch (Console.ReadKey(true).Key)
{
@@ -833,14 +139,14 @@ public static void Config()
for (int n = -1; n < WaveOut.DeviceCount; n++)
{
var caps = WaveOut.GetCapabilities(n);
- Console.WriteLine($"{n}: {caps.ProductName}");
+ ConsoleExt.WriteLine($"{n}: {caps.ProductName}");
}
Console.Write("Enter sound device ID:\x20");
Settings.Default.SoundDevice = int.Parse(Console.ReadLine());
break;
case ConsoleKey.D2:
Console.Clear();
- foreach (var voice in new SpeechSynthesizer().GetInstalledVoices()) Console.WriteLine(voice.VoiceInfo.Name);
+ foreach (var voice in new SpeechSynthesizer().GetInstalledVoices()) ConsoleExt.WriteLine(voice.VoiceInfo.Name);
Console.Write("Enter speech voice name:\x20");
Settings.Default.SpeechVoice = Console.ReadLine();
break;
@@ -855,11 +161,11 @@ public static void Config()
while (!ProgressToNextPage)
{
Console.Clear();
- Console.WriteLine($"--- Statuses ---");
- Console.WriteLine($"1. statusTest = {Settings.Default.statusTest} | Relay test alerts");
- Console.WriteLine($"2. statusActual = {Settings.Default.statusActual} | Relay actual alerts");
- Console.WriteLine();
- Console.WriteLine($"Press ENTER to go to the next page.");
+ ConsoleExt.WriteLine($"--- Statuses ---");
+ ConsoleExt.WriteLine($"1. statusTest = {Settings.Default.statusTest} | Relay test alerts");
+ ConsoleExt.WriteLine($"2. statusActual = {Settings.Default.statusActual} | Relay actual alerts");
+ ConsoleExt.WriteLine();
+ ConsoleExt.WriteLine($"Press ENTER to go to the next page.");
while (!Console.KeyAvailable) Thread.Sleep(100);
switch (Console.ReadKey(true).Key)
{
@@ -880,13 +186,13 @@ public static void Config()
while (!ProgressToNextPage)
{
Console.Clear();
- Console.WriteLine($"--- Types ---");
- Console.WriteLine($"1. messageTypeAlert = {Settings.Default.messageTypeAlert} | Relay alert messages");
- Console.WriteLine($"2. messageTypeUpdate = {Settings.Default.messageTypeUpdate} | Relay update messages");
- Console.WriteLine($"3. messageTypeCancel = {Settings.Default.messageTypeCancel} | Relay cancel messages");
- Console.WriteLine($"4. messageTypeTest = {Settings.Default.messageTypeTest} | Relay test messages");
- Console.WriteLine();
- Console.WriteLine($"Press ENTER to go to the next page.");
+ ConsoleExt.WriteLine($"--- Types ---");
+ ConsoleExt.WriteLine($"1. messageTypeAlert = {Settings.Default.messageTypeAlert} | Relay alert messages");
+ ConsoleExt.WriteLine($"2. messageTypeUpdate = {Settings.Default.messageTypeUpdate} | Relay update messages");
+ ConsoleExt.WriteLine($"3. messageTypeCancel = {Settings.Default.messageTypeCancel} | Relay cancel messages");
+ ConsoleExt.WriteLine($"4. messageTypeTest = {Settings.Default.messageTypeTest} | Relay test messages");
+ ConsoleExt.WriteLine();
+ ConsoleExt.WriteLine($"Press ENTER to go to the next page.");
while (!Console.KeyAvailable) Thread.Sleep(100);
switch (Console.ReadKey(true).Key)
{
@@ -913,14 +219,14 @@ public static void Config()
while (!ProgressToNextPage)
{
Console.Clear();
- Console.WriteLine($"--- Severities ---");
- Console.WriteLine($"1. severityExtreme = {Settings.Default.severityExtreme} | Relay extreme messages");
- Console.WriteLine($"2. severitySevere = {Settings.Default.severitySevere} | Relay severe messages");
- Console.WriteLine($"3. severityModerate = {Settings.Default.severityModerate} | Relay moderate messages");
- Console.WriteLine($"4. severityMinor = {Settings.Default.severityMinor} | Relay minor messages");
- Console.WriteLine($"5. severityUnknown = {Settings.Default.severityUnknown} | Relay unknown messages");
- Console.WriteLine();
- Console.WriteLine($"Press ENTER to go to the next page.");
+ ConsoleExt.WriteLine($"--- Severities ---");
+ ConsoleExt.WriteLine($"1. severityExtreme = {Settings.Default.severityExtreme} | Relay extreme messages");
+ ConsoleExt.WriteLine($"2. severitySevere = {Settings.Default.severitySevere} | Relay severe messages");
+ ConsoleExt.WriteLine($"3. severityModerate = {Settings.Default.severityModerate} | Relay moderate messages");
+ ConsoleExt.WriteLine($"4. severityMinor = {Settings.Default.severityMinor} | Relay minor messages");
+ ConsoleExt.WriteLine($"5. severityUnknown = {Settings.Default.severityUnknown} | Relay unknown messages");
+ ConsoleExt.WriteLine();
+ ConsoleExt.WriteLine($"Press ENTER to go to the next page.");
while (!Console.KeyAvailable) Thread.Sleep(100);
switch (Console.ReadKey(true).Key)
{
@@ -950,13 +256,13 @@ public static void Config()
while (!ProgressToNextPage)
{
Console.Clear();
- Console.WriteLine($"--- Urgency ---");
- Console.WriteLine($"1. urgencyImmediate = {Settings.Default.urgencyImmediate} | Relay immediate urgency messages");
- Console.WriteLine($"2. urgencyExpected = {Settings.Default.urgencyExpected} | Relay expected urgency messages");
- Console.WriteLine($"3. urgencyFuture = {Settings.Default.urgencyFuture} | Relay future urgency messages");
- Console.WriteLine($"4. urgencyPast = {Settings.Default.urgencyPast} | Relay past urgency messages");
- Console.WriteLine();
- Console.WriteLine($"Press ENTER to go to the next page.");
+ ConsoleExt.WriteLine($"--- Urgency ---");
+ ConsoleExt.WriteLine($"1. urgencyImmediate = {Settings.Default.urgencyImmediate} | Relay immediate urgency messages");
+ ConsoleExt.WriteLine($"2. urgencyExpected = {Settings.Default.urgencyExpected} | Relay expected urgency messages");
+ ConsoleExt.WriteLine($"3. urgencyFuture = {Settings.Default.urgencyFuture} | Relay future urgency messages");
+ ConsoleExt.WriteLine($"4. urgencyPast = {Settings.Default.urgencyPast} | Relay past urgency messages");
+ ConsoleExt.WriteLine();
+ ConsoleExt.WriteLine($"Press ENTER to go to the next page.");
while (!Console.KeyAvailable) Thread.Sleep(100);
switch (Console.ReadKey(true).Key)
{
@@ -983,15 +289,15 @@ public static void Config()
while (!ProgressToNextPage)
{
Console.Clear();
- Console.WriteLine($"--- Geocodes ---");
- Console.WriteLine();
- foreach (string geo in Settings.Default.AllowedLocations_Geocodes) Console.WriteLine(geo);
- if (Settings.Default.AllowedLocations_Geocodes.Count == 0) Console.WriteLine("All");
- Console.WriteLine();
- Console.WriteLine($"1. AllowedLocations_Geocodes | Relay messages with the specified geocodes");
- Console.WriteLine($"2. Relay messages with any location values");
- Console.WriteLine();
- Console.WriteLine($"Press ENTER to go to the next page.");
+ ConsoleExt.WriteLine($"--- Geocodes ---");
+ ConsoleExt.WriteLine();
+ foreach (string geo in Settings.Default.AllowedLocations_Geocodes) ConsoleExt.WriteLine(geo);
+ if (Settings.Default.AllowedLocations_Geocodes.Count == 0) ConsoleExt.WriteLine("All");
+ ConsoleExt.WriteLine();
+ ConsoleExt.WriteLine($"1. AllowedLocations_Geocodes | Relay messages with the specified geocodes");
+ ConsoleExt.WriteLine($"2. Relay messages with any location values");
+ ConsoleExt.WriteLine();
+ ConsoleExt.WriteLine($"Press ENTER to go to the next page.");
while (!Console.KeyAvailable) Thread.Sleep(100);
switch (Console.ReadKey(true).Key)
{
@@ -1014,471 +320,276 @@ public static void Config()
while (!ProgressToNextPage)
{
Console.Clear();
- Console.WriteLine($"--- Miscellaneous ---");
- Console.WriteLine($"1. CurrentLanguage = {Settings.Default.CurrentLanguage} | Use the program in a different language");
- Console.WriteLine();
- Console.WriteLine($"Press ENTER to finish.");
+ ConsoleExt.WriteLine($"--- Relay ---");
+ ConsoleExt.WriteLine($"EnforceMaximumTime = {Settings.Default.EnforceMaximumTime} | Enforce a maximum playback time limit (in seconds)");
+ ConsoleExt.WriteLine($"1. 60 seconds");
+ ConsoleExt.WriteLine($"2. 120 seconds");
+ ConsoleExt.WriteLine($"3. 240 seconds");
+ ConsoleExt.WriteLine($"4. Do not enforce any maximum");
+ ConsoleExt.WriteLine();
+ ConsoleExt.WriteLine($"Press ENTER to finish.");
while (!Console.KeyAvailable) Thread.Sleep(100);
switch (Console.ReadKey(true).Key)
{
case ConsoleKey.D1:
- Settings.Default.CurrentLanguage = "en";
+ Settings.Default.EnforceMaximumTime = 60;
+ break;
+ case ConsoleKey.D2:
+ Settings.Default.EnforceMaximumTime = 120;
+ break;
+ case ConsoleKey.D3:
+ Settings.Default.EnforceMaximumTime = 240;
+ break;
+ case ConsoleKey.D4:
+ Settings.Default.EnforceMaximumTime = -1;
break;
case ConsoleKey.Enter:
ProgressToNextPage = true;
break;
}
}
- Console.Clear();
- Settings.Default.Save();
- Console.WriteLine("Your preferences have been saved.");
- Thread.Sleep(2500);
- Console.Clear();
- return;
- case ConsoleKey.R:
- Console.Clear();
- Settings.Default.Reset();
- Console.WriteLine("All preferences have been restored to their default configuration.");
- Thread.Sleep(2500);
- Console.Clear();
- return;
- }
- }
- }
- Console.Clear();
- }
-
- public static void ColorLine(string value, ConsoleColor foreground)
- {
- var og = Console.ForegroundColor;
- Console.ForegroundColor = foreground;
- Console.WriteLine(value);
- Console.ForegroundColor = og;
- }
-
- public static EventDetails GetEventDetails(string eventCode)
- {
- var eventDetailsDictionary = new Dictionary
- {
- { "airQuality", new EventDetails("Air Quality", "Severe or Extreme", "Observed") },
- { "civilEmerg", new EventDetails("Civil Emergency", "Severe or Extreme", "Observed") },
- { "terrorism", new EventDetails("Terrorism", "Severe or Extreme", "Observed") },
- { "animalDang", new EventDetails("Dangerous Animal", "Severe or Extreme", "Observed") },
- { "wildFire", new EventDetails("Wildfire", "Severe or Extreme", "Likely or Observed") },
- { "industryFire", new EventDetails("Industrial Fire", "Severe or Extreme", "Observed") },
- { "urbanFire", new EventDetails("Urban Fire", "Severe or Extreme", "Observed") },
- { "forestFire", new EventDetails("Forest Fire", "Severe or Extreme", "Likely or Observed") },
- { "stormSurge", new EventDetails("Storm Surge", "Severe or Extreme", "Likely or Observed") },
- { "flashFlood", new EventDetails("Flash Flood", "Severe or Extreme", "Likely or Observed") },
- { "damOverflow", new EventDetails("Dam Overflow", "Severe or Extreme", "Likely or Observed") },
- { "earthquake", new EventDetails("Earthquake", "Severe or Extreme", "Likely or Observed") },
- { "magnetStorm", new EventDetails("Magnetic Storm", "Severe or Extreme", "Likely or Observed") },
- { "landslide", new EventDetails("Landslide", "Severe or Extreme", "Likely or Observed") },
- { "meteor", new EventDetails("Meteor", "Severe or Extreme", "Likely or Observed") },
- { "tsunami", new EventDetails("Tsunami", "Severe or Extreme", "Likely or Observed") },
- { "lahar", new EventDetails("Lahar", "Severe or Extreme", "Likely or Observed") },
- { "pyroclasticS", new EventDetails("Pyroclastic Surge", "Severe or Extreme", "Likely or Observed") },
- { "pyroclasticF", new EventDetails("Pyroclastic Flow", "Severe or Extreme", "Likely or Observed") },
- { "volcanicAsh", new EventDetails("Volcanic Ash", "Severe or Extreme", "Likely or Observed") },
- { "chemical", new EventDetails("Chemical", "Severe or Extreme", "Observed") },
- { "biological", new EventDetails("Biological", "Severe or Extreme", "Observed") },
- { "radiological", new EventDetails("Radiological", "Severe or Extreme", "Observed") },
- { "explosives", new EventDetails("Explosives", "Severe or Extreme", "Likely or Observed") },
- { "fallObject", new EventDetails("Falling Object", "Severe or Extreme", "Observed") },
- { "drinkingWate", new EventDetails("Drinking Water", "Severe or Extreme", "Observed") },
- { "amber", new EventDetails("Amber Alert", "Severe or Extreme", "Observed") },
- { "hurricane", new EventDetails("Hurricane", "Severe or Extreme", "Observed") },
- { "thunderstorm", new EventDetails("Thunderstorm", "Severe or Extreme", "Observed") },
- { "tornado", new EventDetails("Tornado", "Severe or Extreme", "Likely or Observed") },
- { "testMessage", new EventDetails("Test Message", "Minor", "Observed") },
- { "911Service", new EventDetails("911 Service", "Severe or Extreme", "Observed") }
- };
-
- if (eventDetailsDictionary.TryGetValue(eventCode, out EventDetails eventDetails))
- {
- return eventDetails;
- }
- else
- {
- return new EventDetails(eventCode, "Unknown Severity", "Unknown Certainty");
- }
- }
-
- public class EventDetails
- {
- public string FriendlyName { get; }
- public string Severity { get; }
- public string Certainty { get; }
-
- public EventDetails(string friendlyName, string severity, string certainty)
- {
- FriendlyName = friendlyName;
- Severity = severity;
- Certainty = certainty;
- }
- }
-
- private static void WaitForFile(string filePath)
- {
- Task.Run(() =>
- {
- bool fileInUse = true;
- while (fileInUse)
- {
- try
- {
- if (File.Exists(filePath))
- {
- using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None))
- {
- fileInUse = false;
- }
- }
- else
- {
- Console.WriteLine($"{filePath} does not exist yet.");
- fileInUse = false;
- }
- }
- catch (IOException)
- {
- fileInUse = true;
- Console.WriteLine($"{filePath} is still in use.");
- Thread.Sleep(500);
- }
- }
- }).Wait(2500);
- }
- public static void Relay()
- {
- while (true)
- {
- Console.WriteLine($"{SVDictionary.LastDataReceived(Settings.Default.CurrentLanguage)} {DateTime.Now:yyyy-MM-dd HH:mm:ss}.");
- string resultFileName = Check.WatchNotify();
- ColorLine($"[Relayer] {SVDictionary.CapturedFromFileWatcher(Settings.Default.CurrentLanguage)} {resultFileName}", ConsoleColor.Cyan);
- if (File.Exists($"{AssemblyDirectory}\\relay.xml")) File.Delete($"{AssemblyDirectory}\\relay.xml");
- WaitForFile($"{FileQueueDirectory}\\{resultFileName}");
- File.Move($"{FileQueueDirectory}\\{resultFileName}", $"{AssemblyDirectory}\\relay.xml");
-
- string relayXML = File.ReadAllText("relay.xml", Encoding.UTF8);
+ ProgressToNextPage = false;
- if (relayXML.Contains("NAADS-Heartbeat"))
- {
- ColorLine($"[Relayer] {SVDictionary.HeartbeatDetected(Settings.Default.CurrentLanguage)}", ConsoleColor.Green);
- Match referencesMatch = Regex.Match(relayXML, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
- if (referencesMatch.Success)
- {
- string references = referencesMatch.Groups[1].Value;
- //Console.WriteLine(referencesMatch.Groups[0].Value);
- //Console.WriteLine(referencesMatch.Groups[1].Value);
- Check.Heartbeat(references);
- }
- }
- else
- {
- ColorLine($"[Relayer] {SVDictionary.AlertDetected(Settings.Default.CurrentLanguage)}", ConsoleColor.Green);
- File.Move("relay.xml", $"{FileHistoryDirectory}\\{resultFileName}");
- bool IsUI = Settings.Default.WirelessAlertMode;
- foreach (Match match in Regex.Matches(relayXML, @"([^<]+)\s*([^<]+)", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline))
- {
- if (match.Groups[1].Value == "layer:SOREM:2.0:WirelessText")
- {
- if (!string.IsNullOrWhiteSpace(match.Groups[2].Value))
+ while (!ProgressToNextPage)
{
- IsUI = true;
- break;
+ Console.Clear();
+ ConsoleExt.WriteLine($"--- Event Blacklist ---");
+ ConsoleExt.WriteLine();
+ foreach (string item in Settings.Default.EnforceEventBlacklist) ConsoleExt.WriteLine(item);
+ if (Settings.Default.EnforceEventBlacklist.Count == 0) ConsoleExt.WriteLine("None");
+ ConsoleExt.WriteLine();
+ ConsoleExt.WriteLine($"1. Add to blacklist | Don't relay messages with the specified event codes");
+ ConsoleExt.WriteLine($"2. Clear the blacklist");
+ ConsoleExt.WriteLine();
+ ConsoleExt.WriteLine($"Press ENTER to go to the next page.");
+ while (!Console.KeyAvailable) Thread.Sleep(100);
+ switch (Console.ReadKey(true).Key)
+ {
+ case ConsoleKey.D1:
+ Console.Clear();
+ Console.Write("Enter code to add:\x20");
+ Settings.Default.EnforceEventBlacklist.Add(Console.ReadLine());
+ break;
+ case ConsoleKey.D2:
+ Settings.Default.EnforceEventBlacklist.Clear();
+ break;
+ case ConsoleKey.Enter:
+ ProgressToNextPage = true;
+ break;
+ }
}
- }
-
- //Console.WriteLine($"valueName: {match.Groups[1].Value}");
- //Console.WriteLine($"value: {match.Groups[2].Value}");
- }
-
- Match sentMatch = Regex.Match(relayXML, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
- Match statusMatch = Regex.Match(relayXML, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
- Match messageTypeMatch = Regex.Match(relayXML, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
- MatchCollection broadcastImmediatelyMatches = Regex.Matches(relayXML, @"layer:SOREM:1.0:Broadcast_Immediately\s*\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
- MatchCollection urgencyMatches = Regex.Matches(relayXML, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
- MatchCollection severityMatches = Regex.Matches(relayXML, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
-
- bool final = false;
-
- for (int i = 0; i < severityMatches.Count; i++)
- {
- if (Check.Config(relayXML, statusMatch.Groups[1].Value, messageTypeMatch.Groups[1].Value, severityMatches[i].Groups[1].Value, urgencyMatches[i].Groups[1].Value, broadcastImmediatelyMatches[i].Groups[1].Value))
- {
- final = true;
- break;
- }
- }
-
- if (!final)
- {
- Console.WriteLine($"[Relayer] {SVDictionary.FileIgnoredDueToPreferences(Settings.Default.CurrentLanguage)}");
- continue;
- }
-
- MatchCollection infoMatches = Regex.Matches(relayXML, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
- int infoProc = 0;
-
- foreach (Match infoMatch in infoMatches)
- {
- infoProc++;
- Console.WriteLine($"[Relayer] Processing match {infoProc} of {infoMatches.Count}.");
- string infoEN = $"{infoMatch.Groups[1].Value}";
- string lang = "en";
- if (Regex.Match(infoEN, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value == "fr-CA")
- {
- lang = "fr";
- }
- if (lang != "en")
- {
- continue;
- }
-
- string Status = statusMatch.Groups[1].Value;
- string MsgType = messageTypeMatch.Groups[1].Value;
- string EventType = Regex.Match(infoEN, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value;
- string urgency = Regex.Match(infoEN, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value;
- string severity = Regex.Match(infoEN, @"\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value;
- string broadcastImmediately;
- Match broadcastImmediatelyMatch = Regex.Match(infoEN, @"layer:SOREM:1.0:Broadcast_Immediately\s*\s*(.*?)\s*", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Singleline);
- if (broadcastImmediatelyMatch.Success)
- {
- broadcastImmediately = broadcastImmediatelyMatch.Groups[1].Value;
- }
- else
- {
- broadcastImmediately = "No";
- }
-
- EventDetails EventInfo = GetEventDetails(EventType);
-
- ColorLine(Status, ConsoleColor.DarkGray);
- ColorLine(MsgType, ConsoleColor.DarkGray);
- ColorLine($"{EventType} | {EventInfo.FriendlyName} | EventInfo.Color", ConsoleColor.DarkGray);
- ColorLine(urgency, ConsoleColor.DarkGray);
- ColorLine(severity, ConsoleColor.DarkGray);
- ColorLine(broadcastImmediately, ConsoleColor.DarkGray);
-
- if (Check.Config(infoEN, statusMatch.Groups[1].Value, MsgType, severity, urgency, broadcastImmediately))
- {
- Console.WriteLine($"[Relayer] {SVDictionary.GeneratingProductText(Settings.Default.CurrentLanguage)}");
-
- Console.WriteLine($"0: {messageTypeMatch.Groups[0].Value}");
- Console.WriteLine($"1: {messageTypeMatch.Groups[1].Value}");
- Console.WriteLine($"2: {messageTypeMatch.Groups[2].Value}");
- Console.WriteLine($"3: {messageTypeMatch.Groups[3].Value}");
- Console.WriteLine($"4: {messageTypeMatch.Groups[4].Value}");
- Generate gen = new Generate(infoEN, sentMatch.Groups[1].Value, DateTime.Now.ToString());
-
- var info = gen.BroadcastInfo(lang);
+ ProgressToNextPage = false;
- if (true) //(!string.IsNullOrWhiteSpace(info.BroadcastText))
+ while (!ProgressToNextPage)
{
- //Console.WriteLine($"[Relayer] {SVDictionary.GeneratingProductAudio}");
- File.WriteAllText($"{AssemblyDirectory}\\inactive-text.txt", string.Empty);
- File.WriteAllText($"{AssemblyDirectory}\\active-text.txt", $"{info.BroadcastText}\x20");
- File.WriteAllText($"{AssemblyDirectory}\\static-text.txt", $"{info.BroadcastText}\x20");
-
- Console.WriteLine($"[Relayer] -> {info.BroadcastText}");
-
- gen.GenerateAudio(info.BroadcastText, lang);
-
- WaitForFile($"{FileQueueDirectory}\\{resultFileName}");
-
- if (IsUI)
- {
- Color BackColor;
- Color ForeColor;
-
- switch (severity)
- {
- case "Extreme":
- BackColor = Color.Red;
- ForeColor = Color.Yellow;
- break;
- case "Severe":
- BackColor = Color.OrangeRed;
- ForeColor = Color.Black;
- break;
- case "Moderate":
- BackColor = Color.Gold;
- ForeColor = Color.Black;
- break;
- case "Minor":
- BackColor = Color.LightGreen;
- ForeColor = Color.Black;
- break;
- case "Unknown":
- BackColor = Color.White;
- ForeColor = Color.Black;
- break;
- default:
- BackColor = Color.White;
- ForeColor = Color.Black;
- break;
- }
-
- //Task.Run(() =>
- //{
- // AlertForm af = new AlertForm
- // {
- // PlayAudio = () => Play($"{AudioDirectory}\\audio.wav"),
- // EventBackColor = BackColor,
- // EventForeColor = ForeColor,
- // EventTextContent = EventInfo.FriendlyName
- // };
- // af.Show();
- //}).Wait(30000);
-
- Task.Run(() =>
- {
- NotifyOverlay no = new NotifyOverlay
- {
- EventShortInfoText = $"{EventInfo.FriendlyName}",
- EventLongInfoText = $"{info.BroadcastText}",
- EventTypeText = $"{EventInfo.FriendlyName}"
- };
- no.ShowDialog();
- }).Wait(30000);
- }
- else
+ Console.Clear();
+ ConsoleExt.WriteLine($"--- Language ---");
+ ConsoleExt.WriteLine($"CurrentLanguage = {Settings.Default.CurrentLanguage} | Use the program in a different language");
+ ConsoleExt.WriteLine($"1. English | Use the program in English");
+ ConsoleExt.WriteLine($"2. Français | Use the program in French");
+ ConsoleExt.WriteLine();
+ ConsoleExt.WriteLine($"Press ENTER to finish.");
+ while (!Console.KeyAvailable) Thread.Sleep(100);
+ switch (Console.ReadKey(true).Key)
{
- Console.WriteLine($"[Relayer] {SVDictionary.PlayingAudio(Settings.Default.CurrentLanguage)}");
- Console.WriteLine($"[Relayer] Played {Play($"{AudioDirectory}\\in.wav").AudioLength.TotalMilliseconds} millisecond(s) of audio.");
- if (EventInfo.Severity.Contains("Severe") || EventInfo.Severity.Contains("Extreme"))
- Console.WriteLine($"[Relayer] Played {Play($"{AudioDirectory}\\attn.wav").AudioLength.TotalMilliseconds} millisecond(s) of audio.");
- else
- {
- var (FilePlayed, AudioLength) = Play($"{AudioDirectory}\\attn-minor.wav");
- if (FilePlayed)
- Console.WriteLine($"[Relayer] Played {Play($"{AudioDirectory}\\attn-minor.wav").AudioLength.TotalMilliseconds} millisecond(s) of audio.");
- else
- Console.WriteLine($"[Relayer] Played {Play($"{AudioDirectory}\\attn.wav").AudioLength.TotalMilliseconds} millisecond(s) of audio.");
- }
- //Console.WriteLine($"[Relayer] Attention tone not played because the alert severity is not severe or extreme.");
- Console.WriteLine($"[Relayer] Played {Play($"{AudioDirectory}\\audio.wav").AudioLength.TotalMilliseconds} millisecond(s) of audio.");
- Console.WriteLine($"[Relayer] Played {Play($"{AudioDirectory}\\out.wav").AudioLength.TotalMilliseconds} millisecond(s) of audio.");
+ case ConsoleKey.D1:
+ Settings.Default.CurrentLanguage = "english";
+ break;
+ case ConsoleKey.D2:
+ Settings.Default.CurrentLanguage = "french";
+ break;
+ case ConsoleKey.Enter:
+ ProgressToNextPage = true;
+ break;
}
-
- File.WriteAllText($"{AssemblyDirectory}\\active-text.txt", string.Empty);
- File.WriteAllText($"{AssemblyDirectory}\\inactive-text.txt", $"{info.BroadcastText}\x20");
- }
- else
- {
- Console.WriteLine($"[Relayer] {SVDictionary.GeneratedProductEmpty(Settings.Default.CurrentLanguage)}");
}
- }
- else
- {
- Console.WriteLine($"[Relayer] {SVDictionary.FileIgnoredDueToPreferences(Settings.Default.CurrentLanguage)}");
- }
+
+ Console.Clear();
+ Settings.Default.Save();
+ ConsoleExt.WriteLine("Your preferences have been saved.");
+ Thread.Sleep(2500);
+ Console.Clear();
+ return;
+ case ConsoleKey.R:
+ Console.Clear();
+ Settings.Default.Reset();
+ ConsoleExt.WriteLine("All preferences have been restored to their default configuration.");
+ Thread.Sleep(2500);
+ Console.Clear();
+ return;
}
}
}
+ Console.Clear();
}
- public static void CAP()
+ //private static void WaitForFile(string filePath)
+ //{
+ // Task.Run(() =>
+ // {
+ // bool fileInUse = true;
+ // while (fileInUse)
+ // {
+ // try
+ // {
+ // if (File.Exists(filePath))
+ // {
+ // using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None))
+ // {
+ // fileInUse = false;
+ // }
+ // }
+ // else
+ // {
+ // ConsoleExt.WriteLine($"{filePath} does not exist yet.");
+ // fileInUse = false;
+ // }
+ // }
+ // catch (IOException)
+ // {
+ // fileInUse = true;
+ // ConsoleExt.WriteLine($"{filePath} is still in use.");
+ // Thread.Sleep(500);
+ // }
+ // }
+ // }).Wait(2500);
+ //}
+
+ public static void StreamProcessor()
{
while (true)
{
- if (new Capture().Main())
+ Capture = new FeedCapture();
+ if (Capture.Main())
{
break;
}
- Thread.Sleep(5000);
- }
- }
-
- public static Capture capture;
+ Thread.Sleep(100);
+ }
+ }
+
+ public static FeedCapture Capture;
+ public static List ClientThreads = new List();
+
+ //public static Thread MethodToThread(Action method)
+ //{
+ // return new Thread(() =>
+ // {
+ // try
+ // {
+ // method();
+ // }
+ // catch (ThreadAbortException ex)
+ // {
+ // ConsoleExt.WriteLine($"Shutdown caught in thread: {ex.Message}");
+ // File.AppendAllText($"{AssemblyDirectory}\\exception.log",
+ // $"{DateTime.Now:G} | Shutdown in {method.Method.Name}\r\n" +
+ // $"{ex.StackTrace}\r\n" +
+ // $"{ex.Source}\r\n" +
+ // $"{ex.Message}\r\n");
+ // }
+ // catch (Exception ex)
+ // {
+ // ConsoleExt.WriteLine($"Exception caught in thread: {ex.Message}");
+ // File.AppendAllText($"{AssemblyDirectory}\\exception.log",
+ // $"{DateTime.Now:G} | Exception in {method.Method.Name}\r\n" +
+ // $"{ex.StackTrace}\r\n" +
+ // $"{ex.Source}\r\n" +
+ // $"{ex.Message}\r\n");
+ // }
+ // });
+ //}
- private static (bool FilePlayed, TimeSpan AudioLength) Play(string filePath, float volume = 1, bool DefaultDevice = false)
+ public static void KeyboardProcessor()
{
- if (File.Exists(filePath))
+ //try
{
- using (var audioFile = new AudioFileReader(filePath))
- using (var outputDevice = new WaveOutEvent
- {
- Volume = volume
- })
+ while (true)
{
- if (!DefaultDevice) outputDevice.DeviceNumber = Settings.Default.SoundDevice;
- outputDevice.Init(audioFile);
- outputDevice.Play();
- while (outputDevice.PlaybackState == PlaybackState.Playing)
+ //try
{
- Thread.Sleep(100);
+ switch (Console.ReadKey(true).Key)
+ {
+ case ConsoleKey.D0:
+ ConsoleExt.WriteLine("What do you want me to do? Divide by zero?");
+ break;
+ case ConsoleKey.D1:
+ ConsoleExt.WriteLine("--- SharpDataQueue ---");
+ foreach (SharpDataItem item in SharpDataQueue)
+ {
+ ConsoleExt.WriteLine($"{item.Name}");
+ }
+ ConsoleExt.WriteLine("--- SharpDataHistory ---");
+ foreach (SharpDataItem item in SharpDataHistory)
+ {
+ ConsoleExt.WriteLine($"{item.Name}");
+ }
+ break;
+ case ConsoleKey.D2:
+ ConsoleExt.WriteLine(FriendlyVersion);
+ break;
+ case ConsoleKey.Escape:
+ new Thread(() => MainExt.UnsafeStateShutdown(KeyboardProcessor, new ArithmeticException(), "Crash initiated manually.", true)).Start();
+ break;
+ case ConsoleKey.Delete:
+ SharpDataHistory.Clear();
+ ConsoleExt.WriteLine("Cleared history list.");
+ break;
+ case ConsoleKey.Spacebar:
+ SkipPlayback = true;
+ ConsoleExt.WriteLine("Audio playback has been disabled for this time only.");
+ break;
+ //case ConsoleKey.G:
+ // ConsoleExt.WriteLine("GUI shown.");
+ // break;
+ }
}
- return (true, outputDevice.GetPositionTimeSpan());
+ Thread.Sleep(100);
}
}
- else return (false, TimeSpan.Zero);
}
- public static Thread MethodToThread(Action method)
+ public static void AddThread(ThreadStart method)
{
- return new Thread(() =>
+ Thread thread = new Thread(() =>
{
- try
- {
- method();
- }
- catch (ThreadAbortException ex)
- {
- Console.WriteLine($"Shutdown caught in thread: {ex.Message}");
- File.AppendAllText($"{AssemblyDirectory}\\exception.log",
- $"{DateTime.Now:G} | Shutdown in {method.Method.Name}\r\n" +
- $"{ex.StackTrace}\r\n" +
- $"{ex.Source}\r\n" +
- $"{ex.Message}\r\n");
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Exception caught in thread: {ex.Message}");
- File.AppendAllText($"{AssemblyDirectory}\\exception.log",
- $"{DateTime.Now:G} | Exception in {method.Method.Name}\r\n" +
- $"{ex.StackTrace}\r\n" +
- $"{ex.Source}\r\n" +
- $"{ex.Message}\r\n");
- }
+ try { method(); }
+ catch (ThreadAbortException) { }
+ catch (Exception e) { MainExt.UnsafeStateShutdown(null, e, e.Message); }
});
+ Program.MainThreads.Add((thread, method));
+ thread.Start();
}
- public static void KeyboardProcessor()
+ public static void RestartAllThreads()
{
- try
+ foreach (var (thread, method) in Program.MainThreads)
{
- while (true)
- {
- try
- {
- switch (Console.ReadKey(true).Key)
- {
- case ConsoleKey.D0:
- Console.WriteLine("What do you want me to do? Divide by zero?");
- break;
- case ConsoleKey.Delete:
- ClearFolder(FileHistoryDirectory);
- Console.WriteLine("Cleared history folder.");
- break;
- case ConsoleKey.G:
- Console.WriteLine("GUI shown.");
- break;
- }
- }
- catch (Exception)
- {
+ RestartThread(thread, method);
+ }
+ }
- }
- Thread.Sleep(250);
- }
+ public static void RestartThread(Thread serviceThread, ThreadStart method)
+ {
+ if (serviceThread != null)
+ {
+ if (serviceThread.ThreadState != ThreadState.Stopped && serviceThread.ThreadState != ThreadState.Unstarted)
+ serviceThread.Abort();
+ }
+
+ Thread newThread = new Thread(method);
+ newThread.Start();
+
+ int index = Program.MainThreads.IndexOf((serviceThread, method));
+ if (index >= 0)
+ {
+ Program.MainThreads[index] = (newThread, method);
}
- catch (ThreadAbortException)
+ else
{
- Console.WriteLine("Keyboard Processor was stopped.");
+ Program.MainThreads.Add((newThread, method));
}
}
@@ -1486,37 +597,34 @@ public static Thread Watchdog()
{
return new Thread(() =>
{
- string ProgramVersion = Program.FriendlyVersion;
+ string ProgramVersion = FriendlyVersion;
Init(ProgramVersion, false);
- void RestartThread(ref Thread serviceThread, ThreadStart method)
- {
- if (serviceThread.ThreadState != ThreadState.Stopped && serviceThread.ThreadState != ThreadState.Unstarted)
- serviceThread.Abort();
-
- serviceThread = new Thread(method);
- serviceThread.Start();
- }
-
void ShutdownCapture()
{
- capture.ShutdownCapture = true;
- Console.WriteLine("Waiting for CAP to shutdown.");
- while (capture.ShutdownCapture)
+ if (Capture != null)
{
- Thread.Sleep(500);
+ Capture.ShutdownCapture = true;
+ while (Capture.ShutdownCapture)
+ {
+ Thread.Sleep(500);
+ }
}
- Console.WriteLine("CAP has been stopped.");
+ ConsoleExt.WriteLine($"{LanguageStrings.ThreadShutdown(Settings.Default.CurrentLanguage, $"Data Processor")}");
}
+ Config();
+
while (true)
{
- Config();
Check.LastHeartbeat = DateTime.Now;
- RestartThread(ref Program.CAPService, CAP);
- RestartThread(ref Program.RelayService, Relay);
- RestartThread(ref Program.KeyboardProc, KeyboardProcessor);
+ //if (!Program.MainThreads.Contains(Thread.CurrentThread)) Program.MainThreads.Add(Thread.CurrentThread);
+
+ AddThread(StreamProcessor);
+ AddThread(DataProcessor);
+ AddThread(AlertProcessor);
+ AddThread(KeyboardProcessor);
while (true)
{
@@ -1524,15 +632,12 @@ void ShutdownCapture()
{
if ((DateTime.Now - Check.LastHeartbeat).TotalMinutes >= 10)
{
- ColorLine($"[Watchdog] {SVDictionary.WatchdogForceRestartingProcess(Settings.Default.CurrentLanguage)}", ConsoleColor.Red);
+ ConsoleExt.WriteLine($"[Watchdog] {LanguageStrings.WatchdogForceRestartingProcess(Settings.Default.CurrentLanguage)}", ConsoleColor.Red);
try
{
ShutdownCapture();
- RestartThread(ref Program.CAPService, CAP);
- RestartThread(ref Program.RelayService, Relay);
- RestartThread(ref Program.KeyboardProc, KeyboardProcessor);
-
+ RestartAllThreads();
Init(ProgramVersion, true);
Thread.Sleep(5000);
}
@@ -1543,7 +648,7 @@ void ShutdownCapture()
break;
}
- else ColorLine($"[Watchdog] {SVDictionary.WatchdogForcedRestartWarning(Settings.Default.CurrentLanguage)}", ConsoleColor.Red);
+ //else ConsoleExt.WriteLine($"[Watchdog] {LanguageStrings.WatchdogForcedRestartWarning(Settings.Default.CurrentLanguage)}", ConsoleColor.Red);
}
Thread.Sleep(5000);
}
@@ -1554,31 +659,23 @@ void ShutdownCapture()
internal static class Program
{
- public const int ReleaseVersion = 1;
- public const int MinorVersion = 1;
- public const bool IsCuttingEdge = false;
- public static string FriendlyVersion = string.Empty;
-
internal static Thread WatchdogService;
- internal static Thread CAPService;
- internal static Thread RelayService;
- internal static Thread KeyboardProc;
- internal static Thread BatteryProc;
+ //internal static Thread StreamService;
+ //internal static Thread RelayService;
+ //internal static Thread KeyboardProc;
+ //internal static Thread BatteryProc;
+ internal static List<(Thread, ThreadStart)> MainThreads = new List<(Thread, ThreadStart)>();
[STAThread]
- private static void Main()
+ internal static void Main()
{
- if (!IsCuttingEdge)
- {
- FriendlyVersion = $"SharpENDEC {ReleaseVersion}.{MinorVersion} | Release";
- }
- else
- {
- FriendlyVersion = $"SharpENDEC {ReleaseVersion}.{MinorVersion}-c | Cutting Edge (unstable)";
- }
+ Console.Title = "SharpENDEC";
+ Console.ForegroundColor = ConsoleColor.White;
// PLUGIN IMPLEMENTATION!!!
// BATTERY IMPLEMENTATION!!!
// GUI IMPLEMENTATION!!!
+ //Thread thread = new Thread(() => new ConsoleForm().ShowDialog());
+ //thread.Start();
WatchdogService = ENDEC.Watchdog();
WatchdogService.Start();
Console.CancelKeyPress += CancelAllOperations;
@@ -1586,449 +683,7 @@ private static void Main()
private static void CancelAllOperations(object sender, ConsoleCancelEventArgs e)
{
- WatchdogService.Abort();
- CAPService.Abort();
- RelayService.Abort();
- ENDEC.capture.ShutdownCapture = true;
- Console.WriteLine("(-^-)");
- Thread.Sleep(2500);
- Environment.Exit(0);
- }
- }
-
- public static class SVDictionary
- {
- public static string RecoveredFromFailure(string lang)
- {
- switch (lang)
- {
- case "fr":
- return "Le chien de garde a récemment détecté un problème et a effacé toutes les données XML stockées.\r\n" +
- "Les alertes précédemment relayées peuvent être relayées à nouveau lorsque le prochain battement de coeur arrive.";
- case "en":
- default:
- return "The watchdog has recently detected a problem, and has cleared all XML data stored.\r\n" +
- "Alerts previously relayed may relay again when the next heartbeat arrives.";
- }
- }
-
- public static string WatchdogForcedRestartWarning(string lang)
- {
- switch (lang)
- {
- case "fr":
- return "Cela fait plus de 5 minutes depuis le dernier battement de coeur. Si aucun battement de coeur n'est détecté dans les 5 minutes supplémentaires, le programme redémarrera automatiquement.";
- case "en":
- default:
- return "It has been more than 5 minutes since the last heartbeat. If a heartbeat is not detected within 5 additional minutes, the program will automatically restart.";
- }
- }
-
- public static string WatchdogForceRestartingProcess(string lang)
- {
- switch (lang)
- {
- case "fr":
- return "Le battement de coeur a été présumé mort. Redémarrage de tous les services dans quelques instants.";
- case "en":
- default:
- return "The heartbeat has been presumed dead. Restarting all services in a few moments.";
- }
- }
-
- public static string WatchingFiles(string lang)
- {
- switch (lang)
- {
- case "fr":
- return "Surveillance du répertoire pour les alertes.";
- case "en":
- default:
- return "Watching directory for alerts.";
- }
- }
-
- public static string HeartbeatDetected(string lang)
- {
- switch (lang)
- {
- case "fr":
- return "Battement de coeur détecté.";
- case "en":
- default:
- return "Heartbeat detected.";
- }
- }
-
- public static string AlertDetected(string lang)
- {
- switch (lang)
- {
- case "fr":
- return "Alerte détectée.";
- case "en":
- default:
- return "Alert detected.";
- }
- }
-
- public static string ConnectedToServer(string lang, string host, int port)
- {
- switch (lang)
- {
- case "fr":
- return $"Connecté à {host} sur le port {port}.";
- case "en":
- default:
- return $"Connected to {host} on port {port}.";
- }
- }
-
- public static string HostTimedOut(string lang, string host)
- {
- switch (lang)
- {
- case "fr":
- return $"{host} n'a envoyé aucune donnée dans le délai minimum.";
- case "en":
- default:
- return $"{host} hasn't sent any data within the minimum time limit.";
- }
- }
-
- public static string RestartingAfterException(string lang)
- {
- switch (lang)
- {
- case "fr":
- return "Le fil de capture est mort de façon inattendue. Il redémarrera automatiquement dans quelques instants.";
- case "en":
- default:
- return "The capture thread has died unexpectedly. It will automatically restart in a few moments.";
- }
- }
-
- public static string FileDownloaded(string lang, string directory, string filename, string host)
- {
- switch (lang)
- {
- case "fr":
- return $"Fichier enregistré : {directory}\\{filename} | De : {host}";
- case "en":
- default:
- return $"File saved: {directory}\\{filename} | From: {host}";
- }
- }
-
- public static string DownloadingFiles(string lang)
- {
- switch (lang)
- {
- case "fr":
- return "Téléchargement de fichiers à partir du signal cardiaque reçu.";
- case "en":
- default:
- return "Downloading files from received heartbeat.";
- }
- }
-
- public static string FileIgnoredDueToMatchingPair(string lang)
- {
- switch (lang)
- {
- case "fr":
- return "Paire correspondante détectée. Ce fichier ne sera pas traité davantage.";
- case "en":
- default:
- return "Matching pair detected. This file won't be processed.";
- }
- }
-
- public static string FilesIgnoredDueToMatchingPairs(string lang, int count)
- {
- switch (lang)
- {
- case "fr":
- return $"{count} fichier(s) avaient des paires correspondantes et n'ont pas été traités.";
- case "en":
- default:
- return $"{count} file(s) had matching pairs, and were not processed.";
- }
- }
-
- public static string FileIgnoredDueToPreferences(string lang)
- {
- switch (lang)
- {
- case "fr":
- return "Les préférences ne permettent pas le relais de cette alerte. Ce fichier ne sera pas traité davantage.";
- case "en":
- default:
- return "Preferences do not allow the relay of this alert. This file won't be processed.";
- }
- }
-
- public static string GeneratingProductText(string lang)
- {
- switch (lang)
- {
- case "fr":
- return "Génération de texte en cours.";
- case "en":
- default:
- return "Generating text.";
- }
- }
-
- public static string GeneratingProductAudio(string lang)
- {
- switch (lang)
- {
- case "fr":
- return "Génération audio en cours.";
- case "en":
- default:
- return "Generating audio.";
- }
- }
-
- public static string GeneratedProductEmpty(string lang)
- {
- switch (lang)
- {
- case "fr":
- return "Il n’y avait rien à générer.";
- case "en":
- default:
- return "There was nothing to generate.";
- }
- }
-
- public static string PlayingAudio(string lang)
- {
- switch (lang)
- {
- case "fr":
- return "La lecture audio a commencé.";
- case "en":
- default:
- return "Audio playback started.";
- }
- }
-
- public static string CapturedFromFileWatcher(string lang)
- {
- switch (lang)
- {
- case "fr":
- return "File Watcher a capturé un fichier :";
- case "en":
- default:
- return "File Watcher captured a file:";
- }
- }
-
- public static string ProcessingStream(string lang)
- {
- switch (lang)
- {
- case "fr":
- return "Flux de données de traitement.";
- case "en":
- default:
- return "Processing data stream.";
- }
- }
-
- public static string ProcessedStream(string lang, int total, DateTime started)
- {
- switch (lang)
- {
- case "fr":
- return $"Traité {total} dans {(DateTime.Now - started).TotalSeconds}s.";
- case "en":
- default:
- return $"Processed {total} in {(DateTime.Now - started).TotalSeconds}s.";
- }
- }
-
- public static string LastDataReceived(string lang)
- {
- switch (lang)
- {
- case "fr":
- return "Dernières données reçues :";
- case "en":
- default:
- return "Last data received:";
- }
- }
- }
-
- public static class SVDictionaryLegacy
- {
- private static bool isFrench = false;
-
- public static bool IsFrench
- {
- get => isFrench;
- set => isFrench = value;
- }
-
- public static string RecoveredFromFailure
- {
- get => IsFrench
- ? "Le chien de garde a récemment détecté un problème et a effacé toutes les données XML stockées.\r\n" +
- "Les alertes précédemment relayées peuvent être relayées à nouveau lorsque le prochain battement de coeur arrive."
- : "The watchdog has recently detected a problem, and has cleared all XML data stored.\r\n" +
- "Alerts previously relayed may relay again when the next heartbeat arrives.";
- }
-
- public static string WatchdogForcedRestartWarning
- {
- get => IsFrench
- ? "Cela fait plus de 5 minutes depuis le dernier battement de coeur. Si aucun battement de coeur n'est détecté dans les 5 minutes supplémentaires, le programme redémarrera automatiquement."
- : "It has been more than 5 minutes since the last heartbeat. If a heartbeat is not detected within 5 additional minutes, the program will automatically restart.";
- }
-
- public static string WatchdogForceRestartingProcess
- {
- get => IsFrench
- ? "Le battement de coeur a été présumé mort. Redémarrage de tous les services dans quelques instants."
- : "The heartbeat has been presumed dead. Restarting all services in a few moments.";
- }
-
- public static string WatchingFiles
- {
- get => IsFrench
- ? "Surveillance du répertoire pour les alertes."
- : "Watching directory for alerts.";
- }
-
- public static string HeartbeatDetected
- {
- get => IsFrench
- ? "Battement de coeur détecté."
- : "Heartbeat detected.";
- }
-
- public static string AlertDetected
- {
- get => IsFrench
- ? "Battement de coeur détecté."
- : "Alert detected.";
- }
-
- public static string ConnectedToServer(string host, int port)
- {
- return IsFrench
- ? $"Connecté à {host} sur le port {port}."
- : $"Connected to {host} on port {port}.";
- }
-
- public static string HostTimedOut(string host)
- {
- return IsFrench
- ? $"{host} n'a envoyé aucune donnée dans le délai minimum."
- : $"{host} hasn't sent any data within the minimum time limit.";
- }
-
- public static string RestartingAfterException
- {
- get => IsFrench
- ? "Le fil de capture est mort de façon inattendue. Il redémarrera automatiquement dans quelques instants."
- : "The capture thread has died unexpectedly. It will automatically restart in a few moments.";
- }
-
- public static string FileDownloaded(string directory, string filename, string host)
- {
- return IsFrench
- ? $"Fichier enregistré : {directory}\\{filename} | De : {host}"
- : $"File saved: {directory}\\{filename} | From: {host}";
- }
-
- public static string DownloadingFiles
- {
- get => IsFrench
- ? "Téléchargement de fichiers à partir du signal cardiaque reçu."
- : "Downloading files from received heartbeat.";
- }
-
- public static string FileIgnoredDueToMatchingPair
- {
- get => IsFrench
- ? "Paire correspondante détectée. Ce fichier ne sera pas traité davantage."
- : "Matching pair detected. This file won't be processed.";
- }
-
- public static string FilesIgnoredDueToMatchingPairs(int count)
- {
- return IsFrench
- ? $"{count} fichier(s) avaient des paires correspondantes et n'ont pas été traités."
- : $"{count} file(s) had matching pairs, and were not processed.";
- }
-
- public static string FileIgnoredDueToPreferences
- {
- get => IsFrench
- ? "Les préférences ne permettent pas le relais de cette alerte. Ce fichier ne sera pas traité davantage."
- : "Preferences do not allow the relay of this alert. This file won't be processed.";
- }
-
- public static string GeneratingProductText
- {
- get => IsFrench
- ? "Génération de texte en cours."
- : "Generating text.";
- }
-
- public static string GeneratingProductAudio
- {
- get => IsFrench
- ? "Génération audio en cours."
- : "Generating audio.";
- }
-
- public static string GeneratedProductEmpty
- {
- get => IsFrench
- ? "Il n’y avait rien à générer."
- : "There was nothing to generate.";
- }
-
- public static string PlayingAudio
- {
- get => IsFrench
- ? "La lecture audio a commencé."
- : "Audio playback started.";
- }
-
- public static string CapturedFromFileWatcher
- {
- get => IsFrench
- ? "File Watcher a capturé un fichier :"
- : "File Watcher captured a file:";
- }
-
- public static string ProcessingStream
- {
- get => IsFrench
- ? "Flux de données de traitement."
- : "Processing data stream.";
- }
- public static string ProcessedStream(int total, DateTime started)
- {
- return IsFrench
- ? $"Traité {total} dans {(DateTime.Now - started).TotalSeconds}s."
- : $"Processed {total} in {(DateTime.Now - started).TotalSeconds}s.";
- }
-
- public static string LastDataReceived
- {
- get => IsFrench
- ? "Dernières données reçues :"
- : "Last data received:";
}
}
}
\ No newline at end of file
diff --git a/SharpENDEC/Properties/AssemblyInfo.cs b/SharpENDEC/Properties/AssemblyInfo.cs
index 45abf4d..db53ac2 100644
--- a/SharpENDEC/Properties/AssemblyInfo.cs
+++ b/SharpENDEC/Properties/AssemblyInfo.cs
@@ -32,4 +32,4 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
diff --git a/SharpENDEC/Properties/Settings.Designer.cs b/SharpENDEC/Properties/Settings.Designer.cs
index fd37056..613459a 100644
--- a/SharpENDEC/Properties/Settings.Designer.cs
+++ b/SharpENDEC/Properties/Settings.Designer.cs
@@ -13,7 +13,7 @@ namespace SharpENDEC.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.9.0.0")]
- internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+ public sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@@ -133,7 +133,7 @@ public bool severityModerate {
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Configuration.DefaultSettingValueAttribute("False")]
+ [global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool severityMinor {
get {
return ((bool)(this["severityMinor"]));
@@ -145,7 +145,7 @@ public bool severityMinor {
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Configuration.DefaultSettingValueAttribute("False")]
+ [global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool severityUnknown {
get {
return ((bool)(this["severityUnknown"]));
@@ -218,7 +218,7 @@ public bool urgencyPast {
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Configuration.DefaultSettingValueAttribute("en")]
+ [global::System.Configuration.DefaultSettingValueAttribute("english")]
public string CurrentLanguage {
get {
return ((string)(this["CurrentLanguage"]));
@@ -242,7 +242,7 @@ public int SoundDevice {
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Configuration.DefaultSettingValueAttribute("Tom")]
+ [global::System.Configuration.DefaultSettingValueAttribute("Ava")]
public string SpeechVoice {
get {
return ((string)(this["SpeechVoice"]));
@@ -291,5 +291,30 @@ public bool WirelessAlertModeSpeech {
this["CanadianServers"] = value;
}
}
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("120")]
+ public int EnforceMaximumTime {
+ get {
+ return ((int)(this["EnforceMaximumTime"]));
+ }
+ set {
+ this["EnforceMaximumTime"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("\r\n")]
+ public global::System.Collections.Specialized.StringCollection EnforceEventBlacklist {
+ get {
+ return ((global::System.Collections.Specialized.StringCollection)(this["EnforceEventBlacklist"]));
+ }
+ set {
+ this["EnforceEventBlacklist"] = value;
+ }
+ }
}
}
diff --git a/SharpENDEC/Properties/Settings.settings b/SharpENDEC/Properties/Settings.settings
index 1a89e59..5e8c9ba 100644
--- a/SharpENDEC/Properties/Settings.settings
+++ b/SharpENDEC/Properties/Settings.settings
@@ -30,10 +30,10 @@
True
- False
+ True
- False
+ True
True
@@ -52,13 +52,13 @@
<ArrayOfString xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
- en
+ english
-1
- Tom
+ Ava
False
@@ -73,5 +73,12 @@
<string>streaming2.naad-adna.pelmorex.com</string>
</ArrayOfString>
+
+ 120
+
+
+ <?xml version="1.0" encoding="utf-16"?>
+<ArrayOfString xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
+
\ No newline at end of file
diff --git a/SharpENDEC/Settings.cs b/SharpENDEC/Settings.cs
index c0e056d..74698a1 100644
--- a/SharpENDEC/Settings.cs
+++ b/SharpENDEC/Settings.cs
@@ -1,13 +1,11 @@
-using System;
-
-namespace SharpENDEC.Properties
+namespace SharpENDEC.Properties
{
// This class allows you to handle specific events on the settings class:
// The SettingChanging event is raised before a setting's value is changed.
// The PropertyChanged event is raised after a setting's value is changed.
// The SettingsLoaded event is raised after the setting values are loaded.
// The SettingsSaving event is raised before the setting values are saved.
- internal sealed partial class Settings
+ public sealed partial class Settings
{
public Settings()
@@ -18,12 +16,12 @@ public Settings()
private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e)
{
- Console.WriteLine($"{e.SettingName} = {e.NewValue}");
+ //ConsoleExt.WriteLine($"{e.SettingName} = {e.NewValue}");
}
private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e)
{
- Console.WriteLine("Settings saved!");
+ ConsoleExt.WriteLine("Saving is in progress. Do not close the application.");
}
}
}
diff --git a/SharpENDEC/SharpENDEC.csproj b/SharpENDEC/SharpENDEC.csproj
index 48bb9a7..3fe8c0c 100644
--- a/SharpENDEC/SharpENDEC.csproj
+++ b/SharpENDEC/SharpENDEC.csproj
@@ -9,7 +9,7 @@
Exe
SharpENDEC
SharpENDEC
- v4.8
+ v4.8.1
512
true
false
@@ -30,9 +30,10 @@
true
+
- AnyCPU
+ x64
true
full
false
@@ -40,6 +41,8 @@
DEBUG;TRACE
prompt
4
+ true
+ false
x64
@@ -213,6 +216,20 @@
+
+
+
+ Form
+
+
+ ConsoleForm.cs
+
+
+
+
+
+
+
Form
@@ -240,17 +257,26 @@
+
+
+
+ ConsoleForm.cs
+
AlertForm.cs
+ Designer
NotifyOverlay.cs
+ Designer
MainForm.cs
+ Designer
WeatherForm.cs
+ Designer
ResXFileCodeGenerator
@@ -264,7 +290,7 @@
- SettingsSingleFileGenerator
+ PublicSettingsSingleFileGenerator
Settings.Designer.cs
@@ -272,6 +298,7 @@
Settings.settings
True
+
@@ -279,7 +306,6 @@
-
@@ -315,7 +341,10 @@ del "$(TargetDir)NAudio.xml"
del "$(TargetDir)Newtonsoft.Json.xml"
-del "$(TargetDir)System.Diagnostics.DiagnosticSource.xml"
-
+del "$(TargetDir)System.Diagnostics.DiagnosticSource.xml"
+
+
+ cd $(ProjectDir)
+powershell -ExecutionPolicy Bypass -File "$(ProjectDir)UpdateVersionInfo.ps1"
\ No newline at end of file
diff --git a/SharpENDEC/Unused/WeatherForm.cs b/SharpENDEC/Unused/WeatherForm.cs
index e16db32..c76151f 100644
--- a/SharpENDEC/Unused/WeatherForm.cs
+++ b/SharpENDEC/Unused/WeatherForm.cs
@@ -95,7 +95,7 @@ private void FrenchLangCheckBox_CheckedChanged(object sender, EventArgs e)
{
//Settings.Default.CurrentLanguage = ((CheckBox)sender).Checked;
//Settings.Default.Save();
- //SVDictionary.IsFrench = ((CheckBox)sender).Checked;
+ //LanguageStrings.IsFrench = ((CheckBox)sender).Checked;
}
private void sTest_CheckedChanged(object sender, EventArgs e)
diff --git a/SharpENDEC/UpdateVersionInfo.ps1 b/SharpENDEC/UpdateVersionInfo.ps1
new file mode 100644
index 0000000..376528a
--- /dev/null
+++ b/SharpENDEC/UpdateVersionInfo.ps1
@@ -0,0 +1,22 @@
+$versionInfoTemplatePath = ".\VersionInfoTemplate.cs"
+$versionInfoPath = ".\VersionInfo.cs"
+
+$currentDate = Get-Date -Format "yyyy-MM-dd"
+$currentTime = Get-Date -Format "HH:mm"
+$timeZone = Get-TimeZone
+$timeId = $timeZone.Id
+
+$content = Get-Content $versionInfoTemplatePath
+$contentNew = Get-Content $versionInfoPath
+
+$currentBuildNumber = [regex]::Match($contentNew, 'public const int BuildNumber = (\d+);').Groups[1].Value
+$incrementedBuildNumber = [int]$currentBuildNumber + 1
+
+$content = $content -replace 'BuiltOnDate = "";', "BuiltOnDate = `"$currentDate`";"
+$content = $content -replace 'BuiltOnTime = "";', "BuiltOnTime = `"$currentTime`";"
+$content = $content -replace 'BuiltTimeZone = "";', "BuiltTimeZone = `"$timeId`";"
+$content = $content -replace 'public const int BuildNumber = \d+;', "public const int BuildNumber = $incrementedBuildNumber;"
+$content = $content -replace 'class VersionInfoTemplate', 'class VersionInfo'
+$content = $content -replace '// Do not change consts!', '// Use VersionInfoTemplate.cs!'
+
+Set-Content $versionInfoPath $content
diff --git a/SharpENDEC/VersionInfo.cs b/SharpENDEC/VersionInfo.cs
new file mode 100644
index 0000000..f0a2847
--- /dev/null
+++ b/SharpENDEC/VersionInfo.cs
@@ -0,0 +1,35 @@
+using System.Diagnostics;
+
+namespace SharpENDEC
+{
+ public static class VersionInfo
+ {
+ // This file contains the version information. It should not be modified at runtime.
+ // You can change the release, minor, and cutting edge variables.
+ // ---
+ // Use VersionInfoTemplate.cs!
+ public const int BuildNumber = 596;
+ public const string BuiltOnDate = "2024-10-20";
+ public const string BuiltOnTime = "09:14";
+ public const string BuiltTimeZone = "Eastern Standard Time";
+ public static readonly int ReleaseVersion = 2;
+ public static readonly int MinorVersion = 0;
+ public static readonly bool IsCuttingEdge = false;
+ public static string FriendlyVersion
+ {
+ get
+ {
+ if (!IsCuttingEdge)
+ {
+ return $"SharpENDEC | Release {ReleaseVersion}.{MinorVersion} (Build {BuildNumber}) | Built on {BuiltOnDate} {BuiltOnTime} ({BuiltTimeZone})";
+ }
+ else
+ {
+ if (Debugger.IsAttached) return $"SharpENDEC | Cutting Edge {ReleaseVersion}.{MinorVersion}-c (Build {BuildNumber}) | Built on {BuiltOnDate} {BuiltOnTime} ({BuiltTimeZone})";
+ else return $"SharpENDEC | Cutting Edge {ReleaseVersion}.{MinorVersion}-c (Build {BuildNumber}) | Built on {BuiltOnDate} {BuiltOnTime} ({BuiltTimeZone})\r\n" +
+ $"Debugger Attached | Is Logging: {Debugger.IsLogging()}";
+ }
+ }
+ }
+ }
+}
diff --git a/SharpENDEC/VersionInfoTemplate.cs b/SharpENDEC/VersionInfoTemplate.cs
new file mode 100644
index 0000000..def75a8
--- /dev/null
+++ b/SharpENDEC/VersionInfoTemplate.cs
@@ -0,0 +1,35 @@
+using System.Diagnostics;
+
+namespace SharpENDEC
+{
+ public static class VersionInfoTemplate
+ {
+ // This file contains the version information. It should not be modified at runtime.
+ // You can change the release, minor, and cutting edge variables.
+ // ---
+ // Do not change consts!
+ public const int BuildNumber = 0;
+ public const string BuiltOnDate = "";
+ public const string BuiltOnTime = "";
+ public const string BuiltTimeZone = "";
+ public static readonly int ReleaseVersion = 2;
+ public static readonly int MinorVersion = 0;
+ public static readonly bool IsCuttingEdge = false;
+ public static string FriendlyVersion
+ {
+ get
+ {
+ if (!IsCuttingEdge)
+ {
+ return $"SharpENDEC | Release {ReleaseVersion}.{MinorVersion} (Build {BuildNumber}) | Built on {BuiltOnDate} {BuiltOnTime} ({BuiltTimeZone})";
+ }
+ else
+ {
+ if (Debugger.IsAttached) return $"SharpENDEC | Cutting Edge {ReleaseVersion}.{MinorVersion}-c (Build {BuildNumber}) | Built on {BuiltOnDate} {BuiltOnTime} ({BuiltTimeZone})";
+ else return $"SharpENDEC | Cutting Edge {ReleaseVersion}.{MinorVersion}-c (Build {BuildNumber}) | Built on {BuiltOnDate} {BuiltOnTime} ({BuiltTimeZone})\r\n" +
+ $"Debugger Attached | Is Logging: {Debugger.IsLogging()}";
+ }
+ }
+ }
+ }
+}
\ No newline at end of file